dingusppc/core/hostevents_sdl.cpp
joevt 59fba285b5 adbmouse: Add tablet and more bits and buttons.
Add absolute coordinates for tablets. Absolute coordinates is relative to window so it can't work for multiple displays? Doesn't work for single display without mouse driver modification.
Add arbitrary number of buttons. Previously, only one mouse button was supported.
Add arbitrary number of bits. Previously, only 7 bits per axis was supported which is good enough for relative movement but not absolute movement.
2024-05-06 06:49:15 -07:00

332 lines
13 KiB
C++

/*
DingusPPC - The Experimental PowerPC Macintosh emulator
Copyright (C) 2018-24 divingkatae and maximum
(theweirdo) spatium
(Contact divingkatae#1017 or powermax#2286 on Discord for more info)
This program 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 3 of the License, or
(at your option) any later version.
This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <core/hostevents.h>
#include <core/coresignal.h>
#include <cpu/ppc/ppcemu.h>
#include <devices/common/adb/adbkeyboard.h>
#include <loguru.hpp>
#include <SDL.h>
EventManager* EventManager::event_manager;
static int get_sdl_event_key_code(const SDL_KeyboardEvent &event);
static void toggle_mouse_grab(const SDL_KeyboardEvent &event);
void EventManager::poll_events()
{
SDL_Event event;
while (SDL_PollEvent(&event)) {
events_captured++;
switch (event.type) {
case SDL_QUIT:
power_on = false;
power_off_reason = po_shut_down;
break;
case SDL_WINDOWEVENT: {
WindowEvent we;
we.sub_type = event.window.event;
we.window_id = event.window.windowID;
this->_window_signal.emit(we);
}
break;
case SDL_KEYDOWN:
case SDL_KEYUP: {
// Internal shortcuts to trigger mouse grab, intentionally not
// sent to the host.
if (event.key.keysym.sym == SDLK_g && SDL_GetModState() == KMOD_LCTRL) {
if (event.type == SDL_KEYUP) {
toggle_mouse_grab(event.key);
}
return;
}
int key_code = get_sdl_event_key_code(event.key);
if (key_code != -1) {
KeyboardEvent ke;
ke.key = key_code;
if (event.type == SDL_KEYDOWN) {
ke.flags = KEYBOARD_EVENT_DOWN;
key_downs++;
} else {
ke.flags = KEYBOARD_EVENT_UP;
key_ups++;
}
// Caps Lock is a special case, since it's a toggle key
if (ke.key == AdbKey_CapsLock) {
ke.flags = SDL_GetModState() & KMOD_CAPS ?
KEYBOARD_EVENT_DOWN : KEYBOARD_EVENT_UP;
}
this->_keyboard_signal.emit(ke);
} else {
LOG_F(WARNING, "Unknown key %x pressed", event.key.keysym.sym);
}
}
break;
case SDL_MOUSEMOTION: {
MouseEvent me;
me.xrel = event.motion.xrel;
me.yrel = event.motion.yrel;
me.xabs = event.motion.x;
me.yabs = event.motion.y;
me.flags = MOUSE_EVENT_MOTION;
this->_mouse_signal.emit(me);
}
break;
case SDL_MOUSEBUTTONDOWN: {
MouseEvent me;
Uint8 adb_button;
switch (event.button.button) {
case SDL_BUTTON_LEFT : adb_button = 0; break;
case SDL_BUTTON_MIDDLE : adb_button = 2; break;
case SDL_BUTTON_RIGHT : adb_button = 1; break;
default : adb_button = event.button.button - 1;
}
me.buttons_state = (this->buttons_state |= (1 << adb_button));
me.xabs = event.button.x;
me.yabs = event.button.y;
me.flags = MOUSE_EVENT_BUTTON;
this->_mouse_signal.emit(me);
}
break;
case SDL_MOUSEBUTTONUP: {
MouseEvent me;
Uint8 adb_button;
switch (event.button.button) {
case SDL_BUTTON_LEFT : adb_button = 0; break;
case SDL_BUTTON_MIDDLE : adb_button = 2; break;
case SDL_BUTTON_RIGHT : adb_button = 1; break;
default : adb_button = event.button.button - 1;
}
me.buttons_state = (this->buttons_state &= ~(1 << adb_button));
me.xabs = event.button.x;
me.yabs = event.button.y;
me.flags = MOUSE_EVENT_BUTTON;
this->_mouse_signal.emit(me);
}
break;
default:
unhandled_events++;
}
}
// perform post-processing
this->_post_signal.emit();
}
static int get_sdl_event_key_code(const SDL_KeyboardEvent &event)
{
switch (event.keysym.sym) {
case SDLK_a: return AdbKey_A;
case SDLK_b: return AdbKey_B;
case SDLK_c: return AdbKey_C;
case SDLK_d: return AdbKey_D;
case SDLK_e: return AdbKey_E;
case SDLK_f: return AdbKey_F;
case SDLK_g: return AdbKey_G;
case SDLK_h: return AdbKey_H;
case SDLK_i: return AdbKey_I;
case SDLK_j: return AdbKey_J;
case SDLK_k: return AdbKey_K;
case SDLK_l: return AdbKey_L;
case SDLK_m: return AdbKey_M;
case SDLK_n: return AdbKey_N;
case SDLK_o: return AdbKey_O;
case SDLK_p: return AdbKey_P;
case SDLK_q: return AdbKey_Q;
case SDLK_r: return AdbKey_R;
case SDLK_s: return AdbKey_S;
case SDLK_t: return AdbKey_T;
case SDLK_u: return AdbKey_U;
case SDLK_v: return AdbKey_V;
case SDLK_w: return AdbKey_W;
case SDLK_x: return AdbKey_X;
case SDLK_y: return AdbKey_Y;
case SDLK_z: return AdbKey_Z;
case SDLK_1: return AdbKey_1;
case SDLK_2: return AdbKey_2;
case SDLK_3: return AdbKey_3;
case SDLK_4: return AdbKey_4;
case SDLK_5: return AdbKey_5;
case SDLK_6: return AdbKey_6;
case SDLK_7: return AdbKey_7;
case SDLK_8: return AdbKey_8;
case SDLK_9: return AdbKey_9;
case SDLK_0: return AdbKey_0;
case SDLK_ESCAPE: return AdbKey_Escape;
case SDLK_BACKQUOTE: return AdbKey_Grave;
case SDLK_MINUS: return AdbKey_Minus;
case SDLK_EQUALS: return AdbKey_Equal;
case SDLK_LEFTBRACKET: return AdbKey_LeftBracket;
case SDLK_RIGHTBRACKET: return AdbKey_RightBracket;
case SDLK_BACKSLASH: return AdbKey_Backslash;
case SDLK_SEMICOLON: return AdbKey_Semicolon;
case SDLK_QUOTE: return AdbKey_Quote;
case SDLK_COMMA: return AdbKey_Comma;
case SDLK_PERIOD: return AdbKey_Period;
case SDLK_SLASH: return AdbKey_Slash;
// Convert shifted variants to unshifted
case SDLK_EXCLAIM: return AdbKey_1;
case SDLK_AT: return AdbKey_2;
case SDLK_HASH: return AdbKey_3;
case SDLK_DOLLAR: return AdbKey_4;
case SDLK_UNDERSCORE: return AdbKey_Minus;
case SDLK_PLUS: return AdbKey_Equal;
case SDLK_COLON: return AdbKey_Semicolon;
case SDLK_QUOTEDBL: return AdbKey_Quote;
case SDLK_LESS: return AdbKey_Comma;
case SDLK_GREATER: return AdbKey_Period;
case SDLK_QUESTION: return AdbKey_Slash;
case SDLK_TAB: return AdbKey_Tab;
case SDLK_RETURN: return AdbKey_Return;
case SDLK_SPACE: return AdbKey_Space;
case SDLK_BACKSPACE: return AdbKey_Delete;
case SDLK_DELETE: return AdbKey_ForwardDelete;
case SDLK_INSERT: return AdbKey_Help;
case SDLK_HOME: return AdbKey_Home;
case SDLK_HELP: return AdbKey_Home;
case SDLK_END: return AdbKey_End;
case SDLK_PAGEUP: return AdbKey_PageUp;
case SDLK_PAGEDOWN: return AdbKey_PageDown;
case SDLK_LCTRL: return AdbKey_Control;
case SDLK_RCTRL: return AdbKey_Control;
case SDLK_LSHIFT: return AdbKey_Shift;
case SDLK_RSHIFT: return AdbKey_Shift;
case SDLK_LALT: return AdbKey_Option;
case SDLK_RALT: return AdbKey_Option;
case SDLK_LGUI: return AdbKey_Command;
case SDLK_RGUI: return AdbKey_Command;
case SDLK_MENU: return AdbKey_Grave;
case SDLK_CAPSLOCK: return AdbKey_CapsLock;
case SDLK_UP: return AdbKey_ArrowUp;
case SDLK_DOWN: return AdbKey_ArrowDown;
case SDLK_LEFT: return AdbKey_ArrowLeft;
case SDLK_RIGHT: return AdbKey_ArrowRight;
;
case SDLK_KP_0: return AdbKey_Keypad0;
case SDLK_KP_1: return AdbKey_Keypad1;
case SDLK_KP_2: return AdbKey_Keypad2;
case SDLK_KP_3: return AdbKey_Keypad3;
case SDLK_KP_4: return AdbKey_Keypad4;
case SDLK_KP_5: return AdbKey_Keypad5;
case SDLK_KP_6: return AdbKey_Keypad6;
case SDLK_KP_7: return AdbKey_Keypad7;
case SDLK_KP_9: return AdbKey_Keypad9;
case SDLK_KP_8: return AdbKey_Keypad8;
case SDLK_KP_PERIOD: return AdbKey_KeypadDecimal;
case SDLK_KP_PLUS: return AdbKey_KeypadPlus;
case SDLK_KP_MINUS: return AdbKey_KeypadMinus;
case SDLK_KP_MULTIPLY: return AdbKey_KeypadMultiply;
case SDLK_KP_DIVIDE: return AdbKey_KeypadDivide;
case SDLK_KP_ENTER: return AdbKey_KeypadEnter;
case SDLK_KP_EQUALS: return AdbKey_KeypadEquals;
case SDLK_NUMLOCKCLEAR: return AdbKey_KeypadClear;
;
case SDLK_F1: return AdbKey_F1;
case SDLK_F2: return AdbKey_F2;
case SDLK_F3: return AdbKey_F3;
case SDLK_F4: return AdbKey_F4;
case SDLK_F5: return AdbKey_F5;
case SDLK_F6: return AdbKey_F6;
case SDLK_F7: return AdbKey_F7;
case SDLK_F8: return AdbKey_F8;
case SDLK_F9: return AdbKey_F9;
case SDLK_F10: return AdbKey_F10;
case SDLK_F11: return AdbKey_F11;
case SDLK_F12: return AdbKey_F12;
case SDLK_PRINTSCREEN: return AdbKey_F13;
case SDLK_SCROLLLOCK: return AdbKey_F14;
case SDLK_PAUSE: return AdbKey_F15;
//International keyboard support
//Japanese keyboard
case SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_INTERNATIONAL3):
return AdbKey_JIS_Yen;
case SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_INTERNATIONAL1):
return AdbKey_JIS_Underscore;
case 0XBC:
return AdbKey_JIS_KP_Comma;
case 0X89:
return AdbKey_JIS_Eisu;
case SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_INTERNATIONAL2):
return AdbKey_JIS_Kana;
//German keyboard
case 0XB4: return AdbKey_Slash;
case 0X5E: return AdbKey_ISO1;
case 0XDF: return AdbKey_Minus; //Eszett
case 0XE4: return AdbKey_LeftBracket; //A-umlaut
case 0XF6: return AdbKey_Semicolon; //O-umlaut
case 0XFC: return AdbKey_LeftBracket; //U-umlaut
// French keyboard
case 0X29: return AdbKey_Minus; // Right parenthesis
case 0X43: return AdbKey_KeypadMultiply; // Star/Mu
//0XB2 is superscript 2. Which Mac key should this one map to?
case 0XF9: return AdbKey_Quote; // U-grave
// Italian keyboard
case 0XE0: return AdbKey_9; // A-grave
case 0XE8: return AdbKey_6; // E-grave
case 0XEC: return AdbKey_LeftBracket; // I-grave
case 0XF2: return AdbKey_KeypadMultiply; // O-grave
}
return -1;
}
static void toggle_mouse_grab(const SDL_KeyboardEvent &event) {
SDL_Window *window = SDL_GetWindowFromID(event.windowID);
if (SDL_GetRelativeMouseMode()) {
SDL_SetRelativeMouseMode(SDL_FALSE);
SDL_SetWindowTitle(window, "DingusPPC Display");
} else {
// If the mouse is initially outside the window, move it to the middle,
// so that clicks are handled by the window (instead making it lose
// focus, at least with macOS hosts).
int mouse_x, mouse_y, window_x, window_y, window_width, window_height;
SDL_GetGlobalMouseState(&mouse_x, &mouse_y);
SDL_GetWindowPosition(window, &window_x, &window_y);
SDL_GetWindowSize(window, &window_width, &window_height);
if (mouse_x < window_x || mouse_x >= window_x + window_width ||
mouse_y < window_y || mouse_y >= window_y + window_height) {
SDL_WarpMouseInWindow(window, window_width / 2, window_height / 2);
}
SDL_SetRelativeMouseMode(SDL_TRUE);
SDL_SetWindowTitle(window, "DingusPPC Display (Mouse Grabbed)");
}
}