Add option for keyboard layout

This commit is contained in:
Megamouse 2019-08-17 16:08:47 +02:00
parent 8a31c7a7c8
commit 86a8b5924a
13 changed files with 203 additions and 139 deletions

View File

@ -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
)

View File

@ -192,7 +192,7 @@ s32 cellSysutilGetSystemParamInt(CellSysutilParamId id, vm::ptr<s32> 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:

View File

@ -1,4 +1,4 @@
#pragma once
#pragma once
#include "Emu/Memory/vm_ptr.h"

View File

@ -0,0 +1,167 @@
#include "stdafx.h"
#include "KeyboardHandler.h"
#include "Utilities/StrUtil.h"
template <>
void fmt_class_string<CellKbMappingType>::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<std::mutex> 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;
}

View File

@ -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<std::mutex> 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<Keyboard>& GetKeyboards() { return m_keyboards; }

View File

@ -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<CellSysutilLang> language{this, "Language", (CellSysutilLang)1}; // CELL_SYSUTIL_LANG_ENGLISH_US
cfg::_enum<CellKbMappingType> keyboard_type{this, "Keyboard Type", (CellKbMappingType)0}; // CELL_KB_MAPPING_101 = US
cfg::_enum<enter_button_assign> enter_button_assignment{this, "Enter button assignment", enter_button_assign::cross};
} sys{this};

View File

@ -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."

View File

@ -1,4 +1,4 @@
#include "basic_keyboard_handler.h"
#include "basic_keyboard_handler.h"
#include <QApplication>
#include <QKeyEvent>
@ -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();
}

View File

@ -69,6 +69,7 @@
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="Emu\Io\KeyboardHandler.cpp" />
<ClCompile Include="util\atomic.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>

View File

@ -812,6 +812,9 @@
<ClCompile Include="Emu\RSX\RSXOffload.cpp">
<Filter>Emu\GPU\RSX</Filter>
</ClCompile>
<ClCompile Include="Emu\Io\KeyboardHandler.cpp">
<Filter>Emu\Io</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Crypto\aes.h">

View File

@ -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"}},

View File

@ -986,6 +986,9 @@ settings_dialog::settings_dialog(std::shared_ptr<gui_settings> 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);

View File

@ -1306,7 +1306,7 @@
<item>
<layout class="QHBoxLayout" name="horizontalLayout_14" stretch="1,1,1">
<item>
<widget class="QGroupBox" name="groupBox_34">
<widget class="QGroupBox" name="gb_sysLang">
<property name="title">
<string>Console Language</string>
</property>
@ -1318,7 +1318,19 @@
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox">
<widget class="QGroupBox" name="gb_keyboardType">
<property name="title">
<string>Keyboard Type</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_keyboardType">
<item>
<widget class="QComboBox" name="keyboardType"/>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="gb_homebrew">
<property name="title">
<string>Homebrew</string>
</property>
@ -1333,9 +1345,6 @@
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="widget_3" native="true"/>
</item>
</layout>
</item>
<item>