mirror of
https://github.com/RPCS3/rpcs3.git
synced 2026-07-10 01:44:41 -06:00
Linux: get unshifted Qt keys
This commit is contained in:
parent
f5e8a2bfa9
commit
bec42ea93e
@ -81,7 +81,7 @@ if (NOT ANDROID)
|
|||||||
|
|
||||||
# Unix display manager
|
# Unix display manager
|
||||||
if(X11_FOUND)
|
if(X11_FOUND)
|
||||||
target_link_libraries(rpcs3_lib PRIVATE X11::X11)
|
target_link_libraries(rpcs3_lib PRIVATE X11::X11 xkbcommon-x11)
|
||||||
elseif(USE_VULKAN AND UNIX AND NOT WAYLAND_FOUND AND NOT APPLE AND NOT ANDROID)
|
elseif(USE_VULKAN AND UNIX AND NOT WAYLAND_FOUND AND NOT APPLE AND NOT ANDROID)
|
||||||
# Wayland has been checked in 3rdparty/CMakeLists.txt already.
|
# Wayland has been checked in 3rdparty/CMakeLists.txt already.
|
||||||
message(FATAL_ERROR "RPCS3 requires either X11 or Wayland (or both) for Vulkan.")
|
message(FATAL_ERROR "RPCS3 requires either X11 or Wayland (or both) for Vulkan.")
|
||||||
|
|||||||
@ -381,7 +381,7 @@ error_code cellKbRead(u32 port_no, vm::ptr<CellKbData> data)
|
|||||||
data->keycode[i] = current_data.buttons[i].m_keyCode;
|
data->keycode[i] = current_data.buttons[i].m_keyCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
KbConfig& current_config = consumer.GetConfig(port_no);
|
const KbConfig& current_config = consumer.GetConfig(port_no);
|
||||||
|
|
||||||
// For single character mode to work properly we need to "flush" the buffer after reading or else we'll constantly get the same key presses with each call.
|
// For single character mode to work properly we need to "flush" the buffer after reading or else we'll constantly get the same key presses with each call.
|
||||||
// Actual key repeats are handled by adding a new key code to the buffer periodically. Key releases are handled in a similar fashion.
|
// Actual key repeats are handled by adding a new key code to the buffer periodically. Key releases are handled in a similar fashion.
|
||||||
|
|||||||
@ -128,9 +128,9 @@ public:
|
|||||||
|
|
||||||
KbInfo& GetInfo() { return m_info; }
|
KbInfo& GetInfo() { return m_info; }
|
||||||
std::vector<Keyboard>& GetKeyboards() { return m_keyboards; }
|
std::vector<Keyboard>& GetKeyboards() { return m_keyboards; }
|
||||||
KbData& GetData(const u32 keyboard) { return m_keyboards[keyboard].m_data; }
|
KbData& GetData(const u32 keyboard) { return ::at32(m_keyboards, keyboard).m_data; }
|
||||||
KbExtraData& GetExtraData(const u32 keyboard) { return m_keyboards[keyboard].m_extra_data; }
|
KbExtraData& GetExtraData(const u32 keyboard) { return ::at32(m_keyboards, keyboard).m_extra_data; }
|
||||||
KbConfig& GetConfig(const u32 keyboard) { return m_keyboards[keyboard].m_config; }
|
KbConfig& GetConfig(const u32 keyboard) { return ::at32(m_keyboards, keyboard).m_config; }
|
||||||
identifier id() const { return m_id; }
|
identifier id() const { return m_id; }
|
||||||
|
|
||||||
void ReleaseAllKeys();
|
void ReleaseAllKeys();
|
||||||
|
|||||||
@ -7,6 +7,11 @@
|
|||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include "windows.h"
|
#include "windows.h"
|
||||||
|
#elif __linux__
|
||||||
|
#include <xkbcommon/xkbcommon.h>
|
||||||
|
#include <xkbcommon/xkbcommon-x11.h>
|
||||||
|
#include <private/qxkbcommon_p.h>
|
||||||
|
#include <QGuiApplication>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
LOG_CHANNEL(input_log, "Input");
|
LOG_CHANNEL(input_log, "Input");
|
||||||
@ -44,7 +49,7 @@ void basic_keyboard_handler::Init(keyboard_consumer& consumer, const u32 max_con
|
|||||||
/* Sets the target window for the event handler, and also installs an event filter on the target. */
|
/* Sets the target window for the event handler, and also installs an event filter on the target. */
|
||||||
void basic_keyboard_handler::SetTargetWindow(QWindow* target)
|
void basic_keyboard_handler::SetTargetWindow(QWindow* target)
|
||||||
{
|
{
|
||||||
if (target != nullptr)
|
if (target)
|
||||||
{
|
{
|
||||||
m_target = target;
|
m_target = target;
|
||||||
target->installEventFilter(this);
|
target->installEventFilter(this);
|
||||||
@ -119,7 +124,7 @@ void basic_keyboard_handler::keyPressEvent(QKeyEvent* keyEvent)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const int key = getUnmodifiedKey(keyEvent);
|
const int key = get_unmodified_key(keyEvent);
|
||||||
|
|
||||||
if (key < 0 || !HandleKey(static_cast<u32>(key), keyEvent->nativeScanCode(), true, keyEvent->isAutoRepeat(), keyEvent->text().toStdU32String()))
|
if (key < 0 || !HandleKey(static_cast<u32>(key), keyEvent->nativeScanCode(), true, keyEvent->isAutoRepeat(), keyEvent->text().toStdU32String()))
|
||||||
{
|
{
|
||||||
@ -140,7 +145,7 @@ void basic_keyboard_handler::keyReleaseEvent(QKeyEvent* keyEvent)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const int key = getUnmodifiedKey(keyEvent);
|
const int key = get_unmodified_key(keyEvent);
|
||||||
|
|
||||||
if (key < 0 || !HandleKey(static_cast<u32>(key), keyEvent->nativeScanCode(), false, keyEvent->isAutoRepeat(), keyEvent->text().toStdU32String()))
|
if (key < 0 || !HandleKey(static_cast<u32>(key), keyEvent->nativeScanCode(), false, keyEvent->isAutoRepeat(), keyEvent->text().toStdU32String()))
|
||||||
{
|
{
|
||||||
@ -149,8 +154,10 @@ void basic_keyboard_handler::keyReleaseEvent(QKeyEvent* keyEvent)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This should get the actual unmodified key without getting too crazy.
|
// This should get the actual unmodified key without getting too crazy.
|
||||||
// key() only shows the modifiers and the modified key (e.g. no easy way of knowing that - was pressed in 'SHIFT+-' in order to get _)
|
// key() only shows the modifiers and the modified key.
|
||||||
s32 basic_keyboard_handler::getUnmodifiedKey(QKeyEvent* keyEvent)
|
// e.g. 'Shift+1' may result in Qt::Key_Exclam, so we lose the information that Qt::Key_1 was pressed.
|
||||||
|
// We want to find the actual physical key that was pressed (and return Qt::Key_1 in this example).
|
||||||
|
s32 basic_keyboard_handler::get_unmodified_key(QKeyEvent* keyEvent)
|
||||||
{
|
{
|
||||||
if (!keyEvent) [[unlikely]]
|
if (!keyEvent) [[unlikely]]
|
||||||
{
|
{
|
||||||
@ -166,9 +173,9 @@ s32 basic_keyboard_handler::getUnmodifiedKey(QKeyEvent* keyEvent)
|
|||||||
|
|
||||||
u32 raw_key = static_cast<u32>(key);
|
u32 raw_key = static_cast<u32>(key);
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
if (keyEvent->modifiers() != Qt::NoModifier && !keyEvent->text().isEmpty())
|
if (keyEvent->modifiers() != Qt::NoModifier && !keyEvent->text().isEmpty())
|
||||||
{
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
u32 mapped_key = static_cast<u32>(MapVirtualKeyA(static_cast<UINT>(keyEvent->nativeVirtualKey()), MAPVK_VK_TO_CHAR));
|
u32 mapped_key = static_cast<u32>(MapVirtualKeyA(static_cast<UINT>(keyEvent->nativeVirtualKey()), MAPVK_VK_TO_CHAR));
|
||||||
|
|
||||||
if (raw_key != mapped_key)
|
if (raw_key != mapped_key)
|
||||||
@ -179,8 +186,72 @@ s32 basic_keyboard_handler::getUnmodifiedKey(QKeyEvent* keyEvent)
|
|||||||
}
|
}
|
||||||
raw_key = mapped_key;
|
raw_key = mapped_key;
|
||||||
}
|
}
|
||||||
}
|
#elif __linux__
|
||||||
|
class kb_mapper
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
kb_mapper()
|
||||||
|
{
|
||||||
|
m_ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
|
||||||
|
}
|
||||||
|
|
||||||
|
~kb_mapper()
|
||||||
|
{
|
||||||
|
if (m_ctx) xkb_context_unref(m_ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 get_unmodified_key(u32 qt_native_scan_code)
|
||||||
|
{
|
||||||
|
if (!m_ctx) return -1;
|
||||||
|
|
||||||
|
auto* connection = get_connection();
|
||||||
|
if (!connection) return -1;
|
||||||
|
|
||||||
|
const int device_id = xkb_x11_get_core_keyboard_device_id(connection);
|
||||||
|
|
||||||
|
xkb_keymap* keymap = xkb_x11_keymap_new_from_device(m_ctx, connection, device_id, XKB_KEYMAP_COMPILE_NO_FLAGS);
|
||||||
|
if (!keymap) return -1;
|
||||||
|
|
||||||
|
xkb_state* state = xkb_x11_state_new_from_device(keymap, connection, device_id);
|
||||||
|
if (!state)
|
||||||
|
{
|
||||||
|
xkb_keymap_unref(keymap);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const xkb_keycode_t code = static_cast<xkb_keycode_t>(qt_native_scan_code);
|
||||||
|
const xkb_layout_index_t layout = xkb_state_serialize_layout(state, XKB_STATE_LAYOUT_EFFECTIVE);
|
||||||
|
const xkb_keysym_t* syms = nullptr;
|
||||||
|
const int count = xkb_keymap_key_get_syms_by_level(keymap, code, layout, 0, &syms);
|
||||||
|
|
||||||
|
const auto new_key = (syms && count > 0) ? QXkbCommon::keysymToQtKey(syms[0], Qt::NoModifier, nullptr, code) : -1;
|
||||||
|
|
||||||
|
xkb_state_unref(state);
|
||||||
|
xkb_keymap_unref(keymap);
|
||||||
|
|
||||||
|
return new_key;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
xcb_connection_t* get_connection()
|
||||||
|
{
|
||||||
|
if (!qGuiApp) return nullptr;
|
||||||
|
auto* native_interface = qGuiApp->nativeInterface<QNativeInterface::QX11Application>();
|
||||||
|
return native_interface ? native_interface->connection() : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
xkb_context* m_ctx = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
static kb_mapper mapper = kb_mapper();
|
||||||
|
if (const int res = mapper.get_unmodified_key(keyEvent->nativeScanCode()); res > 0)
|
||||||
|
{
|
||||||
|
raw_key = res;
|
||||||
|
}
|
||||||
|
#elif __APPLE__
|
||||||
|
// TODO
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
return static_cast<s32>(raw_key);
|
return static_cast<s32>(raw_key);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,7 +17,7 @@ public:
|
|||||||
bool eventFilter(QObject* watched, QEvent* event) override;
|
bool eventFilter(QObject* watched, QEvent* event) override;
|
||||||
void keyPressEvent(QKeyEvent* event);
|
void keyPressEvent(QKeyEvent* event);
|
||||||
void keyReleaseEvent(QKeyEvent* event);
|
void keyReleaseEvent(QKeyEvent* event);
|
||||||
static s32 getUnmodifiedKey(QKeyEvent* event);
|
static s32 get_unmodified_key(QKeyEvent* event);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void LoadSettings(Keyboard& keyboard);
|
void LoadSettings(Keyboard& keyboard);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user