diff --git a/rpcs3/Emu/Io/KeyboardHandler.cpp b/rpcs3/Emu/Io/KeyboardHandler.cpp index bf8c0e17c7..bedeff9630 100644 --- a/rpcs3/Emu/Io/KeyboardHandler.cpp +++ b/rpcs3/Emu/Io/KeyboardHandler.cpp @@ -40,12 +40,14 @@ void fmt_class_string::format(std::string& out, u64 arg) }); } -void KeyboardHandlerBase::Key(u32 code, bool pressed) +void KeyboardHandlerBase::Key(u32 code, bool pressed, const std::u32string& key) { std::lock_guard lock(m_mutex); for (Keyboard& keyboard : m_keyboards) { + bool found_key = false; + KbData& data = keyboard.m_data; KbConfig& config = keyboard.m_config; @@ -54,6 +56,8 @@ void KeyboardHandlerBase::Key(u32 code, bool pressed) if (button.m_keyCode != code) continue; + found_key = true; + u16 kcode = CELL_KEYC_NO_EVENT; bool is_meta_key = IsMetaKey(code); @@ -152,6 +156,18 @@ void KeyboardHandlerBase::Key(u32 code, bool pressed) } } } + + if (!found_key && !key.empty()) + { + if (pressed) + { + keyboard.m_extra_data.pressed_keys.insert(key); + } + else + { + keyboard.m_extra_data.pressed_keys.erase(key); + } + } } } @@ -187,11 +203,18 @@ void KeyboardHandlerBase::SetIntercepted(bool intercepted) void KeyboardHandlerBase::ReleaseAllKeys() { - for (const Keyboard& keyboard : m_keyboards) + for (Keyboard& keyboard : m_keyboards) { for (const KbButton& button : keyboard.m_buttons) { - Key(button.m_keyCode, false); + Key(button.m_keyCode, false, {}); } + + for (const std::u32string& key : keyboard.m_extra_data.pressed_keys) + { + Key(0, false, key); + } + + keyboard.m_extra_data.pressed_keys.clear(); } } diff --git a/rpcs3/Emu/Io/KeyboardHandler.h b/rpcs3/Emu/Io/KeyboardHandler.h index f5ef273f5e..61c4e831cc 100644 --- a/rpcs3/Emu/Io/KeyboardHandler.h +++ b/rpcs3/Emu/Io/KeyboardHandler.h @@ -4,6 +4,7 @@ #include #include +#include #include "util/init_mutex.hpp" @@ -52,6 +53,11 @@ struct KbData std::array buttons{}; }; +struct KbExtraData +{ + std::set pressed_keys{}; +}; + struct KbConfig { u32 arrange = CELL_KB_MAPPING_101; @@ -63,6 +69,7 @@ struct Keyboard { bool m_key_repeat = false; KbData m_data{}; + KbExtraData m_extra_data{}; KbConfig m_config{}; std::vector m_buttons; }; @@ -81,7 +88,7 @@ public: SAVESTATE_INIT_POS(19); - void Key(u32 code, bool pressed); + void Key(u32 code, bool pressed, const std::u32string& key); void SetIntercepted(bool intercepted); static bool IsMetaKey(u32 code); @@ -90,6 +97,7 @@ public: 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; } + KbExtraData& GetExtraData(const u32 keyboard) { return m_keyboards[keyboard].m_extra_data; } KbConfig& GetConfig(const u32 keyboard) { return m_keyboards[keyboard].m_config; } stx::init_mutex init; diff --git a/rpcs3/Emu/RSX/Overlays/overlay_osk.cpp b/rpcs3/Emu/RSX/Overlays/overlay_osk.cpp index 62635db3ea..5eecd901c2 100644 --- a/rpcs3/Emu/RSX/Overlays/overlay_osk.cpp +++ b/rpcs3/Emu/RSX/Overlays/overlay_osk.cpp @@ -586,98 +586,107 @@ namespace rsx } } - void osk_dialog::on_key_pressed(u32 led, u32 mkey, u32 key_code, u32 out_key_code, bool pressed) + void osk_dialog::on_key_pressed(u32 led, u32 mkey, u32 key_code, u32 out_key_code, bool pressed, std::u32string key) { if (!pressed || !keyboard_input_enabled || ignore_input_events) return; - osk.notice("osk_dialog::on_key_pressed(led=%d, mkey=%d, key_code=%d, out_key_code=%d, pressed=%d)", led, mkey, key_code, out_key_code, pressed); + const bool use_key_string_fallback = !key.empty(); - // Get keyboard layout - u32 kb_mapping = CELL_KB_MAPPING_101; - u32 osk_panel_mode = CELL_OSKDIALOG_PANELMODE_DEFAULT; - for (usz i = 0; i < m_panels.size(); ++i) + osk.notice("osk_dialog::on_key_pressed(led=%d, mkey=%d, key_code=%d, out_key_code=%d, pressed=%d, use_key_string_fallback=%d)", led, mkey, key_code, out_key_code, pressed, use_key_string_fallback); + + if (!use_key_string_fallback) { - if (m_panel_index == i) + // Get keyboard layout + u32 kb_mapping = CELL_KB_MAPPING_101; + u32 osk_panel_mode = CELL_OSKDIALOG_PANELMODE_DEFAULT; + for (usz i = 0; i < m_panels.size(); ++i) { - osk_panel_mode = m_panels[i].osk_panel_mode; - break; - } - } - - switch (osk_panel_mode) - { - case CELL_OSKDIALOG_PANELMODE_DEFAULT : kb_mapping = CELL_KB_MAPPING_101; break; - case CELL_OSKDIALOG_PANELMODE_GERMAN : kb_mapping = CELL_KB_MAPPING_GERMAN_GERMANY; break; - case CELL_OSKDIALOG_PANELMODE_ENGLISH : kb_mapping = CELL_KB_MAPPING_ENGLISH_UK; break; - case CELL_OSKDIALOG_PANELMODE_SPANISH : kb_mapping = CELL_KB_MAPPING_SPANISH_SPAIN; break; - case CELL_OSKDIALOG_PANELMODE_FRENCH : kb_mapping = CELL_KB_MAPPING_FRENCH_FRANCE; break; - case CELL_OSKDIALOG_PANELMODE_ITALIAN : kb_mapping = CELL_KB_MAPPING_ITALIAN_ITALY; break; - case CELL_OSKDIALOG_PANELMODE_DUTCH : kb_mapping = CELL_KB_MAPPING_DUTCH_NETHERLANDS; break; - case CELL_OSKDIALOG_PANELMODE_PORTUGUESE : kb_mapping = CELL_KB_MAPPING_PORTUGUESE_PORTUGAL; break; - case CELL_OSKDIALOG_PANELMODE_RUSSIAN : kb_mapping = CELL_KB_MAPPING_RUSSIAN_RUSSIA; break; - case CELL_OSKDIALOG_PANELMODE_JAPANESE : kb_mapping = CELL_KB_MAPPING_106; break; - case CELL_OSKDIALOG_PANELMODE_DEFAULT_NO_JAPANESE: kb_mapping = CELL_KB_MAPPING_106; break; - case CELL_OSKDIALOG_PANELMODE_POLISH : kb_mapping = CELL_KB_MAPPING_POLISH_POLAND; break; - case CELL_OSKDIALOG_PANELMODE_KOREAN : kb_mapping = CELL_KB_MAPPING_KOREAN_KOREA; break; - case CELL_OSKDIALOG_PANELMODE_TURKEY : kb_mapping = CELL_KB_MAPPING_TURKISH_TURKEY; break; - case CELL_OSKDIALOG_PANELMODE_TRADITIONAL_CHINESE: kb_mapping = CELL_KB_MAPPING_CHINESE_TRADITIONAL; break; - case CELL_OSKDIALOG_PANELMODE_SIMPLIFIED_CHINESE : kb_mapping = CELL_KB_MAPPING_CHINESE_SIMPLIFIED; break; - case CELL_OSKDIALOG_PANELMODE_PORTUGUESE_BRAZIL : kb_mapping = CELL_KB_MAPPING_PORTUGUESE_BRAZIL; break; - case CELL_OSKDIALOG_PANELMODE_DANISH : kb_mapping = CELL_KB_MAPPING_DANISH_DENMARK; break; - case CELL_OSKDIALOG_PANELMODE_SWEDISH : kb_mapping = CELL_KB_MAPPING_SWEDISH_SWEDEN; break; - case CELL_OSKDIALOG_PANELMODE_NORWEGIAN : kb_mapping = CELL_KB_MAPPING_NORWEGIAN_NORWAY; break; - case CELL_OSKDIALOG_PANELMODE_FINNISH : kb_mapping = CELL_KB_MAPPING_FINNISH_FINLAND; break; - case CELL_OSKDIALOG_PANELMODE_JAPANESE_HIRAGANA : kb_mapping = CELL_KB_MAPPING_106; break; - case CELL_OSKDIALOG_PANELMODE_JAPANESE_KATAKANA : kb_mapping = CELL_KB_MAPPING_106_KANA; break; - case CELL_OSKDIALOG_PANELMODE_ALPHABET_FULL_WIDTH: kb_mapping = CELL_KB_MAPPING_106; break; - case CELL_OSKDIALOG_PANELMODE_ALPHABET : kb_mapping = CELL_KB_MAPPING_101; break; - case CELL_OSKDIALOG_PANELMODE_LATIN : kb_mapping = CELL_KB_MAPPING_101; break; - case CELL_OSKDIALOG_PANELMODE_NUMERAL_FULL_WIDTH : kb_mapping = CELL_KB_MAPPING_101; break; - case CELL_OSKDIALOG_PANELMODE_NUMERAL : kb_mapping = CELL_KB_MAPPING_101; break; - case CELL_OSKDIALOG_PANELMODE_URL : kb_mapping = CELL_KB_MAPPING_101; break; - case CELL_OSKDIALOG_PANELMODE_PASSWORD : kb_mapping = CELL_KB_MAPPING_101; break; - default : kb_mapping = CELL_KB_MAPPING_101; break; - } - - // Convert key to its u32string presentation - const u16 converted_out_key = cellKbCnvRawCode(kb_mapping, mkey, led, out_key_code); - std::u16string utf16_string; - utf16_string.push_back(converted_out_key); - const std::u32string u32_string = utf16_to_u32string(utf16_string); - const std::string out_key_string = utf16_to_ascii8(utf16_string); - - // Find matching key in the OSK - bool found_key = false; - for (const cell& current_cell : m_grid) - { - // TODO: maybe just ignore the current charset and check all outputs - if (m_selected_charset < current_cell.outputs.size()) - { - for (const auto& str : current_cell.outputs[m_selected_charset]) - { - if (str == u32_string) - { - // Apply key press - if (current_cell.callback) - { - current_cell.callback(str); - } - else - { - on_default_callback(str); - } - - found_key = true; - break; - } - } - - if (found_key) + if (m_panel_index == i) { + osk_panel_mode = m_panels[i].osk_panel_mode; break; } } + + switch (osk_panel_mode) + { + case CELL_OSKDIALOG_PANELMODE_DEFAULT: kb_mapping = CELL_KB_MAPPING_101; break; + case CELL_OSKDIALOG_PANELMODE_GERMAN: kb_mapping = CELL_KB_MAPPING_GERMAN_GERMANY; break; + case CELL_OSKDIALOG_PANELMODE_ENGLISH: kb_mapping = CELL_KB_MAPPING_ENGLISH_UK; break; + case CELL_OSKDIALOG_PANELMODE_SPANISH: kb_mapping = CELL_KB_MAPPING_SPANISH_SPAIN; break; + case CELL_OSKDIALOG_PANELMODE_FRENCH: kb_mapping = CELL_KB_MAPPING_FRENCH_FRANCE; break; + case CELL_OSKDIALOG_PANELMODE_ITALIAN: kb_mapping = CELL_KB_MAPPING_ITALIAN_ITALY; break; + case CELL_OSKDIALOG_PANELMODE_DUTCH: kb_mapping = CELL_KB_MAPPING_DUTCH_NETHERLANDS; break; + case CELL_OSKDIALOG_PANELMODE_PORTUGUESE: kb_mapping = CELL_KB_MAPPING_PORTUGUESE_PORTUGAL; break; + case CELL_OSKDIALOG_PANELMODE_RUSSIAN: kb_mapping = CELL_KB_MAPPING_RUSSIAN_RUSSIA; break; + case CELL_OSKDIALOG_PANELMODE_JAPANESE: kb_mapping = CELL_KB_MAPPING_106; break; + case CELL_OSKDIALOG_PANELMODE_DEFAULT_NO_JAPANESE: kb_mapping = CELL_KB_MAPPING_106; break; + case CELL_OSKDIALOG_PANELMODE_POLISH: kb_mapping = CELL_KB_MAPPING_POLISH_POLAND; break; + case CELL_OSKDIALOG_PANELMODE_KOREAN: kb_mapping = CELL_KB_MAPPING_KOREAN_KOREA; break; + case CELL_OSKDIALOG_PANELMODE_TURKEY: kb_mapping = CELL_KB_MAPPING_TURKISH_TURKEY; break; + case CELL_OSKDIALOG_PANELMODE_TRADITIONAL_CHINESE: kb_mapping = CELL_KB_MAPPING_CHINESE_TRADITIONAL; break; + case CELL_OSKDIALOG_PANELMODE_SIMPLIFIED_CHINESE: kb_mapping = CELL_KB_MAPPING_CHINESE_SIMPLIFIED; break; + case CELL_OSKDIALOG_PANELMODE_PORTUGUESE_BRAZIL: kb_mapping = CELL_KB_MAPPING_PORTUGUESE_BRAZIL; break; + case CELL_OSKDIALOG_PANELMODE_DANISH: kb_mapping = CELL_KB_MAPPING_DANISH_DENMARK; break; + case CELL_OSKDIALOG_PANELMODE_SWEDISH: kb_mapping = CELL_KB_MAPPING_SWEDISH_SWEDEN; break; + case CELL_OSKDIALOG_PANELMODE_NORWEGIAN: kb_mapping = CELL_KB_MAPPING_NORWEGIAN_NORWAY; break; + case CELL_OSKDIALOG_PANELMODE_FINNISH: kb_mapping = CELL_KB_MAPPING_FINNISH_FINLAND; break; + case CELL_OSKDIALOG_PANELMODE_JAPANESE_HIRAGANA: kb_mapping = CELL_KB_MAPPING_106; break; + case CELL_OSKDIALOG_PANELMODE_JAPANESE_KATAKANA: kb_mapping = CELL_KB_MAPPING_106_KANA; break; + case CELL_OSKDIALOG_PANELMODE_ALPHABET_FULL_WIDTH: kb_mapping = CELL_KB_MAPPING_106; break; + case CELL_OSKDIALOG_PANELMODE_ALPHABET: kb_mapping = CELL_KB_MAPPING_101; break; + case CELL_OSKDIALOG_PANELMODE_LATIN: kb_mapping = CELL_KB_MAPPING_101; break; + case CELL_OSKDIALOG_PANELMODE_NUMERAL_FULL_WIDTH: kb_mapping = CELL_KB_MAPPING_101; break; + case CELL_OSKDIALOG_PANELMODE_NUMERAL: kb_mapping = CELL_KB_MAPPING_101; break; + case CELL_OSKDIALOG_PANELMODE_URL: kb_mapping = CELL_KB_MAPPING_101; break; + case CELL_OSKDIALOG_PANELMODE_PASSWORD: kb_mapping = CELL_KB_MAPPING_101; break; + default: kb_mapping = CELL_KB_MAPPING_101; break; + } + + // Convert key to its u32string presentation + const u16 converted_out_key = cellKbCnvRawCode(kb_mapping, mkey, led, out_key_code); + std::u16string utf16_string; + utf16_string.push_back(converted_out_key); + key = utf16_to_u32string(utf16_string); + } + + // Find matching key in the OSK + const auto find_key = [&]() -> bool + { + for (const cell& current_cell : m_grid) + { + for (const auto& output : current_cell.outputs) + { + for (const auto& str : output) + { + if (str == key) + { + // Apply key press + if (current_cell.callback) + { + current_cell.callback(str); + } + else + { + on_default_callback(str); + } + + return true; + } + } + } + } + + return false; + }; + + const bool found_key = find_key(); + + if (use_key_string_fallback) + { + // We don't have a keycode, so there we can't process any of the following code anyway + return; } // Handle special input @@ -686,10 +695,10 @@ namespace rsx switch (out_key_code) { case CELL_KEYC_SPACE: - on_space(u32_string); + on_space(key); break; case CELL_KEYC_BS: - on_backspace(u32_string); + on_backspace(key); break; case CELL_KEYC_ESCAPE: Close(CELL_OSKDIALOG_CLOSE_CANCEL); @@ -701,7 +710,7 @@ namespace rsx } else { - on_enter(u32_string); + on_enter(key); } break; default: diff --git a/rpcs3/Emu/RSX/Overlays/overlay_osk.h b/rpcs3/Emu/RSX/Overlays/overlay_osk.h index a29b4f503e..e83e3540cc 100644 --- a/rpcs3/Emu/RSX/Overlays/overlay_osk.h +++ b/rpcs3/Emu/RSX/Overlays/overlay_osk.h @@ -96,7 +96,7 @@ namespace rsx void update_selection_by_index(u32 index); void on_button_pressed(pad_button button_press) override; - void on_key_pressed(u32 led, u32 mkey, u32 key_code, u32 out_key_code, bool pressed) override; + void on_key_pressed(u32 led, u32 mkey, u32 key_code, u32 out_key_code, bool pressed, std::u32string key) override; void on_text_changed(); void on_default_callback(const std::u32string& str); diff --git a/rpcs3/Emu/RSX/Overlays/overlays.cpp b/rpcs3/Emu/RSX/Overlays/overlays.cpp index a1766f9b14..abceef070c 100644 --- a/rpcs3/Emu/RSX/Overlays/overlays.cpp +++ b/rpcs3/Emu/RSX/Overlays/overlays.cpp @@ -151,17 +151,24 @@ namespace rsx if (!handler.GetKeyboards().empty() && handler.GetInfo().status[0] == CELL_KB_STATUS_CONNECTED) { KbData& current_data = handler.GetData(0); + KbExtraData& extra_data = handler.GetExtraData(0); - if (current_data.len > 0) + if (current_data.len > 0 || !extra_data.pressed_keys.empty()) { for (s32 i = 0; i < current_data.len; i++) { const KbButton& key = current_data.buttons[i]; - on_key_pressed(current_data.led, current_data.mkey, key.m_keyCode, key.m_outKeyCode, key.m_pressed); + on_key_pressed(current_data.led, current_data.mkey, key.m_keyCode, key.m_outKeyCode, key.m_pressed, {}); + } + + for (const std::u32string& key : extra_data.pressed_keys) + { + on_key_pressed(0, 0, 0, 0, true, key); } // Flush buffer unconditionally. Otherwise we get a flood of key events. current_data.len = 0; + extra_data.pressed_keys.clear(); // Ignore gamepad input if a key was recognized refresh(); diff --git a/rpcs3/Emu/RSX/Overlays/overlays.h b/rpcs3/Emu/RSX/Overlays/overlays.h index 745544542b..9fb468760d 100644 --- a/rpcs3/Emu/RSX/Overlays/overlays.h +++ b/rpcs3/Emu/RSX/Overlays/overlays.h @@ -124,7 +124,7 @@ namespace rsx compiled_resource get_compiled() override = 0; virtual void on_button_pressed(pad_button /*button_press*/) {} - virtual void on_key_pressed(u32 /*led*/, u32 /*mkey*/, u32 /*key_code*/, u32 /*out_key_code*/, bool /*pressed*/) {} + virtual void on_key_pressed(u32 /*led*/, u32 /*mkey*/, u32 /*key_code*/, u32 /*out_key_code*/, bool /*pressed*/, std::u32string /*key*/) {} virtual void close(bool use_callback, bool stop_pad_interception); diff --git a/rpcs3/Input/basic_keyboard_handler.cpp b/rpcs3/Input/basic_keyboard_handler.cpp index 80cf662503..016a987770 100644 --- a/rpcs3/Input/basic_keyboard_handler.cpp +++ b/rpcs3/Input/basic_keyboard_handler.cpp @@ -104,7 +104,7 @@ void basic_keyboard_handler::keyPressEvent(QKeyEvent* keyEvent) if (key >= 0) { - Key(static_cast(key), true); + Key(static_cast(key), true, keyEvent->text().toStdU32String()); } } @@ -125,7 +125,7 @@ void basic_keyboard_handler::keyReleaseEvent(QKeyEvent* keyEvent) if (key >= 0) { - Key(static_cast(key), false); + Key(static_cast(key), false, keyEvent->text().toStdU32String()); } }