/** ** Supermodel ** A Sega Model 3 Arcade Emulator. ** Copyright 2011 Bart Trzynadlowski, Nik Henson ** ** This file is part of Supermodel. ** ** Supermodel is free software: you can redistribute it and/or modify it under ** the terms of the GNU General Public License as published by the Free ** Software Foundation, either version 3 of the License, or (at your option) ** any later version. ** ** Supermodel is distributed in the hope that it will be useful, but WITHOUT ** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ** FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ** more details. ** ** You should have received a copy of the GNU General Public License along ** with Supermodel. If not, see . **/ /* * DirectInputSystem.h * * Header file for DirectInput, XInput, and Raw Input input system. */ #ifndef INCLUDED_DIRECTINPUTSYSTEM_H #define INCLUDED_DIRECTINPUTSYSTEM_H #include "Types.h" #include "Inputs/Input.h" #include "Inputs/InputSource.h" #include "Inputs/InputSystem.h" #include #define WIN32_LEAN_AND_MEAN #include #include #include #include #include #define NUM_DI_KEYS (sizeof(s_keyMap) / sizeof(DIKeyMapStruct)) #define DI_EFFECTS_MAX DI_FFNOMINALMAX #define DI_EFFECTS_SCALE (DI_EFFECTS_MAX / 100) #define XI_VIBRATE_MAX 65535 #define XI_VIBRATE_SCALE (XI_VIBRATE_MAX / 100) struct DIKeyMapStruct { const char *keyName; int diKey; }; struct RawMseState { LONG x; LONG y; LONG z; LONG wheelDelta; SHORT wheelDir; USHORT buttons; }; struct DIMseState { LONG x; LONG y; LONG z; SHORT wheelDir; BYTE buttons[5]; }; struct DIJoyInfo { // DirectInput details GUID guid; int dInputNum; LPDIRECTINPUTEFFECT dInputEffects[NUM_JOY_AXES][NUM_FF_EFFECTS]; // XInput details bool isXInput; // True if joystick is XInput controller int xInputNum; // XInput controller number // XInput force feedback state WORD xiConstForceLeft; WORD xiConstForceRight; WORD xiVibrateBoth; }; // RawInput API typedef /*WINUSERAPI*/ INT (WINAPI *GetRawInputDeviceListPtr)(OUT PRAWINPUTDEVICELIST pRawInputDeviceList, IN OUT PUINT puiNumDevices, IN UINT cbSize); typedef /*WINUSERAPI*/ INT (WINAPI *GetRawInputDeviceInfoPtr)(IN HANDLE hDevice, IN UINT uiCommand, OUT LPVOID pData, IN OUT PUINT pcbSize); typedef /*WINUSERAPI*/ bool (WINAPI *RegisterRawInputDevicesPtr)(IN PCRAWINPUTDEVICE pRawInputDevices, IN UINT uiNumDevices, IN UINT cbSize); typedef /*WINUSERAPI*/ INT (WINAPI *GetRawInputDataPtr)(IN HRAWINPUT hRawInput, IN UINT uiCommand, OUT LPVOID pData, IN OUT PUINT pcbSize, IN UINT cbSizeHeader); // XInput API typedef /*WINUSERAPI*/ DWORD (WINAPI *XInputGetCapabilitiesPtr)(IN DWORD dwUserIndex, IN DWORD dwFlags, OUT PXINPUT_CAPABILITIES pCapabilities); typedef /*WINUSERAPI*/ DWORD (WINAPI *XInputGetStatePtr)(IN DWORD dwUserIndex, OUT PXINPUT_STATE pState); typedef /*WINUSERAPI*/ DWORD (WINAPI *XInputSetStatePtr)(IN DWORD dwUserIndex, IN PXINPUT_VIBRATION pVibration); /* * Input system that uses combination of DirectInput, XInput and RawInput APIs. */ class CDirectInputSystem : public CInputSystem { private: const Util::Config::Node &m_config; // Lookup table to map key names to DirectInput keycodes and Virtual keycodes static DIKeyMapStruct s_keyMap[]; static const char *ConstructName(bool useRawInput, bool useXInput); bool m_useRawInput; bool m_useXInput; bool m_enableFFeedback; HWND m_hwnd; DWORD m_screenW; DWORD m_screenH; bool m_initializedCOM; bool m_activated; SDL_Window *m_window = nullptr; // Function pointers for RawInput API GetRawInputDeviceListPtr m_getRIDevListPtr; GetRawInputDeviceInfoPtr m_getRIDevInfoPtr; RegisterRawInputDevicesPtr m_regRIDevsPtr; GetRawInputDataPtr m_getRIDataPtr; // Keyboard, mouse and joystick details std::vector m_keyDetails; std::vector m_mseDetails; std::vector m_joyDetails; // RawInput keyboard and mice handles and states std::vector m_rawKeyboards; std::vector m_rawKeyStates; std::vector m_rawMice; RawMseState m_combRawMseState; std::vector m_rawMseStates; // Function pointers for XInput API XInputGetCapabilitiesPtr m_xiGetCapabilitiesPtr; XInputGetStatePtr m_xiGetStatePtr; XInputSetStatePtr m_xiSetStatePtr; // DirectInput pointers and details LPDIRECTINPUT8 m_di8; LPDIRECTINPUTDEVICE8 m_di8Keyboard; LPDIRECTINPUTDEVICE8 m_di8Mouse; std::vector m_di8Joysticks; // DirectInput keyboard and mouse states BYTE m_diKeyState[256]; DIMseState m_diMseState; // DirectInput joystick infos and states std::vector m_diJoyInfos; std::vector m_diJoyStates; bool GetRegString(HKEY regKey, const char *regPath, std::string &str); bool GetRegDeviceName(const char *rawDevName, char *name); void OpenKeyboardsAndMice(); void ActivateKeyboardsAndMice(); void PollKeyboardsAndMice(); void CloseKeyboardsAndMice(); void ResetMice(); void ProcessRawInput(HRAWINPUT hInput); void OpenJoysticks(); void ActivateJoysticks(); void PollJoysticks(); void CloseJoysticks(); HRESULT CreateJoystickEffect(LPDIRECTINPUTDEVICE8 di8Joystick, int axisNum, ForceFeedbackCmd ffCmd, LPDIRECTINPUTEFFECT *di8Effect); void LoadXInputDLL(); protected: /* * Initializes the DirectInput input system. */ bool InitializeSystem(); int GetKeyIndex(const char *keyName); const char *GetKeyName(int keyIndex); bool IsKeyPressed(int joyNum, int keyIndex); int GetMouseAxisValue(int mseNum, int axisNum); int GetMouseWheelDir(int mseNum); bool IsMouseButPressed(int mseNum, int butNum); int GetJoyAxisValue(int joyNum, int axisNum); bool IsJoyPOVInDir(int joyNum, int povNum, int povDir); bool IsJoyButPressed(int joyNum, int butNum); bool ProcessForceFeedbackCmd(int joyNum, int axisNum, ForceFeedbackCmd ffCmd); bool ConfigMouseCentered(); CInputSource *CreateAnyMouseSource(EMousePart msePart); public: /* * Constructs a DirectInput/XInput/RawInput input system. * If useRawInput is true then RawInput is used for keyboard and mice movements (allowing multiple devices, eg for dual lightguns in gun * games such as Lost World). If false then DirectInput is used instead (which doesn't allow multiple devices). In both cases, * DirectInput/XInput is used for reading joysticks. * If useXInput is true then XInput is used for reading XBox 360 game controllers (and/or XInput compatible joysticks) and DirectInput is used * for all other types of joystick. If false, then DirectInput is used for reading all joysticks (including XBox 360 ones). * The advantage of using XInput for XBox 360 game controllers is that it allows the left and right triggers to be used simultaneously * (ie to brake and accelerate at the same time in order to power slide the car in Daytona USA 2). Under DirectInput the triggers get mapped * to the same shared axis and so cannot be distinguished when pressed together. * If enableFFeedback is true then force feedback is enabled (for those joysticks which are force feedback capable). */ CDirectInputSystem(const Util::Config::Node &config, SDL_Window *window, bool useRawInput, bool useXInput); ~CDirectInputSystem(); int GetNumKeyboards(); int GetNumMice(); int GetNumJoysticks(); const KeyDetails *GetKeyDetails(int kbdNum); const MouseDetails *GetMouseDetails(int mseNum); const JoyDetails *GetJoyDetails(int joyNum); bool Poll(); void GrabMouse(); void UngrabMouse(); void SetMouseVisibility(bool visible); }; #endif // INCLUDED_DIRECTINPUTSYSTEM_H