split this up
Fix losing keyboard input when changing graphics settings (this happened with the old code, too).
This commit is contained in:
@@ -49,3 +49,9 @@ void RageInput::GetDevicesAndDescriptions(vector<InputDevice>& 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();
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ public:
|
||||
|
||||
void Update( float fDeltaTime );
|
||||
void GetDevicesAndDescriptions(vector<InputDevice>& vDevicesOut, vector<CString>& vDescriptionsOut);
|
||||
void WindowReset();
|
||||
};
|
||||
|
||||
extern RageInput* INPUTMAN; // global and accessable from anywhere in our program
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -523,9 +523,6 @@ cl /Zl /nologo /c verstub.cpp /Fo"$(IntDir)"\
|
||||
<File
|
||||
RelativePath="ScreenUnlock.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="ScreenWarning.h">
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Data Structures"
|
||||
@@ -722,6 +719,9 @@ cl /Zl /nologo /c verstub.cpp /Fo"$(IntDir)"\
|
||||
<File
|
||||
RelativePath="RaveHelper.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="ScreenWarning.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Song.cpp">
|
||||
</File>
|
||||
@@ -920,6 +920,12 @@ cl /Zl /nologo /c verstub.cpp /Fo"$(IntDir)"\
|
||||
<File
|
||||
RelativePath="arch\InputHandler\InputHandler_DirectInput.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="arch\InputHandler\InputHandler_DirectInputHelper.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="arch\InputHandler\InputHandler_DirectInputHelper.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="arch\InputHandler\InputHandler_Win32_Pump.cpp">
|
||||
</File>
|
||||
|
||||
@@ -30,6 +30,10 @@ public:
|
||||
virtual void Update(float fDeltaTime) { }
|
||||
virtual ~InputHandler() { }
|
||||
virtual void GetDevicesAndDescriptions(vector<InputDevice>& vDevicesOut, vector<CString>& 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
|
||||
|
||||
@@ -10,56 +10,18 @@
|
||||
#include "archutils/Win32/AppInstance.h"
|
||||
#include "InputFilter.h"
|
||||
|
||||
#define DIRECTINPUT_VERSION 0x0500
|
||||
#include <dinput.h>
|
||||
#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<input_t> Inputs;
|
||||
InputDevice dev;
|
||||
|
||||
DIDevice()
|
||||
{
|
||||
buttons = axes = hats = 0;
|
||||
dev = DEVICE_NONE;
|
||||
buffered = true;
|
||||
memset(&JoystickInst, 0, sizeof(JoystickInst));
|
||||
Device = NULL;
|
||||
}
|
||||
};
|
||||
|
||||
static vector<DIDevice> 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 );
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ public:
|
||||
~InputHandler_DInput();
|
||||
void GetDevicesAndDescriptions(vector<InputDevice>& vDevicesOut, vector<CString>& vDescriptionsOut);
|
||||
void Update(float fDeltaTime);
|
||||
void WindowReset();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
#ifndef INPUTHANDLER_DIRECTINPUT_HELPER_H
|
||||
#define INPUTHANDLER_DIRECTINPUT_HELPER_H
|
||||
|
||||
#include "InputFilter.h"
|
||||
|
||||
#define DIRECTINPUT_VERSION 0x0500
|
||||
#include <dinput.h>
|
||||
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<input_t> Inputs;
|
||||
InputDevice dev;
|
||||
|
||||
DIDevice();
|
||||
|
||||
bool Open();
|
||||
void Close();
|
||||
};
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user