From a83e0aa4079ad8b3d0626260a0717fb4f0c2d123 Mon Sep 17 00:00:00 2001 From: fgsfds Date: Tue, 14 May 2024 20:28:59 +0200 Subject: [PATCH] port: add mouse control to menus; mouse now unlocks when you pause --- port/include/input.h | 118 ++++++++++++++++----------------- port/src/input.c | 34 ++++++---- port/src/main.c | 1 + src/game/bondmove.c | 6 ++ src/game/menu.c | 140 ++++++++++++++++++++++++++++++++++++---- src/game/menuitem.c | 6 ++ src/game/menustop.c | 9 +++ src/game/player.c | 18 ++++++ src/include/data.h | 1 + src/include/game/menu.h | 2 +- src/include/types.h | 9 +++ 11 files changed, 261 insertions(+), 83 deletions(-) diff --git a/port/include/input.h b/port/include/input.h index 2ddaab94a..fcb9d962c 100644 --- a/port/include/input.h +++ b/port/include/input.h @@ -17,68 +17,68 @@ #define CONT_NUM_BUTTONS 32 // not including the stick axes enum virtkey { - /* same order as SDL scancodes */ - VK_KEYBOARD_BEGIN = 0, - VK_RETURN = 40, - VK_ESCAPE = 41, - VK_DELETE = 76, + /* same order as SDL scancodes */ + VK_KEYBOARD_BEGIN = 0, + VK_RETURN = 40, + VK_ESCAPE = 41, + VK_DELETE = 76, - /* 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 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, + /* 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, + 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_X, // gap in CONT_ - CK_Y, // 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_0010, - CK_0020, - CK_0040, - CK_0080, - CK_0100, - CK_0200, - CK_0400, - CK_0800, - CK_1000, - CK_2000, - CK_4000, - CK_8000, - CK_TOTAL_COUNT + CK_C_R, + CK_C_L, + CK_C_D, + CK_C_U, + CK_RTRIG, + CK_LTRIG, + CK_X, // gap in CONT_ + CK_Y, // 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_0010, + CK_0020, + CK_0040, + CK_0080, + CK_0100, + CK_0200, + CK_0400, + CK_0800, + CK_1000, + CK_2000, + CK_4000, + CK_8000, + CK_TOTAL_COUNT }; // returns bitmask of connected controllers or -1 if failed @@ -132,6 +132,7 @@ s32 inputAssignController(s32 cidx, s32 id); // vk is a value from the virtkey enum above s32 inputKeyPressed(u32 vk); +s32 inputKeyJustPressed(u32 vk); // idx is controller index, contbtn is one of the CONT_ constants s32 inputButtonPressed(s32 idx, u32 contbtn); @@ -166,8 +167,9 @@ void inputLockMouse(s32 lock); // returns the current state of the above s32 inputMouseIsLocked(void); -// returns mouse position in native viewport coordinates (ie, 320x240 most of the time) -void inputMouseGetPosition(s32 *x, s32 *y); +// sets x, y to mouse position in native viewport coordinates (ie, 320x240 most of the time) +// returns true if mouse has moved this input frame +s32 inputMouseGetPosition(s32 *x, s32 *y); // returns changes in mouse position since last frame, in window coordinates void inputMouseGetRawDelta(s32 *dx, s32 *dy); diff --git a/port/src/input.c b/port/src/input.c index 96438e3f6..69e28508f 100644 --- a/port/src/input.c +++ b/port/src/input.c @@ -169,6 +169,8 @@ static const char *vkJoyNames[] = { static char vkNames[VK_TOTAL_COUNT][64]; +static s8 vkPrevState[VK_TOTAL_COUNT]; + void inputSetDefaultKeyBinds(s32 cidx, s32 n64mode) { // TODO: make VK constants for all these @@ -799,12 +801,6 @@ static inline void inputUpdateMouse(void) mouseX = mx; mouseY = my; - - if (!mouseLocked && (mouseButtons & SDL_BUTTON_LMASK)) { - inputLockMouse(1); - } else if (mouseLocked && inputKeyPressed(VK_ESCAPE)) { - inputLockMouse(0); - } } void inputUpdate(void) @@ -1051,9 +1047,13 @@ 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) { + } + + if (vk >= VK_MOUSE_BEGIN && vk < VK_JOY_BEGIN) { + return (mouseButtons & SDL_BUTTON(vk - VK_MOUSE_BEGIN + 1)) != 0; + } + + 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]) { @@ -1067,9 +1067,18 @@ s32 inputKeyPressed(u32 vk) } return SDL_GameControllerGetButton(pads[idx], vk); } + return 0; } +s32 inputKeyJustPressed(u32 vk) +{ + const s8 pressed = inputKeyPressed(vk); + const s32 result = pressed && !vkPrevState[vk]; + vkPrevState[vk] = pressed; + return result; +} + static inline u32 inputContToContKey(const u32 cont) { if (cont == 0) { @@ -1099,10 +1108,11 @@ s32 inputMouseIsLocked(void) return mouseLocked; } -void inputMouseGetPosition(s32 *x, s32 *y) +s32 inputMouseGetPosition(s32 *x, s32 *y) { if (x) *x = mouseX * videoGetNativeWidth() / videoGetWidth(); if (y) *y = mouseY * videoGetNativeHeight() / videoGetHeight(); + return (mouseDX != 0 || mouseDY != 0); } void inputMouseGetRawDelta(s32 *dx, s32 *dy) @@ -1172,9 +1182,7 @@ s32 inputGetMouseDefaultLocked(void) void inputSetMouseDefaultLocked(s32 defaultLocked) { mouseDefaultLocked = !!defaultLocked; - if (mouseEnabled) { - inputLockMouse(mouseDefaultLocked); - } + inputLockMouse(mouseDefaultLocked); } const char *inputGetContKeyName(u32 ck) diff --git a/port/src/main.c b/port/src/main.c index fa39ff518..e31e090a2 100644 --- a/port/src/main.c +++ b/port/src/main.c @@ -159,6 +159,7 @@ PD_CONSTRUCTOR static void gameConfigInit(void) { configRegisterInt("Game.MemorySize", &g_OsMemSizeMb, 4, 2048); configRegisterInt("Game.CenterHUD", &g_HudCenter, 0, 2); + configRegisterInt("Game.MenuMouseControl", &g_MenuMouseControl, 0, 1); configRegisterFloat("Game.ScreenShakeIntensity", &g_ViShakeIntensityMult, 0.f, 10.f); configRegisterInt("Game.TickRateDivisor", &g_TickRateDiv, 0, 10); configRegisterInt("Game.ExtraSleep", &g_TickExtraSleep, 0, 1); diff --git a/src/game/bondmove.c b/src/game/bondmove.c index 9b59f3847..ede1b11d0 100644 --- a/src/game/bondmove.c +++ b/src/game/bondmove.c @@ -780,6 +780,12 @@ void bmoveProcessInput(bool allowc1x, bool allowc1y, bool allowc1buttons, bool i movedata.freelookdy = -movedata.freelookdy; } } + // always pause with ESC + if (allowc1buttons && g_Vars.currentplayer->isdead == false && g_Vars.currentplayer->pausemode == PAUSEMODE_UNPAUSED) { + if (inputKeyJustPressed(VK_ESCAPE)) { + c1buttonsthisframe |= START_BUTTON; + } + } #endif // Pausing diff --git a/src/game/menu.c b/src/game/menu.c index 46e743aca..68742bf24 100644 --- a/src/game/menu.c +++ b/src/game/menu.c @@ -50,6 +50,7 @@ #include "types.h" #ifndef PLATFORM_N64 #include "video.h" +#include "input.h" #define BLUR_OFS 10 #else #define BLUR_OFS 30 @@ -136,6 +137,10 @@ char *g_StringPointer2 = &g_CheatMarqueeString[VERSION >= VERSION_PAL_FINAL ? 15 s32 g_MpPlayerNum = 0; +#ifndef PLATFORM_N64 +s32 g_MenuMouseControl = true; +#endif + void menuPlaySound(s32 menusound) { s32 sound = -1; @@ -1347,20 +1352,68 @@ s32 dialogChangeItemFocusHorizontally(struct menudialog *dialog, s32 leftright) return swipedir; } -s32 dialogChangeItemFocus(struct menudialog *dialog, s32 leftright, s32 updown) +#ifndef PLATFORM_N64 + +bool dialogChangeItemFocusWithMouse(struct menudialog *dialog, s32 mx, s32 my) +{ + struct menu *menu = &g_Menus[g_MpPlayerNum]; + s32 col, row; + s32 curx, cury; + s32 colwidth = 0; + + // only allow mouse control of player 1 menus + if (menu->playernum != 0) { + return false; + } + + curx = dialog->x; + + for (col = 0; col < dialog->numcols; col++, curx += colwidth) { + s32 colindex = dialog->colstart + col; + colwidth = menu->cols[colindex].width; + if (mx <= curx || mx >= curx + colwidth) { + continue; + } + + cury = dialog->y + LINEHEIGHT + 1 + dialog->scroll; + for (row = 0; row < menu->cols[colindex].numrows; row++) { + s32 rowindex = menu->cols[colindex].rowstart + row; + s32 rowheight = menu->rows[rowindex].height; + struct menuitem *item = &dialog->definition->items[menu->rows[rowindex].itemindex]; + if (my > cury && my < cury + rowheight && + item != dialog->focuseditem && menuIsItemFocusable(item, dialog, 0)) { + dialog->focuseditem = item; + return true; + } + cury += rowheight; + } + } + + return false; +} + +#endif + +s32 dialogChangeItemFocus(struct menudialog *dialog, struct menuinputs *inputs) { s32 swipedir = 0; - if (leftright == 0 && updown == 0) { + if (inputs->leftright == 0 && inputs->updown == 0) { +#ifndef PLATFORM_N64 + if (!dialogChangeItemFocusWithMouse(dialog, inputs->mousex, inputs->mousey)) { + return 0; + } +#else return 0; +#endif } - if (updown != 0) { - dialogChangeItemFocusVertically(dialog, updown); + if (inputs->updown != 0) { + dialogChangeItemFocusVertically(dialog, inputs->updown); } - if (leftright != 0) { - swipedir = dialogChangeItemFocusHorizontally(dialog, leftright); + if (inputs->leftright != 0) { + swipedir = dialogChangeItemFocusHorizontally(dialog, inputs->leftright); } if (dialog->focuseditem != 0) { @@ -1448,6 +1501,10 @@ void menuOpenDialog(struct menudialogdef *dialogdef, struct menudialog *dialog, dialog->y = dialog->dsty; dialog->width = dialog->dstwidth; dialog->height = dialog->dstheight; + +#ifndef PLATFORM_N64 + dialog->usingmouse = false; +#endif } void menuPushDialog(struct menudialogdef *dialogdef) @@ -3418,6 +3475,12 @@ void menuClose(void) g_Menus[g_MpPlayerNum].curdialog = NULL; g_Menus[g_MpPlayerNum].openinhibit = 10; +#ifndef PLATFORM_N64 + if (inputMouseIsEnabled()) { + inputLockMouse(true); + } +#endif + if (g_MenuData.root == MENUROOT_MPPAUSE) { g_PlayersWithControl[g_Menus[g_MpPlayerNum].playernum] = true; } @@ -3528,6 +3591,12 @@ void menuPushRootDialog(struct menudialogdef *dialogdef, s32 root) g_PlayersWithControl[g_Menus[g_MpPlayerNum].playernum] = false; +#ifndef PLATFORM_N64 + if (inputMouseIsEnabled()) { + inputLockMouse(false); + } +#endif + func0f0f1494(); g_MenuData.count++; @@ -4389,14 +4458,14 @@ void dialogTick(struct menudialog *dialog, struct menuinputs *inputs, u32 tickfl if (layer->numsiblings <= 1) { struct menuitem *prevfocuseditem = dialog->focuseditem; - dialogChangeItemFocus(dialog, inputs->leftright, inputs->updown); + dialogChangeItemFocus(dialog, inputs); if (dialog->focuseditem != prevfocuseditem) { menuPlaySound(MENUSOUND_FOCUS); } } else { struct menuitem *prevfocuseditem = dialog->focuseditem; - s32 swipedir = dialogChangeItemFocus(dialog, inputs->leftright, inputs->updown); + s32 swipedir = dialogChangeItemFocus(dialog, inputs); if (swipedir != 0) { menuSwipe(swipedir); @@ -4441,8 +4510,15 @@ void dialogTick(struct menudialog *dialog, struct menuinputs *inputs, u32 tickfl s32 y = dialogFindItem(dialog, dialog->focuseditem, &rowindex, &colindex); if ((dialog->focuseditem->flags & MENUITEMFLAG_00010000) == 0) { - itemy = y + menu->rows[rowindex].height / 2; - dstscroll = (dialog->height - LINEHEIGHT - 1) / 2 - itemy; +#ifndef PLATFORM_N64 + if (dialog->usingmouse) { + dstscroll = dialog->dstscroll - inputs->mousescroll * LINEHEIGHT; + } else +#endif + { + itemy = y + menu->rows[rowindex].height / 2; + dstscroll = (dialog->height - LINEHEIGHT - 1) / 2 - itemy; + } if (dstscroll > 0) { dstscroll = 0; @@ -4590,6 +4666,28 @@ void menuProcessInput(void) inputs.shoulder = 0; inputs.back2 = 0; +#ifndef PLATFORM_N64 + inputs.mousemoved = false; + inputs.mousescroll = 0; + inputs.mousex = 0; + inputs.mousey = 0; + // only allow mouse controls for player 1 menus + if (menu->playernum == 0) { + // ESC always acts as back + inputs.back = inputKeyJustPressed(VK_ESCAPE); + if (inputMouseIsEnabled() && !inputMouseIsLocked() && g_MenuMouseControl) { + inputs.mousemoved = inputMouseGetPosition(&inputs.mousex, &inputs.mousey); + inputs.mousescroll = inputKeyPressed(VK_MOUSE_WHEEL_DN) - inputKeyPressed(VK_MOUSE_WHEEL_UP); + // aspect correct the X + const f32 cx = ((f32)inputs.mousex - (f32)(SCREEN_WIDTH_LO / 2)) * (videoGetAspect() / SCREEN_ASPECT); + inputs.mousex = (f32)(SCREEN_WIDTH_LO / 2) + cx; + } + if (dialog && inputs.mousemoved) { + dialog->usingmouse = true; + } + } +#endif + if (g_Menus[g_MpPlayerNum].curdialog) { stickx = 0; sticky = 0; @@ -4651,7 +4749,8 @@ void menuProcessInput(void) inputs.select = 1; } - if (buttonsnow & BUTTON_WPNBACK) { + // don't back out on weapon back when using mouse because it's likely bound to wheel + if (!dialog->usingmouse && (buttonsnow & BUTTON_WPNBACK)) { inputs.back = 1; } #endif @@ -4994,6 +5093,25 @@ void menuProcessInput(void) inputs.unk14 = 0; inputs.start = starttap ? true : false; +#ifndef PLATFORM_N64 + // if we haven't been using the mouse but we have been keyboard scrolling disable the mouse + if (!inputs.mousemoved && (inputs.leftright || inputs.updown || inputs.leftrightheld || inputs.updownheld)) { + dialog->usingmouse = false; + } + // otherwise rotate left/right by clicking on the side of the menu + if (dialog->usingmouse && inputs.select && !inputs.leftright && !inputs.leftrightheld) { + if (inputs.mousey > dialog->y && inputs.mousey < dialog->y + dialog->height) { + if (inputs.mousex < dialog->x) { + inputs.leftright = -1; + inputs.select = 0; + } else if (inputs.mousex > dialog->x + dialog->width) { + inputs.leftright = 1; + inputs.select = 0; + } + } + } +#endif + // Handle dialogs that allow pressing start to select, // and handle pressing start on a list item. if (g_Menus[g_MpPlayerNum].curdialog && starttap) { diff --git a/src/game/menuitem.c b/src/game/menuitem.c index 0f5d68b6b..117d92bd4 100644 --- a/src/game/menuitem.c +++ b/src/game/menuitem.c @@ -732,9 +732,15 @@ bool menuitemListTick(struct menuitem *item, struct menuinputs *inputs, u32 tick data->list.targetoffsety = menuitemListGetOffsetY(data->list.index, item); } +#ifdef PLATFORM_N64 if (inputs->updown) { prev2 = data->list.index; data->list.index += inputs->updown; +#else + if (inputs->updown || inputs->mousescroll) { + prev2 = data->list.index; + data->list.index += inputs->updown + inputs->mousescroll; +#endif if (data->list.index < 0) { data->list.index = handlerdata.list.value - 1; diff --git a/src/game/menustop.c b/src/game/menustop.c index a58773847..d86344a46 100644 --- a/src/game/menustop.c +++ b/src/game/menustop.c @@ -26,9 +26,18 @@ #include "lib/snd.h" #include "data.h" #include "types.h" +#ifndef PLATFORM_N64 +#include "input.h" +#endif void menuStop(void) { +#ifndef PLATFORM_N64 + if (inputMouseIsEnabled()) { + inputLockMouse(true); + } +#endif + if (var80062944) { var80062944 = 0; var80062948 = 0; diff --git a/src/game/player.c b/src/game/player.c index eb4e2c891..a74753fa5 100644 --- a/src/game/player.c +++ b/src/game/player.c @@ -2039,6 +2039,12 @@ void playerTickCutscene(bool arg0) g_CutsceneCurTotalFrame60f += g_Vars.lvupdate60freal; } +#ifndef PLATFORM_N64 + if (arg0 && inputKeyJustPressed(VK_ESCAPE)) { + buttons |= START_BUTTON; + } +#endif + #if VERSION >= VERSION_NTSC_1_0 if (g_CutsceneCurTotalFrame60f > 30 && (buttons & 0xffffffff)) { g_CutsceneSkipRequested = true; @@ -3297,6 +3303,12 @@ void playerTick(bool arg0) s8 contpad1 = optionsGetContpadNum1(g_Vars.currentplayerstats->mpindex); u32 buttons = arg0 ? joyGetButtons(contpad1, 0xffffffff) : 0; +#ifndef PLATFORM_N64 + if (arg0 && inputKeyJustPressed(VK_ESCAPE)) { + buttons |= START_BUTTON; + } +#endif + if (g_Vars.currentplayer->isdead == false && g_Vars.currentplayer->pausemode == PAUSEMODE_UNPAUSED && (buttons & START_BUTTON)) { @@ -3577,6 +3589,12 @@ void playerTick(bool arg0) } } +#ifndef PLATFORM_N64 + if (g_PlayersWithControl[g_Vars.currentplayernum] && inputKeyJustPressed(VK_ESCAPE)) { + pause = true; + } +#endif + if (pause) { if (g_Vars.mplayerisrunning == false) { playerPause(MENUROOT_MAINMENU); diff --git a/src/include/data.h b/src/include/data.h index c59d6ba99..853dbd622 100644 --- a/src/include/data.h +++ b/src/include/data.h @@ -540,6 +540,7 @@ extern const struct weathercfg *g_CurWeatherConfig; extern f32 g_ViShakeIntensityMult; extern u32 g_TexFilter2D; extern s32 g_HudCenter; +extern s32 g_MenuMouseControl; extern u32 g_HudAlignModeL; extern u32 g_HudAlignModeR; extern s32 g_PrevFrameFb; diff --git a/src/include/game/menu.h b/src/include/game/menu.h index 46fd44ad6..419fb659e 100644 --- a/src/include/game/menu.h +++ b/src/include/game/menu.h @@ -46,7 +46,7 @@ struct menuitem *dialogFindFirstItem(struct menudialog *dialog); struct menuitem *dialogFindFirstItemRight(struct menudialog *dialog); void dialogChangeItemFocusVertically(struct menudialog *dialog, s32 updown); s32 dialogChangeItemFocusHorizontally(struct menudialog *dialog, s32 leftright); -s32 dialogChangeItemFocus(struct menudialog *dialog, s32 leftright, s32 updown); +s32 dialogChangeItemFocus(struct menudialog *dialog, struct menuinputs *inputs); void menuOpenDialog(struct menudialogdef *dialogdef, struct menudialog *arg1, struct menu *menu); void menuPushDialog(struct menudialogdef *dialogdef); diff --git a/src/include/types.h b/src/include/types.h index 0d772d798..57f018b7a 100644 --- a/src/include/types.h +++ b/src/include/types.h @@ -3739,6 +3739,9 @@ struct menudialog { /*0x6c*/ u8 unk6c; /*0x6d*/ s8 swipedir; /*0x6e*/ u8 unk6e; +#ifndef PLATFORM_N64 + /*0x6f*/ u8 usingmouse; +#endif }; struct menudfc { @@ -4991,6 +4994,12 @@ struct menuinputs { /*0x0c*/ s32 unk0c; /*0x10*/ s32 unk10; /*0x14*/ u8 unk14; +#ifndef PLATFORM_N64 + /*0x15*/ u8 mousemoved; + /*0x16*/ s8 mousescroll; + /*0x18*/ s32 mousex; + /*0x1c*/ s32 mousey; +#endif }; struct mpconfigsim {