diff --git a/include/PR/os_cont.h b/include/PR/os_cont.h index 15ee60f3f..dd3466ad4 100644 --- a/include/PR/os_cont.h +++ b/include/PR/os_cont.h @@ -60,6 +60,12 @@ typedef struct { u16 button; s8 stick_x; /* -80 <= stick_x <= 80 */ s8 stick_y; /* -80 <= stick_y <= 80 */ +#ifndef PLATFORM_N64 /* for that sick mouselook */ + s32 mouse_x; + s32 mouse_y; + s32 mouse_dx; + s32 mouse_dy; +#endif u8 errnum; } OSContPad; diff --git a/port/include/input.h b/port/include/input.h index 6609e7cba..513941cbe 100644 --- a/port/include/input.h +++ b/port/include/input.h @@ -5,8 +5,68 @@ #include #define INPUT_MAX_CONTROLLERS MAXCONTROLLERS +#define INPUT_MAX_CONTROLLER_BUTTONS 32 #define INPUT_RUMBLE_STRENGTH 0.333f +#define CONT_STICK_XNEG 0x10000 +#define CONT_STICK_XPOS 0x20000 +#define CONT_STICK_YNEG 0x40000 +#define CONT_STICK_YPOS 0x80000 + +#define CONT_NUM_BUTTONS 16 // not including the stick axes + +enum virtkey { + /* same order as SDL scancodes */ + VK_KEYBOARD_BEGIN = 0, + VK_RETURN = 40, + VK_ESCAPE = 41, + + /* same order as SDL mouse buttons */ + VK_MOUSE_BEGIN = 512, + VK_MOUSE_LEFT = VK_MOUSE_BEGIN, + VK_MOUSE_MIDDLE, + VK_MOUSE_RIGHT, + VK_MOUSE_X1, + VK_MOUSE_X2, + VK_MOUSE_WHEEL_UP, + VK_MOUSE_WHEEL_DN, + + /* same order as SDL gamecontroller buttons plus two buttons for triggers */ + VK_JOY_BEGIN, + VK_JOY1_BEGIN = VK_JOY_BEGIN, + VK_JOY1_LTRIG = VK_JOY1_BEGIN + 30, + VK_JOY1_RTRIG = VK_JOY1_BEGIN + 31, + VK_JOY2_BEGIN = VK_JOY1_BEGIN + INPUT_MAX_CONTROLLER_BUTTONS, + VK_JOY3_BEGIN = VK_JOY2_BEGIN + INPUT_MAX_CONTROLLER_BUTTONS, + VK_JOY4_BEGIN = VK_JOY3_BEGIN + INPUT_MAX_CONTROLLER_BUTTONS, + + VK_TOTAL_COUNT = VK_JOY_BEGIN + INPUT_MAX_CONTROLLERS * INPUT_MAX_CONTROLLER_BUTTONS, +}; + +enum contkey { + CK_C_R, + CK_C_L, + CK_C_D, + CK_C_U, + CK_RTRIG, + CK_LTRIG, + CK_EXTRA0, // gap in CONT_ + CK_EXTRA1, // gap in CONT_ + CK_DPAD_R, + CK_DPAD_L, + CK_DPAD_D, + CK_DPAD_U, + CK_START, + CK_ZTRIG, + CK_B, + CK_A, + CK_STICK_XNEG, + CK_STICK_XPOS, + CK_STICK_YNEG, + CK_STICK_YPOS, + CK_TOTAL_COUNT +}; + // returns bitmask of connected controllers or -1 if failed s32 inputInit(void); @@ -22,9 +82,22 @@ s32 inputControllerConnected(s32 idx); // returns bitmask of connected controllers s32 inputControllerMask(void); +// vk is a value from the virtkey enum above +s32 inputKeyPressed(u32 vk); + +// bind virtkey vk to n64 pad #idx's button/axis nbtn as represented by its contkey value +// if bind is -1, picks a bind slot automatically +void inputKeyBind(s32 idx, u32 cbtn, s32 bind, u32 vk); + // 0 strength turns it off void inputRumble(s32 idx, f32 strength, f32 time); +// locks the mouse cursor in the window and makes it invisible if argument is true +void inputLockMouse(s32 lock); + +// returns the current state of the above +s32 inputIsMouseLocked(void); + // call this every frame void inputUpdate(void); diff --git a/port/src/input.c b/port/src/input.c index 462e0c843..7d319582b 100644 --- a/port/src/input.c +++ b/port/src/input.c @@ -4,32 +4,65 @@ #include #include "input.h" +#define MAX_BINDS 4 +#define TRIG_THRESHOLD (30 * 256) + static SDL_GameController *pads[INPUT_MAX_CONTROLLERS]; static SDL_Haptic *haptics[INPUT_MAX_CONTROLLERS]; - -static const u16 buttonMap[] = { - /* SDL_CONTROLLER_BUTTON_A */ A_BUTTON, - /* SDL_CONTROLLER_BUTTON_B */ B_BUTTON, - /* SDL_CONTROLLER_BUTTON_X */ Z_TRIG, - /* SDL_CONTROLLER_BUTTON_Y */ Z_TRIG, - /* SDL_CONTROLLER_BUTTON_BACK */ START_BUTTON, - /* SDL_CONTROLLER_BUTTON_GUIDE */ 0, - /* SDL_CONTROLLER_BUTTON_START */ START_BUTTON, - /* SDL_CONTROLLER_BUTTON_LEFTSTICK */ 0, - /* SDL_CONTROLLER_BUTTON_RIGHTSTICK */ 0, - /* SDL_CONTROLLER_BUTTON_LEFTSHOULDER */ L_TRIG, - /* SDL_CONTROLLER_BUTTON_RIGHTSHOULDER */ R_TRIG, - /* SDL_CONTROLLER_BUTTON_DPAD_UP */ U_JPAD, - /* SDL_CONTROLLER_BUTTON_DPAD_DOWN */ D_JPAD, - /* SDL_CONTROLLER_BUTTON_DPAD_LEFT */ L_JPAD, - /* SDL_CONTROLLER_BUTTON_DPAD_RIGHT */ R_JPAD, -}; - -static const u16 buttonTrigLeft = Z_TRIG; -static const u16 buttonTrigRight = Z_TRIG; +static u32 binds[MAXCONTROLLERS][CK_TOTAL_COUNT][MAX_BINDS]; // [i][CK_][b] = [VK_] static s32 connectedMask = 0; +static s32 mouseLocked = 0; +static s32 mouseX, mouseY; +static s32 mouseDX, mouseDY; +static u32 mouseButtons; + +void inputSetDefaultKeyBinds(void) { + // TODO: make VK constants for all these + static const u32 kbbinds[][3] = { + { CK_A, SDL_SCANCODE_Q, 0 }, + { CK_B, SDL_SCANCODE_E, 0 }, + { CK_LTRIG, VK_MOUSE_RIGHT, SDL_SCANCODE_Z }, + { CK_RTRIG, VK_MOUSE_X1, SDL_SCANCODE_X }, + { CK_ZTRIG, VK_MOUSE_LEFT, SDL_SCANCODE_SPACE }, + { CK_START, VK_MOUSE_LEFT, SDL_SCANCODE_RETURN }, + { CK_DPAD_D, SDL_SCANCODE_DOWN, 0 }, + { CK_DPAD_U, SDL_SCANCODE_UP, 0 }, + { CK_DPAD_R, SDL_SCANCODE_RIGHT, 0 }, + { CK_DPAD_L, SDL_SCANCODE_LEFT, 0 }, + { CK_STICK_XNEG, SDL_SCANCODE_A, 0 }, + { CK_STICK_XPOS, SDL_SCANCODE_D, 0 }, + { CK_STICK_YNEG, SDL_SCANCODE_S, 0 }, + { CK_STICK_YPOS, SDL_SCANCODE_W, 0 }, + }; + + static const u32 joybinds[][2] = { + { CK_LTRIG, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, }, + { CK_RTRIG, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, }, + { CK_ZTRIG, VK_JOY1_RTRIG, }, + { CK_START, SDL_CONTROLLER_BUTTON_START, }, + { CK_DPAD_D, SDL_CONTROLLER_BUTTON_DPAD_DOWN, }, + { CK_DPAD_U, SDL_CONTROLLER_BUTTON_DPAD_UP, }, + { CK_DPAD_R, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, }, + { CK_DPAD_L, SDL_CONTROLLER_BUTTON_DPAD_LEFT, }, + }; + + for (u32 i = 0; i < sizeof(kbbinds) / sizeof(kbbinds[0]); ++i) { + for (s32 j = 1; j < 3; ++j) { + if (kbbinds[i][j]) { + inputKeyBind(0, kbbinds[i][0], j - 1, kbbinds[i][j]); + } + } + } + + for (u32 i = 0; i < sizeof(joybinds) / sizeof(joybinds[0]); ++i) { + for (s32 j = 0; j < INPUT_MAX_CONTROLLERS; ++j) { + inputKeyBind(j, joybinds[i][0], -1, joybinds[i][1]); + } + } +} + s32 inputInit(void) { if (!SDL_WasInit(SDL_INIT_GAMECONTROLLER)) { @@ -60,17 +93,51 @@ s32 inputInit(void) } } + inputSetDefaultKeyBinds(); + connectedMask = ret; return ret; } +static inline s32 inputBindPressed(const s32 idx, const u32 ck) +{ + for (s32 i = 0; i < MAX_BINDS; ++i) { + if (binds[idx][ck][i]) { + if (inputKeyPressed(binds[idx][ck][i])) { + return 1; + } + } + } + return 0; +} + s32 inputReadController(s32 idx, OSContPad *npad) { - if (idx < 0 || idx >= INPUT_MAX_CONTROLLERS || !pads[idx] || !npad) { + if (idx < 0 || idx >= INPUT_MAX_CONTROLLERS || !npad) { return -1; } + for (u32 i = 0; i < CONT_NUM_BUTTONS; ++i) { + if (inputBindPressed(idx, i)) { + npad->button |= 1U << i; + } + } + + const s32 xdiff = (inputBindPressed(idx, CK_STICK_XPOS) - inputBindPressed(idx, CK_STICK_XNEG)); + const s32 ydiff = (inputBindPressed(idx, CK_STICK_YPOS) - inputBindPressed(idx, CK_STICK_YNEG)); + npad->stick_x = xdiff < 0 ? -0x80 : (xdiff > 0 ? 0x7F : 0); + npad->stick_y = ydiff < 0 ? -0x80 : (ydiff > 0 ? 0x7F : 0); + + npad->mouse_x = mouseX; + npad->mouse_y = mouseY; + npad->mouse_dx = mouseDX; + npad->mouse_dy = mouseDY; + + if (!pads[idx]) { + return 0; + } + const s16 leftX = SDL_GameControllerGetAxis(pads[idx], SDL_CONTROLLER_AXIS_LEFTX); const s16 leftY = SDL_GameControllerGetAxis(pads[idx], SDL_CONTROLLER_AXIS_LEFTY); const s16 rightX = SDL_GameControllerGetAxis(pads[idx], SDL_CONTROLLER_AXIS_RIGHTX); @@ -83,14 +150,6 @@ s32 inputReadController(s32 idx, OSContPad *npad) if (rightY < -0x4000) npad->button |= U_CBUTTONS; if (rightY > +0x4000) npad->button |= D_CBUTTONS; - for (size_t i = 0; i < sizeof(buttonMap) / sizeof(*buttonMap); ++i) { - if (buttonMap[i]) { - if (SDL_GameControllerGetButton(pads[idx], i)) { - npad->button |= buttonMap[i]; - } - } - } - const s32 stickY = -leftY / 0x100; npad->stick_x = leftX / 0x100; npad->stick_y = (stickY == 128) ? 127 : stickY; @@ -101,6 +160,18 @@ s32 inputReadController(s32 idx, OSContPad *npad) void inputUpdate(void) { SDL_GameControllerUpdate(); + + int mx, my; + mouseButtons = SDL_GetMouseState(&mx, &my); + if (mouseLocked) { + SDL_GetRelativeMouseState(&mouseDX, &mouseDY); + } else { + mouseDX = mx - mouseX; + mouseDY = my - mouseY; + } + mouseX = mx; + mouseY = my; + // TODO: handle controller changes } @@ -136,3 +207,55 @@ s32 inputControllerMask(void) { return connectedMask; } + +void inputKeyBind(s32 idx, u32 cbtn, s32 bind, u32 vk) { + if (idx < 0 || idx >= INPUT_MAX_CONTROLLERS || bind >= MAX_BINDS || cbtn >= CK_TOTAL_COUNT) { + return; + } + + if (bind < 0) { + for (s32 i = 0; i < MAX_BINDS; ++i) { + if (binds[idx][cbtn][i] == 0) { + bind = i; + break; + } + } + if (bind < 0) { + bind = MAX_BINDS - 1; // just overwrite last + } + } + + binds[idx][cbtn][bind] = vk; +} + +s32 inputKeyPressed(u32 vk) +{ + if (vk >= VK_KEYBOARD_BEGIN && vk < VK_MOUSE_BEGIN) { + const u8 *state = SDL_GetKeyboardState(NULL); + return state[vk - VK_KEYBOARD_BEGIN]; + } else if (vk >= VK_MOUSE_BEGIN && vk < VK_JOY_BEGIN) { + return mouseButtons & SDL_BUTTON(vk - VK_MOUSE_BEGIN + 1); + } else if (vk >= VK_JOY_BEGIN && vk < VK_TOTAL_COUNT) { + vk -= VK_JOY_BEGIN; + const s32 idx = vk / INPUT_MAX_CONTROLLER_BUTTONS; + if (idx < 0 || idx >= INPUT_MAX_CONTROLLERS || !pads[idx]) { + return 0; + } + // triggers + if (idx == 30 || idx == 31) { + const s32 trig = SDL_CONTROLLER_AXIS_TRIGGERLEFT + idx - 30; + return SDL_GameControllerGetAxis(pads[idx], trig) > TRIG_THRESHOLD; + } + return SDL_GameControllerGetButton(pads[idx], vk % INPUT_MAX_CONTROLLER_BUTTONS); + } + return 0; +} + +void inputLockMouse(s32 lock) { + mouseLocked = !!lock; + SDL_SetRelativeMouseMode(mouseLocked); +} + +s32 inputIsMouseLocked(void) { + return mouseLocked; +} diff --git a/port/src/system.c b/port/src/system.c index 055377431..aedfaa7ba 100644 --- a/port/src/system.c +++ b/port/src/system.c @@ -41,6 +41,7 @@ void sysFatalError(const char *fmt, ...) va_end(ap); fprintf(stderr, "FATAL ERROR: %s\n", errmsg); + fflush(stderr); SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Fatal error", errmsg, NULL); exit(1);