Use SDL events for keyboard and joystick input. It's simpler.

It's also the "preferred" way of doing it, according to the SDL
docs, so maybe it'll work better.

This will reliably queue events, so we can handle coin events during
loads.

It'll queue events a little too reliably; we might want to flush some events
when we load screens.
This commit is contained in:
Glenn Maynard
2003-02-16 01:35:48 +00:00
parent 70524dcb6a
commit 7578257a17
8 changed files with 169 additions and 422 deletions
+58 -305
View File
@@ -10,40 +10,14 @@
-----------------------------------------------------------------------------
*/
//-----------------------------------------------------------------------------
// In-line Links
//-----------------------------------------------------------------------------
#pragma comment(lib, "ddk/setupapi.lib")
#pragma comment(lib, "ddk/hid.lib")
//-----------------------------------------------------------------------------
// Includes
//-----------------------------------------------------------------------------
#include "RageInput.h"
#include "SDL.h"
#include "SDL_keyboard.h"
#include "RageUtil.h"
#include "SDL_utils.h"
#include "RageLog.h"
#include "RageException.h"
#include "InputFilter.h"
RageInput* INPUTMAN = NULL; // globally accessable input device
struct RageInput::pump_t
{
HANDLE h;
OVERLAPPED ov;
long buf;
bool pending;
pump_t();
~pump_t();
void Update();
bool init(int devno);
int GetPadEvent();
bool current_state[NUM_PUMP_PAD_BUTTONS];
};
RageInput::RageInput()
{
@@ -51,9 +25,6 @@ RageInput::RageInput()
SDL_InitSubSystem( SDL_INIT_JOYSTICK );
// init state info
memset( state, 0, sizeof(state) );
//
// Init keyboard
@@ -68,310 +39,92 @@ RageInput::RageInput()
//
// Init joysticks
//
memset( m_pJoystick, 0, sizeof(m_pJoystick) );
int iNumJoySticks = min( SDL_NumJoysticks(), NUM_JOYSTICKS );
LOG->Info( "Found %d joysticks", iNumJoySticks );
for( int i=0; i<iNumJoySticks; i++ )
{
m_pJoystick[i] = SDL_JoystickOpen( i );
SDL_Joystick *pJoystick = SDL_JoystickOpen( i );
LOG->Info( " %d: '%s' axes: %d, hats: %d, buttons: %d",
i,
SDL_JoystickName(i),
SDL_JoystickNumAxes(m_pJoystick[i]),
SDL_JoystickNumHats(m_pJoystick[i]),
SDL_JoystickNumButtons(m_pJoystick[i]) );
SDL_JoystickNumAxes(pJoystick),
SDL_JoystickNumHats(pJoystick),
SDL_JoystickNumButtons(pJoystick) );
SDL_JoystickClose(pJoystick);
}
SDL_JoystickEventState( SDL_IGNORE );
SDL_JoystickEventState( SDL_ENABLE );
//
// Init pumps
// Init pump
//
m_Pumps = new pump_t[NUM_PUMPS];
for(int pumpNo = 0; pumpNo < NUM_PUMPS; ++pumpNo)
{
if(m_Pumps[pumpNo].init(pumpNo))
LOG->Info("Found Pump pad %i", pumpNo);
}
m_Pump = new PumpPadDevice;
}
RageInput::~RageInput()
{
//
// De-init keyboard
// De-init pump
//
//
// De-init joysticks
//
for( int i=0; i<NUM_JOYSTICKS; i++ )
{
if( m_pJoystick[i] )
{
SDL_JoystickClose(m_pJoystick[i]);
m_pJoystick[i] = NULL;
}
}
//
// De-init pumps
//
delete[] m_Pumps;
delete m_Pump;
SDL_QuitSubSystem( SDL_INIT_JOYSTICK );
}
void RageInput::Update( float fDeltaTime )
{
//
// Move last current state to old state
//
memcpy( &state[LAST], &state[CURRENT], sizeof(state[LAST]) );
//
// Update keyboard
//
SDL_PumpEvents();
Uint8* keystate = SDL_GetKeyState(NULL);
memcpy( state[CURRENT].m_Devices[DEVICE_KEYBOARD].button, keystate, NUM_KEYBOARD_BUTTONS );
//
// Update Joystick
//
SDL_JoystickUpdate();
for( int joy=0; joy<NUM_JOYSTICKS; joy++ ) // foreach joystick
{
state_t::device_t *dev = &state[CURRENT].m_Devices[DEVICE_JOY1+joy];
memset( dev->button, 0, sizeof(dev->button) ); // clear current state
SDL_Joystick* pJoy = m_pJoystick[joy];
if( !pJoy )
continue;
int iNumJoyAxes = min(NUM_JOYSTICK_AXES,SDL_JoystickNumAxes(pJoy));
for( int axis=0; axis<iNumJoyAxes; axis++ )
{
Sint16 val = SDL_JoystickGetAxis(pJoy,axis);
// LOG->Trace( "axis %d = %d", axis, val );
if( val < -16000 )
{
JoystickButton b = (JoystickButton)(JOY_LEFT+2*axis);
dev->button[b] = true;
}
else if( val > +16000 )
{
JoystickButton b = (JoystickButton)(JOY_RIGHT+2*axis);
dev->button[b] = true;
}
}
int iNumJoyHats = min(NUM_JOYSTICK_HATS,SDL_JoystickNumHats(pJoy));
for( int hat=0; hat<iNumJoyHats; hat++ )
{
Uint8 val = SDL_JoystickGetHat(pJoy,hat);
dev->button[JOY_HAT_UP] = (val & SDL_HAT_UP) != 0;
dev->button[JOY_HAT_RIGHT] = (val & SDL_HAT_RIGHT) != 0;
dev->button[JOY_HAT_DOWN] = (val & SDL_HAT_DOWN) != 0;
dev->button[JOY_HAT_LEFT] = (val & SDL_HAT_LEFT) != 0;
}
int iNumJoyButtons = MIN(NUM_JOYSTICK_BUTTONS,SDL_JoystickNumButtons(pJoy));
for( int button=0; button<iNumJoyButtons; button++ )
{
JoystickButton b = (JoystickButton)(JOY_1 + button);
dev->button[b] = SDL_JoystickGetButton(pJoy,button) != 0;
}
}
//
// Update Pump
//
for( int i=0; i<NUM_PUMPS; i++ )
m_Pumps[i].Update();
memcpy(state[CURRENT].m_Devices[DEVICE_PUMP1].button, m_Pumps[0].current_state, sizeof(m_Pumps[0].current_state));
memcpy(state[CURRENT].m_Devices[DEVICE_PUMP2].button, m_Pumps[1].current_state, sizeof(m_Pumps[0].current_state));
m_Pump->Update();
}
bool RageInput::BeingPressed( DeviceInput di, bool bPrevState )
bool RageInput::FeedSDLEvent(const SDL_Event &event)
{
ASSERT(di.button < NUM_DEVICE_BUTTONS);
ASSERT(di.device < NUM_INPUT_DEVICES);
State s = bPrevState? LAST:CURRENT;
return state[s].m_Devices[di.device].button[ di.button ];
}
extern "C" {
#include "ddk/setupapi.h"
/* Quiet header warning: */
#pragma warning( push )
#pragma warning (disable : 4201)
#include "ddk/hidsdi.h"
#pragma warning( pop )
}
char *USB::GetUSBDevicePath (int num)
{
GUID guid;
HidD_GetHidGuid(&guid);
HDEVINFO DeviceInfo = SetupDiGetClassDevs (&guid,
NULL, NULL, (DIGCF_PRESENT | DIGCF_DEVICEINTERFACE));
SP_DEVICE_INTERFACE_DATA DeviceInterface;
DeviceInterface.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
char *ret = NULL;
PSP_INTERFACE_DEVICE_DETAIL_DATA DeviceDetail = NULL;
if (!SetupDiEnumDeviceInterfaces (DeviceInfo,
NULL, &guid, num, &DeviceInterface))
goto err;
unsigned long size;
SetupDiGetDeviceInterfaceDetail (DeviceInfo, &DeviceInterface, NULL, 0, &size, 0);
DeviceDetail = (PSP_INTERFACE_DEVICE_DETAIL_DATA) malloc(size);
DeviceDetail->cbSize = sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA);
if (SetupDiGetDeviceInterfaceDetail (DeviceInfo, &DeviceInterface,
DeviceDetail, size, &size, NULL))
{
ret = strdup(DeviceDetail->DevicePath);
}
err:
SetupDiDestroyDeviceInfoList (DeviceInfo);
free (DeviceDetail);
return ret;
}
HANDLE USB::OpenUSB (int VID, int PID, int num)
{
DWORD index = 0;
char *path;
HANDLE h = INVALID_HANDLE_VALUE;
while ((path = GetUSBDevicePath (index++)) != NULL)
{
if(h != INVALID_HANDLE_VALUE)
CloseHandle (h);
h = CreateFile (path, GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
free(path);
if(h == INVALID_HANDLE_VALUE)
continue;
HIDD_ATTRIBUTES attr;
if (!HidD_GetAttributes (h, &attr))
continue;
if ((VID != -1 && attr.VendorID != VID) &&
(PID != -1 && attr.ProductID != PID))
continue; /* This isn't it. */
/* The VID and PID match. */
if(num-- == 0)
return h;
}
if(h != INVALID_HANDLE_VALUE)
CloseHandle (h);
return INVALID_HANDLE_VALUE;
}
RageInput::pump_t::pump_t()
{
ZeroMemory( &ov, sizeof(ov) );
memset(current_state, 0, sizeof(current_state));
pending=false;
h = INVALID_HANDLE_VALUE;
}
RageInput::pump_t::~pump_t()
{
if(h != INVALID_HANDLE_VALUE)
CloseHandle(h);
}
bool RageInput::pump_t::init(int devno)
{
const int pump_usb_vid = 0x0d2f, pump_usb_pid = 0x0001;
h = USB::OpenUSB (pump_usb_vid, pump_usb_pid, devno);
return h != INVALID_HANDLE_VALUE;
}
int RageInput::pump_t::GetPadEvent()
{
int ret;
if(!pending)
{
/* Request feedback from the device. */
unsigned long r;
ret = ReadFile(h, &buf, sizeof(buf), &r, &ov);
pending=true;
}
/* See if we have a response for our request (which we may
* have made on a previous cal): */
if(WaitForSingleObjectEx(h, 0, TRUE) == WAIT_TIMEOUT)
return -1;
/* We do; get the result. It'll go into the original &buf
* we supplied on the original call; that's why buf is a
* member instead of a local. */
unsigned long cnt;
ret = GetOverlappedResult(h, &ov, &cnt, FALSE);
pending=false;
if(ret == 0 && (GetLastError() == ERROR_IO_PENDING || GetLastError() == ERROR_IO_INCOMPLETE))
return -1;
if(ret == 0) {
LOG->Warn(werr_ssprintf(GetLastError(), "Error reading Pump pad"));
return -1;
}
return buf;
}
void RageInput::pump_t::Update()
{
if(h == INVALID_HANDLE_VALUE) return;
int ret = GetPadEvent();
if(ret == -1)
return; /* no event */
/* Since we're checking for messages, and not polling,
* only zero this out when we actually *have* a new
* message. */
memset( &current_state, 0, sizeof(current_state) );
int bits[] = {
/* P1 */ (1<<9), (1<<12), (1<<13), (1<<11), (1<<10),
/* ESC */ (1<<16),
/* P1 */ (1<<17), (1<<20), (1<<21), (1<<19), (1<<18),
};
for (int butno = 0 ; butno < NUM_PUMP_PAD_BUTTONS ; butno++)
switch(event.type)
{
if(!(ret & bits[butno]))
current_state[butno] = true;
case SDL_KEYDOWN:
case SDL_KEYUP:
{
DeviceInput di(DEVICE_KEYBOARD, event.key.keysym.sym);
INPUTFILTER->ButtonPressed(di, event.key.state == SDL_PRESSED);
return true;
}
case SDL_JOYBUTTONDOWN:
case SDL_JOYBUTTONUP:
{
InputDevice i = InputDevice(DEVICE_JOY1 + event.jbutton.which);
JoystickButton Button = JoystickButton(JOY_1 + event.jbutton.button);
if(Button >= NUM_JOYSTICK_BUTTONS)
{
LOG->Warn("Ignored joystick event (button too high)");
return true;
}
DeviceInput di(i, Button);
INPUTFILTER->ButtonPressed(di, event.jbutton.state == SDL_PRESSED);
return true;
}
case SDL_JOYAXISMOTION:
{
InputDevice i = InputDevice(DEVICE_JOY1 + event.jaxis.which);
JoystickButton neg = (JoystickButton)(JOY_LEFT+2*event.jaxis.axis);
JoystickButton pos = (JoystickButton)(JOY_RIGHT+2*event.jaxis.axis);
INPUTFILTER->ButtonPressed(DeviceInput(i, neg), event.jaxis.value < -16000);
INPUTFILTER->ButtonPressed(DeviceInput(i, pos), event.jaxis.value > +16000);
return true;
}
case SDL_JOYHATMOTION:
{
InputDevice i = InputDevice(DEVICE_JOY1 + event.jhat.which);
INPUTFILTER->ButtonPressed(DeviceInput(i, JOY_HAT_UP), !!(event.jhat.value & SDL_HAT_UP));
INPUTFILTER->ButtonPressed(DeviceInput(i, JOY_HAT_DOWN), !!(event.jhat.value & JOY_HAT_DOWN));
INPUTFILTER->ButtonPressed(DeviceInput(i, JOY_HAT_LEFT), !!(event.jhat.value & JOY_HAT_LEFT));
INPUTFILTER->ButtonPressed(DeviceInput(i, JOY_HAT_RIGHT), !!(event.jhat.value & JOY_HAT_RIGHT));
return true;
}
}
return false;
}