diff --git a/src/xenia/hid/input_driver.h b/src/xenia/hid/input_driver.h index 99f21918e..e2b04daff 100644 --- a/src/xenia/hid/input_driver.h +++ b/src/xenia/hid/input_driver.h @@ -32,6 +32,9 @@ public: uint32_t user_index, X_INPUT_STATE& out_state) = 0; virtual X_RESULT SetState( uint32_t user_index, X_INPUT_VIBRATION& vibration) = 0; + virtual X_RESULT GetKeystroke( + uint32_t user_index, uint32_t flags, + X_INPUT_KEYSTROKE& out_keystroke) = 0; protected: InputDriver(InputSystem* input_system); diff --git a/src/xenia/hid/input_system.cc b/src/xenia/hid/input_system.cc index d1ac04c6b..b82ca11af 100644 --- a/src/xenia/hid/input_system.cc +++ b/src/xenia/hid/input_system.cc @@ -23,7 +23,7 @@ InputSystem::InputSystem(Emulator* emulator) : } InputSystem::~InputSystem() { - for (std::vector::iterator it = drivers_.begin(); + for (auto it = drivers_.begin(); it != drivers_.end(); ++it) { InputDriver* driver = *it; delete driver; @@ -42,8 +42,7 @@ void InputSystem::AddDriver(InputDriver* driver) { X_RESULT InputSystem::GetCapabilities( uint32_t user_index, uint32_t flags, X_INPUT_CAPABILITIES& out_caps) { - for (std::vector::iterator it = drivers_.begin(); - it != drivers_.end(); ++it) { + for (auto it = drivers_.begin(); it != drivers_.end(); ++it) { InputDriver* driver = *it; if (XSUCCEEDED(driver->GetCapabilities(user_index, flags, out_caps))) { return X_ERROR_SUCCESS; @@ -53,8 +52,7 @@ X_RESULT InputSystem::GetCapabilities( } X_RESULT InputSystem::GetState(uint32_t user_index, X_INPUT_STATE& out_state) { - for (std::vector::iterator it = drivers_.begin(); - it != drivers_.end(); ++it) { + for (auto it = drivers_.begin(); it != drivers_.end(); ++it) { InputDriver* driver = *it; if (driver->GetState(user_index, out_state) == X_ERROR_SUCCESS) { return X_ERROR_SUCCESS; @@ -65,8 +63,7 @@ X_RESULT InputSystem::GetState(uint32_t user_index, X_INPUT_STATE& out_state) { X_RESULT InputSystem::SetState( uint32_t user_index, X_INPUT_VIBRATION& vibration) { - for (std::vector::iterator it = drivers_.begin(); - it != drivers_.end(); ++it) { + for (auto it = drivers_.begin(); it != drivers_.end(); ++it) { InputDriver* driver = *it; if (XSUCCEEDED(driver->SetState(user_index, vibration))) { return X_ERROR_SUCCESS; @@ -74,3 +71,14 @@ X_RESULT InputSystem::SetState( } return X_ERROR_DEVICE_NOT_CONNECTED; } + +X_RESULT InputSystem::GetKeystroke( + uint32_t user_index, uint32_t flags, X_INPUT_KEYSTROKE& out_keystroke) { + for (auto it = drivers_.begin(); it != drivers_.end(); ++it) { + InputDriver* driver = *it; + if (XSUCCEEDED(driver->GetKeystroke(user_index, flags, out_keystroke))) { + return X_ERROR_SUCCESS; + } + } + return X_ERROR_DEVICE_NOT_CONNECTED; +} \ No newline at end of file diff --git a/src/xenia/hid/input_system.h b/src/xenia/hid/input_system.h index 352a7462e..a86fc8525 100644 --- a/src/xenia/hid/input_system.h +++ b/src/xenia/hid/input_system.h @@ -41,6 +41,8 @@ public: uint32_t user_index, uint32_t flags, X_INPUT_CAPABILITIES& out_caps); X_RESULT GetState(uint32_t user_index, X_INPUT_STATE& out_state); X_RESULT SetState(uint32_t user_index, X_INPUT_VIBRATION& vibration); + X_RESULT GetKeystroke(uint32_t user_index, uint32_t flags, + X_INPUT_KEYSTROKE& out_keystroke); private: Emulator* emulator_; diff --git a/src/xenia/hid/nop/nop_input_driver.cc b/src/xenia/hid/nop/nop_input_driver.cc index 502f74365..d6a75c7fe 100644 --- a/src/xenia/hid/nop/nop_input_driver.cc +++ b/src/xenia/hid/nop/nop_input_driver.cc @@ -45,3 +45,8 @@ X_RESULT NopInputDriver::SetState( uint32_t user_index, X_INPUT_VIBRATION& vibration) { return X_ERROR_DEVICE_NOT_CONNECTED; } + +X_RESULT NopInputDriver::GetKeystroke( + uint32_t user_index, uint32_t flags, X_INPUT_KEYSTROKE& out_keystroke) { + return X_ERROR_DEVICE_NOT_CONNECTED; +} diff --git a/src/xenia/hid/nop/nop_input_driver.h b/src/xenia/hid/nop/nop_input_driver.h index 911134993..58a205ec5 100644 --- a/src/xenia/hid/nop/nop_input_driver.h +++ b/src/xenia/hid/nop/nop_input_driver.h @@ -34,6 +34,8 @@ public: 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: }; diff --git a/src/xenia/hid/xinput/xinput_input_driver.cc b/src/xenia/hid/xinput/xinput_input_driver.cc index f5480a735..cf1097196 100644 --- a/src/xenia/hid/xinput/xinput_input_driver.cc +++ b/src/xenia/hid/xinput/xinput_input_driver.cc @@ -86,3 +86,22 @@ X_RESULT XInputInputDriver::SetState( DWORD result = XInputSetState(user_index, &native_vibration); return result; } + +X_RESULT XInputInputDriver::GetKeystroke( + uint32_t user_index, uint32_t flags, X_INPUT_KEYSTROKE& out_keystroke) { + // We may want to filter flags/user_index before sending to native. + // flags is reserved on desktop. + XINPUT_KEYSTROKE native_keystroke; + DWORD result = XInputGetKeystroke(user_index, flags, &native_keystroke); + if (result == ERROR_SUCCESS) { + out_keystroke.virtual_key = native_keystroke.VirtualKey; + out_keystroke.unicode = native_keystroke.Unicode; + out_keystroke.flags = native_keystroke.Flags; + out_keystroke.user_index = native_keystroke.UserIndex; + out_keystroke.hid_code = native_keystroke.HidCode; + } + // 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/xinput/xinput_input_driver.h b/src/xenia/hid/xinput/xinput_input_driver.h index fdfc1d2a4..dc9118c1d 100644 --- a/src/xenia/hid/xinput/xinput_input_driver.h +++ b/src/xenia/hid/xinput/xinput_input_driver.h @@ -34,6 +34,8 @@ public: 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: }; diff --git a/src/xenia/kernel/xam_input.cc b/src/xenia/kernel/xam_input.cc index 884b6e187..7324d85ff 100644 --- a/src/xenia/kernel/xam_input.cc +++ b/src/xenia/kernel/xam_input.cc @@ -106,6 +106,71 @@ SHIM_CALL XamInputSetState_shim( } +// http://msdn.microsoft.com/en-us/library/windows/desktop/microsoft.directx_sdk.reference.xinputgetkeystroke(v=vs.85).aspx +SHIM_CALL XamInputGetKeystroke_shim( + PPCContext* ppc_state, KernelState* state) { + uint32_t user_index = SHIM_GET_ARG_32(0); + uint32_t flags = SHIM_GET_ARG_32(1); + uint32_t keystroke_ptr = SHIM_GET_ARG_32(2); + + // http://ffplay360.googlecode.com/svn/Test/Common/AtgXime.cpp + // user index = index or XUSER_INDEX_ANY + // flags = XINPUT_FLAG_GAMEPAD (| _ANYUSER | _ANYDEVICE) + + XELOGD( + "XamInputGetKeystroke(%d, %.8X, %.8X)", + user_index, + flags, + keystroke_ptr); + + if (!keystroke_ptr) { + SHIM_SET_RETURN(X_ERROR_BAD_ARGUMENTS); + return; + } + + InputSystem* input_system = state->emulator()->input_system(); + + X_INPUT_KEYSTROKE keystroke; + X_RESULT result = input_system->GetKeystroke(user_index, flags, keystroke); + if (XSUCCEEDED(result)) { + keystroke.Write(SHIM_MEM_BASE, keystroke_ptr); + } + SHIM_SET_RETURN(result); +} + + +// Same as non-ex, just takes a pointer to user index. +SHIM_CALL XamInputGetKeystrokeEx_shim( + PPCContext* ppc_state, KernelState* state) { + uint32_t user_index_ptr = SHIM_GET_ARG_32(0); + uint32_t flags = SHIM_GET_ARG_32(1); + uint32_t keystroke_ptr = SHIM_GET_ARG_32(2); + + uint32_t user_index = SHIM_MEM_32(user_index_ptr); + + XELOGD( + "XamInputGetKeystroke(%.8X(%.d), %.8X, %.8X)", + user_index_ptr, user_index, + flags, + keystroke_ptr); + + if (!keystroke_ptr) { + SHIM_SET_RETURN(X_ERROR_BAD_ARGUMENTS); + return; + } + + InputSystem* input_system = state->emulator()->input_system(); + + X_INPUT_KEYSTROKE keystroke; + X_RESULT result = input_system->GetKeystroke(user_index, flags, keystroke); + if (XSUCCEEDED(result)) { + SHIM_SET_MEM_32(user_index_ptr, keystroke.user_index); + keystroke.Write(SHIM_MEM_BASE, keystroke_ptr); + } + SHIM_SET_RETURN(result); +} + + } // namespace kernel } // namespace xe @@ -115,4 +180,6 @@ void xe::kernel::xam::RegisterInputExports( SHIM_SET_MAPPING("xam.xex", XamInputGetCapabilities, state); SHIM_SET_MAPPING("xam.xex", XamInputGetState, state); SHIM_SET_MAPPING("xam.xex", XamInputSetState, state); + SHIM_SET_MAPPING("xam.xex", XamInputGetKeystroke, state); + SHIM_SET_MAPPING("xam.xex", XamInputGetKeystrokeEx, state); } diff --git a/src/xenia/xbox.h b/src/xenia/xbox.h index f48912470..8e679192e 100644 --- a/src/xenia/xbox.h +++ b/src/xenia/xbox.h @@ -59,6 +59,7 @@ typedef uint32_t X_RESULT; #define X_ERROR_BUSY ((uint32_t)0x800700AAL) #define X_ERROR_DEVICE_NOT_CONNECTED ((uint32_t)0x8007048FL) #define X_ERROR_CANCELLED ((uint32_t)0x800704C7L) +#define X_ERROR_EMPTY ((uint32_t)0x000010D2L) // MEM_*, used by NtAllocateVirtualMemory #define X_MEM_COMMIT 0x00001000 @@ -396,6 +397,43 @@ public: vibration.Zero(); } }; +// http://msdn.microsoft.com/en-us/library/windows/desktop/microsoft.directx_sdk.reference.xinput_keystroke(v=vs.85).aspx +class X_INPUT_KEYSTROKE { +public: + uint16_t virtual_key; + uint16_t unicode; + uint16_t flags; + uint8_t user_index; + uint8_t hid_code; + + X_INPUT_KEYSTROKE() { + Zero(); + } + X_INPUT_KEYSTROKE(const uint8_t* base, uint32_t p) { + Read(base, p); + } + void Read(const uint8_t* base, uint32_t p) { + virtual_key = XEGETUINT16BE(base + p + 0); + unicode = XEGETUINT16BE(base + p + 2); + flags = XEGETUINT16BE(base + p + 4); + user_index = XEGETUINT8BE(base + p + 6); + hid_code = XEGETUINT8BE(base + p + 7); + } + void Write(uint8_t* base, uint32_t p) { + XESETUINT16BE(base + p + 0, virtual_key); + XESETUINT16BE(base + p + 2, unicode); + XESETUINT16BE(base + p + 4, flags); + XESETUINT8BE(base + p + 6, user_index); + XESETUINT8BE(base + p + 7, hid_code); + } + void Zero() { + virtual_key = 0; + unicode = 0; + flags = 0; + user_index = 0; + hid_code = 0; + } +}; } // namespace xe