diff --git a/rpcs3/Emu/CMakeLists.txt b/rpcs3/Emu/CMakeLists.txt index 200bc36954..4335eab39c 100644 --- a/rpcs3/Emu/CMakeLists.txt +++ b/rpcs3/Emu/CMakeLists.txt @@ -1,4 +1,4 @@ -add_library(rpcs3_emu +add_library(rpcs3_emu IdManager.cpp System.cpp VFS.cpp @@ -298,6 +298,7 @@ target_link_libraries(rpcs3_emu # Io target_sources(rpcs3_emu PRIVATE + Io/KeyboardHandler.cpp Io/PadHandler.cpp ) diff --git a/rpcs3/Emu/Cell/Modules/cellSysutil.cpp b/rpcs3/Emu/Cell/Modules/cellSysutil.cpp index db498b60b6..30774bd965 100644 --- a/rpcs3/Emu/Cell/Modules/cellSysutil.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSysutil.cpp @@ -192,7 +192,7 @@ s32 cellSysutilGetSystemParamInt(CellSysutilParamId id, vm::ptr value) break; case CELL_SYSUTIL_SYSTEMPARAM_ID_KEYBOARD_TYPE: - *value = 0; + *value = g_cfg.sys.keyboard_type; break; case CELL_SYSUTIL_SYSTEMPARAM_ID_JAPANESE_KEYBOARD_ENTRY_METHOD: diff --git a/rpcs3/Emu/Cell/Modules/cellSysutil.h b/rpcs3/Emu/Cell/Modules/cellSysutil.h index db23e68989..47e4af7a01 100644 --- a/rpcs3/Emu/Cell/Modules/cellSysutil.h +++ b/rpcs3/Emu/Cell/Modules/cellSysutil.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "Emu/Memory/vm_ptr.h" diff --git a/rpcs3/Emu/Io/KeyboardHandler.cpp b/rpcs3/Emu/Io/KeyboardHandler.cpp new file mode 100644 index 0000000000..b902055b88 --- /dev/null +++ b/rpcs3/Emu/Io/KeyboardHandler.cpp @@ -0,0 +1,167 @@ +#include "stdafx.h" +#include "KeyboardHandler.h" +#include "Utilities/StrUtil.h" + +template <> +void fmt_class_string::format(std::string& out, u64 arg) +{ + format_enum(out, arg, [](CellKbMappingType value) + { + switch (value) + { + case CELL_KB_MAPPING_101: return "English keyboard (US standard)"; + case CELL_KB_MAPPING_106: return "Japanese keyboard"; + case CELL_KB_MAPPING_106_KANA: return "Japanese keyboard(Kana state)"; + case CELL_KB_MAPPING_GERMAN_GERMANY: return "German keyboard"; + case CELL_KB_MAPPING_SPANISH_SPAIN: return "Spanish keyboard"; + case CELL_KB_MAPPING_FRENCH_FRANCE: return "French keyboard"; + case CELL_KB_MAPPING_ITALIAN_ITALY: return "Italian keyboard"; + case CELL_KB_MAPPING_DUTCH_NETHERLANDS: return "Dutch keyboard"; + case CELL_KB_MAPPING_PORTUGUESE_PORTUGAL: return "Portuguese keyboard(Portugal)"; + case CELL_KB_MAPPING_RUSSIAN_RUSSIA: return "Russian keyboard"; + case CELL_KB_MAPPING_ENGLISH_UK: return "English keyboard(UK standard)"; + case CELL_KB_MAPPING_KOREAN_KOREA: return "Korean keyboard"; + case CELL_KB_MAPPING_NORWEGIAN_NORWAY: return "Norwegian keyboard"; + case CELL_KB_MAPPING_FINNISH_FINLAND: return "Finnish keyboard"; + case CELL_KB_MAPPING_DANISH_DENMARK: return "Danish keyboard"; + case CELL_KB_MAPPING_SWEDISH_SWEDEN: return "Swedish keyboard"; + case CELL_KB_MAPPING_CHINESE_TRADITIONAL: return "Chinese keyboard(Traditional)"; + case CELL_KB_MAPPING_CHINESE_SIMPLIFIED: return "Chinese keyboard(Simplified)"; + case CELL_KB_MAPPING_SWISS_FRENCH_SWITZERLAND: return "French keyboard(Switzerland)"; + case CELL_KB_MAPPING_SWISS_GERMAN_SWITZERLAND: return "German keyboard(Switzerland)"; + case CELL_KB_MAPPING_CANADIAN_FRENCH_CANADA: return "French keyboard(Canada)"; + case CELL_KB_MAPPING_BELGIAN_BELGIUM: return "French keyboard(Belgium)"; + case CELL_KB_MAPPING_POLISH_POLAND: return "Polish keyboard"; + case CELL_KB_MAPPING_PORTUGUESE_BRAZIL: return "Portuguese keyboard(Brazil)"; + case CELL_KB_MAPPING_TURKISH_TURKEY: return "Turkish keyboard"; + } + + return unknown; + }); +} + +void KeyboardHandlerBase::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 KeyboardHandlerBase::IsMetaKey(u32 code) +{ + return code == Key_Control + || code == Key_Shift + || code == Key_Alt + || code == Key_Super_L + || code == Key_Super_R; +} diff --git a/rpcs3/Emu/Io/KeyboardHandler.h b/rpcs3/Emu/Io/KeyboardHandler.h index 206a9df014..9982bc84a0 100644 --- a/rpcs3/Emu/Io/KeyboardHandler.h +++ b/rpcs3/Emu/Io/KeyboardHandler.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "Utilities/types.h" @@ -167,7 +167,7 @@ enum Keys CELL_KEYC_YEN_106 = 0x89, }; -enum CellKbMappingType +enum CellKbMappingType : s32 { CELL_KB_MAPPING_101, CELL_KB_MAPPING_106, @@ -291,131 +291,9 @@ public: virtual ~KeyboardHandlerBase() = default; - void Key(u32 code, bool pressed) - { - // TODO: Key Repeat + void Key(u32 code, bool pressed); - 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; - } + bool IsMetaKey(u32 code); KbInfo& GetInfo() { return m_info; } std::vector& GetKeyboards() { return m_keyboards; } diff --git a/rpcs3/Emu/System.h b/rpcs3/Emu/System.h index a1b917e0b3..597c9fa493 100644 --- a/rpcs3/Emu/System.h +++ b/rpcs3/Emu/System.h @@ -203,6 +203,7 @@ enum enter_button_assign enum CellNetCtlState : s32; enum CellSysutilLang : s32; +enum CellKbMappingType : s32; struct EmuCallbacks { @@ -590,6 +591,7 @@ struct cfg_root : cfg::node node_sys(cfg::node* _this) : cfg::node(_this, "System") {} cfg::_enum language{this, "Language", (CellSysutilLang)1}; // CELL_SYSUTIL_LANG_ENGLISH_US + cfg::_enum keyboard_type{this, "Keyboard Type", (CellKbMappingType)0}; // CELL_KB_MAPPING_101 = US cfg::_enum enter_button_assignment{this, "Enter button assignment", enter_button_assign::cross}; } sys{this}; diff --git a/rpcs3/Json/tooltips.json b/rpcs3/Json/tooltips.json index 6f63e38b23..9ce55193f6 100644 --- a/rpcs3/Json/tooltips.json +++ b/rpcs3/Json/tooltips.json @@ -158,6 +158,7 @@ }, "system": { "sysLangBox": "Some games may fail to boot if the system language is not available in the game itself.\nOther games will switch language automatically to what is selected here.\nIt is recommended leaving this on a language supported by the game.", + "keyboardType": "Sets the used keyboard layout.\nCurrently only US, Japanese and German layouts are fully supported at this moment.", "enterButtonAssignment": "The button used for enter/accept/confirm in system dialogs.\nChange this to use the circle button instead, which is the default configuration on Japanese systems and in many Japanese games.\nIn these cases having the cross button assigned can often lead to confusion.", "enableHostRoot": "Required for some Homebrew.\nIf unsure, don't use this option.", "limitCacheSize": "Automatically removes older files from disk cache on boot if it grows larger than the specified value.\nGames can use the cache folder to temporarily store data outside of system memory. It is not used for long-term storage." diff --git a/rpcs3/basic_keyboard_handler.cpp b/rpcs3/basic_keyboard_handler.cpp index 03a86a57fc..94383d1c61 100644 --- a/rpcs3/basic_keyboard_handler.cpp +++ b/rpcs3/basic_keyboard_handler.cpp @@ -1,4 +1,4 @@ -#include "basic_keyboard_handler.h" +#include "basic_keyboard_handler.h" #include #include @@ -15,10 +15,7 @@ void basic_keyboard_handler::Init(const u32 max_connect) { Keyboard kb = Keyboard(); - // Only differentiate between japanese and us layouts right now - kb.m_config.arrange = g_cfg.sys.language == 0 // CELL_SYSUTIL_LANG_JAPANESE - ? CELL_KB_MAPPING_106 - : CELL_KB_MAPPING_101; + kb.m_config.arrange = g_cfg.sys.keyboard_type; m_keyboards.emplace_back(); } diff --git a/rpcs3/emucore.vcxproj b/rpcs3/emucore.vcxproj index 199dbb1293..f2a96e9695 100644 --- a/rpcs3/emucore.vcxproj +++ b/rpcs3/emucore.vcxproj @@ -69,6 +69,7 @@ + NotUsing diff --git a/rpcs3/emucore.vcxproj.filters b/rpcs3/emucore.vcxproj.filters index 6a4995ced9..c54746fa5e 100644 --- a/rpcs3/emucore.vcxproj.filters +++ b/rpcs3/emucore.vcxproj.filters @@ -812,6 +812,9 @@ Emu\GPU\RSX + + Emu\Io + diff --git a/rpcs3/rpcs3qt/emu_settings.h b/rpcs3/rpcs3qt/emu_settings.h index 9c6002dfc1..c8ee08b3ab 100644 --- a/rpcs3/rpcs3qt/emu_settings.h +++ b/rpcs3/rpcs3qt/emu_settings.h @@ -138,6 +138,7 @@ public: // System Language, + KeyboardType, EnterButtonAssignment, EnableHostRoot, LimitCacheSize, @@ -368,6 +369,7 @@ private: // System { Language, { "System", "Language"}}, + { KeyboardType, { "System", "Keyboard Type"} }, { EnterButtonAssignment, { "System", "Enter button assignment"}}, { EnableHostRoot, { "VFS", "Enable /host_root/"}}, { LimitCacheSize, { "VFS", "Limit disk cache size"}}, diff --git a/rpcs3/rpcs3qt/settings_dialog.cpp b/rpcs3/rpcs3qt/settings_dialog.cpp index 6f9679ad85..06ccf8e009 100644 --- a/rpcs3/rpcs3qt/settings_dialog.cpp +++ b/rpcs3/rpcs3qt/settings_dialog.cpp @@ -986,6 +986,9 @@ settings_dialog::settings_dialog(std::shared_ptr guiSettings, std: xemu_settings->EnhanceComboBox(ui->sysLangBox, emu_settings::Language, false, false, 0, true); SubscribeTooltip(ui->sysLangBox, json_sys["sysLangBox"].toString()); + xemu_settings->EnhanceComboBox(ui->keyboardType, emu_settings::KeyboardType, false, false, 0, true); + SubscribeTooltip(ui->keyboardType, json_sys["keyboardType"].toString()); + // Checkboxes xemu_settings->EnhanceCheckBox(ui->enableHostRoot, emu_settings::EnableHostRoot); diff --git a/rpcs3/rpcs3qt/settings_dialog.ui b/rpcs3/rpcs3qt/settings_dialog.ui index c7e88cb5bc..2a4fc52f74 100644 --- a/rpcs3/rpcs3qt/settings_dialog.ui +++ b/rpcs3/rpcs3qt/settings_dialog.ui @@ -1306,7 +1306,7 @@ - + Console Language @@ -1318,7 +1318,19 @@ - + + + Keyboard Type + + + + + + + + + + Homebrew @@ -1333,9 +1345,6 @@ - - -