mirror of
https://github.com/jkdansereau/goldeneye-pc-port.git
synced 2026-10-23 15:52:42 +02:00
D118: implement SDL input layer (kbd/mouse/gamepad -> N64 pad)
port/src/input.c was a stub; input only worked via libultra.c's minimal contSnapshotFromKeyboard (no C-buttons, mouse, or gamepad). - input.c: keyboard+mouse + SDL_GameController -> OSContPad. Analog stick = move, C-buttons = aim. Mouse-look bridged to digital C-buttons via a clamped per-axis accumulator (proportional press dwell). RMB/LT = aim mode, LMB/RT = fire. Config: ge007.ini [Input] MouseEnabled / MouseAimSpeed / MouseInvertY. - input.h: add inputConnectedMask() + inputComputePad(). - libultra.c SI section: contSnapshotFromKeyboard() now delegates to the input module (single source of controller state); osContGetReadData() fills all MAXCONTROLLERS channels, not just controller 0. - GE_INPUTLOG=1 gates a per-poll OSContPad trace (zero-cost when unset). Build green (ntsc-final); boots -level_09 crash-free 35s. Live input untested from headless agent - human playtest owed.
This commit is contained in:
1 parent
06c601f9b3
commit
8337a87fb2
3 files changed
+345
-67
No files matched your search
@@ -28,6 +28,16 @@ void inputUpdate(void);
|
||||
/* Number of controllers currently "connected" (1..4). */
|
||||
int inputGetNumControllers(void);
|
||||
|
||||
/* Bitmask of connected controllers (bit N = controller N). Bit 0 is always
|
||||
* set (keyboard/mouse). Consumed by libultra.c's osContInit. */
|
||||
int inputConnectedMask(void);
|
||||
|
||||
/* Compute the N64 button mask + analog stick for controller `idx`.
|
||||
* Returns the 16-bit CONT_* button mask; writes the stick (-80..80) through
|
||||
* the out params. Reads current SDL keyboard/mouse/gamepad state plus the
|
||||
* mouse-aim accumulator maintained by inputUpdate(). */
|
||||
unsigned inputComputePad(int idx, signed char *stick_x, signed char *stick_y);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
+314
-17
@@ -1,15 +1,70 @@
|
||||
/*
|
||||
* Input: SDL2 keyboard/mouse/gamepad -> N64 controller structs.
|
||||
* Input: SDL2 keyboard/mouse/gamepad -> N64 controller state (Phase 3, D118).
|
||||
*
|
||||
* The game reads controllers via osContInit / osContStartReadData (src/joy.c).
|
||||
* This module populates the N64 controller state from SDL events.
|
||||
* The game reads controllers via osContStartReadData / osContGetReadData
|
||||
* (src/joy.c). libultra.c's SI section calls into this module once per
|
||||
* controller poll: inputUpdate() refreshes SDL + accumulates the mouse-aim
|
||||
* delta, then inputComputePad() produces the 16-bit button mask + stick for
|
||||
* one controller. This is the single source of controller state on PC --
|
||||
* the old contSnapshotFromKeyboard() now delegates here.
|
||||
*
|
||||
* Modelled on the PD port's port/src/input.c (~1550 lines). Default bindings
|
||||
* follow the 1964GEPD / Xbox schemes (see the PD port README table).
|
||||
* Deliberately NOT a full port of pd_port/port/src/input.c (1551 lines): GE's
|
||||
* menu/config code never calls that module's VK/bind-string API, so this is a
|
||||
* focused implementation matching port/include/input.h plus the two helpers
|
||||
* libultra.c needs.
|
||||
*
|
||||
* STATUS: scaffolding stub — implement during Phase 3.
|
||||
* ------------------------------------------------------------------------
|
||||
* BINDING SCHEME (documented in docs/PCPortResearch.md sec F "D118")
|
||||
*
|
||||
* GE's default "1.1" control style: analog stick = move/strafe, the four
|
||||
* C-buttons = aim/turn/look (DIGITAL on N64), R = aim mode, Z = fire.
|
||||
*
|
||||
* Keyboard + mouse (controller 0):
|
||||
* W/S/A/D or arrows .. analog stick (move / strafe)
|
||||
* mouse motion ....... C-buttons (proportional pulse -- see below)
|
||||
* left mouse / LCtrl . Z trigger (fire)
|
||||
* right mouse / LShift R trigger (aim mode)
|
||||
* Space / Z / E ...... A button (action / use)
|
||||
* X / R / F ......... B button (reload / cancel)
|
||||
* Q ................. L trigger
|
||||
* Enter / Tab ....... Start
|
||||
*
|
||||
* Xbox / SDL_GameController (controller 0 merges pad 0 with kbd/mouse;
|
||||
* pads 1-3 -> controllers 1-3):
|
||||
* left stick ........ analog stick (move / strafe)
|
||||
* right stick ....... C-buttons (digital, 50% threshold -- aim)
|
||||
* right trigger ..... Z trigger (fire)
|
||||
* left trigger ...... R trigger (aim mode)
|
||||
* A / X ............. A button
|
||||
* B / Y ............. B button
|
||||
* LB ............... L trigger
|
||||
* RB ............... B button (reload)
|
||||
* D-pad ............ N64 D-pad
|
||||
* Start ............ Start
|
||||
*
|
||||
* MOUSE-LOOK -> C-BUTTON BRIDGE
|
||||
* GE has no analog-aim hook we can reach without touching src/ (game
|
||||
* logic). The only lever is OSContPad, so mouse motion is converted to
|
||||
* digital C-button presses. inputUpdate() integrates the relative mouse
|
||||
* delta (scaled by Input.MouseAimSpeed/100) into a signed accumulator per
|
||||
* axis, clamped to +/-AIM_ACCUM_CLAMP. Each poll inputComputePad() emits
|
||||
* the matching C-button while |accum| >= 0.5 and drains one unit. A large
|
||||
* flick therefore holds the C-button down for several frames
|
||||
* (proportional dwell) rather than a single blip.
|
||||
*
|
||||
* Limitations: (a) it is still digital -- GE applies its own accel curve
|
||||
* to a held C-button, so aim speed is not linear in mouse speed;
|
||||
* (b) very fast flicks saturate at the clamp (~8 frames of turn);
|
||||
* (c) diagonal precision is limited to the 8 C-button combinations.
|
||||
* Tunable via ge007.ini [Input] MouseAimSpeed / MouseInvertY. A true
|
||||
* analog aim path would need an #ifdef PORT hook in bondview.c and is
|
||||
* left as a TODO.
|
||||
* ------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#include "platform.h"
|
||||
@@ -17,32 +72,274 @@
|
||||
#include "config.h"
|
||||
#include "input.h"
|
||||
|
||||
/* N64 button bits (from PR/os.h -- duplicated here to avoid pulling os.h,
|
||||
* whose `u8 errno;` field collides with <errno.h>'s macro). */
|
||||
#define GE_CONT_A 0x8000
|
||||
#define GE_CONT_B 0x4000
|
||||
#define GE_CONT_G 0x2000 /* Z trigger */
|
||||
#define GE_CONT_START 0x1000
|
||||
#define GE_CONT_UP 0x0800
|
||||
#define GE_CONT_DOWN 0x0400
|
||||
#define GE_CONT_LEFT 0x0200
|
||||
#define GE_CONT_RIGHT 0x0100
|
||||
#define GE_CONT_L 0x0020
|
||||
#define GE_CONT_R 0x0010
|
||||
#define GE_CONT_E 0x0008 /* C-up */
|
||||
#define GE_CONT_D 0x0004 /* C-down */
|
||||
#define GE_CONT_C 0x0002 /* C-left */
|
||||
#define GE_CONT_F 0x0001 /* C-right */
|
||||
|
||||
#define MAX_PADS 4
|
||||
#define STICK_DEADZONE 7000
|
||||
#define STICK_MAX 80
|
||||
#define TRIG_THRESHOLD (30 * 256)
|
||||
#define RSTICK_THRESHOLD 0x4000
|
||||
#define AIM_ACCUM_CLAMP 8.0
|
||||
#define AIM_EMIT_THRESHOLD 0.5
|
||||
|
||||
static int numControllers = 1;
|
||||
static int connectedMask = 0x1; /* controller 0 always present */
|
||||
|
||||
static SDL_GameController *pads[MAX_PADS];
|
||||
|
||||
static int mouseEnabled = 1;
|
||||
static int mouseAimSpeed = 50; /* /100 -> mouse-px to accumulator units */
|
||||
static int mouseInvertY = 0;
|
||||
|
||||
static double aimAccumX = 0.0;
|
||||
static double aimAccumY = 0.0;
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
static void inputOpenPads(void)
|
||||
{
|
||||
connectedMask = 0x1;
|
||||
int n = SDL_NumJoysticks();
|
||||
for (int i = 0; i < n && i < MAX_PADS; ++i) {
|
||||
if (!SDL_IsGameController(i)) {
|
||||
continue;
|
||||
}
|
||||
if (pads[i]) {
|
||||
continue;
|
||||
}
|
||||
pads[i] = SDL_GameControllerOpen(i);
|
||||
if (pads[i]) {
|
||||
connectedMask |= (1 << i);
|
||||
sysLogPrintf(LOG_NOTE, "input: opened gamepad %d '%s' as controller %d",
|
||||
i, SDL_GameControllerName(pads[i]), i);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < MAX_PADS; ++i) {
|
||||
if (pads[i]) {
|
||||
connectedMask |= (1 << i);
|
||||
}
|
||||
}
|
||||
numControllers = 1;
|
||||
for (int i = 1; i < MAX_PADS; ++i) {
|
||||
if (connectedMask & (1 << i)) {
|
||||
numControllers = i + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int inputInit(void)
|
||||
{
|
||||
/* TODO(Phase 3):
|
||||
* - SDL_InitSubSystem(INPUT)
|
||||
* - open gamepad(s)
|
||||
* - set up relative mouse mode for mouse-look
|
||||
* - load bindings from config
|
||||
*/
|
||||
sysLogPrintf(LOG_INFO, "inputInit: TODO (Phase 3)");
|
||||
return 0;
|
||||
if (!SDL_WasInit(SDL_INIT_GAMECONTROLLER)) {
|
||||
if (SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER) != 0) {
|
||||
sysLogPrintf(LOG_WARNING, "input: SDL_INIT_GAMECONTROLLER failed: %s",
|
||||
SDL_GetError());
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_PADS; ++i) {
|
||||
pads[i] = NULL;
|
||||
}
|
||||
inputOpenPads();
|
||||
|
||||
/* Relative mouse mode for mouse-look. ESC still quits (video.c). */
|
||||
if (mouseEnabled) {
|
||||
SDL_SetRelativeMouseMode(SDL_TRUE);
|
||||
/* Drain the initial jump. */
|
||||
SDL_GetRelativeMouseState(NULL, NULL);
|
||||
}
|
||||
|
||||
sysLogPrintf(LOG_INFO, "input: ready (mask=0x%x, %d controller(s), aimSpeed=%d)",
|
||||
connectedMask, numControllers, mouseAimSpeed);
|
||||
return connectedMask;
|
||||
}
|
||||
|
||||
void inputDestroy(void)
|
||||
{
|
||||
/* TODO(Phase 3) */
|
||||
for (int i = 0; i < MAX_PADS; ++i) {
|
||||
if (pads[i]) {
|
||||
SDL_GameControllerClose(pads[i]);
|
||||
pads[i] = NULL;
|
||||
}
|
||||
}
|
||||
if (SDL_WasInit(SDL_INIT_GAMECONTROLLER)) {
|
||||
SDL_QuitSubSystem(SDL_INIT_GAMECONTROLLER);
|
||||
}
|
||||
}
|
||||
|
||||
/* Poll once per controller-read: refresh SDL device state and integrate the
|
||||
* mouse-aim delta into the accumulator. */
|
||||
void inputUpdate(void)
|
||||
{
|
||||
/* TODO(Phase 3): poll SDL events, write into the controller state that
|
||||
* osContStartReadData / osContRead will return. */
|
||||
SDL_GameControllerUpdate();
|
||||
|
||||
if (!mouseEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
int dx = 0, dy = 0;
|
||||
SDL_GetRelativeMouseState(&dx, &dy);
|
||||
|
||||
const double scale = (double)mouseAimSpeed / 100.0;
|
||||
aimAccumX += dx * scale;
|
||||
aimAccumY += dy * scale * (mouseInvertY ? -1.0 : 1.0);
|
||||
|
||||
if (aimAccumX > AIM_ACCUM_CLAMP) aimAccumX = AIM_ACCUM_CLAMP;
|
||||
if (aimAccumX < -AIM_ACCUM_CLAMP) aimAccumX = -AIM_ACCUM_CLAMP;
|
||||
if (aimAccumY > AIM_ACCUM_CLAMP) aimAccumY = AIM_ACCUM_CLAMP;
|
||||
if (aimAccumY < -AIM_ACCUM_CLAMP) aimAccumY = -AIM_ACCUM_CLAMP;
|
||||
}
|
||||
|
||||
static int scaleAxis(int v)
|
||||
{
|
||||
if (v > -STICK_DEADZONE && v < STICK_DEADZONE) {
|
||||
return 0;
|
||||
}
|
||||
if (v < 0) v += STICK_DEADZONE; else v -= STICK_DEADZONE;
|
||||
int out = (int)((long)v * STICK_MAX / (32767 - STICK_DEADZONE));
|
||||
if (out > STICK_MAX) out = STICK_MAX;
|
||||
if (out < -STICK_MAX) out = -STICK_MAX;
|
||||
return out;
|
||||
}
|
||||
|
||||
static int keyDown(const Uint8 *ks, SDL_Scancode sc)
|
||||
{
|
||||
return ks && ks[sc];
|
||||
}
|
||||
|
||||
/* Fill button mask + stick for controller idx. Returns the 16-bit mask. */
|
||||
unsigned inputComputePad(int idx, signed char *stick_x, signed char *stick_y)
|
||||
{
|
||||
unsigned button = 0;
|
||||
int sx = 0, sy = 0;
|
||||
|
||||
if (idx < 0 || idx >= MAX_PADS) {
|
||||
if (stick_x) *stick_x = 0;
|
||||
if (stick_y) *stick_y = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ---- keyboard + mouse: controller 0 only ---- */
|
||||
if (idx == 0) {
|
||||
const Uint8 *ks = SDL_GetKeyboardState(NULL);
|
||||
Uint32 mb = mouseEnabled ? SDL_GetMouseState(NULL, NULL) : 0;
|
||||
|
||||
if (keyDown(ks, SDL_SCANCODE_W) || keyDown(ks, SDL_SCANCODE_UP)) sy = STICK_MAX;
|
||||
if (keyDown(ks, SDL_SCANCODE_S) || keyDown(ks, SDL_SCANCODE_DOWN)) sy = -STICK_MAX;
|
||||
if (keyDown(ks, SDL_SCANCODE_A) || keyDown(ks, SDL_SCANCODE_LEFT)) sx = -STICK_MAX;
|
||||
if (keyDown(ks, SDL_SCANCODE_D) || keyDown(ks, SDL_SCANCODE_RIGHT)) sx = STICK_MAX;
|
||||
|
||||
if ((mb & SDL_BUTTON(SDL_BUTTON_LEFT)) || keyDown(ks, SDL_SCANCODE_LCTRL))
|
||||
button |= GE_CONT_G;
|
||||
if ((mb & SDL_BUTTON(SDL_BUTTON_RIGHT)) || keyDown(ks, SDL_SCANCODE_LSHIFT))
|
||||
button |= GE_CONT_R;
|
||||
if (keyDown(ks, SDL_SCANCODE_SPACE) || keyDown(ks, SDL_SCANCODE_Z) ||
|
||||
keyDown(ks, SDL_SCANCODE_E))
|
||||
button |= GE_CONT_A;
|
||||
if (keyDown(ks, SDL_SCANCODE_X) || keyDown(ks, SDL_SCANCODE_R) ||
|
||||
keyDown(ks, SDL_SCANCODE_F))
|
||||
button |= GE_CONT_B;
|
||||
if (keyDown(ks, SDL_SCANCODE_Q))
|
||||
button |= GE_CONT_L;
|
||||
if (keyDown(ks, SDL_SCANCODE_RETURN) || keyDown(ks, SDL_SCANCODE_TAB))
|
||||
button |= GE_CONT_START;
|
||||
|
||||
/* mouse-aim accumulator -> C-buttons (drained here) */
|
||||
if (mouseEnabled) {
|
||||
if (aimAccumX >= AIM_EMIT_THRESHOLD) { button |= GE_CONT_F; aimAccumX -= 1.0; }
|
||||
else if (aimAccumX <= -AIM_EMIT_THRESHOLD) { button |= GE_CONT_C; aimAccumX += 1.0; }
|
||||
if (aimAccumY >= AIM_EMIT_THRESHOLD) { button |= GE_CONT_D; aimAccumY -= 1.0; }
|
||||
else if (aimAccumY <= -AIM_EMIT_THRESHOLD) { button |= GE_CONT_E; aimAccumY += 1.0; }
|
||||
}
|
||||
}
|
||||
|
||||
/* ---- gamepad ---- */
|
||||
SDL_GameController *pad = pads[idx];
|
||||
if (pad) {
|
||||
int lx = SDL_GameControllerGetAxis(pad, SDL_CONTROLLER_AXIS_LEFTX);
|
||||
int ly = SDL_GameControllerGetAxis(pad, SDL_CONTROLLER_AXIS_LEFTY);
|
||||
int rx = SDL_GameControllerGetAxis(pad, SDL_CONTROLLER_AXIS_RIGHTX);
|
||||
int ry = SDL_GameControllerGetAxis(pad, SDL_CONTROLLER_AXIS_RIGHTY);
|
||||
|
||||
int px = scaleAxis(lx);
|
||||
int py = -scaleAxis(ly); /* SDL up = negative -> N64 up = positive */
|
||||
if (px) sx = px;
|
||||
if (py) sy = py;
|
||||
|
||||
if (rx > RSTICK_THRESHOLD) button |= GE_CONT_F;
|
||||
if (rx < -RSTICK_THRESHOLD) button |= GE_CONT_C;
|
||||
if (ry > RSTICK_THRESHOLD) button |= GE_CONT_D;
|
||||
if (ry < -RSTICK_THRESHOLD) button |= GE_CONT_E;
|
||||
|
||||
if (SDL_GameControllerGetAxis(pad, SDL_CONTROLLER_AXIS_TRIGGERRIGHT) > TRIG_THRESHOLD)
|
||||
button |= GE_CONT_G;
|
||||
if (SDL_GameControllerGetAxis(pad, SDL_CONTROLLER_AXIS_TRIGGERLEFT) > TRIG_THRESHOLD)
|
||||
button |= GE_CONT_R;
|
||||
|
||||
if (SDL_GameControllerGetButton(pad, SDL_CONTROLLER_BUTTON_A) ||
|
||||
SDL_GameControllerGetButton(pad, SDL_CONTROLLER_BUTTON_X))
|
||||
button |= GE_CONT_A;
|
||||
if (SDL_GameControllerGetButton(pad, SDL_CONTROLLER_BUTTON_B) ||
|
||||
SDL_GameControllerGetButton(pad, SDL_CONTROLLER_BUTTON_Y) ||
|
||||
SDL_GameControllerGetButton(pad, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER))
|
||||
button |= GE_CONT_B;
|
||||
if (SDL_GameControllerGetButton(pad, SDL_CONTROLLER_BUTTON_LEFTSHOULDER))
|
||||
button |= GE_CONT_L;
|
||||
if (SDL_GameControllerGetButton(pad, SDL_CONTROLLER_BUTTON_START))
|
||||
button |= GE_CONT_START;
|
||||
if (SDL_GameControllerGetButton(pad, SDL_CONTROLLER_BUTTON_DPAD_UP))
|
||||
button |= GE_CONT_UP;
|
||||
if (SDL_GameControllerGetButton(pad, SDL_CONTROLLER_BUTTON_DPAD_DOWN))
|
||||
button |= GE_CONT_DOWN;
|
||||
if (SDL_GameControllerGetButton(pad, SDL_CONTROLLER_BUTTON_DPAD_LEFT))
|
||||
button |= GE_CONT_LEFT;
|
||||
if (SDL_GameControllerGetButton(pad, SDL_CONTROLLER_BUTTON_DPAD_RIGHT))
|
||||
button |= GE_CONT_RIGHT;
|
||||
}
|
||||
|
||||
if (sx > STICK_MAX) sx = STICK_MAX;
|
||||
if (sx < -STICK_MAX) sx = -STICK_MAX;
|
||||
if (sy > STICK_MAX) sy = STICK_MAX;
|
||||
if (sy < -STICK_MAX) sy = -STICK_MAX;
|
||||
|
||||
if (stick_x) *stick_x = (signed char)sx;
|
||||
if (stick_y) *stick_y = (signed char)sy;
|
||||
|
||||
if (getenv("GE_INPUTLOG") && (button || sx || sy)) {
|
||||
sysLogPrintf(LOG_NOTE, "GE_INPUTLOG cont%d: btn=%04x stick=(%d,%d)",
|
||||
idx, button, sx, sy);
|
||||
}
|
||||
|
||||
return button;
|
||||
}
|
||||
|
||||
int inputConnectedMask(void)
|
||||
{
|
||||
return connectedMask;
|
||||
}
|
||||
|
||||
int inputGetNumControllers(void)
|
||||
{
|
||||
return numControllers;
|
||||
}
|
||||
|
||||
PD_CONSTRUCTOR static void inputConfigInit(void)
|
||||
{
|
||||
configRegisterInt("Input.MouseEnabled", &mouseEnabled, 0, 1);
|
||||
configRegisterInt("Input.MouseAimSpeed", &mouseAimSpeed, 1, 500);
|
||||
configRegisterInt("Input.MouseInvertY", &mouseInvertY, 0, 1);
|
||||
}
|
||||
+21
-50
@@ -1005,61 +1005,30 @@ static OSContStatus g_contStatus[MAXCONTROLLERS];
|
||||
static OSContPad g_contPad[MAXCONTROLLERS];
|
||||
static u8 g_contConnected = 0x1; /* controller 0 connected */
|
||||
|
||||
/* Keyboard -> N64 pad for controller 0:
|
||||
* A: Z / Space B: X Start: Enter
|
||||
* Z trigger: LCtrl C-stick: arrows D-pad: WASD
|
||||
*/
|
||||
/* Snapshot all controllers from the SDL input module (port/src/input.c).
|
||||
* That module owns the keyboard/mouse/gamepad -> N64 mapping and the
|
||||
* mouse-look -> C-button bridge; this just marshals its output into the
|
||||
* OSContPad / OSContStatus arrays joy.c reads via osContGetReadData(). */
|
||||
static void contSnapshotFromKeyboard(void)
|
||||
{
|
||||
/* SDL2: the keyboard state array is indexed by SCANCODE (512 entries).
|
||||
* Non-ASCII SDLK_* constants carry a 0x40000000 flag (SDLK_UP ==
|
||||
* 0x40000052), so they must be masked to the scancode value before use
|
||||
* as an index — indexing with the raw constant reads ~1 GB past the
|
||||
* array and faults. */
|
||||
#define K(key) keys[(key) & 0xFFFF]
|
||||
const uint8_t *keys = SDL_GetKeyboardState(NULL);
|
||||
u16 button = 0;
|
||||
s8 sx = 0, sy = 0;
|
||||
inputUpdate();
|
||||
|
||||
if (!keys) return; /* SDL not ready yet (first frames before videoInit)
|
||||
* — leave the previous frame's pad state in place. */
|
||||
const s32 mask = inputConnectedMask();
|
||||
g_contConnected = (u8)mask;
|
||||
|
||||
if (K(SDLK_z) || K(SDLK_SPACE)) button |= CONT_A;
|
||||
if (K(SDLK_x)) button |= CONT_B;
|
||||
if (K(SDLK_LCTRL)) button |= CONT_G; /* Z trigger */
|
||||
if (K(SDLK_RETURN)) button |= CONT_START;
|
||||
for (int i = 0; i < MAXCONTROLLERS; ++i) {
|
||||
const int connected = (mask & (1 << i)) != 0;
|
||||
s8 sx = 0, sy = 0;
|
||||
u16 button = connected ? (u16)inputComputePad(i, &sx, &sy) : 0;
|
||||
|
||||
/* C-stick (arrows) — GE's movement stick. */
|
||||
if (K(SDLK_UP)) sy = -80;
|
||||
if (K(SDLK_DOWN)) sy = 80;
|
||||
if (K(SDLK_LEFT)) sx = -80;
|
||||
if (K(SDLK_RIGHT)) sx = 80;
|
||||
|
||||
/* D-pad (WASD) — separate from the C-stick. */
|
||||
if (K(SDLK_w)) button |= CONT_UP;
|
||||
if (K(SDLK_s)) button |= CONT_DOWN;
|
||||
if (K(SDLK_a)) button |= CONT_LEFT;
|
||||
if (K(SDLK_d)) button |= CONT_RIGHT;
|
||||
#undef K
|
||||
|
||||
g_contStatus[0].type = CONT_TYPE_NORMAL;
|
||||
g_contStatus[0].status = 0;
|
||||
g_contStatus[0].errno = 0;
|
||||
/* The pad is kept in a parallel array; joy.c copies it via
|
||||
* osContGetReadData(). */
|
||||
g_contPad[0].button = button;
|
||||
g_contPad[0].stick_x = sx;
|
||||
g_contPad[0].stick_y = sy;
|
||||
g_contPad[0].errno = 0;
|
||||
|
||||
for (int i = 1; i < MAXCONTROLLERS; ++i) {
|
||||
g_contStatus[i].type = 0;
|
||||
g_contStatus[i].type = connected ? CONT_TYPE_NORMAL : 0;
|
||||
g_contStatus[i].status = 0;
|
||||
g_contStatus[i].errno = CONT_NO_RESPONSE_ERROR;
|
||||
g_contPad[i].button = 0;
|
||||
g_contPad[i].stick_x = 0;
|
||||
g_contPad[i].stick_y = 0;
|
||||
g_contPad[i].errno = CONT_NO_RESPONSE_ERROR;
|
||||
g_contStatus[i].errno = connected ? 0 : CONT_NO_RESPONSE_ERROR;
|
||||
|
||||
g_contPad[i].button = button;
|
||||
g_contPad[i].stick_x = connected ? sx : 0;
|
||||
g_contPad[i].stick_y = connected ? sy : 0;
|
||||
g_contPad[i].errno = connected ? 0 : CONT_NO_RESPONSE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1095,7 +1064,9 @@ void osContGetQuery(OSContStatus *status)
|
||||
|
||||
void osContGetReadData(OSContPad *pad)
|
||||
{
|
||||
*pad = g_contPad[0];
|
||||
/* N64 semantics: fill one OSContPad per controller channel. joy.c passes
|
||||
* g_ContData[0].samples[i].pads (a MAXCONTROLLERS-long array). */
|
||||
memcpy(pad, g_contPad, sizeof(g_contPad));
|
||||
}
|
||||
|
||||
s32 osContReset(OSMesgQueue *mq, OSContStatus *status)
|
||||
|
||||
Reference in new issue
Block a user