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:
@@ -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"},
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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" )
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ class XInputInputDriver final : public InputDriver {
|
||||
void* module_;
|
||||
void* XInputGetCapabilities_;
|
||||
void* XInputGetState_;
|
||||
void* XInputGetStateEx_;
|
||||
void* XInputGetKeystroke_;
|
||||
void* XInputSetState_;
|
||||
void* XInputEnable_;
|
||||
|
||||
Reference in New Issue
Block a user