overlays/osk: Implement fallback for unknown keys

Note that those keys won't be passed to the cellOsk event hook callback
This commit is contained in:
Megamouse 2022-10-29 11:29:38 +02:00
parent c214f45e14
commit ad340c3007
7 changed files with 141 additions and 94 deletions

View File

@ -40,12 +40,14 @@ void fmt_class_string<CellKbMappingType>::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<std::mutex> 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();
}
}

View File

@ -4,6 +4,7 @@
#include <mutex>
#include <vector>
#include <set>
#include "util/init_mutex.hpp"
@ -52,6 +53,11 @@ struct KbData
std::array<KbButton, CELL_KB_MAX_KEYCODES> buttons{};
};
struct KbExtraData
{
std::set<std::u32string> 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<KbButton> 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<Keyboard>& GetKeyboards() { return m_keyboards; }
std::vector<KbButton>& 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;

View File

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

View File

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

View File

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

View File

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

View File

@ -104,7 +104,7 @@ void basic_keyboard_handler::keyPressEvent(QKeyEvent* keyEvent)
if (key >= 0)
{
Key(static_cast<u32>(key), true);
Key(static_cast<u32>(key), true, keyEvent->text().toStdU32String());
}
}
@ -125,7 +125,7 @@ void basic_keyboard_handler::keyReleaseEvent(QKeyEvent* keyEvent)
if (key >= 0)
{
Key(static_cast<u32>(key), false);
Key(static_cast<u32>(key), false, keyEvent->text().toStdU32String());
}
}