input: differentiate between left and right modifier keys

This commit is contained in:
Megamouse 2024-06-23 11:26:34 +02:00
parent 1cef7df006
commit 945bfaf0ea
4 changed files with 134 additions and 42 deletions

View file

@ -94,7 +94,7 @@ void KeyboardHandlerBase::RemoveConsumer(keyboard_consumer::identifier id)
}
}
bool KeyboardHandlerBase::HandleKey(u32 code, bool pressed, bool is_auto_repeat, const std::u32string& key)
bool KeyboardHandlerBase::HandleKey(u32 qt_code, u32 native_code, bool pressed, bool is_auto_repeat, const std::u32string& key)
{
bool consumed = false;
@ -102,13 +102,13 @@ bool KeyboardHandlerBase::HandleKey(u32 code, bool pressed, bool is_auto_repeat,
for (auto& [id, consumer] : m_consumers)
{
consumed |= consumer.ConsumeKey(code, pressed, is_auto_repeat, key);
consumed |= consumer.ConsumeKey(qt_code, native_code, pressed, is_auto_repeat, key);
}
return consumed;
}
bool keyboard_consumer::ConsumeKey(u32 code, bool pressed, bool is_auto_repeat, const std::u32string& key)
bool keyboard_consumer::ConsumeKey(u32 qt_code, u32 native_code, bool pressed, bool is_auto_repeat, const std::u32string& key)
{
bool consumed = false;
@ -124,22 +124,24 @@ bool keyboard_consumer::ConsumeKey(u32 code, bool pressed, bool is_auto_repeat,
KbData& data = keyboard.m_data;
const KbConfig& config = keyboard.m_config;
if (auto it = keyboard.m_keys.find(code); it != keyboard.m_keys.end())
if (auto it = keyboard.m_keys.find(qt_code); it != keyboard.m_keys.end())
{
KbButton& button = it->second;
const u32 out_key_code = get_out_key_code(qt_code, native_code, button.m_outKeyCode);
u16 kcode = CELL_KEYC_NO_EVENT;
bool is_meta_key = IsMetaKey(code);
bool is_meta_key = IsMetaKey(qt_code);
if (!is_meta_key)
{
if (config.code_type == CELL_KB_CODETYPE_RAW)
{
kcode = button.m_outKeyCode;
kcode = out_key_code;
}
else // config.code_type == CELL_KB_CODETYPE_ASCII
{
kcode = cellKbCnvRawCode(config.arrange, data.mkey, data.led, button.m_outKeyCode);
kcode = cellKbCnvRawCode(config.arrange, data.mkey, data.led, out_key_code);
}
}
@ -153,33 +155,33 @@ bool keyboard_consumer::ConsumeKey(u32 code, bool pressed, bool is_auto_repeat,
// Meta Keys
if (is_meta_key)
{
data.mkey |= button.m_outKeyCode;
data.mkey |= out_key_code;
if (config.read_mode == CELL_KB_RMODE_INPUTCHAR)
{
data.buttons[0] = KbButton(CELL_KEYC_NO_EVENT, button.m_outKeyCode, true);
data.buttons[0] = KbButton(CELL_KEYC_NO_EVENT, out_key_code, true);
}
else
{
data.buttons[data.len % CELL_KB_MAX_KEYCODES] = KbButton(CELL_KEYC_NO_EVENT, button.m_outKeyCode, true);
data.buttons[data.len % CELL_KB_MAX_KEYCODES] = KbButton(CELL_KEYC_NO_EVENT, out_key_code, true);
}
}
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 (qt_code == Key_CapsLock) data.led ^= CELL_KB_LED_CAPS_LOCK;
if (qt_code == Key_NumLock) data.led ^= CELL_KB_LED_NUM_LOCK;
if (qt_code == Key_ScrollLock) data.led ^= CELL_KB_LED_SCROLL_LOCK;
// if (qt_code == Key_Kana_Lock) data.led ^= CELL_KB_LED_KANA;
// if (qt_code == ???) data.led ^= CELL_KB_LED_COMPOSE;
if (config.read_mode == CELL_KB_RMODE_INPUTCHAR)
{
data.buttons[0] = KbButton(kcode, button.m_outKeyCode, true);
data.buttons[0] = KbButton(kcode, out_key_code, true);
}
else
{
data.buttons[data.len % CELL_KB_MAX_KEYCODES] = KbButton(kcode, button.m_outKeyCode, true);
data.buttons[data.len % CELL_KB_MAX_KEYCODES] = KbButton(kcode, out_key_code, true);
}
}
@ -190,13 +192,13 @@ bool keyboard_consumer::ConsumeKey(u32 code, bool pressed, bool is_auto_repeat,
// Meta Keys
if (is_meta_key)
{
data.mkey &= ~button.m_outKeyCode;
data.mkey &= ~out_key_code;
}
// 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.buttons[0] = KbButton(CELL_KEYC_NO_EVENT, button.m_outKeyCode, false);
data.buttons[0] = KbButton(CELL_KEYC_NO_EVENT, out_key_code, false);
data.len = 1;
}
else
@ -205,7 +207,7 @@ bool keyboard_consumer::ConsumeKey(u32 code, bool pressed, bool is_auto_repeat,
for (s32 i = 0; i < data.len; i++)
{
if (data.buttons[i].m_keyCode == kcode && (!is_meta_key || data.buttons[i].m_outKeyCode == button.m_outKeyCode))
if (data.buttons[i].m_keyCode == kcode && (!is_meta_key || data.buttons[i].m_outKeyCode == out_key_code))
{
index = i;
break;
@ -219,7 +221,7 @@ bool keyboard_consumer::ConsumeKey(u32 code, bool pressed, bool is_auto_repeat,
if (data.len <= 1)
{
data.buttons[0] = KbButton(CELL_KEYC_NO_EVENT, button.m_outKeyCode, false);
data.buttons[0] = KbButton(CELL_KEYC_NO_EVENT, out_key_code, false);
}
data.len = std::max(1, data.len - 1);
@ -247,10 +249,32 @@ bool keyboard_consumer::IsMetaKey(u32 code)
return code == Key_Control
|| code == Key_Shift
|| code == Key_Alt
|| code == Key_Meta
|| code == Key_Super_L
|| code == Key_Super_R;
}
u32 keyboard_consumer::get_out_key_code(u32 qt_code, u32 native_code, u32 out_key_code)
{
// Parse native key codes to differentiate between left and right keys. (Qt sometimes really sucks)
// NOTE: Qt throws a Ctrl key at us when using Alt Gr first, so right Alt does not work at the moment
switch (qt_code)
{
case Key_Control:
return native_code == native_key::ctrl_l ? CELL_KB_MKEY_L_CTRL : CELL_KB_MKEY_R_CTRL;
case Key_Shift:
return native_code == native_key::shift_l ? CELL_KB_MKEY_L_SHIFT : CELL_KB_MKEY_R_SHIFT;
case Key_Alt:
return native_code == native_key::alt_l ? CELL_KB_MKEY_L_ALT : CELL_KB_MKEY_R_ALT;
case Key_Meta:
return native_code == native_key::meta_l ? CELL_KB_MKEY_L_WIN : CELL_KB_MKEY_R_WIN;
default:
break;
}
return out_key_code;
}
void KeyboardHandlerBase::SetIntercepted(bool intercepted)
{
std::lock_guard<std::mutex> lock(m_mutex);
@ -294,12 +318,33 @@ void keyboard_consumer::ReleaseAllKeys()
{
for (const auto& [key_code, button] : keyboard.m_keys)
{
ConsumeKey(button.m_keyCode, false, false, {});
switch (button.m_keyCode)
{
case Key_Control:
ConsumeKey(button.m_keyCode, native_key::ctrl_l, false, false, {});
ConsumeKey(button.m_keyCode, native_key::ctrl_r, false, false, {});
break;
case Key_Shift:
ConsumeKey(button.m_keyCode, native_key::shift_l, false, false, {});
ConsumeKey(button.m_keyCode, native_key::shift_r, false, false, {});
break;
case Key_Alt:
ConsumeKey(button.m_keyCode, native_key::alt_l, false, false, {});
ConsumeKey(button.m_keyCode, native_key::alt_r, false, false, {});
break;
case Key_Meta:
ConsumeKey(button.m_keyCode, native_key::meta_l, false, false, {});
ConsumeKey(button.m_keyCode, native_key::meta_r, false, false, {});
break;
default:
ConsumeKey(button.m_keyCode, 0, false, false, {});
break;
}
}
for (const std::u32string& key : keyboard.m_extra_data.pressed_keys)
{
ConsumeKey(CELL_KEYC_NO_EVENT, false, false, key);
ConsumeKey(CELL_KEYC_NO_EVENT, 0, false, false, key);
}
keyboard.m_extra_data.pressed_keys.clear();

View file

@ -22,6 +22,39 @@ enum QtKeys
Key_Super_R = 0x01000054
};
// See https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_code_values
enum native_key : u32
{
#ifdef _WIN32
ctrl_l = 0x001D,
ctrl_r = 0xE01D,
shift_l = 0x002A,
shift_r = 0x0036,
alt_l = 0x0038,
alt_r = 0xE038,
meta_l = 0xE05B,
meta_r = 0xE05C,
#elif defined (__APPLE__)
ctrl_l = 0x3B, // kVK_Control
ctrl_r = 0x3E, // kVK_RightControl
shift_l = 0x38, // kVK_Shift
shift_r = 0x3C, // kVK_RightShift
alt_l = 0x3A, // kVK_Option
alt_r = 0x3D, // kVK_RightOption
meta_l = 0x37, // kVK_Command
meta_r = 0x36, // kVK_RightCommand
#else
ctrl_l = 0x0025,
ctrl_r = 0x0069,
shift_l = 0x0032,
shift_r = 0x003E,
alt_l = 0x0040,
alt_r = 0x006C,
meta_l = 0x0085,
meta_r = 0x0086,
#endif
};
struct KbInfo
{
u32 max_connect = 0;
@ -88,7 +121,7 @@ public:
keyboard_consumer() {}
keyboard_consumer(identifier id) : m_id(id) {}
bool ConsumeKey(u32 code, bool pressed, bool is_auto_repeat, const std::u32string& key);
bool ConsumeKey(u32 qt_code, u32 native_code, bool pressed, bool is_auto_repeat, const std::u32string& key);
void SetIntercepted(bool intercepted);
static bool IsMetaKey(u32 code);
@ -103,6 +136,8 @@ public:
void ReleaseAllKeys();
protected:
u32 get_out_key_code(u32 qt_code, u32 native_code, u32 out_key_code);
identifier m_id = identifier::unknown;
KbInfo m_info{};
std::vector<Keyboard> m_keyboards;
@ -126,7 +161,7 @@ public:
keyboard_consumer& GetConsumer(keyboard_consumer::identifier id);
void RemoveConsumer(keyboard_consumer::identifier id);
bool HandleKey(u32 code, bool pressed, bool is_auto_repeat, const std::u32string& key);
bool HandleKey(u32 qt_code, u32 native_code, bool pressed, bool is_auto_repeat, const std::u32string& key);
void SetIntercepted(bool intercepted);
stx::init_mutex init;

View file

@ -110,7 +110,7 @@ void basic_keyboard_handler::keyPressEvent(QKeyEvent* keyEvent)
const int key = getUnmodifiedKey(keyEvent);
if (key < 0 || !HandleKey(static_cast<u32>(key), true, keyEvent->isAutoRepeat(), keyEvent->text().toStdU32String()))
if (key < 0 || !HandleKey(static_cast<u32>(key), keyEvent->nativeScanCode(), true, keyEvent->isAutoRepeat(), keyEvent->text().toStdU32String()))
{
keyEvent->ignore();
}
@ -131,7 +131,7 @@ void basic_keyboard_handler::keyReleaseEvent(QKeyEvent* keyEvent)
const int key = getUnmodifiedKey(keyEvent);
if (key < 0 || !HandleKey(static_cast<u32>(key), false, keyEvent->isAutoRepeat(), keyEvent->text().toStdU32String()))
if (key < 0 || !HandleKey(static_cast<u32>(key), keyEvent->nativeScanCode(), false, keyEvent->isAutoRepeat(), keyEvent->text().toStdU32String()))
{
keyEvent->ignore();
}
@ -182,11 +182,14 @@ void basic_keyboard_handler::LoadSettings(Keyboard& keyboard)
buttons.emplace_back(Qt::Key_Control, CELL_KB_MKEY_L_CTRL);
buttons.emplace_back(Qt::Key_Shift, CELL_KB_MKEY_L_SHIFT);
buttons.emplace_back(Qt::Key_Alt, CELL_KB_MKEY_L_ALT);
buttons.emplace_back(Qt::Key_Super_L, CELL_KB_MKEY_L_WIN);
buttons.emplace_back(Qt::Key_Meta, CELL_KB_MKEY_L_WIN);
//buttons.emplace_back(, CELL_KB_MKEY_R_CTRL); // There is no way to know if it's left or right in Qt at the moment
//buttons.emplace_back(, CELL_KB_MKEY_R_SHIFT); // There is no way to know if it's left or right in Qt at the moment
//buttons.emplace_back(, CELL_KB_MKEY_R_ALT); // There is no way to know if it's left or right in Qt at the moment
buttons.emplace_back(Qt::Key_Super_R, CELL_KB_MKEY_R_WIN);
//buttons.emplace_back(, CELL_KB_MKEY_R_WIN); // There is no way to know if it's left or right in Qt at the moment
buttons.emplace_back(Qt::Key_Super_L, CELL_KB_MKEY_L_WIN); // The super keys are supposed to be the windows keys, but they trigger the meta key instead. Let's assign the windows keys to both.
buttons.emplace_back(Qt::Key_Super_R, CELL_KB_MKEY_R_WIN); // The super keys are supposed to be the windows keys, but they trigger the meta key instead. Let's assign the windows keys to both.
// CELL_KB_RAWDAT
//buttons.emplace_back(, CELL_KEYC_NO_EVENT); // Redundant, listed for completeness
@ -222,7 +225,7 @@ void basic_keyboard_handler::LoadSettings(Keyboard& keyboard)
buttons.emplace_back(Qt::Key_Down, CELL_KEYC_DOWN_ARROW);
buttons.emplace_back(Qt::Key_Up, CELL_KEYC_UP_ARROW);
//buttons.emplace_back(, CELL_KEYC_NUM_LOCK);
buttons.emplace_back(Qt::Key_Meta, CELL_KEYC_APPLICATION);
//buttons.emplace_back(, CELL_KEYC_APPLICATION); // This is probably the PS key on the PS3 keyboard
buttons.emplace_back(Qt::Key_Kana_Shift, CELL_KEYC_KANA); // maybe Key_Kana_Lock
buttons.emplace_back(Qt::Key_Henkan, CELL_KEYC_HENKAN);
buttons.emplace_back(Qt::Key_Muhenkan, CELL_KEYC_MUHENKAN);

View file

@ -1,6 +1,7 @@
#include "keyboard_pad_handler.h"
#include "pad_thread.h"
#include "Emu/Io/pad_config.h"
#include "Emu/Io/KeyboardHandler.h"
#include "Input/product_info.h"
#include "rpcs3qt/gs_frame.h"
@ -821,12 +822,16 @@ u32 keyboard_pad_handler::GetKeyCode(const QString& keyName)
int keyboard_pad_handler::native_scan_code_from_string([[maybe_unused]] const std::string& key)
{
// NOTE: Qt throws a Ctrl key at us when using Alt Gr, so there is no point in distinguishing left and right Alt at the moment
// NOTE: Qt throws a Ctrl key at us when using Alt Gr first, so right Alt does not work at the moment
if (key == "Shift Left") return native_key::shift_l;
if (key == "Shift Right") return native_key::shift_r;
if (key == "Ctrl Left") return native_key::ctrl_l;
if (key == "Ctrl Right") return native_key::ctrl_r;
if (key == "Alt Left") return native_key::alt_l;
if (key == "Alt Right") return native_key::alt_r;
if (key == "Meta Left") return native_key::meta_l;
if (key == "Meta Right") return native_key::meta_r;
#ifdef _WIN32
if (key == "Shift Left") return 42;
if (key == "Shift Right") return 54;
if (key == "Ctrl Left") return 29;
if (key == "Ctrl Right") return 285;
if (key == "Num+0" || key == "Num+Ins") return 82;
if (key == "Num+1" || key == "Num+End") return 79;
if (key == "Num+2" || key == "Num+Down") return 80;
@ -851,15 +856,20 @@ int keyboard_pad_handler::native_scan_code_from_string([[maybe_unused]] const st
std::string keyboard_pad_handler::native_scan_code_to_string(int native_scan_code)
{
// NOTE: the other Qt function "nativeVirtualKey" does not distinguish between VK_SHIFT and VK_RSHIFT key in Qt at the moment
// NOTE: Qt throws a Ctrl key at us when using Alt Gr first, so right Alt does not work at the moment
// NOTE: for MacOs: nativeScanCode may not work
switch (native_scan_code)
{
case native_key::shift_l: return "Shift Left";
case native_key::shift_r: return "Shift Right";
case native_key::ctrl_l: return "Ctrl Left";
case native_key::ctrl_r: return "Ctrl Right";
case native_key::alt_l: return "Alt Left";
case native_key::alt_r: return "Alt Right";
case native_key::meta_l: return "Meta Left";
case native_key::meta_r: return "Meta Right";
#ifdef _WIN32
// NOTE: the other Qt function "nativeVirtualKey" does not distinguish between VK_SHIFT and VK_RSHIFT key in Qt at the moment
// NOTE: Qt throws a Ctrl key at us when using Alt Gr, so there is no point in distinguishing left and right Alt at the moment
case 42: return "Shift Left";
case 54: return "Shift Right";
case 29: return "Ctrl Left";
case 285: return "Ctrl Right";
case 82: return "Num+0"; // Also "Num+Ins" depending on numlock
case 79: return "Num+1"; // Also "Num+End" depending on numlock
case 80: return "Num+2"; // Also "Num+Down" depending on numlock
@ -878,7 +888,6 @@ std::string keyboard_pad_handler::native_scan_code_to_string(int native_scan_cod
case 284: return "Num+Enter";
#else
// TODO
// NOTE for MacOs: nativeScanCode may not work
#endif
default: return "";
}