mirror of
https://github.com/jkdansereau/goldeneye-pc-port.git
synced 2026-10-24 00:02:45 +02:00
port: click-to-lock mouse capture + absolute menu cursor + aim retune (D180)
WI-1: Input.MouseCaptureMode (0 = legacy always-grab, default; 1 = Quake/Nightdive-style click-to-lock). In mode 1 the OS cursor is free until a click lands in the game window; ESC, focus loss, or entering any front-end menu frees it again, and re-entering a stage while armed re-locks so unpausing needs no click. Mouse buttons are withheld from the game while the cursor is free in-stage (no phantom fire). Controller input paths are untouched. reconcileGrab() runs once per controller-0 poll off the game's current_menu global (UI context only). WI-2: when capture mode is on and the cursor is free in a menu, the D165/D169 pointer P-controller takes its target from the real cursor's absolute window position mapped onto the live virtual front-end rect (getPlayer_c_screen*), for true 1:1 tracking. The relative-delta path (legacy / grabbed) is unchanged. B3: Input.MouseAimSpeed default 25 -> 16 (aim mode still overshot at 25). Build 241/241; -level_09 framediff 3/3 within threshold (unregressed); GE_STARTMENU menu boot crash-free. Feel-checks owed (headless can't drive the mouse). Claude-Session: https://claude.ai/code/session_01GULf6knbsqfsnW39tMr9WT
This commit is contained in:
1 parent
91b7c5aa4e
commit
ad74865404
3 files changed
+132
-9
No files matched your search
@@ -44,6 +44,16 @@ unsigned inputComputePad(int idx, signed char *stick_x, signed char *stick_y);
|
||||
* disabled in config. */
|
||||
void inputSetMouseGrab(int on);
|
||||
|
||||
/* WI-1 click-to-lock cursor capture (Input.MouseCaptureMode = 1). The host
|
||||
* event pump calls inputNotifyClick() when a mouse button goes down inside the
|
||||
* game window (arms + locks the cursor), and inputReleaseCapture() when ESC is
|
||||
* pressed (frees it; returns 1 if it consumed the key). inputMouseCaptureActive()
|
||||
* is true when capture mode is on and the cursor is currently free -- the pump
|
||||
* uses it to decide whether a click should be swallowed rather than passed on. */
|
||||
void inputNotifyClick(void);
|
||||
int inputReleaseCapture(void);
|
||||
int inputMouseCaptureActive(void);
|
||||
|
||||
/* Queue a mouse-wheel weapon-cycle input (one short A-button press). Sign is
|
||||
* ignored -- GE only cycles forward on a bare A edge. */
|
||||
void inputPostWheel(int notches);
|
||||
|
||||
+104
-9
@@ -161,14 +161,29 @@ extern float cursor_h_pos, cursor_v_pos;
|
||||
#define MENU_EST_DELTA 1.0 /* deltaEst per poll (front.c integrates ~1 tick/frame) */
|
||||
#define MENU_MOUSE_TO_PX 1.0 /* device px -> virtual cursor px (x MenuPointerSpeed/100) */
|
||||
|
||||
static void applyGrab(int want);
|
||||
static void reconcileGrab(int menuMode);
|
||||
|
||||
static int numControllers = 1;
|
||||
static int connectedMask = 0x1; /* controller 0 always present */
|
||||
|
||||
static SDL_GameController *pads[MAX_PADS];
|
||||
|
||||
static int mouseEnabled = 1;
|
||||
static int mouseGrabbed = 1; /* released while the window is unfocused */
|
||||
static int mouseAimSpeed = 25; /* aim-mode sensitivity, percent (B3: was 50, overshot) */
|
||||
static int mouseGrabbed = 1; /* released while the window is unfocused */
|
||||
|
||||
/* WI-1: Quake-style click-to-lock cursor capture.
|
||||
* MouseCaptureMode 0 (default) = legacy: cursor is grabbed whenever the
|
||||
* window has focus and MouseEnabled is set (prior behaviour, byte-exact).
|
||||
* MouseCaptureMode 1 = native-PC: the cursor is free until you click in the
|
||||
* game window; ESC (or focus loss, or opening a menu) frees it again.
|
||||
* Re-entering a stage while still "armed" re-locks automatically so
|
||||
* unpausing / starting a level does not need a click.
|
||||
* Controller input is entirely independent of all of this. */
|
||||
static int mouseCaptureMode = 0;
|
||||
static int captureArmed = 0; /* user has clicked to lock (capture mode) */
|
||||
static int windowFocused = 1;
|
||||
static int mouseAimSpeed = 16; /* aim-mode sensitivity, percent (B3: 50 -> 25 M-29 -> 16; still overshot at 25) */
|
||||
static int aimBand = 20; /* aim mode: usable stick range above the 60 gate */
|
||||
static int mouseTurnSpeed = 100; /* hipfire yaw sensitivity, percent */
|
||||
static int menuPointerSpeed = 100; /* front-end cursor speed, percent */
|
||||
@@ -395,8 +410,9 @@ int inputInit(void)
|
||||
}
|
||||
inputOpenPads();
|
||||
|
||||
/* Relative mouse mode for mouse-look. ESC still quits (video.c). */
|
||||
mouseGrabbed = mouseEnabled;
|
||||
/* Relative mouse mode for mouse-look. In click-to-lock mode we start
|
||||
* released and wait for a click in the window (video.c -> inputNotifyClick). */
|
||||
mouseGrabbed = mouseEnabled && !mouseCaptureMode;
|
||||
if (mouseEnabled) {
|
||||
if (mouseRawInput) {
|
||||
/* Feed the raw device delta straight through: no OS pointer
|
||||
@@ -406,7 +422,7 @@ int inputInit(void)
|
||||
SDL_SetHint(SDL_HINT_MOUSE_RELATIVE_MODE_WARP, "0");
|
||||
sysLogPrintf(LOG_INFO, "input: raw mouse input (no OS pointer accel)");
|
||||
}
|
||||
SDL_SetRelativeMouseMode(SDL_TRUE);
|
||||
SDL_SetRelativeMouseMode(mouseGrabbed ? SDL_TRUE : SDL_FALSE);
|
||||
/* Drain the initial jump. */
|
||||
SDL_GetRelativeMouseState(NULL, NULL);
|
||||
}
|
||||
@@ -487,6 +503,15 @@ unsigned inputComputePad(int idx, signed char *stick_x, signed char *stick_y)
|
||||
int menuMode = (current_menu != GE_MENU_RUN_STAGE &&
|
||||
current_menu != GE_MENU_INVALID);
|
||||
|
||||
reconcileGrab(menuMode);
|
||||
|
||||
/* Click-to-lock, in a stage, cursor free: the mouse buttons must not
|
||||
* reach the game (no phantom fire) -- the first click only re-locks
|
||||
* (handled in video.c -> inputNotifyClick). Menus keep their buttons. */
|
||||
if (mouseCaptureMode && !mouseGrabbed && !menuMode) {
|
||||
mb = 0;
|
||||
}
|
||||
|
||||
/* GE default control (1.1): stick Y = move fwd/back, stick X = turn,
|
||||
* C-left/right = sidestep, C-up/down = look. FPS layout: W/S move,
|
||||
* A/D strafe (C-buttons), mouse X turns (stick X), mouse Y looks. */
|
||||
@@ -575,9 +600,33 @@ unsigned inputComputePad(int idx, signed char *stick_x, signed char *stick_y)
|
||||
menuEstV = menuTgtV = cursor_v_pos;
|
||||
hipPitchPhase = 0.0;
|
||||
}
|
||||
/* WI-2: with click-to-lock the front end has a real free OS
|
||||
* cursor. Map its absolute window position straight onto the
|
||||
* virtual front-end rect so the game crosshair tracks it 1:1
|
||||
* (no drift -- the P-controller below just chases this target).
|
||||
* The relative-delta path (legacy / grabbed) is unchanged. */
|
||||
int haveAbs = 0;
|
||||
if (mouseCaptureMode && !mouseGrabbed) {
|
||||
int mx = 0, my = 0;
|
||||
SDL_GetMouseState(&mx, &my);
|
||||
SDL_Window *w = SDL_GetMouseFocus();
|
||||
int ww = 0, wh = 0;
|
||||
if (w) SDL_GetWindowSize(w, &ww, &wh);
|
||||
if (ww > 0 && wh > 0) {
|
||||
double fx = (double)mx / (double)ww;
|
||||
double fy = (double)my / (double)wh;
|
||||
if (fx < 0.0) fx = 0.0; else if (fx > 1.0) fx = 1.0;
|
||||
if (fy < 0.0) fy = 0.0; else if (fy > 1.0) fy = 1.0;
|
||||
menuTgtH = loH + fx * (hiH - loH);
|
||||
menuTgtV = loV + fy * (hiV - loV);
|
||||
haveAbs = 1;
|
||||
}
|
||||
}
|
||||
double s = (menuPointerSpeed / 100.0) * MENU_MOUSE_TO_PX;
|
||||
menuTgtH += edx * s;
|
||||
menuTgtV += dyLook * s; /* dyLook > 0 => cursor moves down (+V) */
|
||||
if (!haveAbs) {
|
||||
menuTgtH += edx * s;
|
||||
menuTgtV += dyLook * s; /* dyLook > 0 => cursor moves down (+V) */
|
||||
}
|
||||
if (menuTgtH < loH) menuTgtH = loH;
|
||||
if (menuTgtH > hiH) menuTgtH = hiH;
|
||||
if (menuTgtV < loV) menuTgtV = loV;
|
||||
@@ -711,9 +760,9 @@ unsigned inputComputePad(int idx, signed char *stick_x, signed char *stick_y)
|
||||
return button;
|
||||
}
|
||||
|
||||
void inputSetMouseGrab(int on)
|
||||
static void applyGrab(int want)
|
||||
{
|
||||
int want = on && mouseEnabled;
|
||||
want = want && mouseEnabled;
|
||||
if (want == mouseGrabbed) {
|
||||
return;
|
||||
}
|
||||
@@ -725,6 +774,51 @@ void inputSetMouseGrab(int on)
|
||||
mouseDX = mouseDY = 0.0;
|
||||
}
|
||||
|
||||
/* Reconcile the SDL grab state with what the current mode wants. Called once
|
||||
* per controller-0 poll (menuMode known there) and from the notify hooks. */
|
||||
static void reconcileGrab(int menuMode)
|
||||
{
|
||||
int want;
|
||||
if (!mouseCaptureMode) {
|
||||
want = windowFocused; /* legacy */
|
||||
} else {
|
||||
want = captureArmed && windowFocused && !menuMode; /* click-to-lock */
|
||||
}
|
||||
applyGrab(want);
|
||||
}
|
||||
|
||||
/* video.c focus events. In legacy mode this directly grabs/releases; in
|
||||
* capture mode it just records focus and lets reconcileGrab() decide. */
|
||||
void inputSetMouseGrab(int on)
|
||||
{
|
||||
windowFocused = on ? 1 : 0;
|
||||
reconcileGrab(0); /* menuMode re-checked on the next poll anyway */
|
||||
}
|
||||
|
||||
/* A mouse click landed in the game window (video.c). In click-to-lock mode
|
||||
* this arms + grabs; otherwise it is ignored (the game sees the click). */
|
||||
void inputNotifyClick(void)
|
||||
{
|
||||
if (mouseCaptureMode && mouseEnabled && windowFocused) {
|
||||
captureArmed = 1;
|
||||
reconcileGrab(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* ESC pressed (video.c). In click-to-lock mode, releases the cursor and
|
||||
* reports 1 so the caller can swallow the key; otherwise reports 0. */
|
||||
int inputReleaseCapture(void)
|
||||
{
|
||||
if (mouseCaptureMode && mouseGrabbed) {
|
||||
captureArmed = 0;
|
||||
applyGrab(0);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int inputMouseCaptureActive(void) { return mouseCaptureMode && !mouseGrabbed; }
|
||||
|
||||
void inputPostWheel(int notches)
|
||||
{
|
||||
if (notches < 0) notches = -notches; /* both directions cycle forward */
|
||||
@@ -762,6 +856,7 @@ int inputGetNumControllers(void)
|
||||
PD_CONSTRUCTOR static void inputConfigInit(void)
|
||||
{
|
||||
configRegisterInt("Input.MouseEnabled", &mouseEnabled, 0, 1);
|
||||
configRegisterInt("Input.MouseCaptureMode", &mouseCaptureMode, 0, 1);
|
||||
configRegisterInt("Input.MouseAimSpeed", &mouseAimSpeed, 1, 500);
|
||||
configRegisterInt("Input.AimBand", &aimBand, 5, 40);
|
||||
configRegisterInt("Input.MouseTurnSpeed", &mouseTurnSpeed, 1, 500);
|
||||
|
||||
@@ -71,8 +71,16 @@ static int cfgWinX = -1;
|
||||
static int cfgWinY = -1;
|
||||
static int cfgWinMax = 0;
|
||||
|
||||
/*
|
||||
* [Game] gameplay-cosmetic knobs (route-(b) hooks in src/, findings D181).
|
||||
* portScreenShakeScale multiplies every viShake() amplitude (src/fr.c).
|
||||
* 1.0f = original behaviour (headless golden dumps unaffected).
|
||||
*/
|
||||
f32 portScreenShakeScale = 1.0f;
|
||||
|
||||
PD_CONSTRUCTOR static void videoConfigInit(void)
|
||||
{
|
||||
configRegisterFloat("Game.ScreenShakeIntensity", &portScreenShakeScale, 0.0f, 10.0f);
|
||||
configRegisterInt("Video.VSync", &cfgVSync, 0, 1);
|
||||
configRegisterInt("Video.FpsCap", &cfgFpsCap, 0, 1000);
|
||||
configRegisterInt("Video.MSAA", &cfgMSAA, 1, 8);
|
||||
@@ -223,8 +231,18 @@ void videoPumpEvents(void)
|
||||
exit(0);
|
||||
} else if (ev.key.keysym.sym == SDLK_F12 && !ev.key.repeat) {
|
||||
screenshotReq = 1;
|
||||
} else if (ev.key.keysym.sym == SDLK_ESCAPE && !ev.key.repeat) {
|
||||
/* WI-1: in click-to-lock mode ESC frees the captured cursor
|
||||
* (and is swallowed); otherwise it falls through to input.c
|
||||
* where it feeds the N64 B button (D145). */
|
||||
inputReleaseCapture();
|
||||
}
|
||||
break;
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
/* WI-1: a click in the window (re)locks the cursor in
|
||||
* click-to-lock mode; a no-op otherwise. */
|
||||
inputNotifyClick();
|
||||
break;
|
||||
case SDL_MOUSEWHEEL:
|
||||
inputPostWheel(ev.wheel.y); /* weapon cycle */
|
||||
break;
|
||||
|
||||
Reference in new issue
Block a user