diff --git a/src/xenia/hid/winkey/premake5.lua b/src/xenia/hid/winkey/premake5.lua index 4097192a0..c2ecc8c5a 100644 --- a/src/xenia/hid/winkey/premake5.lua +++ b/src/xenia/hid/winkey/premake5.lua @@ -13,5 +13,6 @@ project("xenia-hid-winkey") defines({ }) includedirs({ + project_root.."/third_party/elemental-forms/src", }) local_platform_files() diff --git a/src/xenia/hid/winkey/winkey_input_driver.cc b/src/xenia/hid/winkey/winkey_input_driver.cc index a9b5e1a87..16d4b4bf6 100644 --- a/src/xenia/hid/winkey/winkey_input_driver.cc +++ b/src/xenia/hid/winkey/winkey_input_driver.cc @@ -10,14 +10,41 @@ #include "xenia/hid/winkey/winkey_input_driver.h" #include "xenia/base/platform_win.h" +#include "xenia/emulator.h" #include "xenia/hid/hid_flags.h" +#include "xenia/hid/input_system.h" +#include "xenia/ui/window.h" namespace xe { namespace hid { namespace winkey { WinKeyInputDriver::WinKeyInputDriver(InputSystem* input_system) - : InputDriver(input_system), packet_number_(1) {} + : InputDriver(input_system), packet_number_(1) { + // Register a key listener. + input_system_->emulator()->display_window()->on_key_down.AddListener( + [this](ui::KeyEvent* evt) { + std::lock_guard lock(key_event_mutex_); + + KeyEvent key; + key.vkey = evt->key_code(); + key.transition = true; + key.prev_state = evt->prev_state(); + key.repeat_count = evt->repeat_count(); + key_events_.push(key); + }); + input_system_->emulator()->display_window()->on_key_up.AddListener( + [this](ui::KeyEvent* evt) { + std::lock_guard lock(key_event_mutex_); + + KeyEvent key; + key.vkey = evt->key_code(); + key.transition = false; + key.prev_state = evt->prev_state(); + key.repeat_count = evt->repeat_count(); + key_events_.push(key); + }); +} WinKeyInputDriver::~WinKeyInputDriver() = default; @@ -64,86 +91,88 @@ X_RESULT WinKeyInputDriver::GetState(uint32_t user_index, int16_t thumb_rx = 0; int16_t thumb_ry = 0; - if (IS_KEY_TOGGLED(VK_CAPITAL)) { - // dpad toggled - if (IS_KEY_DOWN(0x41)) { - // A - buttons |= 0x0004; // XINPUT_GAMEPAD_DPAD_LEFT + if (input_system_->emulator()->display_window()->has_focus()) { + if (IS_KEY_TOGGLED(VK_CAPITAL)) { + // dpad toggled + if (IS_KEY_DOWN(0x41)) { + // A + buttons |= 0x0004; // XINPUT_GAMEPAD_DPAD_LEFT + } + if (IS_KEY_DOWN(0x44)) { + // D + buttons |= 0x0008; // XINPUT_GAMEPAD_DPAD_RIGHT + } + if (IS_KEY_DOWN(0x53)) { + // S + buttons |= 0x0002; // XINPUT_GAMEPAD_DPAD_DOWN + } + if (IS_KEY_DOWN(0x57)) { + // W + buttons |= 0x0001; // XINPUT_GAMEPAD_DPAD_UP + } + } else { + // left stick + if (IS_KEY_DOWN(0x41)) { + // A + thumb_lx += SHRT_MIN; + } + if (IS_KEY_DOWN(0x44)) { + // D + thumb_lx += SHRT_MAX; + } + if (IS_KEY_DOWN(0x53)) { + // S + thumb_ly += SHRT_MIN; + } + if (IS_KEY_DOWN(0x57)) { + // W + thumb_ly += SHRT_MAX; + } } - if (IS_KEY_DOWN(0x44)) { - // D - buttons |= 0x0008; // XINPUT_GAMEPAD_DPAD_RIGHT - } - if (IS_KEY_DOWN(0x53)) { - // S - buttons |= 0x0002; // XINPUT_GAMEPAD_DPAD_DOWN - } - if (IS_KEY_DOWN(0x57)) { - // W - buttons |= 0x0001; // XINPUT_GAMEPAD_DPAD_UP - } - } else { - // left stick - if (IS_KEY_DOWN(0x41)) { - // A - thumb_lx += SHRT_MIN; - } - if (IS_KEY_DOWN(0x44)) { - // D - thumb_lx += SHRT_MAX; - } - if (IS_KEY_DOWN(0x53)) { - // S - thumb_ly += SHRT_MIN; - } - if (IS_KEY_DOWN(0x57)) { - // W - thumb_ly += SHRT_MAX; - } - } - // Right stick - if (IS_KEY_DOWN(0x26)) { - // Up - thumb_ry += SHRT_MAX; - } - if (IS_KEY_DOWN(0x28)) { - // Down - thumb_ry += SHRT_MIN; - } - if (IS_KEY_DOWN(0x27)) { - // Right - thumb_rx += SHRT_MAX; - } - if (IS_KEY_DOWN(0x25)) { - // Left - thumb_rx += SHRT_MIN; - } + // Right stick + if (IS_KEY_DOWN(0x26)) { + // Up + thumb_ry += SHRT_MAX; + } + if (IS_KEY_DOWN(0x28)) { + // Down + thumb_ry += SHRT_MIN; + } + if (IS_KEY_DOWN(0x27)) { + // Right + thumb_rx += SHRT_MAX; + } + if (IS_KEY_DOWN(0x25)) { + // Left + thumb_rx += SHRT_MIN; + } - if (IS_KEY_DOWN(0x4C)) { - // L - buttons |= 0x4000; // XINPUT_GAMEPAD_X - } - if (IS_KEY_DOWN(VK_OEM_7)) { - // ' - buttons |= 0x2000; // XINPUT_GAMEPAD_B - } - if (IS_KEY_DOWN(VK_OEM_1)) { - // ; - buttons |= 0x1000; // XINPUT_GAMEPAD_A - } - if (IS_KEY_DOWN(0x50)) { - // P - buttons |= 0x8000; // XINPUT_GAMEPAD_Y - } + if (IS_KEY_DOWN(0x4C)) { + // L + buttons |= 0x4000; // XINPUT_GAMEPAD_X + } + if (IS_KEY_DOWN(VK_OEM_7)) { + // ' + buttons |= 0x2000; // XINPUT_GAMEPAD_B + } + if (IS_KEY_DOWN(VK_OEM_1)) { + // ; + buttons |= 0x1000; // XINPUT_GAMEPAD_A + } + if (IS_KEY_DOWN(0x50)) { + // P + buttons |= 0x8000; // XINPUT_GAMEPAD_Y + } - if (IS_KEY_DOWN(0x5A)) { - // Z - buttons |= 0x0020; // XINPUT_GAMEPAD_BACK - } - if (IS_KEY_DOWN(0x58)) { - // X - buttons |= 0x0010; // XINPUT_GAMEPAD_START + if (IS_KEY_DOWN(0x5A)) { + // Z + buttons |= 0x0020; // XINPUT_GAMEPAD_BACK + } + if (IS_KEY_DOWN(0x58)) { + // X + buttons |= 0x0010; // XINPUT_GAMEPAD_START + } } out_state->packet_number = packet_number_; @@ -180,84 +209,107 @@ X_RESULT WinKeyInputDriver::GetKeystroke(uint32_t user_index, uint32_t flags, uint16_t keystroke_flags = 0; uint8_t hid_code = 0; + // Pop from the queue. + key_event_mutex_.lock(); + if (key_events_.size() == 0) { + key_event_mutex_.unlock(); + + // No keys! + return X_ERROR_EMPTY; + } + + KeyEvent evt = key_events_.front(); + key_events_.pop(); + key_event_mutex_.unlock(); + + // TODO: Some other way to toggle this... if (IS_KEY_TOGGLED(VK_CAPITAL)) { // dpad toggled - if (IS_KEY_DOWN(0x41)) { + if (evt.vkey == (0x41)) { // A virtual_key = 0x5812; // VK_PAD_DPAD_LEFT - } else if (IS_KEY_DOWN(0x44)) { + } else if (evt.vkey == (0x44)) { // D virtual_key = 0x5813; // VK_PAD_DPAD_RIGHT - } else if (IS_KEY_DOWN(0x53)) { + } else if (evt.vkey == (0x53)) { // S virtual_key = 0x5811; // VK_PAD_DPAD_DOWN - } else if (IS_KEY_DOWN(0x57)) { + } else if (evt.vkey == (0x57)) { // W virtual_key = 0x5810; // VK_PAD_DPAD_UP } } else { // left stick - if (IS_KEY_DOWN(0x57)) { + if (evt.vkey == (0x57)) { // W virtual_key = 0x5820; // VK_PAD_LTHUMB_UP } - if (IS_KEY_DOWN(0x53)) { + if (evt.vkey == (0x53)) { // S virtual_key = 0x5821; // VK_PAD_LTHUMB_DOWN } - if (IS_KEY_DOWN(0x44)) { + if (evt.vkey == (0x44)) { // D virtual_key = 0x5822; // VK_PAD_LTHUMB_RIGHT } - if (IS_KEY_DOWN(0x41)) { + if (evt.vkey == (0x41)) { // A virtual_key = 0x5823; // VK_PAD_LTHUMB_LEFT } } // Right stick - if (IS_KEY_DOWN(0x26)) { + if (evt.vkey == (0x26)) { // Up virtual_key = 0x5830; } - if (IS_KEY_DOWN(0x28)) { + if (evt.vkey == (0x28)) { // Down virtual_key = 0x5831; } - if (IS_KEY_DOWN(0x27)) { + if (evt.vkey == (0x27)) { // Right virtual_key = 0x5832; } - if (IS_KEY_DOWN(0x25)) { + if (evt.vkey == (0x25)) { // Left virtual_key = 0x5833; } - if (IS_KEY_DOWN(0x4C)) { + if (evt.vkey == (0x4C)) { // L virtual_key = 0x5802; // VK_PAD_X - } else if (IS_KEY_DOWN(VK_OEM_7)) { + } else if (evt.vkey == (VK_OEM_7)) { // ' virtual_key = 0x5801; // VK_PAD_B - } else if (IS_KEY_DOWN(VK_OEM_1)) { + } else if (evt.vkey == (VK_OEM_1)) { // ; virtual_key = 0x5800; // VK_PAD_A - } else if (IS_KEY_DOWN(0x50)) { + } else if (evt.vkey == (0x50)) { // P virtual_key = 0x5803; // VK_PAD_Y } - if (IS_KEY_DOWN(0x58)) { + if (evt.vkey == (0x58)) { // X virtual_key = 0x5814; // VK_PAD_START } - if (IS_KEY_DOWN(0x5A)) { + if (evt.vkey == (0x5A)) { // Z virtual_key = 0x5815; // VK_PAD_BACK } if (virtual_key != 0) { - keystroke_flags |= 0x0001; // XINPUT_KEYSTROKE_DOWN + if (evt.transition == true) { + keystroke_flags |= 0x0001; // XINPUT_KEYSTROKE_KEYDOWN + } else if (evt.transition == false) { + keystroke_flags |= 0x0002; // XINPUT_KEYSTROKE_KEYUP + } + + if (evt.prev_state == evt.transition) { + keystroke_flags |= 0x0004; // XINPUT_KEYSTROKE_REPEAT + } + result = X_ERROR_SUCCESS; } diff --git a/src/xenia/hid/winkey/winkey_input_driver.h b/src/xenia/hid/winkey/winkey_input_driver.h index 550e99f70..ba8ec9518 100644 --- a/src/xenia/hid/winkey/winkey_input_driver.h +++ b/src/xenia/hid/winkey/winkey_input_driver.h @@ -10,6 +10,9 @@ #ifndef XENIA_HID_WINKEY_WINKEY_INPUT_DRIVER_H_ #define XENIA_HID_WINKEY_WINKEY_INPUT_DRIVER_H_ +#include +#include + #include "xenia/hid/input_driver.h" namespace xe { @@ -31,6 +34,15 @@ class WinKeyInputDriver : public InputDriver { X_INPUT_KEYSTROKE* out_keystroke) override; protected: + struct KeyEvent { + int vkey = 0; + int repeat_count = 0; + bool transition = false; // going up(false) or going down(true) + bool prev_state = false; // down(true) or up(false) + }; + std::queue key_events_; + std::mutex key_event_mutex_; + uint32_t packet_number_; }; diff --git a/src/xenia/ui/ui_event.h b/src/xenia/ui/ui_event.h index 3fdce231c..0717e0fbe 100644 --- a/src/xenia/ui/ui_event.h +++ b/src/xenia/ui/ui_event.h @@ -28,8 +28,11 @@ class UIEvent { class KeyEvent : public UIEvent { public: - KeyEvent(Window* target, int key_code) - : UIEvent(target), key_code_(key_code) {} + KeyEvent(Window* target, int key_code, int repeat_count, bool prev_state) + : UIEvent(target), + key_code_(key_code), + repeat_count_(repeat_count), + prev_state_(prev_state) {} ~KeyEvent() override = default; bool is_handled() const { return handled_; } @@ -37,9 +40,15 @@ class KeyEvent : public UIEvent { int key_code() const { return key_code_; } + int repeat_count() const { return repeat_count_; } + bool prev_state() const { return prev_state_; } + private: bool handled_ = false; int key_code_ = 0; + + int repeat_count_ = 0; + bool prev_state_ = false; // Key previously down(true) or up(false) }; class MouseEvent : public UIEvent { diff --git a/src/xenia/ui/window_win.cc b/src/xenia/ui/window_win.cc index 57558caf5..e2b432aff 100644 --- a/src/xenia/ui/window_win.cc +++ b/src/xenia/ui/window_win.cc @@ -503,7 +503,8 @@ bool Win32Window::HandleMouse(UINT message, WPARAM wParam, LPARAM lParam) { } bool Win32Window::HandleKeyboard(UINT message, WPARAM wParam, LPARAM lParam) { - auto e = KeyEvent(this, static_cast(wParam)); + auto e = KeyEvent(this, static_cast(wParam), lParam & 0xFFFF0000, + !!(lParam & 0x2)); switch (message) { case WM_KEYDOWN: OnKeyDown(&e);