/** ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** * Copyright 2013 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ #include "xenia/base/logging.h" #include "xenia/emulator.h" #include "xenia/hid/input.h" #include "xenia/hid/input_system.h" #include "xenia/kernel/kernel_state.h" #include "xenia/kernel/util/shim_utils.h" #include "xenia/kernel/xam/xam_private.h" #include "xenia/xbox.h" namespace xe { namespace kernel { namespace xam { using xe::hid::X_INPUT_CAPABILITIES; using xe::hid::X_INPUT_KEYSTROKE; using xe::hid::X_INPUT_STATE; using xe::hid::X_INPUT_VIBRATION; constexpr uint32_t XINPUT_FLAG_GAMEPAD = 0x01; constexpr uint32_t XINPUT_FLAG_ANY_USER = 1 << 30; void XamResetInactivity() { // Do we need to do anything? } DECLARE_XAM_EXPORT(XamResetInactivity, ExportTag::kInput | ExportTag::kStub); dword_result_t XamEnableInactivityProcessing(dword_t unk, dword_t enable) { return X_ERROR_SUCCESS; } DECLARE_XAM_EXPORT(XamEnableInactivityProcessing, ExportTag::kInput | ExportTag::kStub); // http://msdn.microsoft.com/en-us/library/windows/desktop/microsoft.directx_sdk.reference.xinputgetcapabilities(v=vs.85).aspx dword_result_t XamInputGetCapabilities(dword_t user_index, dword_t flags, pointer_t caps) { if (!caps) { return X_ERROR_BAD_ARGUMENTS; } if ((flags & 0xFF) && (flags & XINPUT_FLAG_GAMEPAD) == 0) { // Ignore any query for other types of devices. return X_ERROR_DEVICE_NOT_CONNECTED; } uint32_t actual_user_index = user_index; if ((actual_user_index & 0xFF) == 0xFF || (flags & XINPUT_FLAG_ANY_USER)) { // Always pin user to 0. actual_user_index = 0; } auto input_system = kernel_state()->emulator()->input_system(); return input_system->GetCapabilities(actual_user_index, flags, caps); } DECLARE_XAM_EXPORT(XamInputGetCapabilities, ExportTag::kInput | ExportTag::kSketchy); dword_result_t XamInputGetCapabilitiesEx(dword_t unk, dword_t user_index, dword_t flags, pointer_t caps) { if (!caps) { return X_ERROR_BAD_ARGUMENTS; } if ((flags & 0xFF) && (flags & XINPUT_FLAG_GAMEPAD) == 0) { // Ignore any query for other types of devices. return X_ERROR_DEVICE_NOT_CONNECTED; } uint32_t actual_user_index = user_index; if ((actual_user_index & 0xFF) == 0xFF || (flags & XINPUT_FLAG_ANY_USER)) { // Always pin user to 0. actual_user_index = 0; } auto input_system = kernel_state()->emulator()->input_system(); return input_system->GetCapabilities(actual_user_index, flags, caps); } DECLARE_XAM_EXPORT(XamInputGetCapabilitiesEx, ExportTag::kInput | ExportTag::kSketchy); // http://msdn.microsoft.com/en-us/library/windows/desktop/microsoft.directx_sdk.reference.xinputgetstate(v=vs.85).aspx dword_result_t XamInputGetState(dword_t user_index, dword_t flags, pointer_t input_state) { // Games call this with a NULL state ptr, probably as a query. if ((flags & 0xFF) && (flags & XINPUT_FLAG_GAMEPAD) == 0) { // Ignore any query for other types of devices. return X_ERROR_DEVICE_NOT_CONNECTED; } uint32_t actual_user_index = user_index; if ((actual_user_index & 0xFF) == 0xFF || (flags & XINPUT_FLAG_ANY_USER)) { // Always pin user to 0. actual_user_index = 0; } auto input_system = kernel_state()->emulator()->input_system(); return input_system->GetState(user_index, input_state); } DECLARE_XAM_EXPORT(XamInputGetState, ExportTag::kInput | ExportTag::kImplemented); // http://msdn.microsoft.com/en-us/library/windows/desktop/microsoft.directx_sdk.reference.xinputsetstate(v=vs.85).aspx dword_result_t XamInputSetState(dword_t user_index, dword_t unk, pointer_t vibration) { if (!vibration) { return X_ERROR_BAD_ARGUMENTS; } uint32_t actual_user_index = user_index; if ((user_index & 0xFF) == 0xFF) { // Always pin user to 0. actual_user_index = 0; } auto input_system = kernel_state()->emulator()->input_system(); return input_system->SetState(user_index, vibration); } DECLARE_XAM_EXPORT(XamInputSetState, ExportTag::kInput | ExportTag::kImplemented); // http://msdn.microsoft.com/en-us/library/windows/desktop/microsoft.directx_sdk.reference.xinputgetkeystroke(v=vs.85).aspx dword_result_t XamInputGetKeystroke(dword_t user_index, dword_t flags, pointer_t keystroke) { // http://ffplay360.googlecode.com/svn/Test/Common/AtgXime.cpp // user index = index or XUSER_INDEX_ANY // flags = XINPUT_FLAG_GAMEPAD (| _ANYUSER | _ANYDEVICE) if (!keystroke) { return X_ERROR_BAD_ARGUMENTS; } if ((flags & 0xFF) && (flags & XINPUT_FLAG_GAMEPAD) == 0) { // Ignore any query for other types of devices. return X_ERROR_DEVICE_NOT_CONNECTED; } uint32_t actual_user_index = user_index; if ((actual_user_index & 0xFF) == 0xFF || (flags & XINPUT_FLAG_ANY_USER)) { // Always pin user to 0. actual_user_index = 0; } auto input_system = kernel_state()->emulator()->input_system(); return input_system->GetKeystroke(user_index, flags, keystroke); } DECLARE_XAM_EXPORT(XamInputGetKeystroke, ExportTag::kInput | ExportTag::kImplemented); // Same as non-ex, just takes a pointer to user index. dword_result_t XamInputGetKeystrokeEx(lpdword_t user_index_ptr, dword_t flags, pointer_t keystroke) { if (!keystroke) { return X_ERROR_BAD_ARGUMENTS; } if ((flags & 0xFF) && (flags & XINPUT_FLAG_GAMEPAD) == 0) { // Ignore any query for other types of devices. return X_ERROR_DEVICE_NOT_CONNECTED; } uint32_t user_index = *user_index_ptr; if ((user_index & 0xFF) == 0xFF || (flags & XINPUT_FLAG_ANY_USER)) { // Always pin user to 0. user_index = 0; } auto input_system = kernel_state()->emulator()->input_system(); auto result = input_system->GetKeystroke(user_index, flags, keystroke); if (XSUCCEEDED(result)) { *user_index_ptr = keystroke->user_index; } return result; } DECLARE_XAM_EXPORT(XamInputGetKeystrokeEx, ExportTag::kInput | ExportTag::kImplemented); X_HRESULT_result_t XamUserGetDeviceContext(dword_t user_index, dword_t unk, lpdword_t out_ptr) { // Games check the result - usually with some masking. // If this function fails they assume zero, so let's fail AND // set zero just to be safe. *out_ptr = 0; if (!user_index || (user_index & 0xFF) == 0xFF) { return X_E_SUCCESS; } else { return X_E_DEVICE_NOT_CONNECTED; } } DECLARE_XAM_EXPORT(XamUserGetDeviceContext, ExportTag::kInput | ExportTag::kStub); void RegisterInputExports(xe::cpu::ExportResolver* export_resolver, KernelState* kernel_state) {} } // namespace xam } // namespace kernel } // namespace xe