From 019dbbb56e031dd218c38777c6ecbc5a892ffa83 Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Sun, 7 Aug 2022 14:52:44 +0300 Subject: [PATCH] Add mouse wheel support --- src/character_editor.cc | 4 ++ src/core.cc | 39 ++++++++++++ src/core.h | 3 + src/dbox.cc | 4 ++ src/dinput.cc | 16 +++++ src/dinput.h | 3 + src/game.cc | 21 +++++++ src/game_dialog.cc | 2 + src/inventory.cc | 132 ++++++++++++++++++++++++++++++++++++++++ src/loadsave.cc | 4 ++ src/world_map.cc | 14 +++++ 11 files changed, 242 insertions(+) diff --git a/src/character_editor.cc b/src/character_editor.cc index 82378c9..f01bc91 100644 --- a/src/character_editor.cc +++ b/src/character_editor.cc @@ -830,6 +830,8 @@ int characterEditorShow(bool isCreationMode) _frame_time = _get_time(); int keyCode = _get_input(); + convertMouseWheelToArrowKey(&keyCode); + bool done = false; if (keyCode == 500) { done = true; @@ -5962,6 +5964,8 @@ static int perkDialogHandleInput(int count, void (*refreshProc)()) int keyCode = _get_input(); int v19 = 0; + convertMouseWheelToArrowKey(&keyCode); + if (keyCode == 500) { rc = 1; } else if (keyCode == KEY_RETURN) { diff --git a/src/core.cc b/src/core.cc index 284d34f..d22b221 100644 --- a/src/core.cc +++ b/src/core.cc @@ -373,6 +373,9 @@ SDL_Renderer* gSdlRenderer = NULL; SDL_Texture* gSdlTexture = NULL; SDL_Surface* gSdlTextureSurface = NULL; +static int gMouseWheelX = 0; +static int gMouseWheelY = 0; + // 0x4C8A70 int coreInit(int a1) { @@ -1272,6 +1275,9 @@ void _GNW95_process_message() // The data is accumulated in SDL itself and will be processed // in `_mouse_info`. break; + case SDL_MOUSEWHEEL: + handleMouseWheelEvent(&(e.wheel)); + break; case SDL_FINGERDOWN: case SDL_FINGERMOTION: case SDL_FINGERUP: @@ -1679,6 +1685,16 @@ void _mouse_info() } _mouse_simulate_input(x, y, buttons); + + // TODO: Move to `_mouse_simulate_input`. + // TODO: Record wheel event in VCR. + gMouseWheelX = mouseData.wheelX; + gMouseWheelY = mouseData.wheelY; + + if (gMouseWheelX != 0 || gMouseWheelY != 0) { + gMouseEvent |= MOUSE_EVENT_WHEEL; + _raw_buttons |= MOUSE_EVENT_WHEEL; + } } // 0x4CA698 @@ -4804,3 +4820,26 @@ bool mouseHitTestInWindow(int win, int left, int top, int right, int bottom) return _mouse_click_in(left, top, right, bottom); } + +void mouseGetWheel(int* x, int* y) +{ + *x = gMouseWheelX; + *y = gMouseWheelY; +} + +void convertMouseWheelToArrowKey(int* keyCodePtr) +{ + if (*keyCodePtr == -1) { + if ((mouseGetEvent() & MOUSE_EVENT_WHEEL) != 0) { + int wheelX; + int wheelY; + mouseGetWheel(&wheelX, &wheelY); + + if (wheelY > 0) { + *keyCodePtr = KEY_ARROW_UP; + } else if (wheelY < 0) { + *keyCodePtr = KEY_ARROW_DOWN; + } + } + } +} diff --git a/src/core.h b/src/core.h index cf0a736..575a1c9 100644 --- a/src/core.h +++ b/src/core.h @@ -26,6 +26,7 @@ #define MOUSE_EVENT_ANY_BUTTON_UP (MOUSE_EVENT_LEFT_BUTTON_UP | MOUSE_EVENT_RIGHT_BUTTON_UP) #define MOUSE_EVENT_LEFT_BUTTON_DOWN_REPEAT (MOUSE_EVENT_LEFT_BUTTON_DOWN | MOUSE_EVENT_LEFT_BUTTON_REPEAT) #define MOUSE_EVENT_RIGHT_BUTTON_DOWN_REPEAT (MOUSE_EVENT_RIGHT_BUTTON_DOWN | MOUSE_EVENT_RIGHT_BUTTON_REPEAT) +#define MOUSE_EVENT_WHEEL 0x40 #define BUTTON_REPEAT_TIME 250 @@ -682,5 +683,7 @@ int screenGetHeight(); int screenGetVisibleHeight(); void mouseGetPositionInWindow(int win, int* x, int* y); bool mouseHitTestInWindow(int win, int left, int top, int right, int bottom); +void mouseGetWheel(int* x, int* y); +void convertMouseWheelToArrowKey(int* keyCodePtr); #endif /* CORE_H */ diff --git a/src/dbox.cc b/src/dbox.cc index 271611e..9e2abca 100644 --- a/src/dbox.cc +++ b/src/dbox.cc @@ -707,6 +707,8 @@ int showLoadFileDialog(char* title, char** fileList, char* dest, int fileListLen int scrollCounter = 0; bool isScrolling = false; + convertMouseWheelToArrowKey(&keyCode); + if (keyCode == 500) { if (fileListLength != 0) { strncpy(dest, fileList[selectedFileIndex + pageOffset], 16); @@ -1115,6 +1117,8 @@ int showSaveFileDialog(char* title, char** fileList, char* dest, int fileListLen int scrollCounter = 0; bool isScrolling = false; + convertMouseWheelToArrowKey(&keyCode); + if (keyCode == 500) { rc = 0; } else if (keyCode == KEY_RETURN) { diff --git a/src/dinput.cc b/src/dinput.cc index 5272ccc..87b9a81 100644 --- a/src/dinput.cc +++ b/src/dinput.cc @@ -11,6 +11,9 @@ static unsigned int gTouchGestureLastTouchUpTimestamp = 0; static int gTouchGestureTaps = 0; static bool gTouchGestureHandled = false; +static int gMouseWheelDeltaX = 0; +static int gMouseWheelDeltaY = 0; + extern int screenGetWidth(); extern int screenGetHeight(); @@ -64,6 +67,8 @@ bool mouseDeviceGetData(MouseData* mouseState) mouseState->y = gTouchMouseDeltaY; mouseState->buttons[0] = 0; mouseState->buttons[1] = 0; + mouseState->wheelX = 0; + mouseState->wheelY = 0; gTouchMouseDeltaX = 0; gTouchMouseDeltaY = 0; @@ -94,8 +99,13 @@ bool mouseDeviceGetData(MouseData* mouseState) Uint32 buttons = SDL_GetRelativeMouseState(&(mouseState->x), &(mouseState->y)); mouseState->buttons[0] = (buttons & SDL_BUTTON(SDL_BUTTON_LEFT)) != 0; mouseState->buttons[1] = (buttons & SDL_BUTTON(SDL_BUTTON_RIGHT)) != 0; + mouseState->wheelX = gMouseWheelDeltaX; + mouseState->wheelY = gMouseWheelDeltaY; #endif + gMouseWheelDeltaX = 0; + gMouseWheelDeltaY = 0; + return true; } @@ -186,3 +196,9 @@ void handleTouchFingerEvent(SDL_TouchFingerEvent* event) gTouchGestureLastTouchUpTimestamp = event->timestamp; } } + +void handleMouseWheelEvent(SDL_MouseWheelEvent* event) +{ + gMouseWheelDeltaX += event->x; + gMouseWheelDeltaY += event->y; +} diff --git a/src/dinput.h b/src/dinput.h index 7cb8144..d5fca12 100644 --- a/src/dinput.h +++ b/src/dinput.h @@ -7,6 +7,8 @@ typedef struct MouseData { int x; int y; unsigned char buttons[2]; + int wheelX; + int wheelY; } MouseData; typedef struct KeyboardData { @@ -29,5 +31,6 @@ bool keyboardDeviceInit(); void keyboardDeviceFree(); void handleTouchFingerEvent(SDL_TouchFingerEvent* event); +void handleMouseWheelEvent(SDL_MouseWheelEvent* event); #endif /* DINPUT_H */ diff --git a/src/game.cc b/src/game.cc index 21982ef..bf12fd5 100644 --- a/src/game.cc +++ b/src/game.cc @@ -444,6 +444,27 @@ int gameHandleKey(int eventCode, bool isInCombatMode) } if (eventCode == -1) { + if ((mouseGetEvent() & MOUSE_EVENT_WHEEL) != 0) { + int wheelX; + int wheelY; + mouseGetWheel(&wheelX, &wheelY); + + int dx = 0; + if (wheelX > 0) { + dx = 1; + } else if (wheelX < 0) { + dx = -1; + } + + int dy = 0; + if (wheelY > 0) { + dy = -1; + } else if (wheelY < 0) { + dy = 1; + } + + mapScroll(dx, dy); + } return 0; } diff --git a/src/game_dialog.cc b/src/game_dialog.cc index 8b59547..60f0307 100644 --- a/src/game_dialog.cc +++ b/src/game_dialog.cc @@ -1869,6 +1869,8 @@ int _gdProcess() for (;;) { int keyCode = _get_input(); + convertMouseWheelToArrowKey(&keyCode); + if (keyCode == KEY_CTRL_Q || keyCode == KEY_CTRL_X || keyCode == KEY_F10) { showQuitConfirmationDialog(); } diff --git a/src/inventory.cc b/src/inventory.cc index fd9288a..110388c 100644 --- a/src/inventory.cc +++ b/src/inventory.cc @@ -615,6 +615,23 @@ void inventoryOpen() _inven_pickup(keyCode, _stack_offset[_curr_stack]); } } + } else if ((mouseGetEvent() & MOUSE_EVENT_WHEEL) != 0) { + if (mouseHitTestInWindow(gInventoryWindow, INVENTORY_SCROLLER_X, INVENTORY_SCROLLER_Y, INVENTORY_SCROLLER_MAX_X, INVENTORY_SLOT_HEIGHT * gInventorySlotsCount + INVENTORY_SCROLLER_Y)) { + int wheelX; + int wheelY; + mouseGetWheel(&wheelX, &wheelY); + if (wheelY > 0) { + if (_stack_offset[_curr_stack] > 0) { + _stack_offset[_curr_stack] -= 1; + _display_inventory(_stack_offset[_curr_stack], -1, INVENTORY_WINDOW_TYPE_NORMAL); + } + } else if (wheelY < 0) { + if (gInventorySlotsCount + _stack_offset[_curr_stack] < _pud->length) { + _stack_offset[_curr_stack] += 1; + _display_inventory(_stack_offset[_curr_stack], -1, INVENTORY_WINDOW_TYPE_NORMAL); + } + } + } } } } @@ -2188,6 +2205,23 @@ void inventoryOpenUseItemOn(Object* a1) } } } + } else if ((mouseGetEvent() & MOUSE_EVENT_WHEEL) != 0) { + if (mouseHitTestInWindow(gInventoryWindow, INVENTORY_SCROLLER_X, INVENTORY_SCROLLER_Y, INVENTORY_SCROLLER_MAX_X, INVENTORY_SLOT_HEIGHT * gInventorySlotsCount + INVENTORY_SCROLLER_Y)) { + int wheelX; + int wheelY; + mouseGetWheel(&wheelX, &wheelY); + if (wheelY > 0) { + if (_stack_offset[_curr_stack] > 0) { + _stack_offset[_curr_stack] -= 1; + _display_inventory(_stack_offset[_curr_stack], -1, INVENTORY_WINDOW_TYPE_USE_ITEM_ON); + } + } else if (wheelY < 0) { + if (_stack_offset[_curr_stack] + gInventorySlotsCount < _pud->length) { + _stack_offset[_curr_stack] += 1; + _display_inventory(_stack_offset[_curr_stack], -1, INVENTORY_WINDOW_TYPE_USE_ITEM_ON); + } + } + } } } @@ -3713,6 +3747,40 @@ int inventoryOpenLooting(Object* a1, Object* a2) } } } + } else if ((mouseGetEvent() & MOUSE_EVENT_WHEEL) != 0) { + if (mouseHitTestInWindow(gInventoryWindow, INVENTORY_LOOT_LEFT_SCROLLER_X, INVENTORY_LOOT_LEFT_SCROLLER_Y, INVENTORY_LOOT_LEFT_SCROLLER_MAX_X, INVENTORY_SLOT_HEIGHT * gInventorySlotsCount + INVENTORY_LOOT_LEFT_SCROLLER_Y)) { + int wheelX; + int wheelY; + mouseGetWheel(&wheelX, &wheelY); + if (wheelY > 0) { + if (_stack_offset[_curr_stack] > 0) { + _stack_offset[_curr_stack] -= 1; + _display_inventory(_stack_offset[_curr_stack], -1, INVENTORY_WINDOW_TYPE_LOOT); + } + } else if (wheelY < 0) { + if (_stack_offset[_curr_stack] + gInventorySlotsCount < _pud->length) { + _stack_offset[_curr_stack] += 1; + _display_inventory(_stack_offset[_curr_stack], -1, INVENTORY_WINDOW_TYPE_LOOT); + } + } + } else if (mouseHitTestInWindow(gInventoryWindow, INVENTORY_LOOT_RIGHT_SCROLLER_X, INVENTORY_LOOT_RIGHT_SCROLLER_Y, INVENTORY_LOOT_RIGHT_SCROLLER_MAX_X, INVENTORY_SLOT_HEIGHT * gInventorySlotsCount + INVENTORY_LOOT_RIGHT_SCROLLER_Y)) { + int wheelX; + int wheelY; + mouseGetWheel(&wheelX, &wheelY); + if (wheelY > 0) { + if (_target_stack_offset[_target_curr_stack] > 0) { + _target_stack_offset[_target_curr_stack] -= 1; + _display_target_inventory(_target_stack_offset[_target_curr_stack], -1, _target_pud, INVENTORY_WINDOW_TYPE_LOOT); + windowRefresh(gInventoryWindow); + } + } else if (wheelY < 0) { + if (_target_stack_offset[_target_curr_stack] + gInventorySlotsCount < _target_pud->length) { + _target_stack_offset[_target_curr_stack] += 1; + _display_target_inventory(_target_stack_offset[_target_curr_stack], -1, _target_pud, INVENTORY_WINDOW_TYPE_LOOT); + windowRefresh(gInventoryWindow); + } + } + } } } @@ -4535,6 +4603,70 @@ void inventoryOpenTrade(int win, Object* a2, Object* a3, Object* a4, int a5) keyCode = -1; } + } else if ((mouseGetEvent() & MOUSE_EVENT_WHEEL) != 0) { + if (mouseHitTestInWindow(gInventoryWindow, INVENTORY_TRADE_INNER_LEFT_SCROLLER_TRACKING_X, INVENTORY_TRADE_INNER_LEFT_SCROLLER_TRACKING_Y, INVENTORY_TRADE_INNER_LEFT_SCROLLER_TRACKING_MAX_X, INVENTORY_SLOT_HEIGHT * gInventorySlotsCount + INVENTORY_TRADE_INNER_LEFT_SCROLLER_TRACKING_Y)) { + int wheelX; + int wheelY; + mouseGetWheel(&wheelX, &wheelY); + if (wheelY > 0) { + if (_stack_offset[_curr_stack] > 0) { + _stack_offset[_curr_stack] -= 1; + _display_inventory(_stack_offset[_curr_stack], -1, INVENTORY_WINDOW_TYPE_TRADE); + } + } else if (wheelY < 0) { + if (_stack_offset[_curr_stack] + gInventorySlotsCount < _pud->length) { + _stack_offset[_curr_stack] += 1; + _display_inventory(_stack_offset[_curr_stack], -1, INVENTORY_WINDOW_TYPE_TRADE); + } + } + } else if (mouseHitTestInWindow(gInventoryWindow, INVENTORY_TRADE_LEFT_SCROLLER_TRACKING_X, INVENTORY_TRADE_LEFT_SCROLLER_TRACKING_Y, INVENTORY_TRADE_LEFT_SCROLLER_TRACKING_MAX_X, INVENTORY_SLOT_HEIGHT * gInventorySlotsCount + INVENTORY_TRADE_LEFT_SCROLLER_TRACKING_Y)) { + int wheelX; + int wheelY; + mouseGetWheel(&wheelX, &wheelY); + if (wheelY > 0) { + if (_ptable_offset > 0) { + _ptable_offset -= 1; + inventoryWindowRenderInnerInventories(win, a3, a4, -1); + } + } else if (wheelY < 0) { + if (_ptable_offset + gInventorySlotsCount < _ptable_pud->length) { + _ptable_offset += 1; + inventoryWindowRenderInnerInventories(win, a3, a4, -1); + } + } + } else if (mouseHitTestInWindow(gInventoryWindow, INVENTORY_TRADE_RIGHT_SCROLLER_TRACKING_X, INVENTORY_TRADE_RIGHT_SCROLLER_TRACKING_Y, INVENTORY_TRADE_RIGHT_SCROLLER_TRACKING_MAX_X, INVENTORY_SLOT_HEIGHT * gInventorySlotsCount + INVENTORY_TRADE_RIGHT_SCROLLER_TRACKING_Y)) { + int wheelX; + int wheelY; + mouseGetWheel(&wheelX, &wheelY); + if (wheelY > 0) { + if (_target_stack_offset[_target_curr_stack] > 0) { + _target_stack_offset[_target_curr_stack] -= 1; + _display_target_inventory(_target_stack_offset[_target_curr_stack], -1, _target_pud, INVENTORY_WINDOW_TYPE_TRADE); + windowRefresh(gInventoryWindow); + } + } else if (wheelY < 0) { + if (_target_stack_offset[_target_curr_stack] + gInventorySlotsCount < _target_pud->length) { + _target_stack_offset[_target_curr_stack] += 1; + _display_target_inventory(_target_stack_offset[_target_curr_stack], -1, _target_pud, INVENTORY_WINDOW_TYPE_TRADE); + windowRefresh(gInventoryWindow); + } + } + } else if (mouseHitTestInWindow(gInventoryWindow, INVENTORY_TRADE_INNER_RIGHT_SCROLLER_TRACKING_X, INVENTORY_TRADE_INNER_RIGHT_SCROLLER_TRACKING_Y, INVENTORY_TRADE_INNER_RIGHT_SCROLLER_TRACKING_MAX_X, INVENTORY_SLOT_HEIGHT * gInventorySlotsCount + INVENTORY_TRADE_INNER_RIGHT_SCROLLER_TRACKING_Y)) { + int wheelX; + int wheelY; + mouseGetWheel(&wheelX, &wheelY); + if (wheelY > 0) { + if (_btable_offset > 0) { + _btable_offset -= 1; + inventoryWindowRenderInnerInventories(win, a3, a4, -1); + } + } else if (wheelY < 0) { + if (_btable_offset + gInventorySlotsCount < _btable_pud->length) { + _btable_offset++; + inventoryWindowRenderInnerInventories(win, a3, a4, -1); + } + } + } } } } diff --git a/src/loadsave.cc b/src/loadsave.cc index ca66988..28f68e8 100644 --- a/src/loadsave.cc +++ b/src/loadsave.cc @@ -478,6 +478,8 @@ int lsgSaveGame(int mode) int v37 = 0; int v102 = 0; + convertMouseWheelToArrowKey(&keyCode); + if (keyCode == KEY_ESCAPE || keyCode == 501 || _game_user_wants_to_quit != 0) { rc = 0; } else { @@ -890,6 +892,8 @@ int lsgLoadGame(int mode) int v107 = 0; int v108 = -1; + convertMouseWheelToArrowKey(&keyCode); + if (keyCode == KEY_ESCAPE || keyCode == 501 || _game_user_wants_to_quit != 0) { rc = 0; } else { diff --git a/src/world_map.cc b/src/world_map.cc index b7b79c7..21e1d3a 100644 --- a/src/world_map.cc +++ b/src/world_map.cc @@ -3458,6 +3458,20 @@ int _wmWorldMapFunc(int a1) } } + if ((mouseEvent & MOUSE_EVENT_WHEEL) != 0) { + int wheelX; + int wheelY; + mouseGetWheel(&wheelX, &wheelY); + + if (mouseHitTestInWindow(gWorldmapWindow, WM_VIEW_X, WM_VIEW_Y, 472, 465)) { + worldmapWindowScroll(20, 20, wheelX, -wheelY, NULL, true); + } else if (mouseHitTestInWindow(gWorldmapWindow, 501, 135, 501 + 119, 135 + 178)) { + if (wheelY != 0) { + _wmInterfaceScrollTabsStart(wheelY > 0 ? 27 : -27); + } + } + } + if (map != -1 || v25 == -1) { break; }