#pragma once #include // TODO: HLE info (constants, structs, etc.) should not be available here extern u16 cellKbCnvRawCode(u32 arrange, u32 mkey, u32 led, u16 rawcode); // (TODO: Can it be problematic to place SysCalls in middle of nowhere?) enum KbPortStatus { CELL_KB_STATUS_DISCONNECTED = 0x00000000, CELL_KB_STATUS_CONNECTED = 0x00000001, }; enum CellKbReadMode { CELL_KB_RMODE_INPUTCHAR = 0, CELL_KB_RMODE_PACKET = 1, }; enum CellKbCodeType { CELL_KB_CODETYPE_RAW = 0, CELL_KB_CODETYPE_ASCII = 1, }; enum KbLedCodes { CELL_KB_LED_NUM_LOCK = 0x00000001, CELL_KB_LED_CAPS_LOCK = 0x00000002, CELL_KB_LED_SCROLL_LOCK = 0x00000004, CELL_KB_LED_COMPOSE = 0x00000008, CELL_KB_LED_KANA = 0x00000016, }; enum KbMetaKeys { CELL_KB_MKEY_L_CTRL = 0x00000001, CELL_KB_MKEY_L_SHIFT = 0x00000002, CELL_KB_MKEY_L_ALT = 0x00000004, CELL_KB_MKEY_L_WIN = 0x00000008, CELL_KB_MKEY_R_CTRL = 0x00000010, CELL_KB_MKEY_R_SHIFT = 0x00000020, CELL_KB_MKEY_R_ALT = 0x00000040, CELL_KB_MKEY_R_WIN = 0x00000080, }; enum Keys { // Non-ASCII Raw data CELL_KEYC_NO_EVENT = 0x00, CELL_KEYC_E_ROLLOVER = 0x01, CELL_KEYC_E_POSTFAIL = 0x02, CELL_KEYC_E_UNDEF = 0x03, CELL_KEYC_ESCAPE = 0x29, CELL_KEYC_106_KANJI = 0x35, CELL_KEYC_CAPS_LOCK = 0x39, CELL_KEYC_F1 = 0x3a, CELL_KEYC_F2 = 0x3b, CELL_KEYC_F3 = 0x3c, CELL_KEYC_F4 = 0x3d, CELL_KEYC_F5 = 0x3e, CELL_KEYC_F6 = 0x3f, CELL_KEYC_F7 = 0x40, CELL_KEYC_F8 = 0x41, CELL_KEYC_F9 = 0x42, CELL_KEYC_F10 = 0x43, CELL_KEYC_F11 = 0x44, CELL_KEYC_F12 = 0x45, CELL_KEYC_PRINTSCREEN = 0x46, CELL_KEYC_SCROLL_LOCK = 0x47, CELL_KEYC_PAUSE = 0x48, CELL_KEYC_INSERT = 0x49, CELL_KEYC_HOME = 0x4a, CELL_KEYC_PAGE_UP = 0x4b, CELL_KEYC_DELETE = 0x4c, CELL_KEYC_END = 0x4d, CELL_KEYC_PAGE_DOWN = 0x4e, CELL_KEYC_RIGHT_ARROW = 0x4f, CELL_KEYC_LEFT_ARROW = 0x50, CELL_KEYC_DOWN_ARROW = 0x51, CELL_KEYC_UP_ARROW = 0x52, CELL_KEYC_NUM_LOCK = 0x53, CELL_KEYC_APPLICATION = 0x65, CELL_KEYC_KANA = 0x88, CELL_KEYC_HENKAN = 0x8a, CELL_KEYC_MUHENKAN = 0x8b, // Raw keycodes for ASCII keys CELL_KEYC_A = 0x04, CELL_KEYC_B = 0x05, CELL_KEYC_C = 0x06, CELL_KEYC_D = 0x07, CELL_KEYC_E = 0x08, CELL_KEYC_F = 0x09, CELL_KEYC_G = 0x0A, CELL_KEYC_H = 0x0B, CELL_KEYC_I = 0x0C, CELL_KEYC_J = 0x0D, CELL_KEYC_K = 0x0E, CELL_KEYC_L = 0x0F, CELL_KEYC_M = 0x10, CELL_KEYC_N = 0x11, CELL_KEYC_O = 0x12, CELL_KEYC_P = 0x13, CELL_KEYC_Q = 0x14, CELL_KEYC_R = 0x15, CELL_KEYC_S = 0x16, CELL_KEYC_T = 0x17, CELL_KEYC_U = 0x18, CELL_KEYC_V = 0x19, CELL_KEYC_W = 0x1A, CELL_KEYC_X = 0x1B, CELL_KEYC_Y = 0x1C, CELL_KEYC_Z = 0x1D, CELL_KEYC_1 = 0x1E, CELL_KEYC_2 = 0x1F, CELL_KEYC_3 = 0x20, CELL_KEYC_4 = 0x21, CELL_KEYC_5 = 0x22, CELL_KEYC_6 = 0x23, CELL_KEYC_7 = 0x24, CELL_KEYC_8 = 0x25, CELL_KEYC_9 = 0x26, CELL_KEYC_0 = 0x27, CELL_KEYC_ENTER = 0x28, CELL_KEYC_ESC = 0x29, CELL_KEYC_BS = 0x2A, CELL_KEYC_TAB = 0x2B, CELL_KEYC_SPACE = 0x2C, CELL_KEYC_MINUS = 0x2D, CELL_KEYC_EQUAL_101 = 0x2E, CELL_KEYC_ACCENT_CIRCONFLEX_106 = 0x2E, CELL_KEYC_LEFT_BRACKET_101 = 0x2F, CELL_KEYC_ATMARK_106 = 0x2F, CELL_KEYC_RIGHT_BRACKET_101 = 0x30, CELL_KEYC_LEFT_BRACKET_106 = 0x30, CELL_KEYC_BACKSLASH_101 = 0x31, CELL_KEYC_RIGHT_BRACKET_106 = 0x32, CELL_KEYC_SEMICOLON = 0x33, CELL_KEYC_QUOTATION_101 = 0x34, CELL_KEYC_COLON_106 = 0x34, CELL_KEYC_COMMA = 0x36, CELL_KEYC_PERIOD = 0x37, CELL_KEYC_SLASH = 0x38, //CELL_KEYC_CAPS_LOCK = 0x39, CELL_KEYC_KPAD_NUMLOCK = 0x53, CELL_KEYC_KPAD_SLASH = 0x54, CELL_KEYC_KPAD_ASTERISK = 0x55, CELL_KEYC_KPAD_MINUS = 0x56, CELL_KEYC_KPAD_PLUS = 0x57, CELL_KEYC_KPAD_ENTER = 0x58, CELL_KEYC_KPAD_1 = 0x59, CELL_KEYC_KPAD_2 = 0x5A, CELL_KEYC_KPAD_3 = 0x5B, CELL_KEYC_KPAD_4 = 0x5C, CELL_KEYC_KPAD_5 = 0x5D, CELL_KEYC_KPAD_6 = 0x5E, CELL_KEYC_KPAD_7 = 0x5F, CELL_KEYC_KPAD_8 = 0x60, CELL_KEYC_KPAD_9 = 0x61, CELL_KEYC_KPAD_0 = 0x62, CELL_KEYC_KPAD_PERIOD = 0x63, CELL_KEYC_BACKSLASH_106 = 0x87, CELL_KEYC_YEN_106 = 0x89, }; enum CellKbMappingType { CELL_KB_MAPPING_101, CELL_KB_MAPPING_106, CELL_KB_MAPPING_106_KANA, CELL_KB_MAPPING_GERMAN_GERMANY, CELL_KB_MAPPING_SPANISH_SPAIN, CELL_KB_MAPPING_FRENCH_FRANCE, CELL_KB_MAPPING_ITALIAN_ITALY, CELL_KB_MAPPING_DUTCH_NETHERLANDS, CELL_KB_MAPPING_PORTUGUESE_PORTUGAL, CELL_KB_MAPPING_RUSSIAN_RUSSIA, CELL_KB_MAPPING_ENGLISH_UK, CELL_KB_MAPPING_KOREAN_KOREA, CELL_KB_MAPPING_NORWEGIAN_NORWAY, CELL_KB_MAPPING_FINNISH_FINLAND, CELL_KB_MAPPING_DANISH_DENMARK, CELL_KB_MAPPING_SWEDISH_SWEDEN, CELL_KB_MAPPING_CHINESE_TRADITIONAL, CELL_KB_MAPPING_CHINESE_SIMPLIFIED, CELL_KB_MAPPING_SWISS_FRENCH_SWITZERLAND, CELL_KB_MAPPING_SWISS_GERMAN_SWITZERLAND, CELL_KB_MAPPING_CANADIAN_FRENCH_CANADA, CELL_KB_MAPPING_BELGIAN_BELGIUM, CELL_KB_MAPPING_POLISH_POLAND, CELL_KB_MAPPING_PORTUGUESE_BRAZIL, CELL_KB_MAPPING_TURKISH_TURKEY }; enum QtKeys { Key_Shift = 0x01000020, Key_Control = 0x01000021, Key_Meta = 0x01000022, Key_Alt = 0x01000023, Key_CapsLock = 0x01000024, Key_NumLock = 0x01000025, Key_ScrollLock = 0x01000026, Key_Super_L = 0x01000053, Key_Super_R = 0x01000054 }; static const u32 KB_MAX_KEYBOARDS = 127; static const u32 KB_MAX_KEYCODES = 62; struct KbInfo { u32 max_connect; u32 now_connect; u32 info; u8 status[KB_MAX_KEYBOARDS]; }; struct KbData { u32 led; u32 mkey; s32 len; std::pair keycode[KB_MAX_KEYCODES]; KbData() : led(0) , mkey(0) , len(0) { // (TODO: Set initial state of led) } }; struct KbConfig { u32 arrange; u32 read_mode; u32 code_type; KbConfig() : arrange(CELL_KB_MAPPING_101) , read_mode(CELL_KB_RMODE_INPUTCHAR) , code_type(CELL_KB_CODETYPE_ASCII) { } }; struct KbButton { u32 m_keyCode; u32 m_outKeyCode; bool m_pressed; KbButton(u32 keyCode, u32 outKeyCode) : m_pressed(false) , m_keyCode(keyCode) , m_outKeyCode(outKeyCode) { } }; struct Keyboard { bool m_key_repeat; // for future use KbData m_data; KbConfig m_config; std::vector m_buttons; Keyboard() : m_data() , m_config() , m_key_repeat(false) { } }; class KeyboardHandlerBase { protected: KbInfo m_info; std::vector m_keyboards; public: std::mutex m_mutex; virtual void Init(const u32 max_connect) = 0; virtual ~KeyboardHandlerBase() = default; void Key(u32 code, bool pressed) { // TODO: Key Repeat std::lock_guard lock(m_mutex); for (Keyboard& keyboard : m_keyboards) { KbData& data = keyboard.m_data; KbConfig& config = keyboard.m_config; for (const KbButton& button : keyboard.m_buttons) { if (button.m_keyCode != code) continue; u16 kcode = CELL_KEYC_NO_EVENT; bool is_meta_key = IsMetaKey(code); if (!is_meta_key) { if (config.code_type == CELL_KB_CODETYPE_RAW) { kcode = button.m_outKeyCode; } else // config.code_type == CELL_KB_CODETYPE_ASCII { kcode = cellKbCnvRawCode(config.arrange, data.mkey, data.led, button.m_outKeyCode); } } if (pressed) { if (data.len == 1 && data.keycode[0].first == CELL_KEYC_NO_EVENT) { data.len = 0; } // Meta Keys if (is_meta_key) { data.mkey |= button.m_outKeyCode; if (config.read_mode == CELL_KB_RMODE_INPUTCHAR) { data.keycode[0] = {CELL_KEYC_NO_EVENT, button.m_outKeyCode}; } else { data.keycode[data.len % KB_MAX_KEYCODES] = { CELL_KEYC_NO_EVENT, button.m_outKeyCode }; } } else { // Led Keys if (code == Key_CapsLock) data.led ^= CELL_KB_LED_CAPS_LOCK; if (code == Key_NumLock) data.led ^= CELL_KB_LED_NUM_LOCK; if (code == Key_ScrollLock) data.led ^= CELL_KB_LED_SCROLL_LOCK; // if (code == Key_Kana_Lock) data.led ^= CELL_KB_LED_KANA; // if (code == ???) data.led ^= CELL_KB_LED_COMPOSE; if (config.read_mode == CELL_KB_RMODE_INPUTCHAR) { data.keycode[0] = { kcode, 0 }; } else { data.keycode[data.len % KB_MAX_KEYCODES] = { kcode, 0 }; } } data.len = std::min(data.len + 1, (int)KB_MAX_KEYCODES); } else { // Meta Keys if (is_meta_key) { data.mkey &= ~button.m_outKeyCode; } // Needed to indicate key releases. Without this you have to tap another key before using the same key again if (config.read_mode == CELL_KB_RMODE_INPUTCHAR) { data.keycode[0] = { CELL_KEYC_NO_EVENT, 0 }; data.len = 1; } else { s32 index = data.len; for (s32 i = 0; i < data.len; i++) { if (data.keycode[i].first == kcode && (!is_meta_key || data.keycode[i].second == button.m_outKeyCode)) { index = i; break; } } for (s32 i = index; i < data.len - 1; i++) { data.keycode[i] = data.keycode[i + 1]; } if (data.len <= 1) { data.keycode[0] = { CELL_KEYC_NO_EVENT, 0 }; } data.len = std::max(1, data.len - 1); } } } } } bool IsMetaKey(u32 code) { return code == Key_Control || code == Key_Shift || code == Key_Alt || code == Key_Super_L || code == Key_Super_R; } KbInfo& GetInfo() { return m_info; } std::vector& GetKeyboards() { return m_keyboards; } std::vector& GetButtons(const u32 keyboard) { return m_keyboards[keyboard].m_buttons; } KbData& GetData(const u32 keyboard) { return m_keyboards[keyboard].m_data; } KbConfig& GetConfig(const u32 keyboard) { return m_keyboards[keyboard].m_config; } };