[LINUX/HID] Added a generic keyboard input driver.
This commit is contained in:
parent
4cc074df63
commit
7e8e8164ed
|
@ -327,6 +327,10 @@ workspace("xenia")
|
|||
include("src/xenia/hid/sdl")
|
||||
end
|
||||
|
||||
if not os.istarget("windows") then
|
||||
include("src/xenia/hid/keyboard")
|
||||
end
|
||||
|
||||
if os.istarget("windows") then
|
||||
include("src/xenia/apu/xaudio2")
|
||||
include("src/xenia/gpu/d3d12")
|
||||
|
|
|
@ -97,6 +97,10 @@ project("xenia-app")
|
|||
"xenia-hid-sdl",
|
||||
})
|
||||
|
||||
filter("platforms:not Windows")
|
||||
links({
|
||||
"xenia-hid-keyboard"
|
||||
})
|
||||
filter("platforms:Linux")
|
||||
links({
|
||||
"X11",
|
||||
|
|
|
@ -56,6 +56,9 @@
|
|||
#if !XE_PLATFORM_ANDROID
|
||||
#include "xenia/hid/sdl/sdl_hid.h"
|
||||
#endif // !XE_PLATFORM_ANDROID
|
||||
#if !XE_PLATFORM_WIN32
|
||||
#include "xenia/hid/keyboard/keyboard_hid.h"
|
||||
#endif
|
||||
#if XE_PLATFORM_WIN32
|
||||
#include "xenia/hid/winkey/winkey_hid.h"
|
||||
#include "xenia/hid/xinput/xinput_hid.h"
|
||||
|
@ -388,6 +391,9 @@ std::vector<std::unique_ptr<hid::InputDriver>> EmulatorApp::CreateInputDrivers(
|
|||
#if !XE_PLATFORM_ANDROID
|
||||
factory.Add("sdl", xe::hid::sdl::Create);
|
||||
#endif // !XE_PLATFORM_ANDROID
|
||||
#if !XE_PLATFORM_WIN32
|
||||
factory.Add("keyboard", xe::hid::keyboard::Create);
|
||||
#endif
|
||||
#if XE_PLATFORM_WIN32
|
||||
// WinKey input driver should always be the last input driver added!
|
||||
factory.Add("winkey", xe::hid::winkey::Create);
|
||||
|
|
|
@ -40,6 +40,9 @@
|
|||
#if !XE_PLATFORM_ANDROID
|
||||
#include "xenia/hid/sdl/sdl_hid.h"
|
||||
#endif // !XE_PLATFORM_ANDROID
|
||||
#if !XE_PLATFORM_WIN32
|
||||
#include "xenia/hid/keyboard/keyboard_hid.h"
|
||||
#endif
|
||||
#if XE_PLATFORM_WIN32
|
||||
#include "xenia/hid/winkey/winkey_hid.h"
|
||||
#include "xenia/hid/xinput/xinput_hid.h"
|
||||
|
@ -132,6 +135,13 @@ std::vector<std::unique_ptr<hid::InputDriver>> HidDemoApp::CreateInputDrivers(
|
|||
drivers.emplace_back(std::move(driver));
|
||||
}
|
||||
#endif // !XE_PLATFORM_ANDROID
|
||||
#if !XE_PLATFORM_WIN32
|
||||
} else if (cvars::hid.compare("keyboard") == 0) {
|
||||
auto driver = xe::hid::keyboard::Create(window, kZOrderHidInput);
|
||||
if (driver && XSUCCEEDED(driver->Setup())) {
|
||||
drivers.emplace_back(std::move(driver));
|
||||
}
|
||||
#endif
|
||||
#if XE_PLATFORM_WIN32
|
||||
} else if (cvars::hid.compare("winkey") == 0) {
|
||||
auto driver = xe::hid::winkey::Create(window, kZOrderHidInput);
|
||||
|
@ -151,6 +161,12 @@ std::vector<std::unique_ptr<hid::InputDriver>> HidDemoApp::CreateInputDrivers(
|
|||
drivers.emplace_back(std::move(sdl_driver));
|
||||
}
|
||||
#endif // !XE_PLATFORM_ANDROID
|
||||
#if !XE_PLATFORM_WIN32
|
||||
auto keyboard_driver = xe::hid::keyboard::Create(window, kZOrderHidInput);
|
||||
if (keyboard_driver && XSUCCEEDED(keyboard_driver->Setup())) {
|
||||
drivers.emplace_back(std::move(keyboard_driver));
|
||||
}
|
||||
#endif
|
||||
#if XE_PLATFORM_WIN32
|
||||
auto xinput_driver = xe::hid::xinput::Create(window, kZOrderHidInput);
|
||||
if (xinput_driver && XSUCCEEDED(xinput_driver->Setup())) {
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2022 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
// This is a partial file designed to be included by other files when
|
||||
// constructing various tables.
|
||||
|
||||
// clang-format off
|
||||
XE_HID_KEYBOARD_BINDING(DpadLeft, "DPAD_LEFT" , keybind_dpad_left , "^A" )
|
||||
XE_HID_KEYBOARD_BINDING(DpadRight, "DPAD_RIGHT" , keybind_dpad_right , "^D" )
|
||||
XE_HID_KEYBOARD_BINDING(DpadDown, "DPAD_DOWN" , keybind_dpad_down , "^S" )
|
||||
XE_HID_KEYBOARD_BINDING(DpadUp, "DPAD_UP" , keybind_dpad_up , "^W" )
|
||||
XE_HID_KEYBOARD_BINDING(LThumbLeft, "LEFT_THUMB_LEFT" , keybind_left_thumb_left , "_A" )
|
||||
XE_HID_KEYBOARD_BINDING(LThumbRight, "LEFT_THUMB_RIGHT" , keybind_left_thumb_right , "_D" )
|
||||
XE_HID_KEYBOARD_BINDING(LThumbDown, "LEFT_THUMB_DOWN" , keybind_left_thumb_down , "_S" )
|
||||
XE_HID_KEYBOARD_BINDING(LThumbUp, "LEFT_THUMB_UP" , keybind_left_thumb_up , "_W" )
|
||||
XE_HID_KEYBOARD_BINDING(LThumbPress, "LEFT_THUMB_PRESSED" , keybind_left_thumb , "F" )
|
||||
XE_HID_KEYBOARD_BINDING(RThumbUp, "RIGHT_THUMB_UP" , keybind_right_thumb_up , "0x26")
|
||||
XE_HID_KEYBOARD_BINDING(RThumbDown, "RIGHT_THUMB_DOWN" , keybind_right_thumb_down , "0x28")
|
||||
XE_HID_KEYBOARD_BINDING(RThumbRight, "RIGHT_THUMB_RIGHT" , keybind_right_thumb_right, "0x27")
|
||||
XE_HID_KEYBOARD_BINDING(RThumbLeft, "RIGHT_THUMB_LEFT" , keybind_right_thumb_left , "0x25")
|
||||
XE_HID_KEYBOARD_BINDING(RThumbPress, "RIGHT_THUMB_PRESSED", keybind_right_thumb , "K" )
|
||||
XE_HID_KEYBOARD_BINDING(X, "X" , keybind_x , "L" )
|
||||
XE_HID_KEYBOARD_BINDING(B, "B" , keybind_b , "0xDE")
|
||||
XE_HID_KEYBOARD_BINDING(A, "A" , keybind_a , "0xBA")
|
||||
XE_HID_KEYBOARD_BINDING(Y, "Y" , keybind_y , "P" )
|
||||
XE_HID_KEYBOARD_BINDING(LTrigger, "LEFT_TRIGGER" , keybind_left_trigger , "Q I" )
|
||||
XE_HID_KEYBOARD_BINDING(RTrigger, "RIGHT_TRIGGER" , keybind_right_trigger , "E O" )
|
||||
XE_HID_KEYBOARD_BINDING(Back, "BACK" , keybind_back , "Z" )
|
||||
XE_HID_KEYBOARD_BINDING(Start, "START" , keybind_start , "X" )
|
||||
XE_HID_KEYBOARD_BINDING(LShoulder, "LEFT_SHOULDER" , keybind_left_shoulder , "1" )
|
||||
XE_HID_KEYBOARD_BINDING(RShoulder, "RIGHT_SHOULDER" , keybind_right_shoulder , "3" )
|
||||
// clang-format on
|
|
@ -0,0 +1,26 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2014 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "xenia/hid/keyboard/keyboard_hid.h"
|
||||
|
||||
#include "xenia/hid/keyboard/keyboard_input_driver.h"
|
||||
|
||||
namespace xe {
|
||||
namespace hid {
|
||||
namespace keyboard {
|
||||
|
||||
std::unique_ptr<InputDriver> Create(xe::ui::Window* window,
|
||||
size_t window_z_order) {
|
||||
return std::make_unique<xe::hid::keyboard::KeyboardInputDriver>(
|
||||
window, window_z_order);
|
||||
}
|
||||
|
||||
} // namespace keyboard
|
||||
} // namespace hid
|
||||
} // namespace xe
|
|
@ -0,0 +1,28 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2014 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_HID_KEYBOARD_KEYBOARD_HID_H_
|
||||
#define XENIA_HID_KEYBOARD_KEYBOARD_HID_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "xenia/hid/input_system.h"
|
||||
|
||||
namespace xe {
|
||||
namespace hid {
|
||||
namespace keyboard {
|
||||
|
||||
std::unique_ptr<InputDriver> Create(xe::ui::Window* window,
|
||||
size_t window_z_order);
|
||||
|
||||
} // namespace keyboard
|
||||
} // namespace hid
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_HID_WINKEY_WINKEY_HID_H_
|
|
@ -0,0 +1,340 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2022 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "xenia/hid/keyboard/keyboard_input_driver.h"
|
||||
|
||||
#include "xenia/base/logging.h"
|
||||
#include "xenia/hid/hid_flags.h"
|
||||
#include "xenia/hid/input_system.h"
|
||||
#include "xenia/ui/virtual_key.h"
|
||||
#include "xenia/ui/window.h"
|
||||
|
||||
#define XE_HID_KEYBOARD_BINDING(button, description, cvar_name, \
|
||||
cvar_default_value) \
|
||||
DEFINE_string(cvar_name, cvar_default_value, \
|
||||
"List of keys to bind to " description \
|
||||
", separated by spaces", \
|
||||
"HID.Key")
|
||||
#include "keyboard_binding_table.inc"
|
||||
#undef XE_HID_KEYBOARD_BINDING
|
||||
|
||||
namespace xe {
|
||||
namespace hid {
|
||||
namespace keyboard {
|
||||
|
||||
void KeyboardInputDriver::ParseKeyBinding(
|
||||
ui::VirtualKey output_key, const std::string_view description,
|
||||
const std::string_view source_tokens) {
|
||||
for (const std::string_view source_token :
|
||||
utf8::split(source_tokens, " ", true)) {
|
||||
KeyBinding key_binding;
|
||||
key_binding.output_key = output_key;
|
||||
|
||||
std::string_view token = source_token;
|
||||
|
||||
if (utf8::starts_with(token, "_")) {
|
||||
key_binding.uppercase = false;
|
||||
token = token.substr(1);
|
||||
} else if (utf8::starts_with(token, "^")) {
|
||||
key_binding.uppercase = true;
|
||||
token = token.substr(1);
|
||||
}
|
||||
|
||||
if (utf8::starts_with(token, "0x")) {
|
||||
token = token.substr(2);
|
||||
key_binding.input_key = static_cast<ui::VirtualKey>(
|
||||
string_util::from_string<uint16_t>(token, true));
|
||||
} else if (token.size() == 1 && (token[0] >= 'A' && token[0] <= 'Z') ||
|
||||
(token[0] >= '0' && token[0] <= '9')) {
|
||||
key_binding.input_key = static_cast<ui::VirtualKey>(token[0]);
|
||||
}
|
||||
|
||||
if (key_binding.input_key == ui::VirtualKey::kNone) {
|
||||
XELOGW(
|
||||
"keyboard HID: failed to parse binding \"{}\" for controller input "
|
||||
"{}.",
|
||||
source_token, description);
|
||||
continue;
|
||||
}
|
||||
|
||||
key_bindings_.push_back(key_binding);
|
||||
XELOGI("keyboard HID: \"{}\" binds key 0x{:X} to controller input {}.",
|
||||
source_token, static_cast<uint16_t>(key_binding.input_key),
|
||||
description);
|
||||
}
|
||||
}
|
||||
|
||||
KeyboardInputDriver::KeyboardInputDriver(xe::ui::Window* window,
|
||||
size_t window_z_order)
|
||||
: InputDriver(window, window_z_order), window_input_listener_(*this) {
|
||||
#define XE_HID_KEYBOARD_BINDING(button, description, cvar_name, \
|
||||
cvar_default_value) \
|
||||
ParseKeyBinding(xe::ui::VirtualKey::kXInputPad##button, description, \
|
||||
cvars::cvar_name);
|
||||
#include "keyboard_binding_table.inc"
|
||||
#undef XE_HID_KEYBOARD_BINDING
|
||||
|
||||
window->AddInputListener(&window_input_listener_, window_z_order);
|
||||
}
|
||||
|
||||
KeyboardInputDriver::~KeyboardInputDriver() {
|
||||
window()->RemoveInputListener(&window_input_listener_);
|
||||
}
|
||||
|
||||
X_STATUS KeyboardInputDriver::Setup() { return X_STATUS_SUCCESS; }
|
||||
|
||||
X_RESULT KeyboardInputDriver::GetCapabilities(uint32_t user_index,
|
||||
uint32_t flags,
|
||||
X_INPUT_CAPABILITIES* out_caps) {
|
||||
if (user_index != 0) {
|
||||
return X_ERROR_DEVICE_NOT_CONNECTED;
|
||||
}
|
||||
|
||||
// TODO(benvanik): confirm with a real XInput controller.
|
||||
out_caps->type = 0x01; // XINPUT_DEVTYPE_GAMEPAD
|
||||
out_caps->sub_type = 0x01; // XINPUT_DEVSUBTYPE_GAMEPAD
|
||||
out_caps->flags = 0;
|
||||
out_caps->gamepad.buttons = 0xFFFF;
|
||||
out_caps->gamepad.left_trigger = 0xFF;
|
||||
out_caps->gamepad.right_trigger = 0xFF;
|
||||
out_caps->gamepad.thumb_lx = (int16_t)0xFFFFu;
|
||||
out_caps->gamepad.thumb_ly = (int16_t)0xFFFFu;
|
||||
out_caps->gamepad.thumb_rx = (int16_t)0xFFFFu;
|
||||
out_caps->gamepad.thumb_ry = (int16_t)0xFFFFu;
|
||||
out_caps->vibration.left_motor_speed = 0;
|
||||
out_caps->vibration.right_motor_speed = 0;
|
||||
return X_ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
X_RESULT KeyboardInputDriver::GetState(uint32_t user_index,
|
||||
X_INPUT_STATE* out_state) {
|
||||
if (user_index != 0) {
|
||||
return X_ERROR_DEVICE_NOT_CONNECTED;
|
||||
}
|
||||
|
||||
packet_number_++;
|
||||
|
||||
uint16_t buttons = 0;
|
||||
uint8_t left_trigger = 0;
|
||||
uint8_t right_trigger = 0;
|
||||
int16_t thumb_lx = 0;
|
||||
int16_t thumb_ly = 0;
|
||||
int16_t thumb_rx = 0;
|
||||
int16_t thumb_ry = 0;
|
||||
|
||||
if (window()->HasFocus() && is_active()) {
|
||||
for (const KeyBinding& b : key_bindings_) {
|
||||
if (b.is_pressed) {
|
||||
switch (b.output_key) {
|
||||
case ui::VirtualKey::kXInputPadA:
|
||||
buttons |= X_INPUT_GAMEPAD_A;
|
||||
break;
|
||||
case ui::VirtualKey::kXInputPadY:
|
||||
buttons |= X_INPUT_GAMEPAD_Y;
|
||||
break;
|
||||
case ui::VirtualKey::kXInputPadB:
|
||||
buttons |= X_INPUT_GAMEPAD_B;
|
||||
break;
|
||||
case ui::VirtualKey::kXInputPadX:
|
||||
buttons |= X_INPUT_GAMEPAD_X;
|
||||
break;
|
||||
case ui::VirtualKey::kXInputPadGuide:
|
||||
buttons |= X_INPUT_GAMEPAD_GUIDE;
|
||||
break;
|
||||
case ui::VirtualKey::kXInputPadDpadLeft:
|
||||
buttons |= X_INPUT_GAMEPAD_DPAD_LEFT;
|
||||
break;
|
||||
case ui::VirtualKey::kXInputPadDpadRight:
|
||||
buttons |= X_INPUT_GAMEPAD_DPAD_RIGHT;
|
||||
break;
|
||||
case ui::VirtualKey::kXInputPadDpadDown:
|
||||
buttons |= X_INPUT_GAMEPAD_DPAD_DOWN;
|
||||
break;
|
||||
case ui::VirtualKey::kXInputPadDpadUp:
|
||||
buttons |= X_INPUT_GAMEPAD_DPAD_UP;
|
||||
break;
|
||||
case ui::VirtualKey::kXInputPadRThumbPress:
|
||||
buttons |= X_INPUT_GAMEPAD_RIGHT_THUMB;
|
||||
break;
|
||||
case ui::VirtualKey::kXInputPadLThumbPress:
|
||||
buttons |= X_INPUT_GAMEPAD_LEFT_THUMB;
|
||||
break;
|
||||
case ui::VirtualKey::kXInputPadBack:
|
||||
buttons |= X_INPUT_GAMEPAD_BACK;
|
||||
break;
|
||||
case ui::VirtualKey::kXInputPadStart:
|
||||
buttons |= X_INPUT_GAMEPAD_START;
|
||||
break;
|
||||
case ui::VirtualKey::kXInputPadLShoulder:
|
||||
buttons |= X_INPUT_GAMEPAD_LEFT_SHOULDER;
|
||||
break;
|
||||
case ui::VirtualKey::kXInputPadRShoulder:
|
||||
buttons |= X_INPUT_GAMEPAD_RIGHT_SHOULDER;
|
||||
break;
|
||||
case ui::VirtualKey::kXInputPadLTrigger:
|
||||
left_trigger = 0xFF;
|
||||
break;
|
||||
case ui::VirtualKey::kXInputPadRTrigger:
|
||||
right_trigger = 0xFF;
|
||||
break;
|
||||
case ui::VirtualKey::kXInputPadLThumbLeft:
|
||||
thumb_lx += SHRT_MIN;
|
||||
break;
|
||||
case ui::VirtualKey::kXInputPadLThumbRight:
|
||||
thumb_lx += SHRT_MAX;
|
||||
break;
|
||||
case ui::VirtualKey::kXInputPadLThumbDown:
|
||||
thumb_ly += SHRT_MIN;
|
||||
break;
|
||||
case ui::VirtualKey::kXInputPadLThumbUp:
|
||||
thumb_ly += SHRT_MAX;
|
||||
break;
|
||||
case ui::VirtualKey::kXInputPadRThumbUp:
|
||||
thumb_ry += SHRT_MAX;
|
||||
break;
|
||||
case ui::VirtualKey::kXInputPadRThumbDown:
|
||||
thumb_ry += SHRT_MIN;
|
||||
break;
|
||||
case ui::VirtualKey::kXInputPadRThumbRight:
|
||||
thumb_rx += SHRT_MAX;
|
||||
break;
|
||||
case ui::VirtualKey::kXInputPadRThumbLeft:
|
||||
thumb_rx += SHRT_MIN;
|
||||
break;
|
||||
default:
|
||||
assert_unhandled_case(b.output_key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out_state->packet_number = packet_number_;
|
||||
out_state->gamepad.buttons = buttons;
|
||||
out_state->gamepad.left_trigger = left_trigger;
|
||||
out_state->gamepad.right_trigger = right_trigger;
|
||||
out_state->gamepad.thumb_lx = thumb_lx;
|
||||
out_state->gamepad.thumb_ly = thumb_ly;
|
||||
out_state->gamepad.thumb_rx = thumb_rx;
|
||||
out_state->gamepad.thumb_ry = thumb_ry;
|
||||
|
||||
return X_ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
X_RESULT KeyboardInputDriver::SetState(uint32_t user_index,
|
||||
X_INPUT_VIBRATION* vibration) {
|
||||
if (user_index != 0) {
|
||||
return X_ERROR_DEVICE_NOT_CONNECTED;
|
||||
}
|
||||
|
||||
return X_ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
X_RESULT KeyboardInputDriver::GetKeystroke(uint32_t user_index, uint32_t flags,
|
||||
X_INPUT_KEYSTROKE* out_keystroke) {
|
||||
if (user_index != 0) {
|
||||
return X_ERROR_DEVICE_NOT_CONNECTED;
|
||||
}
|
||||
|
||||
if (!is_active()) {
|
||||
return X_ERROR_EMPTY;
|
||||
}
|
||||
|
||||
X_RESULT result = X_ERROR_EMPTY;
|
||||
|
||||
ui::VirtualKey xinput_virtual_key = ui::VirtualKey::kNone;
|
||||
uint16_t unicode = 0;
|
||||
uint16_t keystroke_flags = 0;
|
||||
uint8_t hid_code = 0;
|
||||
|
||||
// Pop from the queue.
|
||||
KeyEvent evt;
|
||||
{
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
if (key_events_.empty()) {
|
||||
// No keys!
|
||||
return X_ERROR_EMPTY;
|
||||
}
|
||||
evt = key_events_.front();
|
||||
key_events_.pop();
|
||||
}
|
||||
|
||||
for (const KeyBinding& b : key_bindings_) {
|
||||
if (b.input_key == evt.virtual_key && b.uppercase == evt.is_capital) {
|
||||
xinput_virtual_key = b.output_key;
|
||||
}
|
||||
}
|
||||
|
||||
if (xinput_virtual_key != ui::VirtualKey::kNone) {
|
||||
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;
|
||||
}
|
||||
|
||||
out_keystroke->virtual_key = uint16_t(xinput_virtual_key);
|
||||
out_keystroke->unicode = unicode;
|
||||
out_keystroke->flags = keystroke_flags;
|
||||
out_keystroke->user_index = 0;
|
||||
out_keystroke->hid_code = hid_code;
|
||||
|
||||
// X_ERROR_EMPTY if no new keys
|
||||
// X_ERROR_DEVICE_NOT_CONNECTED if no device
|
||||
// X_ERROR_SUCCESS if key
|
||||
return result;
|
||||
}
|
||||
|
||||
void KeyboardInputDriver::KeyboardWindowInputListener::OnKeyDown(
|
||||
ui::KeyEvent& e) {
|
||||
driver_.OnKey(e, true);
|
||||
}
|
||||
|
||||
void KeyboardInputDriver::KeyboardWindowInputListener::OnKeyUp(
|
||||
ui::KeyEvent& e) {
|
||||
driver_.OnKey(e, false);
|
||||
}
|
||||
|
||||
void KeyboardInputDriver::OnKey(ui::KeyEvent& e, bool is_down) {
|
||||
if (!is_active()) {
|
||||
return;
|
||||
}
|
||||
|
||||
KeyEvent key;
|
||||
key.virtual_key = e.virtual_key();
|
||||
key.transition = is_down;
|
||||
key.prev_state = e.prev_state();
|
||||
key.repeat_count = e.repeat_count();
|
||||
key.is_capital = e.is_shift_pressed();
|
||||
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
key_events_.push(key);
|
||||
bool found = false;
|
||||
for (auto& key_binding : key_bindings_) {
|
||||
if (key_binding.input_key == key.virtual_key) {
|
||||
found = true;
|
||||
if (key_binding.uppercase == e.is_shift_pressed()) {
|
||||
key_binding.is_pressed = is_down;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
InputType KeyboardInputDriver::GetInputType() const {
|
||||
return InputType::Controller;
|
||||
}
|
||||
|
||||
} // namespace keyboard
|
||||
} // namespace hid
|
||||
} // namespace xe
|
|
@ -0,0 +1,86 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2022 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_HID_KEYBOARD_KEYBOARD_INPUT_DRIVER_H_
|
||||
#define XENIA_HID_KEYBOARD_KEYBOARD_INPUT_DRIVER_H_
|
||||
|
||||
#include <queue>
|
||||
|
||||
#include "xenia/base/mutex.h"
|
||||
#include "xenia/hid/input_driver.h"
|
||||
#include "xenia/ui/virtual_key.h"
|
||||
|
||||
namespace xe {
|
||||
namespace hid {
|
||||
namespace keyboard {
|
||||
|
||||
class KeyboardInputDriver final : public InputDriver {
|
||||
public:
|
||||
explicit KeyboardInputDriver(xe::ui::Window* window, size_t window_z_order);
|
||||
~KeyboardInputDriver() override;
|
||||
|
||||
X_STATUS Setup() override;
|
||||
|
||||
X_RESULT GetCapabilities(uint32_t user_index, uint32_t flags,
|
||||
X_INPUT_CAPABILITIES* out_caps) override;
|
||||
X_RESULT GetState(uint32_t user_index, X_INPUT_STATE* out_state) override;
|
||||
X_RESULT SetState(uint32_t user_index, X_INPUT_VIBRATION* vibration) override;
|
||||
X_RESULT GetKeystroke(uint32_t user_index, uint32_t flags,
|
||||
X_INPUT_KEYSTROKE* out_keystroke) override;
|
||||
virtual InputType GetInputType() const override;
|
||||
|
||||
protected:
|
||||
class KeyboardWindowInputListener final : public ui::WindowInputListener {
|
||||
public:
|
||||
explicit KeyboardWindowInputListener(KeyboardInputDriver& driver)
|
||||
: driver_(driver) {}
|
||||
|
||||
void OnKeyDown(ui::KeyEvent& e) override;
|
||||
void OnKeyUp(ui::KeyEvent& e) override;
|
||||
|
||||
private:
|
||||
KeyboardInputDriver& driver_;
|
||||
};
|
||||
|
||||
struct KeyEvent {
|
||||
ui::VirtualKey virtual_key = ui::VirtualKey::kNone;
|
||||
int repeat_count = 0;
|
||||
bool transition = false; // going up(false) or going down(true)
|
||||
bool prev_state = false; // down(true) or up(false)
|
||||
bool is_capital = false;
|
||||
};
|
||||
|
||||
struct KeyBinding {
|
||||
ui::VirtualKey input_key = ui::VirtualKey::kNone;
|
||||
ui::VirtualKey output_key = ui::VirtualKey::kNone;
|
||||
bool uppercase = false;
|
||||
bool is_pressed = false;
|
||||
};
|
||||
|
||||
void ParseKeyBinding(ui::VirtualKey virtual_key,
|
||||
const std::string_view description,
|
||||
const std::string_view binding);
|
||||
|
||||
void OnKey(ui::KeyEvent& e, bool is_down);
|
||||
|
||||
xe::global_critical_region global_critical_region_;
|
||||
|
||||
std::queue<KeyEvent> key_events_;
|
||||
std::vector<KeyBinding> key_bindings_;
|
||||
|
||||
KeyboardWindowInputListener window_input_listener_;
|
||||
|
||||
uint32_t packet_number_ = 1;
|
||||
};
|
||||
|
||||
} // namespace keyboard
|
||||
} // namespace hid
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_HID_WINKEY_WINKEY_INPUT_DRIVER_H_
|
|
@ -0,0 +1,16 @@
|
|||
project_root = "../../../.."
|
||||
include(project_root.."/tools/build")
|
||||
|
||||
group("src")
|
||||
project("xenia-hid-keyboard")
|
||||
uuid("ab5cfd8d-7877-44cd-9526-63f7c5738609")
|
||||
kind("StaticLib")
|
||||
language("C++")
|
||||
links({
|
||||
"xenia-base",
|
||||
"xenia-hid",
|
||||
"xenia-ui",
|
||||
})
|
||||
defines({
|
||||
})
|
||||
local_platform_files()
|
Loading…
Reference in New Issue