mirror of
https://github.com/xenia-project/xenia.git
synced 2025-12-06 07:12:03 +01:00
Created a generic keyboard hid driver
This commit is contained in:
parent
f6b5424a9f
commit
1ba81e9151
|
|
@ -302,6 +302,10 @@ workspace("xenia")
|
||||||
include("src/xenia/hid/sdl")
|
include("src/xenia/hid/sdl")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if not os.istarget("windows") then
|
||||||
|
include("src/xenia/hid/keyboard")
|
||||||
|
end
|
||||||
|
|
||||||
if os.istarget("windows") then
|
if os.istarget("windows") then
|
||||||
include("src/xenia/apu/xaudio2")
|
include("src/xenia/apu/xaudio2")
|
||||||
include("src/xenia/gpu/d3d12")
|
include("src/xenia/gpu/d3d12")
|
||||||
|
|
|
||||||
|
|
@ -96,6 +96,11 @@ project("xenia-app")
|
||||||
"xenia-hid-sdl",
|
"xenia-hid-sdl",
|
||||||
})
|
})
|
||||||
|
|
||||||
|
filter("platforms:not Windows")
|
||||||
|
links({
|
||||||
|
"xenia-hid-keyboard"
|
||||||
|
})
|
||||||
|
|
||||||
filter("platforms:Linux")
|
filter("platforms:Linux")
|
||||||
links({
|
links({
|
||||||
"X11",
|
"X11",
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,9 @@
|
||||||
#if !XE_PLATFORM_ANDROID
|
#if !XE_PLATFORM_ANDROID
|
||||||
#include "xenia/hid/sdl/sdl_hid.h"
|
#include "xenia/hid/sdl/sdl_hid.h"
|
||||||
#endif // !XE_PLATFORM_ANDROID
|
#endif // !XE_PLATFORM_ANDROID
|
||||||
|
#if !XE_PLATFORM_WIN32
|
||||||
|
#include "xenia/hid/keyboard/keyboard_hid.h"
|
||||||
|
#endif
|
||||||
#if XE_PLATFORM_WIN32
|
#if XE_PLATFORM_WIN32
|
||||||
#include "xenia/hid/winkey/winkey_hid.h"
|
#include "xenia/hid/winkey/winkey_hid.h"
|
||||||
#include "xenia/hid/xinput/xinput_hid.h"
|
#include "xenia/hid/xinput/xinput_hid.h"
|
||||||
|
|
@ -359,6 +362,9 @@ std::vector<std::unique_ptr<hid::InputDriver>> EmulatorApp::CreateInputDrivers(
|
||||||
#if !XE_PLATFORM_ANDROID
|
#if !XE_PLATFORM_ANDROID
|
||||||
factory.Add("sdl", xe::hid::sdl::Create);
|
factory.Add("sdl", xe::hid::sdl::Create);
|
||||||
#endif // !XE_PLATFORM_ANDROID
|
#endif // !XE_PLATFORM_ANDROID
|
||||||
|
#if !XE_PLATFORM_WIN32
|
||||||
|
factory.Add("keyboard", xe::hid::keyboard::Create);
|
||||||
|
#endif
|
||||||
#if XE_PLATFORM_WIN32
|
#if XE_PLATFORM_WIN32
|
||||||
// WinKey input driver should always be the last input driver added!
|
// WinKey input driver should always be the last input driver added!
|
||||||
factory.Add("winkey", xe::hid::winkey::Create);
|
factory.Add("winkey", xe::hid::winkey::Create);
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,9 @@
|
||||||
#if !XE_PLATFORM_ANDROID
|
#if !XE_PLATFORM_ANDROID
|
||||||
#include "xenia/hid/sdl/sdl_hid.h"
|
#include "xenia/hid/sdl/sdl_hid.h"
|
||||||
#endif // !XE_PLATFORM_ANDROID
|
#endif // !XE_PLATFORM_ANDROID
|
||||||
|
#if !XE_PLATFORM_WIN32
|
||||||
|
#include "xenia/hid/keyboard/keyboard_hid.h"
|
||||||
|
#endif
|
||||||
#if XE_PLATFORM_WIN32
|
#if XE_PLATFORM_WIN32
|
||||||
#include "xenia/hid/winkey/winkey_hid.h"
|
#include "xenia/hid/winkey/winkey_hid.h"
|
||||||
#include "xenia/hid/xinput/xinput_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));
|
drivers.emplace_back(std::move(driver));
|
||||||
}
|
}
|
||||||
#endif // !XE_PLATFORM_ANDROID
|
#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
|
#if XE_PLATFORM_WIN32
|
||||||
} else if (cvars::hid.compare("winkey") == 0) {
|
} else if (cvars::hid.compare("winkey") == 0) {
|
||||||
auto driver = xe::hid::winkey::Create(window, kZOrderHidInput);
|
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));
|
drivers.emplace_back(std::move(sdl_driver));
|
||||||
}
|
}
|
||||||
#endif // !XE_PLATFORM_ANDROID
|
#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
|
#if XE_PLATFORM_WIN32
|
||||||
auto xinput_driver = xe::hid::xinput::Create(window, kZOrderHidInput);
|
auto xinput_driver = xe::hid::xinput::Create(window, kZOrderHidInput);
|
||||||
if (xinput_driver && XSUCCEEDED(xinput_driver->Setup())) {
|
if (xinput_driver && XSUCCEEDED(xinput_driver->Setup())) {
|
||||||
|
|
|
||||||
38
src/xenia/hid/keyboard/keyboard_binding_table.inc
Normal file
38
src/xenia/hid/keyboard/keyboard_binding_table.inc
Normal file
|
|
@ -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
|
||||||
25
src/xenia/hid/keyboard/keyboard_hid.cc
Normal file
25
src/xenia/hid/keyboard/keyboard_hid.cc
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* 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 winkey
|
||||||
|
} // namespace hid
|
||||||
|
} // namespace xe
|
||||||
28
src/xenia/hid/keyboard/keyboard_hid.h
Normal file
28
src/xenia/hid/keyboard/keyboard_hid.h
Normal file
|
|
@ -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 winkey
|
||||||
|
} // namespace hid
|
||||||
|
} // namespace xe
|
||||||
|
|
||||||
|
#endif // XENIA_HID_WINKEY_WINKEY_HID_H_
|
||||||
325
src/xenia/hid/keyboard/keyboard_input_driver.cc
Normal file
325
src/xenia/hid/keyboard/keyboard_input_driver.cc
Normal file
|
|
@ -0,0 +1,325 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* 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.WinKey")
|
||||||
|
#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("winkey: failed to parse binding \"{}\" for controller input {}.",
|
||||||
|
source_token, description);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
key_bindings_.push_back(key_binding);
|
||||||
|
XELOGI("winkey: \"{}\" binds key 0x{:X} to controller input {}.",
|
||||||
|
source_token, 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 |= 0x1000; // XINPUT_GAMEPAD_A
|
||||||
|
break;
|
||||||
|
case ui::VirtualKey::kXInputPadY:
|
||||||
|
buttons |= 0x8000; // XINPUT_GAMEPAD_Y
|
||||||
|
break;
|
||||||
|
case ui::VirtualKey::kXInputPadB:
|
||||||
|
buttons |= 0x2000; // XINPUT_GAMEPAD_B
|
||||||
|
break;
|
||||||
|
case ui::VirtualKey::kXInputPadX:
|
||||||
|
buttons |= 0x4000; // XINPUT_GAMEPAD_X
|
||||||
|
break;
|
||||||
|
case ui::VirtualKey::kXInputPadDpadLeft:
|
||||||
|
buttons |= 0x0004; // XINPUT_GAMEPAD_DPAD_LEFT
|
||||||
|
break;
|
||||||
|
case ui::VirtualKey::kXInputPadDpadRight:
|
||||||
|
buttons |= 0x0008; // XINPUT_GAMEPAD_DPAD_RIGHT
|
||||||
|
break;
|
||||||
|
case ui::VirtualKey::kXInputPadDpadDown:
|
||||||
|
buttons |= 0x0002; // XINPUT_GAMEPAD_DPAD_DOWN
|
||||||
|
break;
|
||||||
|
case ui::VirtualKey::kXInputPadDpadUp:
|
||||||
|
buttons |= 0x0001; // XINPUT_GAMEPAD_DPAD_UP
|
||||||
|
break;
|
||||||
|
case ui::VirtualKey::kXInputPadRThumbPress:
|
||||||
|
buttons |= 0x0080; // XINPUT_GAMEPAD_RIGHT_THUMB
|
||||||
|
break;
|
||||||
|
case ui::VirtualKey::kXInputPadLThumbPress:
|
||||||
|
buttons |= 0x0040; // XINPUT_GAMEPAD_LEFT_THUMB
|
||||||
|
break;
|
||||||
|
case ui::VirtualKey::kXInputPadBack:
|
||||||
|
buttons |= 0x0020; // XINPUT_GAMEPAD_BACK
|
||||||
|
break;
|
||||||
|
case ui::VirtualKey::kXInputPadStart:
|
||||||
|
buttons |= 0x0010; // XINPUT_GAMEPAD_START
|
||||||
|
break;
|
||||||
|
case ui::VirtualKey::kXInputPadLShoulder:
|
||||||
|
buttons |= 0x0100; // XINPUT_GAMEPAD_LEFT_SHOULDER
|
||||||
|
break;
|
||||||
|
case ui::VirtualKey::kXInputPadRShoulder:
|
||||||
|
buttons |= 0x0200; // XINPUT_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);
|
||||||
|
for (auto& key_binding : key_bindings_) {
|
||||||
|
if (key_binding.input_key == key.virtual_key) {
|
||||||
|
if (key_binding.uppercase == e.is_shift_pressed()) {
|
||||||
|
key_binding.is_pressed = is_down;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace winkey
|
||||||
|
} // namespace hid
|
||||||
|
} // namespace xe
|
||||||
87
src/xenia/hid/keyboard/keyboard_input_driver.h
Normal file
87
src/xenia/hid/keyboard/keyboard_input_driver.h
Normal file
|
|
@ -0,0 +1,87 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
|
||||||
|
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 winkey
|
||||||
|
} // namespace hid
|
||||||
|
} // namespace xe
|
||||||
|
|
||||||
|
#endif // XENIA_HID_WINKEY_WINKEY_INPUT_DRIVER_H_
|
||||||
16
src/xenia/hid/keyboard/premake5.lua
Normal file
16
src/xenia/hid/keyboard/premake5.lua
Normal file
|
|
@ -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()
|
||||||
|
|
@ -45,6 +45,11 @@ project("xenia-hid-demo")
|
||||||
"xenia-hid-sdl",
|
"xenia-hid-sdl",
|
||||||
})
|
})
|
||||||
|
|
||||||
|
filter("platforms:not Windows")
|
||||||
|
links({
|
||||||
|
"xenia-hid-keyboard"
|
||||||
|
})
|
||||||
|
|
||||||
filter("platforms:Linux")
|
filter("platforms:Linux")
|
||||||
links({
|
links({
|
||||||
"SDL2",
|
"SDL2",
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue