From 81fbead16bc93055eb5088822f6db08a2f7cd172 Mon Sep 17 00:00:00 2001 From: Glenn Maynard Date: Wed, 18 Jun 2003 05:43:12 +0000 Subject: [PATCH] split this up Fix losing keyboard input when changing graphics settings (this happened with the old code, too). --- stepmania/src/RageInput.cpp | 6 + stepmania/src/RageInput.h | 1 + stepmania/src/StepMania.cpp | 3 + stepmania/src/StepMania.dsp | 17 + stepmania/src/StepMania.vcproj | 12 +- .../src/arch/InputHandler/InputHandler.h | 4 + .../InputHandler/InputHandler_DirectInput.cpp | 372 +++--------------- .../InputHandler/InputHandler_DirectInput.h | 1 + .../InputHandler_DirectInputHelper.cpp | 310 +++++++++++++++ .../InputHandler_DirectInputHelper.h | 41 ++ 10 files changed, 440 insertions(+), 327 deletions(-) create mode 100644 stepmania/src/arch/InputHandler/InputHandler_DirectInputHelper.cpp create mode 100644 stepmania/src/arch/InputHandler/InputHandler_DirectInputHelper.h diff --git a/stepmania/src/RageInput.cpp b/stepmania/src/RageInput.cpp index d0f2c57eaf..2120d12a9f 100644 --- a/stepmania/src/RageInput.cpp +++ b/stepmania/src/RageInput.cpp @@ -49,3 +49,9 @@ void RageInput::GetDevicesAndDescriptions(vector& vDevicesOut, vect for(unsigned i = 0; i < Devices.size(); ++i) Devices[i]->GetDevicesAndDescriptions( vDevicesOut, vDescriptionsOut ); } + +void RageInput::WindowReset() +{ + for(unsigned i = 0; i < Devices.size(); ++i) + Devices[i]->WindowReset(); +} diff --git a/stepmania/src/RageInput.h b/stepmania/src/RageInput.h index 9e013bb8f8..bde00cd15d 100644 --- a/stepmania/src/RageInput.h +++ b/stepmania/src/RageInput.h @@ -22,6 +22,7 @@ public: void Update( float fDeltaTime ); void GetDevicesAndDescriptions(vector& vDevicesOut, vector& vDescriptionsOut); + void WindowReset(); }; extern RageInput* INPUTMAN; // global and accessable from anywhere in our program diff --git a/stepmania/src/StepMania.cpp b/stepmania/src/StepMania.cpp index 2eda811d50..53d9972ad0 100644 --- a/stepmania/src/StepMania.cpp +++ b/stepmania/src/StepMania.cpp @@ -123,6 +123,9 @@ void ApplyGraphicOptions() PREFSMAN->m_iRefreshRate, PREFSMAN->m_bVsync ? "Vsync" : "NoVsync", PREFSMAN->m_bAntiAliasing? "AA" : "NoAA" ) ); + + /* Give the input handlers a chance to re-open devices as necessary. */ + INPUTMAN->WindowReset(); } void ExitGame() diff --git a/stepmania/src/StepMania.dsp b/stepmania/src/StepMania.dsp index 2f685c4686..e6062a67ff 100644 --- a/stepmania/src/StepMania.dsp +++ b/stepmania/src/StepMania.dsp @@ -1523,6 +1523,23 @@ SOURCE=.\arch\InputHandler\InputHandler_DirectInput.h # End Source File # Begin Source File +SOURCE=.\arch\InputHandler\InputHandler_DirectInputHelper.cpp + +!IF "$(CFG)" == "StepMania - Win32 Debug" + +!ELSEIF "$(CFG)" == "StepMania - Xbox Debug" + +!ELSEIF "$(CFG)" == "StepMania - Win32 Release" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\arch\InputHandler\InputHandler_DirectInputHelper.h +# End Source File +# Begin Source File + SOURCE=.\arch\InputHandler\InputHandler_Win32_Pump.cpp !IF "$(CFG)" == "StepMania - Win32 Debug" diff --git a/stepmania/src/StepMania.vcproj b/stepmania/src/StepMania.vcproj index ba61d0a95a..3eba7a7ddc 100644 --- a/stepmania/src/StepMania.vcproj +++ b/stepmania/src/StepMania.vcproj @@ -523,9 +523,6 @@ cl /Zl /nologo /c verstub.cpp /Fo"$(IntDir)"\ - - + + @@ -920,6 +920,12 @@ cl /Zl /nologo /c verstub.cpp /Fo"$(IntDir)"\ + + + + diff --git a/stepmania/src/arch/InputHandler/InputHandler.h b/stepmania/src/arch/InputHandler/InputHandler.h index 4b32ebefa8..bc65878933 100644 --- a/stepmania/src/arch/InputHandler/InputHandler.h +++ b/stepmania/src/arch/InputHandler/InputHandler.h @@ -30,6 +30,10 @@ public: virtual void Update(float fDeltaTime) { } virtual ~InputHandler() { } virtual void GetDevicesAndDescriptions(vector& vDevicesOut, vector& vDescriptionsOut) = 0; + + /* In Windows, some devices need to be recreated if we recreate our main window. + * Override this if you need to do that. */ + virtual void WindowReset() { } }; #endif diff --git a/stepmania/src/arch/InputHandler/InputHandler_DirectInput.cpp b/stepmania/src/arch/InputHandler/InputHandler_DirectInput.cpp index 74f1f5e598..372bb9d6ed 100644 --- a/stepmania/src/arch/InputHandler/InputHandler_DirectInput.cpp +++ b/stepmania/src/arch/InputHandler/InputHandler_DirectInput.cpp @@ -10,56 +10,18 @@ #include "archutils/Win32/AppInstance.h" #include "InputFilter.h" -#define DIRECTINPUT_VERSION 0x0500 -#include +#include "InputHandler_DirectInputHelper.h" -#define INPUT_QSIZE 32 /* Buffer up to 32 input messages */ - -static LPDIRECTINPUT dinput = NULL; - -#pragma comment(lib, "dinput.lib") /*extern "C" { extern HINSTANCE __declspec(dllimport) SDL_Instance; };*/ -typedef struct input_t -{ - /* DirectInput offset for this input type: */ - DWORD ofs; - - /* Button, axis or hat: */ - enum Type { KEY, BUTTON, AXIS, HAT } type; - - int num; -} input_t; - -struct DIDevice -{ - DIDEVICEINSTANCE JoystickInst; - LPDIRECTINPUTDEVICE2 Device; - - enum { KEYBOARD, JOYSTICK } type; - - bool buffered; - int buttons, axes, hats; - vector Inputs; - InputDevice dev; - - DIDevice() - { - buttons = axes = hats = 0; - dev = DEVICE_NONE; - buffered = true; - memset(&JoystickInst, 0, sizeof(JoystickInst)); - Device = NULL; - } -}; - static vector Devices; /* Number of joysticks found: */ static int g_NumJoysticks; + static BOOL CALLBACK EnumDevices( const DIDEVICEINSTANCE *pdidInstance, void *pContext ) { DIDevice device; @@ -95,6 +57,7 @@ static BOOL CALLBACK EnumDevices( const DIDEVICEINSTANCE *pdidInstance, void *pC InputHandler_DInput::InputHandler_DInput() { + LOG->Trace( "InputHandler_DInput::InputHandler_DInput()" ); g_NumJoysticks = 0; AppInstance inst; @@ -102,6 +65,7 @@ InputHandler_DInput::InputHandler_DInput() if ( hr != DI_OK ) RageException::Throw( hr_ssprintf(hr, "InputHandler_DInput: DirectInputCreate") ); + LOG->Trace( "InputHandler_DInput::IDirectInput_EnumDevices()" ); hr = IDirectInput_EnumDevices(dinput, 0 /*DIDEVTYPE_KEYBOARD*/, EnumDevices, NULL, DIEDFL_ATTACHEDONLY ); if ( hr != DI_OK ) RageException::Throw( hr_ssprintf(hr, "InputHandler_DInput: IDirectInput_EnumDevices") ); @@ -134,299 +98,41 @@ InputHandler_DInput::InputHandler_DInput() } } -static HWND GetHwnd() -{ - SDL_SysWMinfo info; - SDL_VERSION(&info.version); - if( SDL_GetWMInfo(&info) < 0 ) - RageException::Throw( "SDL_GetWMInfo failed" ); - - return info.window; -} - -static BOOL CALLBACK DIJoystick_EnumDevObjectsProc(LPCDIDEVICEOBJECTINSTANCE dev, - LPVOID data) -{ - DIDevice *device = (DIDevice *) data; - HRESULT hr; - - input_t in; - const int SupportedMask = DIDFT_BUTTON | DIDFT_POV | DIDFT_AXIS; - if(!(dev->dwType & SupportedMask)) - return DIENUM_CONTINUE; /* unsupported */ - - in.ofs = dev->dwOfs; - - if(dev->dwType & DIDFT_BUTTON) { - if( device->buttons == 24 ) - return DIENUM_CONTINUE; /* too many buttons */ - - in.type = in.BUTTON; - in.num = device->buttons; - device->buttons++; - } else if(dev->dwType & DIDFT_POV) { - in.type = in.HAT; - in.num = device->hats; - device->hats++; - } else { /* dev->dwType & DIDFT_AXIS */ - DIPROPRANGE diprg; - DIPROPDWORD dilong; - - in.type = in.AXIS; - in.num = device->axes; - - diprg.diph.dwSize = sizeof(diprg); - diprg.diph.dwHeaderSize = sizeof(diprg.diph); - diprg.diph.dwObj = dev->dwOfs; - diprg.diph.dwHow = DIPH_BYOFFSET; - diprg.lMin = -100; - diprg.lMax = 100; - - hr = IDirectInputDevice2_SetProperty(device->Device, DIPROP_RANGE, &diprg.diph); - if ( hr != DI_OK ) - return DIENUM_CONTINUE; /* don't use this axis */ - - /* Set dead zone to 0. */ - dilong.diph.dwSize = sizeof(dilong); - dilong.diph.dwHeaderSize = sizeof(dilong.diph); - dilong.diph.dwObj = dev->dwOfs; - dilong.diph.dwHow = DIPH_BYOFFSET; - dilong.dwData = 0; - hr = IDirectInputDevice2_SetProperty(device->Device, DIPROP_DEADZONE, &dilong.diph); - if ( hr != DI_OK ) - return DIENUM_CONTINUE; /* don't use this axis */ - - device->axes++; - } - - device->Inputs.push_back(in); - - return DIENUM_CONTINUE; -} - -static int ConvertScancodeToKey( int scancode ) -{ - switch(scancode) - { - case DIK_ESCAPE: return SDLK_ESCAPE; - case DIK_1: return SDLK_1; - case DIK_2: return SDLK_2; - case DIK_3: return SDLK_3; - case DIK_4: return SDLK_4; - case DIK_5: return SDLK_5; - case DIK_6: return SDLK_6; - case DIK_7: return SDLK_7; - case DIK_8: return SDLK_8; - case DIK_9: return SDLK_9; - case DIK_0: return SDLK_0; - case DIK_MINUS: return SDLK_MINUS; - case DIK_EQUALS: return SDLK_EQUALS; - case DIK_BACK: return SDLK_BACKSPACE; - case DIK_TAB: return SDLK_TAB; - case DIK_Q: return SDLK_q; - case DIK_W: return SDLK_w; - case DIK_E: return SDLK_e; - case DIK_R: return SDLK_r; - case DIK_T: return SDLK_t; - case DIK_Y: return SDLK_y; - case DIK_U: return SDLK_u; - case DIK_I: return SDLK_i; - case DIK_O: return SDLK_o; - case DIK_P: return SDLK_p; - case DIK_LBRACKET: return SDLK_LEFTBRACKET; - case DIK_RBRACKET: return SDLK_RIGHTBRACKET; - case DIK_RETURN: return SDLK_RETURN; - case DIK_LCONTROL: return SDLK_LCTRL; - case DIK_A: return SDLK_a; - case DIK_S: return SDLK_s; - case DIK_D: return SDLK_d; - case DIK_F: return SDLK_f; - case DIK_G: return SDLK_g; - case DIK_H: return SDLK_h; - case DIK_J: return SDLK_j; - case DIK_K: return SDLK_k; - case DIK_L: return SDLK_l; - case DIK_SEMICOLON: return SDLK_SEMICOLON; - case DIK_APOSTROPHE: return SDLK_QUOTE; - case DIK_GRAVE: return SDLK_BACKQUOTE; - case DIK_LSHIFT: return SDLK_LSHIFT; - case DIK_BACKSLASH: return SDLK_BACKSLASH; - case DIK_OEM_102: return SDLK_BACKSLASH; - case DIK_Z: return SDLK_z; - case DIK_X: return SDLK_x; - case DIK_C: return SDLK_c; - case DIK_V: return SDLK_v; - case DIK_B: return SDLK_b; - case DIK_N: return SDLK_n; - case DIK_M: return SDLK_m; - case DIK_COMMA: return SDLK_COMMA; - case DIK_PERIOD: return SDLK_PERIOD; - case DIK_SLASH: return SDLK_SLASH; - case DIK_RSHIFT: return SDLK_RSHIFT; - case DIK_MULTIPLY: return SDLK_KP_MULTIPLY; - case DIK_LMENU: return SDLK_LALT; - case DIK_SPACE: return SDLK_SPACE; - case DIK_CAPITAL: return SDLK_CAPSLOCK; - case DIK_F1: return SDLK_F1; - case DIK_F2: return SDLK_F2; - case DIK_F3: return SDLK_F3; - case DIK_F4: return SDLK_F4; - case DIK_F5: return SDLK_F5; - case DIK_F6: return SDLK_F6; - case DIK_F7: return SDLK_F7; - case DIK_F8: return SDLK_F8; - case DIK_F9: return SDLK_F9; - case DIK_F10: return SDLK_F10; - case DIK_NUMLOCK: return SDLK_NUMLOCK; - case DIK_SCROLL: return SDLK_SCROLLOCK; - case DIK_NUMPAD7: return SDLK_KP7; - case DIK_NUMPAD8: return SDLK_KP8; - case DIK_NUMPAD9: return SDLK_KP9; - case DIK_SUBTRACT: return SDLK_KP_MINUS; - case DIK_NUMPAD4: return SDLK_KP4; - case DIK_NUMPAD5: return SDLK_KP5; - case DIK_NUMPAD6: return SDLK_KP6; - case DIK_ADD: return SDLK_KP_PLUS; - case DIK_NUMPAD1: return SDLK_KP1; - case DIK_NUMPAD2: return SDLK_KP2; - case DIK_NUMPAD3: return SDLK_KP3; - case DIK_NUMPAD0: return SDLK_KP0; - case DIK_DECIMAL: return SDLK_KP_PERIOD; - case DIK_F11: return SDLK_F11; - case DIK_F12: return SDLK_F12; - - case DIK_F13: return SDLK_F13; - case DIK_F14: return SDLK_F14; - case DIK_F15: return SDLK_F15; - - case DIK_NUMPADEQUALS: return SDLK_KP_EQUALS; - case DIK_NUMPADENTER: return SDLK_KP_ENTER; - case DIK_RCONTROL: return SDLK_RCTRL; - case DIK_DIVIDE: return SDLK_KP_DIVIDE; - case DIK_SYSRQ: return SDLK_SYSREQ; - case DIK_RMENU: return SDLK_RALT; - case DIK_PAUSE: return SDLK_PAUSE; - case DIK_HOME: return SDLK_HOME; - case DIK_UP: return SDLK_UP; - case DIK_PRIOR: return SDLK_PAGEUP; - case DIK_LEFT: return SDLK_LEFT; - case DIK_RIGHT: return SDLK_RIGHT; - case DIK_END: return SDLK_END; - case DIK_DOWN: return SDLK_DOWN; - case DIK_NEXT: return SDLK_PAGEDOWN; - case DIK_INSERT: return SDLK_INSERT; - case DIK_DELETE: return SDLK_DELETE; - case DIK_LWIN: return SDLK_LMETA; - case DIK_RWIN: return SDLK_RMETA; - case DIK_APPS: return SDLK_MENU; - default: return '?'; - }; -} - +/* device.JoystickInst and device.dev must be filled in. Opens the device and + * fills in the remaining parameters. */ bool InputHandler_DInput::OpenDevice(DIDevice &device) { - LOG->Trace( "Opening device '%s'", device.JoystickInst.tszProductName ); - device.buffered = true; - - LPDIRECTINPUTDEVICE tmpdevice; - HRESULT hr = IDirectInput_CreateDevice(dinput, device.JoystickInst.guidInstance, - &tmpdevice, NULL); - if ( hr != DI_OK ) - { - LOG->Info( hr_ssprintf(hr, "OpenDevice: IDirectInput_CreateDevice") ); - return false; - } - - hr = IDirectInputDevice_QueryInterface(tmpdevice, - IID_IDirectInputDevice2, (LPVOID *) &device.Device); - IDirectInputDevice_Release(tmpdevice); - if ( hr != DI_OK ) - { - LOG->Info( hr_ssprintf(hr, "OpenDevice(%s): IDirectInputDevice_QueryInterface", device.JoystickInst.tszProductName) ); - return false; - } - - int coop = DISCL_NONEXCLUSIVE | DISCL_BACKGROUND; - if( device.type == device.KEYBOARD ) - coop = DISCL_FOREGROUND|DISCL_NONEXCLUSIVE; - - hr = IDirectInputDevice2_SetCooperativeLevel( device.Device, GetHwnd(), coop ); - if ( hr != DI_OK ) - { - LOG->Info( hr_ssprintf(hr, "OpenDevice(%s): IDirectInputDevice2_SetCooperativeLevel", device.JoystickInst.tszProductName) ); - return false; - } - - hr = IDirectInputDevice2_SetDataFormat(device.Device, - device.type == device.JOYSTICK? &c_dfDIJoystick: &c_dfDIKeyboard); - if ( hr != DI_OK ) - { - LOG->Info( hr_ssprintf(hr, "OpenDevice(%s): IDirectInputDevice2_SetDataFormat", device.JoystickInst.tszProductName) ); - return false; - } - - switch( device.type ) - { - case device.JOYSTICK: - IDirectInputDevice2_EnumObjects(device.Device, - DIJoystick_EnumDevObjectsProc, - &device, - DIDFT_BUTTON | DIDFT_AXIS | DIDFT_POV); - break; - case device.KEYBOARD: - /* Always 256-button. */ - for( int b = 0; b < 256; ++b ) - { - input_t in; - in.type = in.KEY; - - in.num = ConvertScancodeToKey(b); - in.ofs = b; - device.buttons++; - device.Inputs.push_back(in); - } - break; - } - - { - DIPROPDWORD dipdw; - memset(&dipdw, 0, sizeof(dipdw)); - dipdw.diph.dwSize = sizeof(dipdw); - dipdw.diph.dwHeaderSize = sizeof(dipdw.diph); - dipdw.diph.dwObj = 0; - dipdw.diph.dwHow = DIPH_DEVICE; - dipdw.dwData = INPUT_QSIZE; - hr = IDirectInputDevice2_SetProperty(device.Device, - DIPROP_BUFFERSIZE, &dipdw.diph); - /* XXX: Try to use event notification. It might give better response in a thread. */ - if ( hr == DI_POLLEDDEVICE ) - { - /* This device doesn't support buffering, so we're forced - * to use less reliable polling. */ - device.buffered = false; - } else if ( hr != DI_OK ) { - LOG->Info( hr_ssprintf(hr, "OpenDevice(%s): IDirectInputDevice2_SetProperty", device.JoystickInst.tszProductName) ); - return false; - } - } - - return true; + return device.Open(); } + InputHandler_DInput::~InputHandler_DInput() { for( unsigned i = 0; i < Devices.size(); ++i ) - { - IDirectInputDevice2_Unacquire(Devices[i].Device); - IDirectInputDevice2_Release(Devices[i].Device); - } + Devices[i].Close(); Devices.clear(); IDirectInput_Release(dinput); dinput = NULL; } +void InputHandler_DInput::WindowReset() +{ + /* We need to reopen keyboards. */ + for( unsigned i = 0; i < Devices.size(); ++i ) + { + if( Devices[i].type != Devices[i].KEYBOARD ) + continue; + + Devices[i].Close(); + bool ret = Devices[i].Open(); + + /* Reopening it should succeed. */ + ASSERT( ret ); + } +} + static int TranslatePOV(DWORD value) { const int HAT_VALS[] = { @@ -458,7 +164,13 @@ HRESULT GetDeviceState(LPDIRECTINPUTDEVICE2 dev, int size, void *ptr) { HRESULT hr = IDirectInputDevice2_GetDeviceState(dev, size, ptr); if ( hr == DIERR_INPUTLOST || hr == DIERR_NOTACQUIRED ) { - IDirectInputDevice2_Acquire(dev); + hr = IDirectInputDevice2_Acquire(dev); + if ( hr != DI_OK ) + { + LOG->Trace( hr_ssprintf(hr, "?") ); + return hr; + } + hr = IDirectInputDevice2_GetDeviceState(dev, size, ptr); } @@ -475,11 +187,18 @@ void UpdatePolled(DIDevice &device) if ( hr == DIERR_INPUTLOST || hr == DIERR_NOTACQUIRED ) return; + if ( hr != DI_OK ) + { + LOG->MapLog( "UpdatePolled", hr_ssprintf(hr, "Failures on polled keyboard update") ); + return; + } + for( int k = 0; k < 256; ++k ) { const int key = device.Inputs[k].num; INPUTFILTER->ButtonPressed(DeviceInput(device.dev, key), !!(keys[k] & 0x80)); } + return; } DIJOYSTATE state; @@ -500,8 +219,8 @@ void UpdatePolled(DIDevice &device) { DeviceInput di(dev, JOY_1 + in.num); INPUTFILTER->ButtonPressed(di, !!state.rgbButtons[in.ofs - DIJOFS_BUTTON0]); - } break; + } case in.AXIS: { @@ -526,9 +245,9 @@ void UpdatePolled(DIDevice &device) INPUTFILTER->ButtonPressed(DeviceInput(dev, JOY_ROT_Z_DOWN), state.lRz > 50); break; } - } break; + } case in.HAT: { @@ -541,7 +260,7 @@ void UpdatePolled(DIDevice &device) INPUTFILTER->ButtonPressed(DeviceInput(dev, JOY_HAT_RIGHT), !!(pos & SDL_HAT_RIGHT)); break; - } + } } } } @@ -632,7 +351,12 @@ void InputHandler_DInput::Update(float fDeltaTime) HRESULT hr = IDirectInputDevice2_Poll( Devices[i].Device ); if ( hr == DIERR_INPUTLOST || hr == DIERR_NOTACQUIRED ) { - IDirectInputDevice2_Acquire( Devices[i].Device ); + /* This will fail with "access denied" on the keyboard if we don't + * have focus. */ + hr = IDirectInputDevice2_Acquire( Devices[i].Device ); + if ( hr != DI_OK ) + continue; + IDirectInputDevice2_Poll( Devices[i].Device ); } diff --git a/stepmania/src/arch/InputHandler/InputHandler_DirectInput.h b/stepmania/src/arch/InputHandler/InputHandler_DirectInput.h index c5b58ecd73..a14b1f0f28 100644 --- a/stepmania/src/arch/InputHandler/InputHandler_DirectInput.h +++ b/stepmania/src/arch/InputHandler/InputHandler_DirectInput.h @@ -13,6 +13,7 @@ public: ~InputHandler_DInput(); void GetDevicesAndDescriptions(vector& vDevicesOut, vector& vDescriptionsOut); void Update(float fDeltaTime); + void WindowReset(); }; #endif diff --git a/stepmania/src/arch/InputHandler/InputHandler_DirectInputHelper.cpp b/stepmania/src/arch/InputHandler/InputHandler_DirectInputHelper.cpp new file mode 100644 index 0000000000..a01d6cfaff --- /dev/null +++ b/stepmania/src/arch/InputHandler/InputHandler_DirectInputHelper.cpp @@ -0,0 +1,310 @@ +#include "global.h" +#include "InputHandler_DirectInputHelper.h" +#include "RageUtil.h" +#include "RageLog.h" +#include "SDL_utils.h" + +#pragma comment(lib, "dinput.lib") +LPDIRECTINPUT dinput = NULL; + +static int ConvertScancodeToKey( int scancode ); +static BOOL CALLBACK DIJoystick_EnumDevObjectsProc(LPCDIDEVICEOBJECTINSTANCE dev, LPVOID data); +static HWND GetHwnd(); + +DIDevice::DIDevice() +{ + buttons = axes = hats = 0; + dev = DEVICE_NONE; + buffered = true; + memset(&JoystickInst, 0, sizeof(JoystickInst)); + Device = NULL; +} + +bool DIDevice::Open() +{ + LOG->Trace( "Opening device '%s'", JoystickInst.tszProductName ); + buffered = true; + + LPDIRECTINPUTDEVICE tmpdevice; + HRESULT hr = IDirectInput_CreateDevice(dinput, JoystickInst.guidInstance, + &tmpdevice, NULL); + if ( hr != DI_OK ) + { + LOG->Info( hr_ssprintf(hr, "OpenDevice: IDirectInput_CreateDevice") ); + return false; + } + + hr = IDirectInputDevice_QueryInterface(tmpdevice, + IID_IDirectInputDevice2, (LPVOID *) &Device); + IDirectInputDevice_Release(tmpdevice); + if ( hr != DI_OK ) + { + LOG->Info( hr_ssprintf(hr, "OpenDevice(%s): IDirectInputDevice_QueryInterface", JoystickInst.tszProductName) ); + return false; + } + + int coop = DISCL_NONEXCLUSIVE | DISCL_BACKGROUND; + if( type == KEYBOARD ) + coop = DISCL_FOREGROUND|DISCL_NONEXCLUSIVE; + + hr = IDirectInputDevice2_SetCooperativeLevel( Device, GetHwnd(), coop ); + if ( hr != DI_OK ) + { + LOG->Info( hr_ssprintf(hr, "OpenDevice(%s): IDirectInputDevice2_SetCooperativeLevel", JoystickInst.tszProductName) ); + return false; + } + + hr = IDirectInputDevice2_SetDataFormat(Device, + type == JOYSTICK? &c_dfDIJoystick: &c_dfDIKeyboard); + if ( hr != DI_OK ) + { + LOG->Info( hr_ssprintf(hr, "OpenDevice(%s): IDirectInputDevice2_SetDataFormat", JoystickInst.tszProductName) ); + return false; + } + + switch( type ) + { + case JOYSTICK: + IDirectInputDevice2_EnumObjects(Device, DIJoystick_EnumDevObjectsProc, + this, DIDFT_BUTTON | DIDFT_AXIS | DIDFT_POV); + break; + case KEYBOARD: + /* Always 256-button. */ + for( int b = 0; b < 256; ++b ) + { + input_t in; + in.type = in.KEY; + + in.num = ConvertScancodeToKey(b); + in.ofs = b; + buttons++; + Inputs.push_back(in); + } + break; + } + + { + DIPROPDWORD dipdw; + memset(&dipdw, 0, sizeof(dipdw)); + dipdw.diph.dwSize = sizeof(dipdw); + dipdw.diph.dwHeaderSize = sizeof(dipdw.diph); + dipdw.diph.dwObj = 0; + dipdw.diph.dwHow = DIPH_DEVICE; + dipdw.dwData = INPUT_QSIZE; + hr = IDirectInputDevice2_SetProperty(Device, + DIPROP_BUFFERSIZE, &dipdw.diph); + /* XXX: Try to use event notification. It might give better response in a thread. */ + if ( hr == DI_POLLEDDEVICE ) + { + /* This device doesn't support buffering, so we're forced + * to use less reliable polling. */ + buffered = false; + } else if ( hr != DI_OK ) { + LOG->Info( hr_ssprintf(hr, "OpenDevice(%s): IDirectInputDevice2_SetProperty", JoystickInst.tszProductName) ); + return false; + } + } + + return true; +} + +void DIDevice::Close() +{ + /* Don't try to close a device that isn't open. */ + ASSERT( Device != NULL ); + + IDirectInputDevice2_Unacquire(Device); + IDirectInputDevice2_Release(Device); + + Device = NULL; + buttons = axes = hats = NULL; + Inputs.clear(); +} + +static BOOL CALLBACK DIJoystick_EnumDevObjectsProc(LPCDIDEVICEOBJECTINSTANCE dev, LPVOID data) +{ + DIDevice *device = (DIDevice *) data; + HRESULT hr; + + input_t in; + const int SupportedMask = DIDFT_BUTTON | DIDFT_POV | DIDFT_AXIS; + if(!(dev->dwType & SupportedMask)) + return DIENUM_CONTINUE; /* unsupported */ + + in.ofs = dev->dwOfs; + + if(dev->dwType & DIDFT_BUTTON) { + if( device->buttons == 24 ) + return DIENUM_CONTINUE; /* too many buttons */ + + in.type = in.BUTTON; + in.num = device->buttons; + device->buttons++; + } else if(dev->dwType & DIDFT_POV) { + in.type = in.HAT; + in.num = device->hats; + device->hats++; + } else { /* dev->dwType & DIDFT_AXIS */ + DIPROPRANGE diprg; + DIPROPDWORD dilong; + + in.type = in.AXIS; + in.num = device->axes; + + diprg.diph.dwSize = sizeof(diprg); + diprg.diph.dwHeaderSize = sizeof(diprg.diph); + diprg.diph.dwObj = dev->dwOfs; + diprg.diph.dwHow = DIPH_BYOFFSET; + diprg.lMin = -100; + diprg.lMax = 100; + + hr = IDirectInputDevice2_SetProperty(device->Device, DIPROP_RANGE, &diprg.diph); + if ( hr != DI_OK ) + return DIENUM_CONTINUE; /* don't use this axis */ + + /* Set dead zone to 0. */ + dilong.diph.dwSize = sizeof(dilong); + dilong.diph.dwHeaderSize = sizeof(dilong.diph); + dilong.diph.dwObj = dev->dwOfs; + dilong.diph.dwHow = DIPH_BYOFFSET; + dilong.dwData = 0; + hr = IDirectInputDevice2_SetProperty(device->Device, DIPROP_DEADZONE, &dilong.diph); + if ( hr != DI_OK ) + return DIENUM_CONTINUE; /* don't use this axis */ + + device->axes++; + } + + device->Inputs.push_back(in); + + return DIENUM_CONTINUE; +} + +static int ConvertScancodeToKey( int scancode ) +{ + switch(scancode) + { + case DIK_ESCAPE: return SDLK_ESCAPE; + case DIK_1: return SDLK_1; + case DIK_2: return SDLK_2; + case DIK_3: return SDLK_3; + case DIK_4: return SDLK_4; + case DIK_5: return SDLK_5; + case DIK_6: return SDLK_6; + case DIK_7: return SDLK_7; + case DIK_8: return SDLK_8; + case DIK_9: return SDLK_9; + case DIK_0: return SDLK_0; + case DIK_MINUS: return SDLK_MINUS; + case DIK_EQUALS: return SDLK_EQUALS; + case DIK_BACK: return SDLK_BACKSPACE; + case DIK_TAB: return SDLK_TAB; + case DIK_Q: return SDLK_q; + case DIK_W: return SDLK_w; + case DIK_E: return SDLK_e; + case DIK_R: return SDLK_r; + case DIK_T: return SDLK_t; + case DIK_Y: return SDLK_y; + case DIK_U: return SDLK_u; + case DIK_I: return SDLK_i; + case DIK_O: return SDLK_o; + case DIK_P: return SDLK_p; + case DIK_LBRACKET: return SDLK_LEFTBRACKET; + case DIK_RBRACKET: return SDLK_RIGHTBRACKET; + case DIK_RETURN: return SDLK_RETURN; + case DIK_LCONTROL: return SDLK_LCTRL; + case DIK_A: return SDLK_a; + case DIK_S: return SDLK_s; + case DIK_D: return SDLK_d; + case DIK_F: return SDLK_f; + case DIK_G: return SDLK_g; + case DIK_H: return SDLK_h; + case DIK_J: return SDLK_j; + case DIK_K: return SDLK_k; + case DIK_L: return SDLK_l; + case DIK_SEMICOLON: return SDLK_SEMICOLON; + case DIK_APOSTROPHE: return SDLK_QUOTE; + case DIK_GRAVE: return SDLK_BACKQUOTE; + case DIK_LSHIFT: return SDLK_LSHIFT; + case DIK_BACKSLASH: return SDLK_BACKSLASH; + case DIK_OEM_102: return SDLK_BACKSLASH; + case DIK_Z: return SDLK_z; + case DIK_X: return SDLK_x; + case DIK_C: return SDLK_c; + case DIK_V: return SDLK_v; + case DIK_B: return SDLK_b; + case DIK_N: return SDLK_n; + case DIK_M: return SDLK_m; + case DIK_COMMA: return SDLK_COMMA; + case DIK_PERIOD: return SDLK_PERIOD; + case DIK_SLASH: return SDLK_SLASH; + case DIK_RSHIFT: return SDLK_RSHIFT; + case DIK_MULTIPLY: return SDLK_KP_MULTIPLY; + case DIK_LMENU: return SDLK_LALT; + case DIK_SPACE: return SDLK_SPACE; + case DIK_CAPITAL: return SDLK_CAPSLOCK; + case DIK_F1: return SDLK_F1; + case DIK_F2: return SDLK_F2; + case DIK_F3: return SDLK_F3; + case DIK_F4: return SDLK_F4; + case DIK_F5: return SDLK_F5; + case DIK_F6: return SDLK_F6; + case DIK_F7: return SDLK_F7; + case DIK_F8: return SDLK_F8; + case DIK_F9: return SDLK_F9; + case DIK_F10: return SDLK_F10; + case DIK_NUMLOCK: return SDLK_NUMLOCK; + case DIK_SCROLL: return SDLK_SCROLLOCK; + case DIK_NUMPAD7: return SDLK_KP7; + case DIK_NUMPAD8: return SDLK_KP8; + case DIK_NUMPAD9: return SDLK_KP9; + case DIK_SUBTRACT: return SDLK_KP_MINUS; + case DIK_NUMPAD4: return SDLK_KP4; + case DIK_NUMPAD5: return SDLK_KP5; + case DIK_NUMPAD6: return SDLK_KP6; + case DIK_ADD: return SDLK_KP_PLUS; + case DIK_NUMPAD1: return SDLK_KP1; + case DIK_NUMPAD2: return SDLK_KP2; + case DIK_NUMPAD3: return SDLK_KP3; + case DIK_NUMPAD0: return SDLK_KP0; + case DIK_DECIMAL: return SDLK_KP_PERIOD; + case DIK_F11: return SDLK_F11; + case DIK_F12: return SDLK_F12; + + case DIK_F13: return SDLK_F13; + case DIK_F14: return SDLK_F14; + case DIK_F15: return SDLK_F15; + + case DIK_NUMPADEQUALS: return SDLK_KP_EQUALS; + case DIK_NUMPADENTER: return SDLK_KP_ENTER; + case DIK_RCONTROL: return SDLK_RCTRL; + case DIK_DIVIDE: return SDLK_KP_DIVIDE; + case DIK_SYSRQ: return SDLK_SYSREQ; + case DIK_RMENU: return SDLK_RALT; + case DIK_PAUSE: return SDLK_PAUSE; + case DIK_HOME: return SDLK_HOME; + case DIK_UP: return SDLK_UP; + case DIK_PRIOR: return SDLK_PAGEUP; + case DIK_LEFT: return SDLK_LEFT; + case DIK_RIGHT: return SDLK_RIGHT; + case DIK_END: return SDLK_END; + case DIK_DOWN: return SDLK_DOWN; + case DIK_NEXT: return SDLK_PAGEDOWN; + case DIK_INSERT: return SDLK_INSERT; + case DIK_DELETE: return SDLK_DELETE; + case DIK_LWIN: return SDLK_LMETA; + case DIK_RWIN: return SDLK_RMETA; + case DIK_APPS: return SDLK_MENU; + default: return '?'; + }; +} + +static HWND GetHwnd() +{ + SDL_SysWMinfo info; + SDL_VERSION(&info.version); + if( SDL_GetWMInfo(&info) < 0 ) + RageException::Throw( "SDL_GetWMInfo failed" ); + + return info.window; +} diff --git a/stepmania/src/arch/InputHandler/InputHandler_DirectInputHelper.h b/stepmania/src/arch/InputHandler/InputHandler_DirectInputHelper.h new file mode 100644 index 0000000000..def9faee65 --- /dev/null +++ b/stepmania/src/arch/InputHandler/InputHandler_DirectInputHelper.h @@ -0,0 +1,41 @@ +#ifndef INPUTHANDLER_DIRECTINPUT_HELPER_H +#define INPUTHANDLER_DIRECTINPUT_HELPER_H + +#include "InputFilter.h" + +#define DIRECTINPUT_VERSION 0x0500 +#include +extern LPDIRECTINPUT dinput; + +#define INPUT_QSIZE 32 + +typedef struct input_t +{ + /* DirectInput offset for this input type: */ + DWORD ofs; + + /* Button, axis or hat: */ + enum Type { KEY, BUTTON, AXIS, HAT } type; + + int num; +} input_t; + +struct DIDevice +{ + DIDEVICEINSTANCE JoystickInst; + LPDIRECTINPUTDEVICE2 Device; + + enum { KEYBOARD, JOYSTICK } type; + + bool buffered; + int buttons, axes, hats; + vector Inputs; + InputDevice dev; + + DIDevice(); + + bool Open(); + void Close(); +}; + +#endif