/* 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 . */ #include #include #include #include #include #include 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)"); } }