diff --git a/src/xenia/hid/hid.cc b/src/xenia/hid/hid.cc index 9aa58c618..fc3a3b9e6 100644 --- a/src/xenia/hid/hid.cc +++ b/src/xenia/hid/hid.cc @@ -17,11 +17,12 @@ using namespace xe::hid; DEFINE_string(hid, "any", - "Input system. Use: [any, nop, xinput]"); + "Input system. Use: [any, nop, winkey, xinput]"); #include #if XE_PLATFORM_WIN32 +#include #include #endif // WIN32 @@ -33,6 +34,8 @@ InputSystem* xe::hid::Create(Emulator* emulator) { if (FLAGS_hid.compare("nop") == 0) { input_system->AddDriver(xe::hid::nop::Create(input_system)); #if XE_PLATFORM_WIN32 + } else if (FLAGS_hid.compare("winkey") == 0) { + input_system->AddDriver(xe::hid::winkey::Create(input_system)); } else if (FLAGS_hid.compare("xinput") == 0) { input_system->AddDriver(xe::hid::xinput::Create(input_system)); #endif // WIN32 @@ -43,6 +46,11 @@ InputSystem* xe::hid::Create(Emulator* emulator) { // NOTE: in any mode we create as many as we can, falling back to nop. #if XE_PLATFORM_WIN32 + InputDriver* winkey_driver = xe::hid::winkey::Create(input_system); + if (winkey_driver) { + input_system->AddDriver(winkey_driver); + any_created = true; + } InputDriver* xinput_driver = xe::hid::xinput::Create(input_system); if (xinput_driver) { input_system->AddDriver(xinput_driver); diff --git a/src/xenia/hid/sources.gypi b/src/xenia/hid/sources.gypi index e166ec3f0..079d059ca 100644 --- a/src/xenia/hid/sources.gypi +++ b/src/xenia/hid/sources.gypi @@ -17,6 +17,7 @@ 'conditions': [ ['OS == "win"', { 'includes': [ + 'winkey/sources.gypi', 'xinput/sources.gypi', ], }], diff --git a/src/xenia/hid/winkey/sources.gypi b/src/xenia/hid/winkey/sources.gypi new file mode 100644 index 000000000..792ac571d --- /dev/null +++ b/src/xenia/hid/winkey/sources.gypi @@ -0,0 +1,10 @@ +# Copyright 2013 Ben Vanik. All Rights Reserved. +{ + 'sources': [ + 'winkey_hid-private.h', + 'winkey_hid.cc', + 'winkey_hid.h', + 'winkey_input_driver.cc', + 'winkey_input_driver.h', + ], +} diff --git a/src/xenia/hid/winkey/winkey_hid-private.h b/src/xenia/hid/winkey/winkey_hid-private.h new file mode 100644 index 000000000..2100f9185 --- /dev/null +++ b/src/xenia/hid/winkey/winkey_hid-private.h @@ -0,0 +1,31 @@ +/** + ****************************************************************************** + * 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_WINKEY_WINKEY_HID_PRIVATE_H_ +#define XENIA_HID_WINKEY_WINKEY_HID_PRIVATE_H_ + +#include + +#include + + +namespace xe { +namespace hid { +namespace winkey { + + + + + +} // namespace winkey +} // namespace hid +} // namespace xe + + +#endif // XENIA_HID_WINKEY_WINKEY_HID_PRIVATE_H_ diff --git a/src/xenia/hid/winkey/winkey_hid.cc b/src/xenia/hid/winkey/winkey_hid.cc new file mode 100644 index 000000000..43d363271 --- /dev/null +++ b/src/xenia/hid/winkey/winkey_hid.cc @@ -0,0 +1,44 @@ +/** + ****************************************************************************** + * 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 + +#include + + +using namespace xe; +using namespace xe::hid; +using namespace xe::hid::winkey; + + +namespace { + void InitializeIfNeeded(); + void CleanupOnShutdown(); + + void InitializeIfNeeded() { + static bool has_initialized = false; + if (has_initialized) { + return; + } + has_initialized = true; + + // + + atexit(CleanupOnShutdown); + } + + void CleanupOnShutdown() { + } +} + + +InputDriver* xe::hid::winkey::Create(InputSystem* input_system) { + InitializeIfNeeded(); + return new WinKeyInputDriver(input_system); +} diff --git a/src/xenia/hid/winkey/winkey_hid.h b/src/xenia/hid/winkey/winkey_hid.h new file mode 100644 index 000000000..a5ed273bc --- /dev/null +++ b/src/xenia/hid/winkey/winkey_hid.h @@ -0,0 +1,33 @@ +/** + ****************************************************************************** + * 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_WINKEY_WINKEY_HID_H_ +#define XENIA_HID_WINKEY_WINKEY_HID_H_ + +#include + + +XEDECLARECLASS2(xe, hid, InputDriver); +XEDECLARECLASS2(xe, hid, InputSystem); + + +namespace xe { +namespace hid { +namespace winkey { + + +InputDriver* Create(InputSystem* input_system); + + +} // namespace winkey +} // namespace hid +} // namespace xe + + +#endif // XENIA_HID_WINKEY_WINKEY_HID_H_ diff --git a/src/xenia/hid/winkey/winkey_input_driver.cc b/src/xenia/hid/winkey/winkey_input_driver.cc new file mode 100644 index 000000000..d0e63d64b --- /dev/null +++ b/src/xenia/hid/winkey/winkey_input_driver.cc @@ -0,0 +1,181 @@ +/** + ****************************************************************************** + * 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 + +#include + + +using namespace xe; +using namespace xe::hid; +using namespace xe::hid::winkey; + + +WinKeyInputDriver::WinKeyInputDriver(InputSystem* input_system) : + packet_number_(1), + InputDriver(input_system) { +} + +WinKeyInputDriver::~WinKeyInputDriver() { +} + +X_STATUS WinKeyInputDriver::Setup() { + return X_STATUS_SUCCESS; +} + +X_RESULT WinKeyInputDriver::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)0xFFFF; + out_caps.gamepad.thumb_ly = (int16_t)0xFFFF; + out_caps.gamepad.thumb_rx = (int16_t)0xFFFF; + out_caps.gamepad.thumb_ry = (int16_t)0xFFFF; + out_caps.vibration.left_motor_speed = 0; + out_caps.vibration.right_motor_speed = 0; + return X_ERROR_SUCCESS; +} + +#define IS_KEY_TOGGLED(key) ((GetKeyState(key) & 0x1) == 0x1) +#define IS_KEY_DOWN(key) ((GetAsyncKeyState(key) & 0x8000) == 0x8000) + +X_RESULT WinKeyInputDriver::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 (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(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 + } + + 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 WinKeyInputDriver::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 WinKeyInputDriver::GetKeystroke( + uint32_t user_index, uint32_t flags, X_INPUT_KEYSTROKE& out_keystroke) { + if (user_index != 0) { + return X_ERROR_DEVICE_NOT_CONNECTED; + } + + X_RESULT result = X_ERROR_EMPTY; + + uint16_t virtual_key = 0; + uint16_t unicode = 0; + uint16_t keystroke_flags = 0; + uint8_t hid_code = 0; + + out_keystroke.virtual_key = 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; +} diff --git a/src/xenia/hid/winkey/winkey_input_driver.h b/src/xenia/hid/winkey/winkey_input_driver.h new file mode 100644 index 000000000..b1d00fd10 --- /dev/null +++ b/src/xenia/hid/winkey/winkey_input_driver.h @@ -0,0 +1,50 @@ +/** + ****************************************************************************** + * 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_WINKEY_WINKEY_DRIVER_H_ +#define XENIA_HID_WINKEY_WINKEY_DRIVER_H_ + +#include + +#include +#include + + +namespace xe { +namespace hid { +namespace winkey { + + +class WinKeyInputDriver : public InputDriver { +public: + WinKeyInputDriver(InputSystem* input_system); + virtual ~WinKeyInputDriver(); + + virtual X_STATUS Setup(); + + virtual X_RESULT GetCapabilities( + uint32_t user_index, uint32_t flags, X_INPUT_CAPABILITIES& out_caps); + virtual X_RESULT GetState( + uint32_t user_index, X_INPUT_STATE& out_state); + virtual X_RESULT SetState( + uint32_t user_index, X_INPUT_VIBRATION& vibration); + virtual X_RESULT GetKeystroke( + uint32_t user_index, uint32_t flags, X_INPUT_KEYSTROKE& out_keystroke); + +protected: + uint32_t packet_number_; +}; + + +} // namespace winkey +} // namespace hid +} // namespace xe + + +#endif // XENIA_HID_WINKEY_WINKEY_DRIVER_H_