From dd7dee72321151516d9c356634e287c274e2b40b Mon Sep 17 00:00:00 2001 From: superp00t Date: Fri, 6 Sep 2024 12:24:35 -0400 Subject: [PATCH] feat(event): implement OsInputGetMousePosition; add common behavior for SDL interaction regardless of your OS --- src/event/CMakeLists.txt | 6 + src/event/Input.hpp | 2 + src/event/linux/Input.cpp | 28 +++- src/event/mac/Input.cpp | 23 ++- src/event/sdl/Input.cpp | 301 ++++++++++++++++++++++++++++++++++++++ src/event/sdl/Input.hpp | 12 ++ src/event/win/Input.cpp | 51 ++++++- 7 files changed, 418 insertions(+), 5 deletions(-) create mode 100644 src/event/sdl/Input.cpp create mode 100644 src/event/sdl/Input.hpp diff --git a/src/event/CMakeLists.txt b/src/event/CMakeLists.txt index 0670307..6c4b3db 100644 --- a/src/event/CMakeLists.txt +++ b/src/event/CMakeLists.txt @@ -22,6 +22,12 @@ if(WHOA_SYSTEM_LINUX) list(APPEND PRIVATE_SOURCES ${LINUX_SOURCES}) endif() +# SDL has its own input event processing +if(WHOA_BUILD_GLSDL) + file(GLOB SDL_SOURCES "sdl/*.cpp") + list(APPEND PRIVATE_SOURCES ${SDL_SOURCES}) +endif() + add_library(event STATIC ${PRIVATE_SOURCES} ) diff --git a/src/event/Input.hpp b/src/event/Input.hpp index b899d39..e913099 100644 --- a/src/event/Input.hpp +++ b/src/event/Input.hpp @@ -64,6 +64,8 @@ void OsInputPostEvent(OSINPUT id, int32_t param0, int32_t param1, int32_t param2 void OsInputSetMouseMode(OS_MOUSE_MODE mode); +void OsInputGetMousePosition(int32_t* x, int32_t* y); + int32_t OsQueueGet(OSINPUT* id, int32_t* param0, int32_t* param1, int32_t* param2, int32_t* param3); void OsQueuePut(OSINPUT id, int32_t param0, int32_t param1, int32_t param2, int32_t param3); diff --git a/src/event/linux/Input.cpp b/src/event/linux/Input.cpp index da49d03..bd381f0 100644 --- a/src/event/linux/Input.cpp +++ b/src/event/linux/Input.cpp @@ -1,7 +1,17 @@ -#include "event/Input.hpp" #include +#include "event/Input.hpp" + +#if defined(WHOA_BUILD_GLSDL) +#include "event/sdl/Input.hpp" +#endif + int32_t OsInputGet(OSINPUT* id, int32_t* param0, int32_t* param1, int32_t* param2, int32_t* param3) { +#if defined(WHOA_BUILD_GLSDL) + if (SDLInputActive()) { + return SDLInputGet(id, param0, param1, param2, param3); + } +#endif if (Input::s_queueTail == Input::s_queueHead) { return 0; } @@ -18,3 +28,19 @@ void OsInputSetMouseMode(OS_MOUSE_MODE mode) { int32_t OsWindowProc(void* window, uint32_t message, uintptr_t wparam, intptr_t lparam) { return 0; } + +void OsInputGetMousePosition(int32_t* x, int32_t* y) { +#if defined(WHOA_BUILD_GLSDL) + if (SDLInputActive()) { + SDLInputGetMousePosition(x, y); + return; + } +#endif + + if (x) { + *x = 0; + } + if (y) { + *y = 0; + } +} diff --git a/src/event/mac/Input.cpp b/src/event/mac/Input.cpp index b55e1f7..3263d76 100644 --- a/src/event/mac/Input.cpp +++ b/src/event/mac/Input.cpp @@ -1,5 +1,8 @@ #include "event/Input.hpp" #include +#include + +static C2iVector s_mousePos; int32_t OsInputGet(OSINPUT* id, int32_t* param0, int32_t* param1, int32_t* param2, int32_t* param3) { // TODO @@ -19,13 +22,31 @@ int32_t OsInputGet(OSINPUT* id, int32_t* param0, int32_t* param1, int32_t* param OsQueueSetParam(3, OsGetAsyncTimeMs()); - return OsQueueGet(id, param0, param1, param2, param3); + auto queue_result = OsQueueGet(id, param0, param1, param2, param3); + if (queue_result) { + if (*id == OS_INPUT_MOUSE_MOVE) { + s_mousePos.x = *param1; + s_mousePos.y = *param2; + } + } + + return queue_result; } void OsInputSetMouseMode(OS_MOUSE_MODE mode) { // TODO } +void OsInputGetMousePosition(int32_t* x, int32_t* y) { + if (x) { + *x = s_mousePos.x; + } + + if (y) { + *y = s_mousePos.y; + } +} + int32_t OsWindowProc(void* window, uint32_t message, uintptr_t wparam, intptr_t lparam) { return 0; } diff --git a/src/event/sdl/Input.cpp b/src/event/sdl/Input.cpp new file mode 100644 index 0000000..096ece0 --- /dev/null +++ b/src/event/sdl/Input.cpp @@ -0,0 +1,301 @@ +#include +#include +#include + +#include "event/sdl/Input.hpp" +#include "client/gui/OsGui.hpp" +#include "gx/Device.hpp" +#include "gx/Window.hpp" + +static const std::unordered_map s_keyConversion = { + { SDL_SCANCODE_LSHIFT, KEY_LSHIFT }, + { SDL_SCANCODE_RSHIFT, KEY_RSHIFT }, + { SDL_SCANCODE_LCTRL, KEY_LCONTROL }, + { SDL_SCANCODE_RCTRL, KEY_RCONTROL }, + { SDL_SCANCODE_LALT, KEY_LALT }, + { SDL_SCANCODE_RALT, KEY_RALT }, + { SDL_SCANCODE_SPACE, KEY_SPACE }, + { SDL_SCANCODE_0, KEY_0 }, + { SDL_SCANCODE_1, KEY_1 }, + { SDL_SCANCODE_2, KEY_2 }, + { SDL_SCANCODE_3, KEY_3 }, + { SDL_SCANCODE_4, KEY_4 }, + { SDL_SCANCODE_5, KEY_5 }, + { SDL_SCANCODE_6, KEY_6 }, + { SDL_SCANCODE_7, KEY_7 }, + { SDL_SCANCODE_8, KEY_8 }, + { SDL_SCANCODE_9, KEY_9 }, + { SDL_SCANCODE_A, KEY_A }, + { SDL_SCANCODE_B, KEY_B }, + { SDL_SCANCODE_C, KEY_C }, + { SDL_SCANCODE_D, KEY_D }, + { SDL_SCANCODE_E, KEY_E }, + { SDL_SCANCODE_F, KEY_F }, + { SDL_SCANCODE_G, KEY_G }, + { SDL_SCANCODE_H, KEY_H }, + { SDL_SCANCODE_I, KEY_I }, + { SDL_SCANCODE_J, KEY_J }, + { SDL_SCANCODE_K, KEY_K }, + { SDL_SCANCODE_L, KEY_L }, + { SDL_SCANCODE_M, KEY_M }, + { SDL_SCANCODE_N, KEY_N }, + { SDL_SCANCODE_O, KEY_O }, + { SDL_SCANCODE_P, KEY_P }, + { SDL_SCANCODE_Q, KEY_Q }, + { SDL_SCANCODE_R, KEY_R }, + { SDL_SCANCODE_S, KEY_S }, + { SDL_SCANCODE_T, KEY_T }, + { SDL_SCANCODE_U, KEY_U }, + { SDL_SCANCODE_V, KEY_V }, + { SDL_SCANCODE_W, KEY_W }, + { SDL_SCANCODE_X, KEY_X }, + { SDL_SCANCODE_Y, KEY_Y }, + { SDL_SCANCODE_Z, KEY_Z }, + { SDL_SCANCODE_GRAVE, KEY_TILDE }, + { SDL_SCANCODE_KP_0, KEY_NUMPAD0 }, + { SDL_SCANCODE_KP_1, KEY_NUMPAD1 }, + { SDL_SCANCODE_KP_2, KEY_NUMPAD2 }, + { SDL_SCANCODE_KP_3, KEY_NUMPAD3 }, + { SDL_SCANCODE_KP_4, KEY_NUMPAD4 }, + { SDL_SCANCODE_KP_5, KEY_NUMPAD5 }, + { SDL_SCANCODE_KP_6, KEY_NUMPAD6 }, + { SDL_SCANCODE_KP_7, KEY_NUMPAD7 }, + { SDL_SCANCODE_KP_8, KEY_NUMPAD8 }, + { SDL_SCANCODE_KP_9, KEY_NUMPAD9 }, + { SDL_SCANCODE_KP_PLUS, KEY_NUMPAD_PLUS }, + { SDL_SCANCODE_KP_MINUS, KEY_NUMPAD_MINUS }, + { SDL_SCANCODE_KP_MULTIPLY, KEY_NUMPAD_MULTIPLY }, + { SDL_SCANCODE_KP_DIVIDE, KEY_NUMPAD_DIVIDE }, + { SDL_SCANCODE_KP_DECIMAL, KEY_NUMPAD_DECIMAL }, + { SDL_SCANCODE_KP_EQUALS, KEY_NUMPAD_EQUALS }, + { SDL_SCANCODE_EQUALS, KEY_PLUS }, + { SDL_SCANCODE_MINUS, KEY_MINUS }, + { SDL_SCANCODE_LEFTBRACKET, KEY_BRACKET_OPEN }, + { SDL_SCANCODE_RIGHTBRACKET, KEY_BRACKET_CLOSE }, + { SDL_SCANCODE_SLASH, KEY_SLASH }, + { SDL_SCANCODE_BACKSLASH, KEY_BACKSLASH }, + { SDL_SCANCODE_SEMICOLON, KEY_SEMICOLON }, + { SDL_SCANCODE_APOSTROPHE, KEY_APOSTROPHE }, + { SDL_SCANCODE_COMMA, KEY_COMMA }, + { SDL_SCANCODE_PERIOD, KEY_PERIOD }, + { SDL_SCANCODE_ESCAPE, KEY_ESCAPE }, + { SDL_SCANCODE_RETURN, KEY_ENTER }, + { SDL_SCANCODE_BACKSPACE, KEY_BACKSPACE }, + { SDL_SCANCODE_TAB, KEY_TAB }, + { SDL_SCANCODE_LEFT, KEY_LEFT }, + { SDL_SCANCODE_UP, KEY_UP }, + { SDL_SCANCODE_RIGHT, KEY_RIGHT }, + { SDL_SCANCODE_DOWN, KEY_DOWN }, + { SDL_SCANCODE_INSERT, KEY_INSERT }, + { SDL_SCANCODE_DELETE, KEY_DELETE }, + { SDL_SCANCODE_HOME, KEY_HOME }, + { SDL_SCANCODE_END, KEY_END }, + { SDL_SCANCODE_PAGEUP, KEY_PAGEUP }, + { SDL_SCANCODE_PAGEDOWN, KEY_PAGEDOWN }, + { SDL_SCANCODE_CAPSLOCK, KEY_CAPSLOCK }, + { SDL_SCANCODE_NUMLOCKCLEAR, KEY_NUMLOCK }, + { SDL_SCANCODE_SCROLLLOCK, KEY_SCROLLLOCK }, + { SDL_SCANCODE_PAUSE, KEY_PAUSE }, + { SDL_SCANCODE_PRINTSCREEN, KEY_PRINTSCREEN }, + { SDL_SCANCODE_F1, KEY_F1 }, + { SDL_SCANCODE_F2, KEY_F2 }, + { SDL_SCANCODE_F3, KEY_F3 }, + { SDL_SCANCODE_F4, KEY_F4 }, + { SDL_SCANCODE_F5, KEY_F5 }, + { SDL_SCANCODE_F6, KEY_F6 }, + { SDL_SCANCODE_F7, KEY_F7 }, + { SDL_SCANCODE_F8, KEY_F8 }, + { SDL_SCANCODE_F9, KEY_F9 }, + { SDL_SCANCODE_F10, KEY_F10 }, + { SDL_SCANCODE_F11, KEY_F11 }, + { SDL_SCANCODE_F12, KEY_F12 }, + { SDL_SCANCODE_F13, KEY_F13 }, + { SDL_SCANCODE_F14, KEY_F14 }, + { SDL_SCANCODE_F15, KEY_F15 }, + { SDL_SCANCODE_F16, KEY_F16 }, + { SDL_SCANCODE_F17, KEY_F17 }, + { SDL_SCANCODE_F18, KEY_F18 }, + { SDL_SCANCODE_F19, KEY_F19 } +}; + +static MOUSEBUTTON s_buttonConversion[16] = { + MOUSE_BUTTON_NONE, + MOUSE_BUTTON_LEFT, + MOUSE_BUTTON_MIDDLE, + MOUSE_BUTTON_RIGHT, + MOUSE_BUTTON_XBUTTON1, + MOUSE_BUTTON_XBUTTON2, + MOUSE_BUTTON_XBUTTON3, + MOUSE_BUTTON_XBUTTON4, + MOUSE_BUTTON_XBUTTON5, + MOUSE_BUTTON_XBUTTON6, + MOUSE_BUTTON_XBUTTON7, + MOUSE_BUTTON_XBUTTON8, + MOUSE_BUTTON_XBUTTON9, + MOUSE_BUTTON_XBUTTON10, + MOUSE_BUTTON_XBUTTON11, + MOUSE_BUTTON_XBUTTON12 +}; + +bool SDLInputActive() { + return OsGuiGetWindow(0) != nullptr && GxDevApi() == GxApi_GLSDL; +} + +void SDLInputGetMousePosition(int32_t* x, int32_t *y) { + int mouseX; + int mouseY; + + if (Input::s_osMouseMode == OS_MOUSE_MODE_RELATIVE) { + SDL_GetMouseState(&mouseX, &mouseY); + } else { + SDL_GetGlobalMouseState(&mouseX, &mouseY); + } + + if (x) { + *x = static_cast(mouseX); + } + + if (y) { + *y = static_cast(mouseY); + } + return; +} + +bool ConvertScancode(SDL_Scancode scancode, KEY& key) { + // What key does this SDL scancode correspond to? + auto lookup = s_keyConversion.find(scancode); + if (lookup != s_keyConversion.end()) { + // Scancode was found + key = lookup->second; + return true; + } + + return false; +} + +int32_t SDLInputGet(OSINPUT* id, int32_t* param0, int32_t* param1, int32_t* param2, int32_t* param3) { + *id = static_cast(-1); + + if (Input::s_queueTail != Input::s_queueHead) { + OsQueueGet(id, param0, param1, param2, param3); + return 1; + } + + auto gxWindow = OsGuiGetWindow(0); + + auto sdlWindow = static_cast(gxWindow); + + SDL_Event event; + + while (SDL_PollEvent(&event)) { + switch (event.type) { + case SDL_KEYDOWN: + case SDL_KEYUP: { + KEY key; + if (ConvertScancode(event.key.keysym.scancode, key)) { + *id = event.type == SDL_KEYUP ? OS_INPUT_KEY_UP : OS_INPUT_KEY_DOWN; + *param0 = key; + return 1; + } + + break; + } + case SDL_MOUSEBUTTONDOWN: + case SDL_MOUSEBUTTONUP: { + // Is this an up or down mouse click? + *id = event.type == SDL_MOUSEBUTTONUP ? OS_INPUT_MOUSE_UP : OS_INPUT_MOUSE_DOWN; + + // XY click coordinates + auto x = static_cast(event.button.x); + auto y = static_cast(event.button.y); + + // Convert SDL button index into internal MOUSEBUTTON ID + auto buttonIndex = event.button.button; + if (buttonIndex > 15) { + break; + } + + auto button = s_buttonConversion[buttonIndex]; + + *param0 = button; + *param1 = x; + *param2 = y; + *param3 = 0; + + return 1; + } + case SDL_MOUSEMOTION: { + auto x = static_cast(event.motion.x); + auto y = static_cast(event.motion.y); + + *id = OS_INPUT_MOUSE_MOVE; + *param0 = 0; + *param1 = x; + *param2 = y; + *param3 = 0; + return 1; + } + case SDL_TEXTINPUT: { + // text input string holding one or more UTF-8 characters + auto text = reinterpret_cast(event.text.text); + + // Because SDL_TextInputEvent can hold multiple UTF-8 characters + // split into UTF-8 characters + while (*text != '\0') { + // byte size of current UTF-8 character + int32_t charactersize = 0; + + // Read UTF-8 character + auto character = static_cast(SUniSGetUTF8(text, &charactersize)); + if (character < 0) { + // Cancel in case of invalid input + break; + } + + // Push character to input queue + OsQueuePut(OS_INPUT_CHAR, character, 1, 0, 0); + + // Advance text pointer + text += charactersize; + } + + // deque first character if any + if (Input::s_queueTail != Input::s_queueHead) { + OsQueueGet(id, param0, param1, param2, param3); + return 1; + } + + // continue loop if there was not a single character in this event + + break; + } + case SDL_WINDOWEVENT_RESIZED: { + auto width = static_cast(event.window.data1); + auto height = static_cast(event.window.data2); + + // static_cast(g_theGxDevicePtr)->Resize(width, height); + + *id = OS_INPUT_SIZE; + *param0 = width; + *param1 = height; + + auto bounds = GetSavedWindowBounds(); + Rect newBounds = { + bounds->top, + bounds->left, + static_cast(bounds->top + height), + static_cast(bounds->left + width) + }; + SetSavedWindowBounds(newBounds); + } + case SDL_QUIT: { + *id = OS_INPUT_CLOSE; + return 1; + } + default: + break; + } + } + + return 0; +} diff --git a/src/event/sdl/Input.hpp b/src/event/sdl/Input.hpp new file mode 100644 index 0000000..4843acb --- /dev/null +++ b/src/event/sdl/Input.hpp @@ -0,0 +1,12 @@ +#ifndef EVENT_SDL_INPUT_HPP +#define EVENT_SDL_INPUT_HPP + +#include "event/Input.hpp" + +bool SDLInputActive(); + +int32_t SDLInputGet(OSINPUT* id, int32_t* param0, int32_t* param1, int32_t* param2, int32_t* param3); + +void SDLInputGetMousePosition(int32_t* x, int32_t *y); + +#endif diff --git a/src/event/win/Input.cpp b/src/event/win/Input.cpp index a3a2f12..687892b 100644 --- a/src/event/win/Input.cpp +++ b/src/event/win/Input.cpp @@ -1,11 +1,19 @@ #include "event/Input.hpp" #include "client/Gui.hpp" #include +#include #include +#if defined(WHOA_BUILD_GLSDL) +#include "event/sdl/Input.hpp" +#endif + static RECT s_defaultWindowRect; static int32_t s_savedResize; +static HWND s_mouseWnd; +static C2iVector s_mousePos; + void CenterMouse() { // TODO } @@ -14,8 +22,10 @@ void RestoreMouse() { // TODO } -void SaveMouse(POINT mousePos, HWND hwnd) { - // TODO +void SaveMouse(HWND window, const POINT& pt) { + s_mouseWnd = window; + s_mousePos.x = static_cast(pt.x); + s_mousePos.y = static_cast(pt.y); } int32_t ConvertButton(uint32_t message, uintptr_t wparam, MOUSEBUTTON* button) { @@ -328,6 +338,13 @@ int32_t HandleMouseUp(uint32_t message, uintptr_t wparam, bool* xbutton, HWND hw } int32_t OsInputGet(OSINPUT* id, int32_t* param0, int32_t* param1, int32_t* param2, int32_t* param3) { +#if defined(WHOA_BUILD_GLSDL) + if (SDLInputActive()) { + // SDL handles input events for us + return SDLInputGet(id, param0, param1, param2, param3); + } +#endif + *id = static_cast(-1); if (s_savedResize) { @@ -424,6 +441,34 @@ void OsInputSetMouseMode(OS_MOUSE_MODE mode) { } } +void OsInputGetMousePosition(int32_t* x, int32_t* y) { +#if defined(WHOA_BUILD_GLSDL) + if (SDLInputActive()) { + SDLInputGetMousePosition(x, y); + return; + } +#endif + + // Get HWND created by CGxDevice + auto window = static_cast(OsGuiGetWindow(0)); + + POINT pt; + GetCursorPos(&pt); + ScreenToClient(window, &pt); + + if (Input::s_osMouseMode != OS_MOUSE_MODE_RELATIVE) { + SaveMouse(window, pt); + } + + // Provide mouse position to caller + if (x) { + *x = static_cast(pt.x); + } + if (y) { + *y = static_cast(pt.y); + } +} + int32_t OsWindowProc(void* window, uint32_t message, uintptr_t wparam, intptr_t lparam) { auto hwnd = static_cast(window); @@ -546,7 +591,7 @@ int32_t OsWindowProc(void* window, uint32_t message, uintptr_t wparam, intptr_t GetCursorPos(&mousePos); ScreenToClient(hwnd, &mousePos); OsQueuePut(OS_INPUT_MOUSE_MOVE, 0, mousePos.x, mousePos.y, 0); - SaveMouse(mousePos, hwnd); + SaveMouse(hwnd, mousePos); } break;