diff --git a/rpcs3/Emu/Cell/Modules/cellKb.cpp b/rpcs3/Emu/Cell/Modules/cellKb.cpp index 206f06222a..e1c9f5254d 100644 --- a/rpcs3/Emu/Cell/Modules/cellKb.cpp +++ b/rpcs3/Emu/Cell/Modules/cellKb.cpp @@ -71,6 +71,8 @@ error_code cellKbClearBuf(u32 port_no) if (port_no >= CELL_KB_MAX_KEYBOARDS) return CELL_KB_ERROR_INVALID_PARAMETER; + std::lock_guard lock(handler->m_mutex); + const KbInfo& current_info = handler->GetInfo(); if (port_no >= handler->GetKeyboards().size() || current_info.status[port_no] != CELL_KB_STATUS_CONNECTED) @@ -83,7 +85,7 @@ error_code cellKbClearBuf(u32 port_no) for (int i = 0; i < CELL_KB_MAX_KEYCODES; i++) { - current_data.keycode[i] = 0; + current_data.keycode[i] = { 0, 0 }; } return CELL_OK; @@ -110,27 +112,102 @@ u16 cellKbCnvRawCode(u32 arrange, u32 mkey, u32 led, u16 rawcode) if (rawcode == 0x58) return 0x0A | 0x4000; // '\n' // ASCII + + const bool is_shift = mkey & (CELL_KB_MKEY_L_SHIFT | CELL_KB_MKEY_R_SHIFT); + const bool is_caps_lock = led & (CELL_KB_LED_CAPS_LOCK); + + auto get_ascii = [is_shift, is_caps_lock](u16 lower, u16 upper) + { + return is_shift || is_caps_lock ? upper : lower; + }; + + if (arrange == CELL_KB_MAPPING_106) // (Japanese) + { + if (rawcode == 0x1E) return get_ascii(rawcode + 0x13, 0x21); // '1' or '!' + if (rawcode == 0x1F) return get_ascii(rawcode + 0x13, 0x22); // '2' or '"' + if (rawcode == 0x20) return get_ascii(rawcode + 0x13, 0x23); // '3' or '#' + if (rawcode == 0x21) return get_ascii(rawcode + 0x13, 0x24); // '4' or '$' + if (rawcode == 0x22) return get_ascii(rawcode + 0x13, 0x25); // '5' or '%' + if (rawcode == 0x23) return get_ascii(rawcode + 0x13, 0x26); // '6' or '&' + if (rawcode == 0x24) return get_ascii(rawcode + 0x13, 0x27); // '7' or ''' + if (rawcode == 0x25) return get_ascii(rawcode + 0x13, 0x28); // '8' or '(' + if (rawcode == 0x26) return get_ascii(rawcode + 0x13, 0x29); // '9' or ')' + if (rawcode == 0x27) return get_ascii(0x303, 0x7E); // '0' or '~' + + if (rawcode == 0x2E) return get_ascii(0x5E, 0x7E); // '^' or '~' + if (rawcode == 0x2F) return get_ascii(0x40, 0x60); // '@' or '`' + if (rawcode == 0x30) return get_ascii(0x5B, 0x7B); // '[' or '{' + if (rawcode == 0x32) return get_ascii(0x5D, 0x7D); // ']' or '}' + if (rawcode == 0x33) return get_ascii(0x3B, 0x2B); // ';' or '+' + if (rawcode == 0x34) return get_ascii(0x3A, 0x2A); // ':' or '*' + if (rawcode == 0x87) return get_ascii(rawcode, 0x5F); // '\' or '_' + if (rawcode == 0x36) return get_ascii(0x2C, 0x3C); // ',' or '<' + if (rawcode == 0x37) return get_ascii(0x2E, 0x3E); // '.' or '>' + if (rawcode == 0x38) return get_ascii(0x2F, 0x3F); // '/' or '?' + if (rawcode == 0x89) return get_ascii(0xBE, 0x7C); // '¥' or '|' + } + else if (arrange == CELL_KB_MAPPING_101) // (US) + { + if (rawcode == 0x1E) return get_ascii(rawcode + 0x13, 0x21); // '1' or '!' + if (rawcode == 0x1F) return get_ascii(rawcode + 0x13, 0x40); // '2' or '@' + if (rawcode == 0x20) return get_ascii(rawcode + 0x13, 0x23); // '3' or '#' + if (rawcode == 0x21) return get_ascii(rawcode + 0x13, 0x24); // '4' or '$' + if (rawcode == 0x22) return get_ascii(rawcode + 0x13, 0x25); // '5' or '%' + if (rawcode == 0x23) return get_ascii(rawcode + 0x13, 0x5E); // '6' or '^' + if (rawcode == 0x24) return get_ascii(rawcode + 0x13, 0x26); // '7' or '&' + if (rawcode == 0x25) return get_ascii(rawcode + 0x13, 0x2A); // '8' or '*' + if (rawcode == 0x26) return get_ascii(rawcode + 0x13, 0x28); // '9' or '(' + if (rawcode == 0x27) return get_ascii(0x303, 0x29); // '0' or ')' + + if (rawcode == 0x2D) return get_ascii(0x2D, 0x5F); // '-' or '_' + if (rawcode == 0x2E) return get_ascii(0x3D, 0x2B); // '=' or '+' + if (rawcode == 0x2F) return get_ascii(0x5B, 0x7B); // '[' or '{' + if (rawcode == 0x30) return get_ascii(0x5D, 0x7D); // ']' or '}' + if (rawcode == 0x31) return get_ascii(0x5C, 0x7C); // '\' or '|' + if (rawcode == 0x33) return get_ascii(0x3B, 0x3A); // ';' or ':' + if (rawcode == 0x34) return get_ascii(0x27, 0x22); // ''' or '"' + if (rawcode == 0x36) return get_ascii(0x2C, 0x3C); // ',' or '<' + if (rawcode == 0x37) return get_ascii(0x2E, 0x3E); // '.' or '>' + if (rawcode == 0x38) return get_ascii(0x2F, 0x3F); // '/' or '?' + } + else if (arrange == CELL_KB_MAPPING_GERMAN_GERMANY) + { + if (rawcode == 0x1E) return get_ascii(rawcode + 0x13, 0x21); // '1' or '!' + if (rawcode == 0x1F) return get_ascii(rawcode + 0x13, 0x22); // '2' or '"' + if (rawcode == 0x20) return rawcode + 0x13; // '3' (or '�') + if (rawcode == 0x21) return get_ascii(rawcode + 0x13, 0x24); // '4' or '$' + if (rawcode == 0x22) return get_ascii(rawcode + 0x13, 0x25); // '5' or '%' + if (rawcode == 0x23) return get_ascii(rawcode + 0x13, 0x26); // '6' or '&' + if (rawcode == 0x24) return get_ascii(rawcode + 0x13, 0x2F); // '7' or '/' + if (rawcode == 0x25) return get_ascii(rawcode + 0x13, 0x28); // '8' or '(' + if (rawcode == 0x26) return get_ascii(rawcode + 0x13, 0x29); // '9' or ')' + if (rawcode == 0x27) return get_ascii(0x303, 0x3D); // '0' or '=' + + if (rawcode == 0x2D) return get_ascii(0x2D, 0x5F); // '-' or '_' + if (rawcode == 0x2E) return 0x5E; // '^' (or '�') + if (rawcode == 0x36) return get_ascii(0x2C, 0x3B); // ',' or ';' + if (rawcode == 0x37) return get_ascii(0x2E, 0x3A); // '.' or ':' + + // TODO: <>#'+*~[]{}\| + } + if (rawcode >= 0x04 && rawcode <= 0x1D) // 'A' - 'Z' { rawcode -= - (mkey&(CELL_KB_MKEY_L_SHIFT|CELL_KB_MKEY_R_SHIFT)) ? - ((led&(CELL_KB_LED_CAPS_LOCK)) ? 0 : 0x20) : - ((led&(CELL_KB_LED_CAPS_LOCK)) ? 0x20 : 0); + (is_shift) + ? ((led & (CELL_KB_LED_CAPS_LOCK)) ? 0 : 0x20) + : ((led & (CELL_KB_LED_CAPS_LOCK)) ? 0x20 : 0); return rawcode + 0x5D; } if (rawcode >= 0x1E && rawcode <= 0x26) return rawcode + 0x13; // '1' - '9' if (rawcode == 0x27) return 0x30; // '0' if (rawcode == 0x28) return 0x0A; // '\n' + if (rawcode == 0x29) return 0x1B; // 'ESC' + if (rawcode == 0x2A) return 0x08; // '\b' if (rawcode == 0x2B) return 0x09; // '\t' - if (rawcode == 0x2C) return 0x20; // ' ' - if (rawcode == 0x2D) return 0x2D; // '-' - if (rawcode == 0x2E) return 0x3D; // '=' - if (rawcode == 0x36) return 0x2C; // ',' - if (rawcode == 0x37) return 0x2E; // '.' - if (rawcode == 0x38) return 0x2F; // '/' - if (rawcode == 0x87) return 0x5C; // '\' + if (rawcode == 0x2C) return 0x20; // 'space' - // (TODO: Add more cases) + // TODO: Add more cases (e.g. what about '`' and '~' on english layouts) and layouts (e.g. german) return 0x0000; } @@ -147,6 +224,8 @@ error_code cellKbGetInfo(vm::ptr info) if (!info) return CELL_KB_ERROR_INVALID_PARAMETER; + std::lock_guard lock(handler->m_mutex); + const KbInfo& current_info = handler->GetInfo(); info->max_connect = current_info.max_connect; info->now_connect = current_info.now_connect; @@ -172,6 +251,8 @@ error_code cellKbRead(u32 port_no, vm::ptr data) if (port_no >= CELL_KB_MAX_KEYBOARDS || !data) return CELL_KB_ERROR_INVALID_PARAMETER; + std::lock_guard lock(handler->m_mutex); + const KbInfo& current_info = handler->GetInfo(); if (port_no >= handler->GetKeyboards().size() || current_info.status[port_no] != CELL_KB_STATUS_CONNECTED) @@ -184,11 +265,9 @@ error_code cellKbRead(u32 port_no, vm::ptr data) for (s32 i = 0; i < current_data.len; i++) { - data->keycode[i] = current_data.keycode[i]; + data->keycode[i] = current_data.keycode[i].first; } - current_data.len = 0; - return CELL_OK; } @@ -207,6 +286,8 @@ error_code cellKbSetCodeType(u32 port_no, u32 type) if (port_no >= handler->GetKeyboards().size()) return CELL_OK; + std::lock_guard lock(handler->m_mutex); + KbConfig& current_config = handler->GetConfig(port_no); current_config.code_type = type; @@ -233,6 +314,8 @@ error_code cellKbSetLEDStatus(u32 port_no, u8 led) if (port_no >= handler->GetKeyboards().size() || handler->GetInfo().status[port_no] != CELL_KB_STATUS_CONNECTED) return CELL_KB_ERROR_FATAL; + std::lock_guard lock(handler->m_mutex); + KbData& current_data = handler->GetData(port_no); current_data.led = static_cast(led); @@ -254,6 +337,8 @@ error_code cellKbSetReadMode(u32 port_no, u32 rmode) if (port_no >= handler->GetKeyboards().size()) return CELL_OK; + std::lock_guard lock(handler->m_mutex); + KbConfig& current_config = handler->GetConfig(port_no); current_config.read_mode = rmode; @@ -274,6 +359,8 @@ error_code cellKbGetConfiguration(u32 port_no, vm::ptr config) if (port_no >= CELL_KB_MAX_KEYBOARDS) return CELL_KB_ERROR_INVALID_PARAMETER; + std::lock_guard lock(handler->m_mutex); + const KbInfo& current_info = handler->GetInfo(); if (port_no >= handler->GetKeyboards().size() || current_info.status[port_no] != CELL_KB_STATUS_CONNECTED) diff --git a/rpcs3/Emu/Io/KeyboardHandler.h b/rpcs3/Emu/Io/KeyboardHandler.h index 60bbfef0f1..9ac53f75df 100644 --- a/rpcs3/Emu/Io/KeyboardHandler.h +++ b/rpcs3/Emu/Io/KeyboardHandler.h @@ -1,5 +1,7 @@ #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?) @@ -192,6 +194,19 @@ enum CellKbMappingType 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; @@ -208,7 +223,7 @@ struct KbData u32 led; u32 mkey; s32 len; - u16 keycode[KB_MAX_KEYCODES]; + std::pair keycode[KB_MAX_KEYCODES]; KbData() : led(0) @@ -225,7 +240,7 @@ struct KbConfig u32 code_type; KbConfig() - : arrange(CELL_KB_MAPPING_106) + : arrange(CELL_KB_MAPPING_101) , read_mode(CELL_KB_RMODE_INPUTCHAR) , code_type(CELL_KB_CODETYPE_ASCII) { @@ -268,66 +283,138 @@ protected: std::vector m_keyboards; public: + std::mutex m_mutex; + virtual void Init(const u32 max_connect) = 0; virtual ~KeyboardHandlerBase() = default; - void Key(const u32 code, bool pressed) + void Key(u32 code, bool pressed) { - for(Keyboard& keyboard : m_keyboards) + // TODO: Key Repeat + + std::lock_guard lock(m_mutex); + + for (Keyboard& keyboard : m_keyboards) { KbData& data = keyboard.m_data; KbConfig& config = keyboard.m_config; - // TODO: handle read modes - - for(KbButton& button : keyboard.m_buttons) + for (const KbButton& button : keyboard.m_buttons) { - if(button.m_keyCode != code) + 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 (code == 308 || code == 307 || code == 306 || code == 393 || code == 396 || code == 394) + 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 == 364) data.led ^= CELL_KB_LED_NUM_LOCK; - if (code == 311) data.led ^= CELL_KB_LED_CAPS_LOCK; - if (code == 365) data.led ^= CELL_KB_LED_SCROLL_LOCK; + 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; - u16 kcode; - if (config.code_type == CELL_KB_CODETYPE_RAW) + if (config.read_mode == CELL_KB_RMODE_INPUTCHAR) { - kcode = button.m_outKeyCode; + data.keycode[0] = { kcode, 0 }; } - else //config.code_type == CELL_KB_CODETYPE_ASCII + else { - kcode = cellKbCnvRawCode(config.arrange, data.mkey, data.led, button.m_outKeyCode); + data.keycode[data.len % KB_MAX_KEYCODES] = { kcode, 0 }; } - data.keycode[data.len % KB_MAX_KEYCODES] = kcode; - data.len++; } + + data.len = std::min(data.len + 1, (int)KB_MAX_KEYCODES); } else { // Meta Keys - if (code == 308 || code == 307 || code == 306 || code == 393 || code == 396 || code == 394) + 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 - data.keycode[0] = CELL_KEYC_NO_EVENT; - data.len = 1; + 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; } diff --git a/rpcs3/Emu/System.h b/rpcs3/Emu/System.h index fcf40faa91..b0021c2f99 100644 --- a/rpcs3/Emu/System.h +++ b/rpcs3/Emu/System.h @@ -510,7 +510,7 @@ struct cfg_root : cfg::node { node_sys(cfg::node* _this) : cfg::node(_this, "System") {} - cfg::_enum language{this, "Language"}; + cfg::_enum language{this, "Language", (CellSysutilLang)1}; // CELL_SYSUTIL_LANG_ENGLISH_US } sys{this}; diff --git a/rpcs3/basic_keyboard_handler.cpp b/rpcs3/basic_keyboard_handler.cpp index 4fdf2bdf65..ac679729da 100644 --- a/rpcs3/basic_keyboard_handler.cpp +++ b/rpcs3/basic_keyboard_handler.cpp @@ -3,11 +3,20 @@ #include #include +#include "Emu/System.h" + void basic_keyboard_handler::Init(const u32 max_connect) { - for (u32 i = 0; i