Implemented Controller Hotkeys (#111)

Implemented Controller Hotkeys

Added controller hotkeys
Added guide button support for XInput and winkey

The hotkey configurations can be found in HID -> Display controller hotkeys
If the Xbox Gamebar overlay is enabled then use the Back button instead of the Guide button.

- Fixed hotkey thread destruction
- Fixed XINPUT_STATE by padding 4 bytes
- Added hotkey vibration for user feedback
- Replaced MessageBoxA with ImGuiDialog::ShowMessageBox

Co-authored-by: Margen67 <Margen67@users.noreply.github.com>
This commit is contained in:
Adrian
2023-01-13 08:17:43 +00:00
committed by GitHub
parent ea1003c6bf
commit 459497f0b6
12 changed files with 455 additions and 50 deletions

View File

@@ -345,6 +345,7 @@ void HidDemoApp::DrawUserInputGetKeystroke(uint32_t user_index, bool poll,
bool clear_log) const {
static const std::unordered_map<ui::VirtualKey, const std::string> kVkPretty =
{
{ui::VirtualKey::kXInputPadGuide, "Guide"},
{ui::VirtualKey::kXInputPadA, "A"},
{ui::VirtualKey::kXInputPadB, "B"},
{ui::VirtualKey::kXInputPadX, "X"},

View File

@@ -9,5 +9,5 @@
#include "xenia/hid/hid_flags.h"
DEFINE_bool(guide_button, false, "Forward guide button presses to guest.",
DEFINE_bool(guide_button, true, "Forward guide button presses to guest.",
"HID");

View File

@@ -249,7 +249,7 @@ X_RESULT SDLInputDriver::GetKeystroke(uint32_t users, uint32_t flags,
// The order of this list is also the order in which events are send if
// multiple buttons change at once.
static_assert(sizeof(X_INPUT_GAMEPAD::buttons) == 2);
static constexpr std::array<ui::VirtualKey, 34> kVkLookup = {
static constexpr std::array<ui::VirtualKey, 35> kVkLookup = {
// 00 - True buttons from xinput button field
ui::VirtualKey::kXInputPadDpadUp,
ui::VirtualKey::kXInputPadDpadDown,
@@ -261,7 +261,8 @@ X_RESULT SDLInputDriver::GetKeystroke(uint32_t users, uint32_t flags,
ui::VirtualKey::kXInputPadRThumbPress,
ui::VirtualKey::kXInputPadLShoulder,
ui::VirtualKey::kXInputPadRShoulder,
ui::VirtualKey::kNone, /* Guide has no VK */
// Guide has no VK (kNone), however using kXInputPadGuide.
ui::VirtualKey::kXInputPadGuide,
ui::VirtualKey::kNone, /* Unknown */
ui::VirtualKey::kXInputPadA,
ui::VirtualKey::kXInputPadB,

View File

@@ -11,6 +11,7 @@
// constructing various tables.
// clang-format off
XE_HID_WINKEY_BINDING(Guide, "GUIDE" , keybind_guide , "0x08")
XE_HID_WINKEY_BINDING(DpadLeft, "DPAD_LEFT" , keybind_dpad_left , "^A" )
XE_HID_WINKEY_BINDING(DpadRight, "DPAD_RIGHT" , keybind_dpad_right , "^D" )
XE_HID_WINKEY_BINDING(DpadDown, "DPAD_DOWN" , keybind_dpad_down , "^S" )

View File

@@ -145,46 +145,49 @@ X_RESULT WinKeyInputDriver::GetState(uint32_t user_index,
IsKeyDown(b.input_key)) {
switch (b.output_key) {
case ui::VirtualKey::kXInputPadA:
buttons |= 0x1000; // XINPUT_GAMEPAD_A
buttons |= X_INPUT_GAMEPAD_A;
break;
case ui::VirtualKey::kXInputPadY:
buttons |= 0x8000; // XINPUT_GAMEPAD_Y
buttons |= X_INPUT_GAMEPAD_Y;
break;
case ui::VirtualKey::kXInputPadB:
buttons |= 0x2000; // XINPUT_GAMEPAD_B
buttons |= X_INPUT_GAMEPAD_B;
break;
case ui::VirtualKey::kXInputPadX:
buttons |= 0x4000; // XINPUT_GAMEPAD_X
buttons |= X_INPUT_GAMEPAD_X;
break;
case ui::VirtualKey::kXInputPadGuide:
buttons |= X_INPUT_GAMEPAD_GUIDE;
break;
case ui::VirtualKey::kXInputPadDpadLeft:
buttons |= 0x0004; // XINPUT_GAMEPAD_DPAD_LEFT
buttons |= X_INPUT_GAMEPAD_DPAD_LEFT;
break;
case ui::VirtualKey::kXInputPadDpadRight:
buttons |= 0x0008; // XINPUT_GAMEPAD_DPAD_RIGHT
buttons |= X_INPUT_GAMEPAD_DPAD_RIGHT;
break;
case ui::VirtualKey::kXInputPadDpadDown:
buttons |= 0x0002; // XINPUT_GAMEPAD_DPAD_DOWN
buttons |= X_INPUT_GAMEPAD_DPAD_DOWN;
break;
case ui::VirtualKey::kXInputPadDpadUp:
buttons |= 0x0001; // XINPUT_GAMEPAD_DPAD_UP
buttons |= X_INPUT_GAMEPAD_DPAD_UP;
break;
case ui::VirtualKey::kXInputPadRThumbPress:
buttons |= 0x0080; // XINPUT_GAMEPAD_RIGHT_THUMB
buttons |= X_INPUT_GAMEPAD_RIGHT_THUMB;
break;
case ui::VirtualKey::kXInputPadLThumbPress:
buttons |= 0x0040; // XINPUT_GAMEPAD_LEFT_THUMB
buttons |= X_INPUT_GAMEPAD_LEFT_THUMB;
break;
case ui::VirtualKey::kXInputPadBack:
buttons |= 0x0020; // XINPUT_GAMEPAD_BACK
buttons |= X_INPUT_GAMEPAD_BACK;
break;
case ui::VirtualKey::kXInputPadStart:
buttons |= 0x0010; // XINPUT_GAMEPAD_START
buttons |= X_INPUT_GAMEPAD_START;
break;
case ui::VirtualKey::kXInputPadLShoulder:
buttons |= 0x0100; // XINPUT_GAMEPAD_LEFT_SHOULDER
buttons |= X_INPUT_GAMEPAD_LEFT_SHOULDER;
break;
case ui::VirtualKey::kXInputPadRShoulder:
buttons |= 0x0200; // XINPUT_GAMEPAD_RIGHT_SHOULDER
buttons |= X_INPUT_GAMEPAD_RIGHT_SHOULDER;
break;
case ui::VirtualKey::kXInputPadLTrigger:
left_trigger = 0xFF;

View File

@@ -27,6 +27,7 @@ XInputInputDriver::XInputInputDriver(xe::ui::Window* window,
module_(nullptr),
XInputGetCapabilities_(nullptr),
XInputGetState_(nullptr),
XInputGetStateEx_(nullptr),
XInputGetKeystroke_(nullptr),
XInputSetState_(nullptr),
XInputEnable_(nullptr) {}
@@ -37,6 +38,7 @@ XInputInputDriver::~XInputInputDriver() {
module_ = nullptr;
XInputGetCapabilities_ = nullptr;
XInputGetState_ = nullptr;
XInputGetStateEx_ = nullptr;
XInputGetKeystroke_ = nullptr;
XInputSetState_ = nullptr;
XInputEnable_ = nullptr;
@@ -49,9 +51,13 @@ X_STATUS XInputInputDriver::Setup() {
return X_STATUS_DLL_NOT_FOUND;
}
// Support guide button with XInput using XInputGetStateEx
auto const XInputGetStateEx = (LPCSTR)100;
// Required.
auto xigc = GetProcAddress(module, "XInputGetCapabilities");
auto xigs = GetProcAddress(module, "XInputGetState");
auto xigsEx = GetProcAddress(module, XInputGetStateEx);
auto xigk = GetProcAddress(module, "XInputGetKeystroke");
auto xiss = GetProcAddress(module, "XInputSetState");
@@ -67,17 +73,14 @@ X_STATUS XInputInputDriver::Setup() {
module_ = module;
XInputGetCapabilities_ = xigc;
XInputGetState_ = xigs;
XInputGetStateEx_ = xigsEx;
XInputGetKeystroke_ = xigk;
XInputSetState_ = xiss;
XInputEnable_ = xie;
if (cvars::guide_button) {
// Theoretically there is XInputGetStateEx
// but thats undocumented and milage varies.
XELOGW("XInput: Guide button support is not implemented.");
}
return X_STATUS_SUCCESS;
}
constexpr uint64_t SKIP_INVALID_CONTROLLER_TIME = 1100;
static uint64_t last_invalid_time[4];
@@ -137,10 +140,18 @@ X_RESULT XInputInputDriver::GetState(uint32_t user_index,
if (skipper) {
return skipper;
}
XINPUT_STATE native_state;
auto xigs = (decltype(&XInputGetState))XInputGetState_;
struct {
XINPUT_STATE state;
unsigned int xinput_state_ex_padding; // Add padding in case we are using XInputGetStateEx
} native_state;
DWORD result = xigs(user_index, &native_state);
// If the guide button is enabled use XInputGetStateEx, otherwise use the default XInputGetState.
auto xigs = cvars::guide_button
? (decltype(&XInputGetState))XInputGetStateEx_
: (decltype(&XInputGetState))XInputGetState_;
DWORD result = xigs(user_index, &native_state.state);
if (result) {
if (result == ERROR_DEVICE_NOT_CONNECTED) {
set_skip(user_index);
@@ -148,14 +159,14 @@ X_RESULT XInputInputDriver::GetState(uint32_t user_index,
return result;
}
out_state->packet_number = native_state.dwPacketNumber;
out_state->gamepad.buttons = native_state.Gamepad.wButtons;
out_state->gamepad.left_trigger = native_state.Gamepad.bLeftTrigger;
out_state->gamepad.right_trigger = native_state.Gamepad.bRightTrigger;
out_state->gamepad.thumb_lx = native_state.Gamepad.sThumbLX;
out_state->gamepad.thumb_ly = native_state.Gamepad.sThumbLY;
out_state->gamepad.thumb_rx = native_state.Gamepad.sThumbRX;
out_state->gamepad.thumb_ry = native_state.Gamepad.sThumbRY;
out_state->packet_number = native_state.state.dwPacketNumber;
out_state->gamepad.buttons = native_state.state.Gamepad.wButtons;
out_state->gamepad.left_trigger = native_state.state.Gamepad.bLeftTrigger;
out_state->gamepad.right_trigger = native_state.state.Gamepad.bRightTrigger;
out_state->gamepad.thumb_lx = native_state.state.Gamepad.sThumbLX;
out_state->gamepad.thumb_ly = native_state.state.Gamepad.sThumbLY;
out_state->gamepad.thumb_rx = native_state.state.Gamepad.sThumbRX;
out_state->gamepad.thumb_ry = native_state.state.Gamepad.sThumbRY;
return result;
}

View File

@@ -34,6 +34,7 @@ class XInputInputDriver final : public InputDriver {
void* module_;
void* XInputGetCapabilities_;
void* XInputGetState_;
void* XInputGetStateEx_;
void* XInputGetKeystroke_;
void* XInputSetState_;
void* XInputEnable_;