From ab45b5ec8a63ff08e2a07db555a742f391be66dd Mon Sep 17 00:00:00 2001 From: Flyinghead Date: Tue, 19 Oct 2021 16:56:46 +0200 Subject: [PATCH] ggpo: keyboard/mouse games support. Fix chat when keyboard disabled ggpo: support for arcade games using keyboard (totd, luptype) and mouse/rotary encoders (waiwai drive) Chat and UI now usable when the keyboard is not set to a maple port. --- CMakeLists.txt | 4 +- core/cfg/option.cpp | 1 + core/cfg/option.h | 1 + core/hw/maple/maple_cfg.cpp | 35 ++-- core/hw/maple/maple_cfg.h | 24 ++- core/hw/maple/maple_devs.cpp | 124 ++----------- core/hw/maple/maple_devs.h | 14 -- core/hw/maple/maple_jvs.cpp | 21 +-- core/input/gamepad_device.cpp | 54 +----- core/input/gamepad_device.h | 72 -------- core/input/keyboard_device.h | 62 ++++--- core/input/mouse.cpp | 168 ++++++++++++++++++ core/input/mouse.h | 104 +++++++++++ core/network/ggpo.cpp | 118 +++++++++--- core/rend/gui.cpp | 30 ++-- core/rend/gui.h | 1 + core/rend/gui_chat.h | 3 +- core/sdl/sdl_gamepad.h | 3 +- .../src/main/jni/src/android_gamepad.h | 1 + .../apple/emulator-ios/emulator/ios_gamepad.h | 1 + shell/apple/emulator-ios/emulator/ios_mouse.h | 2 +- .../emulator-osx/emulator-osx/osx_gamepad.h | 2 +- shell/libretro/libretro.cpp | 23 ++- 23 files changed, 515 insertions(+), 353 deletions(-) create mode 100644 core/input/mouse.cpp create mode 100644 core/input/mouse.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 04f5ef988..84a5f35a7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -738,7 +738,9 @@ if(NOT LIBRETRO) core/input/gamepad_device.h core/input/keyboard_device.h core/input/mapping.cpp - core/input/mapping.h) + core/input/mapping.h + core/input/mouse.cpp + core/input/mouse.h) endif() if(WIN32) diff --git a/core/cfg/option.cpp b/core/cfg/option.cpp index e2f21e85c..114f83cce 100644 --- a/core/cfg/option.cpp +++ b/core/cfg/option.cpp @@ -120,6 +120,7 @@ Option GGPOEnable("GGPO", false, "network"); Option GGPODelay("GGPODelay", 0, "network"); Option NetworkStats("Stats", true, "network"); Option GGPOAnalogAxes("GGPOAnalogAxes", 0, "network"); +Option GGPOChat("GGPOChat", true, "network"); #ifdef SUPPORT_DISPMANX Option DispmanxMaintainAspect("maintain_aspect", true, "dispmanx"); diff --git a/core/cfg/option.h b/core/cfg/option.h index 4dc110c2f..06ff3e014 100644 --- a/core/cfg/option.h +++ b/core/cfg/option.h @@ -492,6 +492,7 @@ extern Option GGPOEnable; extern Option GGPODelay; extern Option NetworkStats; extern Option GGPOAnalogAxes; +extern Option GGPOChat; #ifdef SUPPORT_DISPMANX extern Option DispmanxMaintainAspect; diff --git a/core/hw/maple/maple_cfg.cpp b/core/hw/maple/maple_cfg.cpp index 401442ec1..da2540d3d 100644 --- a/core/hw/maple/maple_cfg.cpp +++ b/core/hw/maple/maple_cfg.cpp @@ -2,12 +2,13 @@ #include "maple_helper.h" #include "maple_if.h" #include "hw/naomi/naomi_cart.h" -#include "input/gamepad_device.h" #include "cfg/option.h" #include "stdclass.h" MapleInputState mapleInputState[4]; +void (*MapleConfigMap::UpdateVibration)(u32 port, float power, float inclination, u32 duration_ms); + static u8 GetBtFromSgn(s8 val) { return val+128; @@ -156,20 +157,24 @@ void MapleConfigMap::SetImage(u8 *img) void MapleConfigMap::GetAbsCoordinates(int& x, int& y) { const MapleInputState& inputState = mapleInputState[playerNum()]; - x = inputState.absPointerX; - y = inputState.absPointerY; + x = inputState.absPos.x; + y = inputState.absPos.y; } void MapleConfigMap::GetMouseInput(u8& buttons, int& x, int& y, int& wheel) { - u32 playerNum = this->playerNum(); - buttons = mo_buttons[playerNum] & 0xff; - x = (int)std::round(mo_x_delta[playerNum]); - y = (int)std::round(mo_y_delta[playerNum]); - wheel = (int)std::round(mo_wheel_delta[playerNum]); - mo_x_delta[playerNum] = 0; - mo_y_delta[playerNum] = 0; - mo_wheel_delta[playerNum] = 0; + const MapleInputState& inputState = mapleInputState[playerNum()]; + buttons = inputState.mouseButtons; + x = inputState.relPos.x; + y = inputState.relPos.y * (invertMouseY ? -1 : 1); + wheel = inputState.relPos.wheel; +} + +void MapleConfigMap::GetKeyboardInput(u8& shift, u8 keys[6]) +{ + const MapleInputState& inputState = mapleInputState[playerNum()]; + shift = inputState.keyboard.shift; + memcpy(keys, inputState.keyboard.key, sizeof(inputState.keyboard.key)); } bool maple_atomiswave_coin_chute(int slot) @@ -201,7 +206,10 @@ static void createNaomiDevices() mcfg_DestroyDevices(); mcfg_Create(MDT_NaomiJamma, 0, 5); if (settings.input.JammaSetup == JVS::Keyboard) + { mcfg_Create(MDT_Keyboard, 1, 5, 0); + mcfg_Create(MDT_Keyboard, 2, 5, 1); + } else { // Connect VMU B1 @@ -247,6 +255,11 @@ static void createAtomiswaveDevices() // Waiwai drive needs two track-balls mcfg_Create(MDT_Mouse, 2, 5, 0); mcfg_Create(MDT_Mouse, 3, 5, 1); + if (settings.content.gameId == "DRIVE") + { + MapleDevices[2][5]->config->invertMouseY = true; + MapleDevices[3][5]->config->invertMouseY = true; + } } } diff --git a/core/hw/maple/maple_cfg.h b/core/hw/maple/maple_cfg.h index 1d52e56ba..7b798aaa4 100644 --- a/core/hw/maple/maple_cfg.h +++ b/core/hw/maple/maple_cfg.h @@ -62,8 +62,12 @@ public: void GetInput(PlainJoystickState* pjs); void GetAbsCoordinates(int& x, int& y); void GetMouseInput(u8& buttons, int& x, int& y, int& wheel); + void GetKeyboardInput(u8& shift, u8 keys[6]); void SetImage(u8 *img); + static void (*UpdateVibration)(u32 port, float power, float inclination, u32 duration_ms); + bool invertMouseY = false; + private: u32 playerNum(); @@ -72,13 +76,27 @@ private: struct MapleInputState { - MapleInputState() : halfAxes{}, fullAxes{} {} + MapleInputState() : halfAxes{}, fullAxes{} { + memset(keyboard.key, 0, sizeof(keyboard.key)); + } u32 kcode = ~0; u8 halfAxes[PJTI_Count]; // LT, RT int8_t fullAxes[PJAI_Count]; // Left X, Y, Right X, Y - int absPointerX = -1; - int absPointerY = -1; + u8 mouseButtons = ~0; + struct { + int x = -1; + int y = -1; + } absPos; + struct { + int16_t x = 0; + int16_t y = 0; + int16_t wheel = 0; + } relPos; + struct { + u8 shift = 0; // modifier keys bitmask + u8 key[6]; // normal keys pressed + } keyboard; }; extern MapleInputState mapleInputState[4]; diff --git a/core/hw/maple/maple_devs.cpp b/core/hw/maple/maple_devs.cpp index ab22715cd..7b38a0b3d 100755 --- a/core/hw/maple/maple_devs.cpp +++ b/core/hw/maple/maple_devs.cpp @@ -1042,10 +1042,6 @@ struct maple_sega_purupuru : maple_base } }; -u8 kb_shift[MAPLE_PORTS]; // shift keys pressed (bitmask) -u8 kb_led[MAPLE_PORTS]; // leds currently lit -u8 kb_key[MAPLE_PORTS][6]; // normal keys pressed - struct maple_keyboard : maple_base { MapleDeviceType get_device_type() override @@ -1102,16 +1098,21 @@ struct maple_keyboard : maple_base return cmd == MDC_DeviceRequest ? MDRS_DeviceStatus : MDRS_DeviceStatusAll; case MDCF_GetCondition: - w32(MFID_6_Keyboard); - //struct data - //int8 shift ; shift keys pressed (bitmask) //1 - w8(kb_shift[player_num]); - //int8 led ; leds currently lit //1 - w8(kb_led[player_num]); - //int8 key[6] ; normal keys pressed //6 - for (int i = 0; i < 6; i++) - w8(kb_key[player_num][i]); + { + u8 shift; + u8 keys[6]; + config->GetKeyboardInput(shift, keys); + w32(MFID_6_Keyboard); + //struct data + //int8 shift ; shift keys pressed (bitmask) //1 + w8(shift); + //int8 led ; leds currently lit //1 + w8(0); + //int8 key[6] ; normal keys pressed //6 + for (int i = 0; i < 6; i++) + w8(keys[i]); + } return MDRS_DataTransfer; case MDC_DeviceReset: @@ -1127,28 +1128,6 @@ struct maple_keyboard : maple_base } }; -// Mouse buttons -// bit 0: Button C -// bit 1: Right button (B) -// bit 2: Left button (A) -// bit 3: Wheel button -u8 mo_buttons[4] = { 0xFF, 0xFF, 0xFF, 0xFF }; -// Relative mouse coordinates [-512:511] -f32 mo_x_delta[4]; -f32 mo_y_delta[4]; -f32 mo_wheel_delta[4]; -// Absolute mouse coordinates -// Range [0:639] [0:479] -// but may be outside this range if the pointer is offscreen or outside the 4:3 window. -s32 mo_x_abs[4]; -s32 mo_y_abs[4]; -// previous mouse coordinates for relative motion -s32 mo_x_prev[4] = { -1, -1, -1, -1 }; -s32 mo_y_prev[4] = { -1, -1, -1, -1 }; -// last known screen/window size -static s32 mo_width; -static s32 mo_height; - struct maple_mouse : maple_base { MapleDeviceType get_device_type() override @@ -1411,78 +1390,3 @@ maple_device* maple_Create(MapleDeviceType type) return rv; } -static void screenToNative(int& x, int& y, int width, int height) -{ - float fx, fy; - if (!config::Rotate90) - { - float scale = 480.f / height; - fy = y * scale; - scale /= config::ScreenStretching / 100.f; - fx = (x - (width - 640.f / scale) / 2.f) * scale; - } - else - { - float scale = 640.f / width; - fx = x * scale; - scale /= config::ScreenStretching / 100.f; - fy = (y - (height - 480.f / scale) / 2.f) * scale; - } - x = (int)std::round(fx); - y = (int)std::round(fy); -} - -void SetMousePosition(int x, int y, int width, int height, u32 mouseId) -{ - if (mouseId >= MAPLE_PORTS) - return; - mo_width = width; - mo_height = height; - - if (config::Rotate90) - { - int t = y; - y = x; - x = height - 1 - t; - std::swap(width, height); - } - screenToNative(x, y, width, height); - mo_x_abs[mouseId] = x; - mo_y_abs[mouseId] = y; - - if (mo_x_prev[mouseId] != -1) - { - mo_x_delta[mouseId] += (f32)(x - mo_x_prev[mouseId]) * config::MouseSensitivity / 100.f; - mo_y_delta[mouseId] += (f32)(y - mo_y_prev[mouseId]) * config::MouseSensitivity / 100.f; - } - mo_x_prev[mouseId] = x; - mo_y_prev[mouseId] = y; -} - -void SetRelativeMousePosition(float xrel, float yrel, u32 mouseId) -{ - if (mouseId >= MAPLE_PORTS) - return; - int width = mo_width; - int height = mo_height; - if (config::Rotate90) - { - std::swap(xrel, yrel); - xrel = -xrel; - std::swap(width, height); - } - float dx = xrel * config::MouseSensitivity / 100.f; - float dy = yrel * config::MouseSensitivity / 100.f; - mo_x_delta[mouseId] += dx; - mo_y_delta[mouseId] += dy; - int minX = -width / 32; - int minY = -height / 32; - int maxX = width + width / 32; - int maxY = height + height / 32; - screenToNative(minX, minY, width, height); - screenToNative(maxX, maxY, width, height); - mo_x_abs[mouseId] += (int)std::round(dx); - mo_y_abs[mouseId] += (int)std::round(dy); - mo_x_abs[mouseId] = std::min(std::max(mo_x_abs[mouseId], minX), maxX); - mo_y_abs[mouseId] = std::min(std::max(mo_y_abs[mouseId], minY), maxY); -} diff --git a/core/hw/maple/maple_devs.h b/core/hw/maple/maple_devs.h index caa0566d5..7c00b9eef 100755 --- a/core/hw/maple/maple_devs.h +++ b/core/hw/maple/maple_devs.h @@ -166,20 +166,6 @@ void limit_joystick_magnitude(s8& joyx, s8& joyy) extern u8 EEPROM[0x100]; void load_naomi_eeprom(); -// Mouse position and buttons -extern u8 mo_buttons[4]; -extern s32 mo_x_abs[4]; -extern s32 mo_y_abs[4]; -extern f32 mo_x_delta[4]; -extern f32 mo_y_delta[4]; -extern f32 mo_wheel_delta[4]; - -extern s32 mo_x_prev[4]; -extern s32 mo_y_prev[4]; - -void SetMousePosition(int x, int y, int width, int height, u32 mouseId = 0); -void SetRelativeMousePosition(float xrel, float yrel, u32 mouseId = 0); - #define SWAP32(a) ((((a) & 0xff) << 24) | (((a) & 0xff00) << 8) | (((a) >> 8) & 0xff00) | (((a) >> 24) & 0xff)) const char *GetCurrentGameButtonName(DreamcastKey key); diff --git a/core/hw/maple/maple_jvs.cpp b/core/hw/maple/maple_jvs.cpp index cb1aea6f3..837043385 100644 --- a/core/hw/maple/maple_jvs.cpp +++ b/core/hw/maple/maple_jvs.cpp @@ -20,7 +20,6 @@ #include #include "maple_devs.h" #include "hw/naomi/naomi_cart.h" -#include "input/gamepad_device.h" #include #include "oslib/oslib.h" #include "stdclass.h" @@ -482,7 +481,7 @@ protected: if (init_in_progress) return 0; const MapleInputState& inputState = mapleInputState[std::min(player_num, (int)ARRAY_SIZE(mapleInputState) - 1)]; - if (inputState.absPointerX < 0 || inputState.absPointerX > 639 || inputState.absPointerY < 0 || inputState.absPointerY > 479) + if (inputState.absPos.x < 0 || inputState.absPos.x > 639 || inputState.absPos.y < 0 || inputState.absPos.y > 479) return 0; else return 0x8000; @@ -1494,8 +1493,8 @@ u32 jvs_io_board::handle_jvs_message(u8 *buffer_in, u32 length_in, u8 *buffer_ou const MapleInputState& inputState = mapleInputState[std::min(playerNum, (int)ARRAY_SIZE(mapleInputState) - 1)]; u16 x; u16 y; - if (inputState.absPointerX < 0 || inputState.absPointerX > 639 - || inputState.absPointerY < 0 || inputState.absPointerY > 479 + if (inputState.absPos.x < 0 || inputState.absPos.x > 639 + || inputState.absPos.y < 0 || inputState.absPos.y > 479 || (buttons[playerNum] & NAOMI_RELOAD_KEY) != 0) { x = 0; @@ -1503,8 +1502,8 @@ u32 jvs_io_board::handle_jvs_message(u8 *buffer_in, u32 length_in, u8 *buffer_ou } else { - x = inputState.absPointerX * 0xFFFF / 639; - y = inputState.absPointerY * 0xFFFF / 479; + x = inputState.absPos.x * 0xFFFF / 639; + y = inputState.absPos.y * 0xFFFF / 479; } LOGJVS("x,y:%4x,%4x ", x, y); JVS_OUT(x >> 8); // X, MSB @@ -1571,10 +1570,8 @@ u32 jvs_io_board::handle_jvs_message(u8 *buffer_in, u32 length_in, u8 *buffer_ou static s16 roty = 0; // TODO Add more players. // I can't think of any naomi multiplayer game that uses rotary encoders - rotx += mo_x_delta[first_player] * 5; - roty -= mo_y_delta[first_player] * 5; - mo_x_delta[first_player] = 0; - mo_y_delta[first_player] = 0; + rotx += mapleInputState[first_player].relPos.x * 5; + roty -= mapleInputState[first_player].relPos.y * 5; LOGJVS("rotenc "); for (int chan = 0; chan < buffer_in[cmdi + 1]; chan++) { @@ -1622,8 +1619,8 @@ u32 jvs_io_board::handle_jvs_message(u8 *buffer_in, u32 length_in, u8 *buffer_ou // Ninja Assault: u32 xr = 0x19d - 0x37; u32 yr = 0x1fe - 0x40; - x = mapleInputState[playerNum].absPointerX * xr / 639 + 0x37; - y = mapleInputState[playerNum].absPointerY * yr / 479 + 0x40; + x = mapleInputState[playerNum].absPos.x * xr / 639 + 0x37; + y = mapleInputState[playerNum].absPos.y * yr / 479 + 0x40; } LOGJVS("lightgun %4x,%4x ", x, y); JVS_OUT(x >> 8); // X, MSB diff --git a/core/input/gamepad_device.cpp b/core/input/gamepad_device.cpp index 24bd6626c..53c883deb 100644 --- a/core/input/gamepad_device.cpp +++ b/core/input/gamepad_device.cpp @@ -39,6 +39,9 @@ s8 joyrx[4]; s8 joyry[4]; u8 rt[4]; u8 lt[4]; +// Keyboards +u8 kb_shift[MAPLE_PORTS]; // shift keys pressed (bitmask) +u8 kb_key[MAPLE_PORTS][6]; // normal keys pressed std::vector> GamepadDevice::_gamepads; std::mutex GamepadDevice::_gamepads_mutex; @@ -426,7 +429,7 @@ void GamepadDevice::save_mapping(int system) InputMapping::SaveMapping(filename.c_str(), input_mapper); } -void UpdateVibration(u32 port, float power, float inclination, u32 duration_ms) +static void updateVibration(u32 port, float power, float inclination, u32 duration_ms) { int i = GamepadDevice::GetGamepadCount() - 1; for ( ; i >= 0; i--) @@ -493,6 +496,7 @@ void GamepadDevice::Register(const std::shared_ptr& gamepad) _gamepads_mutex.lock(); _gamepads.push_back(gamepad); _gamepads_mutex.unlock(); + MapleConfigMap::UpdateVibration = updateVibration; } void GamepadDevice::Unregister(const std::shared_ptr& gamepad) @@ -517,54 +521,6 @@ void GamepadDevice::SaveMaplePorts() } } -void Mouse::setAbsPos(int x, int y, int width, int height) { - SetMousePosition(x, y, width, height, maple_port()); -} - -void Mouse::setRelPos(float deltax, float deltay) { - SetRelativeMousePosition(deltax, deltay, maple_port()); -} - -void Mouse::setWheel(int delta) { - if (maple_port() >= 0 && maple_port() < (int)ARRAY_SIZE(mo_wheel_delta)) - mo_wheel_delta[maple_port()] += delta; -} - -void Mouse::setButton(Button button, bool pressed) -{ - if (maple_port() >= 0 && maple_port() < (int)ARRAY_SIZE(mo_buttons)) - { - if (pressed) - mo_buttons[maple_port()] &= ~(1 << (int)button); - else - mo_buttons[maple_port()] |= 1 << (int)button; - } - if ((gui_is_open() || gui_mouse_captured()) && !is_detecting_input()) - // Don't register mouse clicks as gamepad presses when gui is open - // This makes the gamepad presses to be handled first and the mouse position to be ignored - return; - gamepad_btn_input(button, pressed); -} - - -void SystemMouse::setAbsPos(int x, int y, int width, int height) { - gui_set_mouse_position(x, y); - Mouse::setAbsPos(x, y, width, height); -} - -void SystemMouse::setButton(Button button, bool pressed) { - int uiBtn = (int)button - 1; - if (uiBtn < 2) - uiBtn ^= 1; - gui_set_mouse_button(uiBtn, pressed); - Mouse::setButton(button, pressed); -} - -void SystemMouse::setWheel(int delta) { - gui_set_mouse_wheel(delta * 35); - Mouse::setWheel(delta); -} - #ifdef TEST_AUTOMATION #include "cfg/option.h" static bool replay_inited; diff --git a/core/input/gamepad_device.h b/core/input/gamepad_device.h index 66961e786..e1452fef6 100644 --- a/core/input/gamepad_device.h +++ b/core/input/gamepad_device.h @@ -156,75 +156,3 @@ extern u32 kcode[4]; extern u8 rt[4], lt[4]; extern s8 joyx[4], joyy[4]; extern s8 joyrx[4], joyry[4]; - -void UpdateVibration(u32 port, float power, float inclination, u32 duration_ms); - -class MouseInputMapping : public InputMapping -{ -public: - MouseInputMapping() - { - name = "Mouse"; - set_button(DC_BTN_A, 2); // Left - set_button(DC_BTN_B, 1); // Right - set_button(DC_BTN_START, 3); // Middle - - dirty = false; - } -}; - -class Mouse : public GamepadDevice -{ -protected: - Mouse(const char *apiName, int maplePort = 0) : GamepadDevice(maplePort, apiName) { - this->_name = "Mouse"; - } - - virtual std::shared_ptr getDefaultMapping() override { - return std::make_shared(); - } - -public: - enum Button { - LEFT_BUTTON = 2, - RIGHT_BUTTON = 1, - MIDDLE_BUTTON = 3, - BUTTON_4 = 4, - BUTTON_5 = 5 - }; - - virtual const char *get_button_name(u32 code) override - { - switch((Button)code) - { - case LEFT_BUTTON: - return "Left Button"; - case RIGHT_BUTTON: - return "Right Button"; - case MIDDLE_BUTTON: - return "Middle Button"; - case BUTTON_4: - return "Button 4"; - case BUTTON_5: - return "Button 5"; - default: - return nullptr; - } - } - - void setAbsPos(int x, int y, int width, int height); - void setRelPos(float deltax, float deltay); - void setButton(Button button, bool pressed); - void setWheel(int delta); -}; - -class SystemMouse : public Mouse -{ -protected: - SystemMouse(const char *apiName, int maplePort = 0) : Mouse(apiName, maplePort) {} - -public: - void setAbsPos(int x, int y, int width, int height); - void setButton(Button button, bool pressed); - void setWheel(int delta); -}; diff --git a/core/input/keyboard_device.h b/core/input/keyboard_device.h index ede668fc9..539ad1128 100644 --- a/core/input/keyboard_device.h +++ b/core/input/keyboard_device.h @@ -404,41 +404,40 @@ static inline void setFlag(int& v, u32 bitmask, bool set) template void KeyboardDeviceTemplate::keyboard_input(Keycode keycode, bool pressed, int modifier_keys) { - const int port = maple_port(); - if (port < 0 || port > (int)ARRAY_SIZE(kb_key)) - return; - u8 dc_keycode = convert_keycode(keycode); - if (port < (int)ARRAY_SIZE(kb_key)) + // Some OSes (Mac OS) don't distinguish left and right modifier keys to we set them both. + // But not for Alt since Right Alt is used as a special modifier keys on some international + // keyboards. + switch (dc_keycode) { - // Some OSes (Mac OS) don't distinguish left and right modifier keys to we set them both. - // But not for Alt since Right Alt is used as a special modifier keys on some international - // keyboards. - switch (dc_keycode) - { - case 0xE1: // Left Shift - case 0xE5: // Right Shift - setFlag(_modifier_keys, DC_KBMOD_LEFTSHIFT | DC_KBMOD_RIGHTSHIFT, pressed); - break; - case 0xE0: // Left Ctrl - case 0xE4: // Right Ctrl - setFlag(_modifier_keys, DC_KBMOD_LEFTCTRL | DC_KBMOD_RIGHTCTRL, pressed); - break; - case 0xE2: // Left Alt - setFlag(_modifier_keys, DC_KBMOD_LEFTALT, pressed); - break; - case 0xE6: // Right Alt - setFlag(_modifier_keys, DC_KBMOD_RIGHTALT, pressed); - break; - case 0xE7: // S2 special key - setFlag(_modifier_keys, DC_KBMOD_S2, pressed); - break; - default: - break; - } + case 0xE1: // Left Shift + case 0xE5: // Right Shift + setFlag(_modifier_keys, DC_KBMOD_LEFTSHIFT | DC_KBMOD_RIGHTSHIFT, pressed); + break; + case 0xE0: // Left Ctrl + case 0xE4: // Right Ctrl + setFlag(_modifier_keys, DC_KBMOD_LEFTCTRL | DC_KBMOD_RIGHTCTRL, pressed); + break; + case 0xE2: // Left Alt + setFlag(_modifier_keys, DC_KBMOD_LEFTALT, pressed); + break; + case 0xE6: // Right Alt + setFlag(_modifier_keys, DC_KBMOD_RIGHTALT, pressed); + break; + case 0xE7: // S2 special key + setFlag(_modifier_keys, DC_KBMOD_S2, pressed); + break; + default: + break; + } + const int port = maple_port(); + if (port >= 0 && port < (int)ARRAY_SIZE(kb_shift)) kb_shift[port] = _modifier_keys; - if (dc_keycode != 0 && dc_keycode < 0xE0) + if (dc_keycode != 0 && dc_keycode < 0xE0) + { + gui_keyboard_key(dc_keycode, pressed, _modifier_keys); + if (port >= 0 && port < (int)ARRAY_SIZE(kb_key)) { if (pressed) { @@ -474,7 +473,6 @@ void KeyboardDeviceTemplate::keyboard_input(Keycode keycode, bool press if (gui_keyboard_captured()) { // chat: disable the keyboard controller. Only accept emu keys (menu, escape...) - const int port = maple_port(); set_maple_port(-1); gamepad_btn_input(dc_keycode, pressed); set_maple_port(port); diff --git a/core/input/mouse.cpp b/core/input/mouse.cpp new file mode 100644 index 000000000..b4629816f --- /dev/null +++ b/core/input/mouse.cpp @@ -0,0 +1,168 @@ +/* + Copyright 2021 flyinghead + + This file is part of Flycast. + + Flycast is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + Flycast is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Flycast. If not, see . +*/ +#include "mouse.h" +#include "rend/gui.h" + +// Mouse buttons +// bit 0: Button C +// bit 1: Right button (B) +// bit 2: Left button (A) +// bit 3: Wheel button +u8 mo_buttons[4] = { 0xFF, 0xFF, 0xFF, 0xFF }; +// Relative mouse coordinates [-512:511] +f32 mo_x_delta[4]; +f32 mo_y_delta[4]; +f32 mo_wheel_delta[4]; +// Absolute mouse coordinates +// Range [0:639] [0:479] +// but may be outside this range if the pointer is offscreen or outside the 4:3 window. +s32 mo_x_abs[4]; +s32 mo_y_abs[4]; +// previous mouse coordinates for relative motion +s32 mo_x_prev[4] = { -1, -1, -1, -1 }; +s32 mo_y_prev[4] = { -1, -1, -1, -1 }; +// last known screen/window size +static s32 mo_width; +static s32 mo_height; + +void Mouse::setAbsPos(int x, int y, int width, int height) { + SetMousePosition(x, y, width, height, maple_port()); +} + +void Mouse::setRelPos(float deltax, float deltay) { + SetRelativeMousePosition(deltax, deltay, maple_port()); +} + +void Mouse::setWheel(int delta) { + if (maple_port() >= 0 && maple_port() < (int)ARRAY_SIZE(mo_wheel_delta)) + mo_wheel_delta[maple_port()] += delta; +} + +void Mouse::setButton(Button button, bool pressed) +{ + if (maple_port() >= 0 && maple_port() < (int)ARRAY_SIZE(mo_buttons)) + { + if (pressed) + mo_buttons[maple_port()] &= ~(1 << (int)button); + else + mo_buttons[maple_port()] |= 1 << (int)button; + } + if ((gui_is_open() || gui_mouse_captured()) && !is_detecting_input()) + // Don't register mouse clicks as gamepad presses when gui is open + // This makes the gamepad presses to be handled first and the mouse position to be ignored + return; + gamepad_btn_input(button, pressed); +} + + +void SystemMouse::setAbsPos(int x, int y, int width, int height) { + gui_set_mouse_position(x, y); + Mouse::setAbsPos(x, y, width, height); +} + +void SystemMouse::setButton(Button button, bool pressed) { + int uiBtn = (int)button - 1; + if (uiBtn < 2) + uiBtn ^= 1; + gui_set_mouse_button(uiBtn, pressed); + Mouse::setButton(button, pressed); +} + +void SystemMouse::setWheel(int delta) { + gui_set_mouse_wheel(delta * 35); + Mouse::setWheel(delta); +} + + +static void screenToNative(int& x, int& y, int width, int height) +{ + float fx, fy; + if (!config::Rotate90) + { + float scale = 480.f / height; + fy = y * scale; + scale /= config::ScreenStretching / 100.f; + fx = (x - (width - 640.f / scale) / 2.f) * scale; + } + else + { + float scale = 640.f / width; + fx = x * scale; + scale /= config::ScreenStretching / 100.f; + fy = (y - (height - 480.f / scale) / 2.f) * scale; + } + x = (int)std::round(fx); + y = (int)std::round(fy); +} + +void SetMousePosition(int x, int y, int width, int height, u32 mouseId) +{ + if (mouseId >= ARRAY_SIZE(mo_x_abs)) + return; + mo_width = width; + mo_height = height; + + if (config::Rotate90) + { + int t = y; + y = x; + x = height - 1 - t; + std::swap(width, height); + } + screenToNative(x, y, width, height); + mo_x_abs[mouseId] = x; + mo_y_abs[mouseId] = y; + + if (mo_x_prev[mouseId] != -1) + { + mo_x_delta[mouseId] += (f32)(x - mo_x_prev[mouseId]) * config::MouseSensitivity / 100.f; + mo_y_delta[mouseId] += (f32)(y - mo_y_prev[mouseId]) * config::MouseSensitivity / 100.f; + } + mo_x_prev[mouseId] = x; + mo_y_prev[mouseId] = y; +} + +void SetRelativeMousePosition(float xrel, float yrel, u32 mouseId) +{ + if (mouseId >= ARRAY_SIZE(mo_x_delta)) + return; + int width = mo_width; + int height = mo_height; + if (config::Rotate90) + { + std::swap(xrel, yrel); + xrel = -xrel; + std::swap(width, height); + } + float dx = xrel * config::MouseSensitivity / 100.f; + float dy = yrel * config::MouseSensitivity / 100.f; + mo_x_delta[mouseId] += dx; + mo_y_delta[mouseId] += dy; + int minX = -width / 32; + int minY = -height / 32; + int maxX = width + width / 32; + int maxY = height + height / 32; + screenToNative(minX, minY, width, height); + screenToNative(maxX, maxY, width, height); + mo_x_abs[mouseId] += (int)std::round(dx); + mo_y_abs[mouseId] += (int)std::round(dy); + mo_x_abs[mouseId] = std::min(std::max(mo_x_abs[mouseId], minX), maxX); + mo_y_abs[mouseId] = std::min(std::max(mo_y_abs[mouseId], minY), maxY); +} + diff --git a/core/input/mouse.h b/core/input/mouse.h new file mode 100644 index 000000000..96163b32b --- /dev/null +++ b/core/input/mouse.h @@ -0,0 +1,104 @@ +/* + Copyright 2021 flyinghead + + This file is part of Flycast. + + Flycast is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + Flycast is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Flycast. If not, see . +*/ +#pragma once +#include "gamepad_device.h" + +// Mouse position and buttons +extern u8 mo_buttons[4]; +extern s32 mo_x_abs[4]; +extern s32 mo_y_abs[4]; +extern f32 mo_x_delta[4]; +extern f32 mo_y_delta[4]; +extern f32 mo_wheel_delta[4]; + +extern s32 mo_x_prev[4]; +extern s32 mo_y_prev[4]; + +void SetMousePosition(int x, int y, int width, int height, u32 mouseId = 0); +void SetRelativeMousePosition(float xrel, float yrel, u32 mouseId = 0); + +class MouseInputMapping : public InputMapping +{ +public: + MouseInputMapping() + { + name = "Mouse"; + set_button(DC_BTN_A, 2); // Left + set_button(DC_BTN_B, 1); // Right + set_button(DC_BTN_START, 3); // Middle + + dirty = false; + } +}; + +class Mouse : public GamepadDevice +{ +protected: + Mouse(const char *apiName, int maplePort = 0) : GamepadDevice(maplePort, apiName) { + this->_name = "Mouse"; + } + + virtual std::shared_ptr getDefaultMapping() override { + return std::make_shared(); + } + +public: + enum Button { + LEFT_BUTTON = 2, + RIGHT_BUTTON = 1, + MIDDLE_BUTTON = 3, + BUTTON_4 = 4, + BUTTON_5 = 5 + }; + + virtual const char *get_button_name(u32 code) override + { + switch((Button)code) + { + case LEFT_BUTTON: + return "Left Button"; + case RIGHT_BUTTON: + return "Right Button"; + case MIDDLE_BUTTON: + return "Middle Button"; + case BUTTON_4: + return "Button 4"; + case BUTTON_5: + return "Button 5"; + default: + return nullptr; + } + } + + void setAbsPos(int x, int y, int width, int height); + void setRelPos(float deltax, float deltay); + void setButton(Button button, bool pressed); + void setWheel(int delta); +}; + +class SystemMouse : public Mouse +{ +protected: + SystemMouse(const char *apiName, int maplePort = 0) : Mouse(apiName, maplePort) {} + +public: + void setAbsPos(int x, int y, int width, int height); + void setButton(Button button, bool pressed); + void setWheel(int delta); +}; diff --git a/core/network/ggpo.cpp b/core/network/ggpo.cpp index 38f51c39d..0db586b19 100644 --- a/core/network/ggpo.cpp +++ b/core/network/ggpo.cpp @@ -20,6 +20,8 @@ #include "hw/maple/maple_cfg.h" #include "hw/maple/maple_devs.h" #include "input/gamepad_device.h" +#include "input/keyboard_device.h" +#include "input/mouse.h" #include "cfg/option.h" #include @@ -42,8 +44,17 @@ static void getLocalInput(MapleInputState inputState[4]) state.fullAxes[PJAI_Y1] = joyy[player]; state.fullAxes[PJAI_X2] = joyrx[player]; state.fullAxes[PJAI_Y2] = joyry[player]; - state.absPointerX = mo_x_abs[player]; - state.absPointerY = mo_y_abs[player]; + state.mouseButtons = mo_buttons[player]; + state.absPos.x = mo_x_abs[player]; + state.absPos.y = mo_y_abs[player]; + state.keyboard.shift = kb_shift[player]; + memcpy(state.keyboard.key, kb_key[player], sizeof(kb_key[player])); + state.relPos.x = std::round(mo_x_delta[player]); + state.relPos.y = std::round(mo_y_delta[player]); + state.relPos.wheel = std::round(mo_wheel_delta[player]); + mo_x_delta[player] -= state.relPos.x; + mo_y_delta[player] -= state.relPos.y; + mo_wheel_delta[player] -= state.relPos.wheel; } } @@ -101,6 +112,9 @@ static bool _endOfFrame; static MiniUPnP miniupnp; static int analogAxes; static bool absPointerPos; +static bool keyboardGame; +static bool mouseGame; +static int inputSize; static bool inRollback; static void (*chatCallback)(int playerNum, const std::string& msg); @@ -122,6 +136,30 @@ static int lastSavedFrame = -1; static int timesyncOccurred; #pragma pack(push, 1) +struct Inputs +{ + u32 kcode:20; + u32 mouseButtons:4; + u8 kbModifiers; + + union { + struct { + u8 x; + u8 y; + } analog; + struct { + s16 x; + s16 y; + } absPos; + struct { + s16 x; + s16 y; + s16 wheel; + } relPos; + u8 keys[6]; + } u; +}; + struct GameEvent { enum : char { @@ -440,8 +478,14 @@ void startSession(int localPort, int localPlayerNum) { analogAxes = 0; absPointerPos = false; + keyboardGame = false; + mouseGame = false; if (settings.input.JammaSetup == JVS::LightGun || settings.input.JammaSetup == JVS::LightGunAsAnalog) absPointerPos = true; + else if (settings.input.JammaSetup == JVS::Keyboard) + keyboardGame = true; + else if (settings.input.JammaSetup == JVS::RotaryEncoders) + mouseGame = true; else if (NaomiGameInputs != nullptr) { for (const auto& axis : NaomiGameInputs->axes) @@ -454,7 +498,8 @@ void startSession(int localPort, int localPlayerNum) } NOTICE_LOG(NETWORK, "GGPO: Using %d full analog axes", analogAxes); } - const u32 inputSize = sizeof(kcode[0]) + analogAxes + (int)absPointerPos * 4; + inputSize = sizeof(kcode[0]) + analogAxes + (int)absPointerPos * sizeof(Inputs::u.absPos) + + (int)keyboardGame * sizeof(Inputs::u.keys) + (int)mouseGame * sizeof(Inputs::u.relPos); VerificationData verif; MD5Sum().add(settings.network.md5.bios) @@ -551,10 +596,9 @@ void getInput(MapleInputState inputState[4]) for (int player = 0; player < 4; player++) inputState[player] = {}; - u32 inputSize = sizeof(u32) + analogAxes + (int)absPointerPos * 4; - std::vector inputs(inputSize * MAX_PLAYERS); + std::vector inputData(inputSize * MAX_PLAYERS); // should not call any callback - GGPOErrorCode error = ggpo_synchronize_input(ggpoSession, (void *)&inputs[0], inputs.size(), nullptr); + GGPOErrorCode error = ggpo_synchronize_input(ggpoSession, (void *)&inputData[0], inputData.size(), nullptr); if (error != GGPO_OK) { stopSession(); @@ -564,17 +608,30 @@ void getInput(MapleInputState inputState[4]) for (int player = 0; player < MAX_PLAYERS; player++) { MapleInputState& state = inputState[player]; - state.kcode = ~(*(u32 *)&inputs[player * inputSize]); + const Inputs *inputs = (Inputs *)&inputData[player * inputSize]; + state.kcode = ~inputs->kcode; if (analogAxes > 0) { - state.fullAxes[PJAI_X1] = inputs[player * inputSize + 4]; + state.fullAxes[PJAI_X1] = inputs->u.analog.x; if (analogAxes >= 2) - state.fullAxes[PJAI_Y1] = inputs[player * inputSize + 5]; + state.fullAxes[PJAI_Y1] = inputs->u.analog.y; } else if (absPointerPos) { - state.absPointerX = *(s16 *)&inputs[player * inputSize + 4]; - state.absPointerY = *(s16 *)&inputs[player * inputSize + 6]; + state.absPos.x = inputs->u.absPos.x; + state.absPos.y = inputs->u.absPos.y; + } + else if (keyboardGame) + { + memcpy(state.keyboard.key, inputs->u.keys, sizeof(state.keyboard.key)); + state.keyboard.shift = inputs->kbModifiers; + } + else if (mouseGame) + { + state.relPos.x = inputs->u.relPos.x; + state.relPos.y = inputs->u.relPos.y; + state.relPos.wheel = inputs->u.relPos.wheel; + state.mouseButtons = ~inputs->mouseButtons; } state.halfAxes[PJTI_R] = (state.kcode & BTN_TRIGGER_RIGHT) == 0 ? 255 : 0; state.halfAxes[PJTI_L] = (state.kcode & BTN_TRIGGER_LEFT) == 0 ? 255 : 0; @@ -620,30 +677,43 @@ bool nextFrame() do { if (!config::ThreadedRendering) UpdateInputState(); - u32 input = ~kcode[localPlayerNum]; + Inputs inputs; + inputs.kcode = ~kcode[localPlayerNum]; if (rt[localPlayerNum] >= 64) - input |= BTN_TRIGGER_RIGHT; + inputs.kcode |= BTN_TRIGGER_RIGHT; else - input &= ~BTN_TRIGGER_RIGHT; + inputs.kcode &= ~BTN_TRIGGER_RIGHT; if (lt[localPlayerNum] >= 64) - input |= BTN_TRIGGER_LEFT; + inputs.kcode |= BTN_TRIGGER_LEFT; else - input &= ~BTN_TRIGGER_LEFT; - u32 inputSize = sizeof(input) + analogAxes + (int)absPointerPos * 4; - std::vector allInput(inputSize); - *(u32 *)&allInput[0] = input; + inputs.kcode &= ~BTN_TRIGGER_LEFT; if (analogAxes > 0) { - allInput[4] = joyx[localPlayerNum]; + inputs.u.analog.x = joyx[localPlayerNum]; if (analogAxes >= 2) - allInput[5] = joyy[localPlayerNum]; + inputs.u.analog.y = joyy[localPlayerNum]; } else if (absPointerPos) { - *(s16 *)&allInput[4] = mo_x_abs[localPlayerNum]; - *(s16 *)&allInput[6] = mo_y_abs[localPlayerNum]; + inputs.u.absPos.x = mo_x_abs[localPlayerNum]; + inputs.u.absPos.y = mo_y_abs[localPlayerNum]; } - GGPOErrorCode result = ggpo_add_local_input(ggpoSession, localPlayer, &allInput[0], inputSize); + else if (keyboardGame) + { + inputs.kbModifiers = kb_shift[localPlayerNum]; + memcpy(inputs.u.keys, kb_key[localPlayerNum], sizeof(kb_key[localPlayerNum])); + } + else if (mouseGame) + { + inputs.mouseButtons = ~mo_buttons[localPlayerNum]; + inputs.u.relPos.x = std::round(mo_x_delta[localPlayerNum]); + inputs.u.relPos.y = std::round(mo_y_delta[localPlayerNum]); + inputs.u.relPos.wheel = std::round(mo_wheel_delta[localPlayerNum]); + mo_x_delta[localPlayerNum] -= inputs.u.relPos.x; + mo_y_delta[localPlayerNum] -= inputs.u.relPos.y; + mo_wheel_delta[localPlayerNum] -= inputs.u.relPos.wheel; + } + GGPOErrorCode result = ggpo_add_local_input(ggpoSession, localPlayer, &inputs, inputSize); if (result == GGPO_OK) break; if (result != GGPO_ERRORCODE_PREDICTION_THRESHOLD) diff --git a/core/rend/gui.cpp b/core/rend/gui.cpp index 5747e93e1..3a522ed69 100644 --- a/core/rend/gui.cpp +++ b/core/rend/gui.cpp @@ -31,6 +31,7 @@ #include "network/ggpo.h" #include "wsi/context.h" #include "input/gamepad_device.h" +#include "input/mouse.h" #include "gui_util.h" #include "gui_android.h" #include "game_scanner.h" @@ -46,9 +47,6 @@ static bool game_started; -extern u8 kb_shift[MAPLE_PORTS]; // shift keys pressed (bitmask) -extern u8 kb_key[MAPLE_PORTS][6]; // normal keys pressed - int screen_dpi = 96; int insetLeft, insetRight, insetTop, insetBottom; @@ -279,6 +277,16 @@ void gui_keyboard_inputUTF8(const std::string& s) io.AddInputCharactersUTF8(s.c_str()); } +void gui_keyboard_key(u8 keyCode, bool pressed, u8 modifiers) +{ + if (!inited) + return; + ImGuiIO& io = ImGui::GetIO(); + io.KeyCtrl = (modifiers & (0x01 | 0x10)) != 0; + io.KeyShift = (modifiers & (0x02 | 0x20)) != 0; + io.KeysDown[keyCode] = pressed; +} + bool gui_keyboard_captured() { ImGuiIO& io = ImGui::GetIO(); @@ -323,21 +331,6 @@ static void ImGui_Impl_NewFrame() ImGuiIO& io = ImGui::GetIO(); - // Read keyboard modifiers inputs - io.KeyCtrl = 0; - io.KeyShift = 0; - io.KeyAlt = false; - io.KeySuper = false; - memset(&io.KeysDown[0], 0, sizeof(io.KeysDown)); - for (int port = 0; port < 4; port++) - { - io.KeyCtrl |= (kb_shift[port] & (0x01 | 0x10)) != 0; - io.KeyShift |= (kb_shift[port] & (0x02 | 0x20)) != 0; - - for (int i = 0; i < IM_ARRAYSIZE(kb_key[0]); i++) - if (kb_key[port][i] != 0) - io.KeysDown[kb_key[port][i]] = true; - } if (mouseX < 0 || mouseX >= settings.display.width || mouseY < 0 || mouseY >= settings.display.height) io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX); else @@ -1895,6 +1888,7 @@ static void gui_display_settings() ImGui::SameLine(); OptionRadioButton("Full", config::GGPOAnalogAxes, 2, "Use the left thumbstick horizontal and vertical axes"); + OptionCheckbox("Enable Chat", config::GGPOChat, "Open the chat window when a chat message is received"); OptionCheckbox("Network Statistics", config::NetworkStats, "Display network statistics on screen"); } diff --git a/core/rend/gui.h b/core/rend/gui.h index d4280222b..62787553e 100644 --- a/core/rend/gui.h +++ b/core/rend/gui.h @@ -32,6 +32,7 @@ void gui_refresh_files(); void gui_cheats(); void gui_keyboard_input(u16 wc); void gui_keyboard_inputUTF8(const std::string& s); +void gui_keyboard_key(u8 keyCode, bool pressed, u8 modifiers); bool gui_keyboard_captured(); bool gui_mouse_captured(); void gui_set_mouse_position(int x, int y); diff --git a/core/rend/gui_chat.h b/core/rend/gui_chat.h index 1ffd69f77..958b882b1 100644 --- a/core/rend/gui_chat.h +++ b/core/rend/gui_chat.h @@ -100,7 +100,8 @@ public: void receive(int playerNum, const std::string& msg) { - visible = true; + if (config::GGPOChat) + visible = true; std::string line = "<" + playerName(true) + "> " + msg; lines.push_back(std::make_pair(YELLOW, line)); newMessage = true; diff --git a/core/sdl/sdl_gamepad.h b/core/sdl/sdl_gamepad.h index bf9dbb1bc..e5bc57f96 100644 --- a/core/sdl/sdl_gamepad.h +++ b/core/sdl/sdl_gamepad.h @@ -1,4 +1,5 @@ -#include "../input/gamepad_device.h" +#include "input/gamepad_device.h" +#include "input/mouse.h" #include "oslib/oslib.h" #include "sdl.h" #include "rend/gui.h" diff --git a/shell/android-studio/flycast/src/main/jni/src/android_gamepad.h b/shell/android-studio/flycast/src/main/jni/src/android_gamepad.h index a60795b14..aefab734a 100644 --- a/shell/android-studio/flycast/src/main/jni/src/android_gamepad.h +++ b/shell/android-studio/flycast/src/main/jni/src/android_gamepad.h @@ -19,6 +19,7 @@ #pragma once #include "input/gamepad_device.h" +#include "input/mouse.h" #include static jobject input_device_manager; diff --git a/shell/apple/emulator-ios/emulator/ios_gamepad.h b/shell/apple/emulator-ios/emulator/ios_gamepad.h index ea21b9886..bbf5fcc01 100644 --- a/shell/apple/emulator-ios/emulator/ios_gamepad.h +++ b/shell/apple/emulator-ios/emulator/ios_gamepad.h @@ -22,6 +22,7 @@ #include #include "input/gamepad_device.h" +#include "input/mouse.h" #include "rend/gui.h" enum IOSButton { diff --git a/shell/apple/emulator-ios/emulator/ios_mouse.h b/shell/apple/emulator-ios/emulator/ios_mouse.h index 6d0a4c31a..1bfc8f93f 100644 --- a/shell/apple/emulator-ios/emulator/ios_mouse.h +++ b/shell/apple/emulator-ios/emulator/ios_mouse.h @@ -7,7 +7,7 @@ #pragma once #import -#include "input/gamepad_device.h" +#include "input/mouse.h" class API_AVAILABLE(ios(14.0)) IOSMouse : public SystemMouse { diff --git a/shell/apple/emulator-osx/emulator-osx/osx_gamepad.h b/shell/apple/emulator-osx/emulator-osx/osx_gamepad.h index 6c7fe13e9..6c1553858 100644 --- a/shell/apple/emulator-osx/emulator-osx/osx_gamepad.h +++ b/shell/apple/emulator-osx/emulator-osx/osx_gamepad.h @@ -5,7 +5,7 @@ // Created by flyinghead on 26/02/2019. // Copyright © 2019 reicast. All rights reserved. // -#include "input/gamepad_device.h" +#include "input/mouse.h" class OSXMouse : public SystemMouse { diff --git a/shell/libretro/libretro.cpp b/shell/libretro/libretro.cpp index 9d48baddc..ac88f0123 100644 --- a/shell/libretro/libretro.cpp +++ b/shell/libretro/libretro.cpp @@ -116,6 +116,21 @@ u8 lt[4]; u32 vks[4]; s8 joyx[4], joyy[4]; s8 joyrx[4], joyry[4]; +// Mouse buttons +// bit 0: Button C +// bit 1: Right button (B) +// bit 2: Left button (A) +// bit 3: Wheel button +u8 mo_buttons[4] = { 0xFF, 0xFF, 0xFF, 0xFF }; +// Relative mouse coordinates [-512:511] +f32 mo_x_delta[4]; +f32 mo_y_delta[4]; +f32 mo_wheel_delta[4]; +// Absolute mouse coordinates +// Range [0:639] [0:479] +// but may be outside this range if the pointer is offscreen or outside the 4:3 window. +s32 mo_x_abs[4]; +s32 mo_y_abs[4]; static bool enable_purupuru = true; static u32 vib_stop_time[4]; @@ -151,6 +166,7 @@ static void init_disk_control_interface(); static bool read_m3u(const char *file); void UpdateInputState(); void gui_display_notification(const char *msg, int duration); +static void updateVibration(u32 port, float power, float inclination, u32 durationMs); static std::string game_data; static char g_base_name[128]; @@ -276,6 +292,7 @@ void retro_init() ERROR_LOG(VMEM, "Cannot reserve memory space"); os_InstallFaultHandler(); + MapleConfigMap::UpdateVibration = updateVibration; } void retro_deinit() @@ -2571,7 +2588,7 @@ void UpdateInputState() UpdateInputState(3); } -void UpdateVibration(u32 port, float power, float inclination, u32 durationMs) +static void updateVibration(u32 port, float power, float inclination, u32 durationMs) { if (!rumble.set_rumble_state) return; @@ -2583,8 +2600,8 @@ void UpdateVibration(u32 port, float power, float inclination, u32 durationMs) vib_delta[port] = inclination; } -extern u8 kb_key[4][6]; // normal keys pressed -extern u8 kb_shift[4]; // modifier keys pressed (bitmask) +u8 kb_key[4][6]; // normal keys pressed +u8 kb_shift[4]; // modifier keys pressed (bitmask) static int kb_used; static void release_key(unsigned dc_keycode)