From 70524dcb6ab190857e2e34da21d4bc417a02b90a Mon Sep 17 00:00:00 2001 From: Glenn Maynard Date: Sun, 16 Feb 2003 01:16:25 +0000 Subject: [PATCH] add input device abstraction --- .../src/arch/InputHandler/InputHandler.h | 30 +++ .../InputHandler/InputHandler_Win32_Pump.cpp | 203 ++++++++++++++++++ .../InputHandler/InputHandler_Win32_Pump.h | 20 ++ 3 files changed, 253 insertions(+) create mode 100644 stepmania/src/arch/InputHandler/InputHandler.h create mode 100644 stepmania/src/arch/InputHandler/InputHandler_Win32_Pump.cpp create mode 100644 stepmania/src/arch/InputHandler/InputHandler_Win32_Pump.h diff --git a/stepmania/src/arch/InputHandler/InputHandler.h b/stepmania/src/arch/InputHandler/InputHandler.h new file mode 100644 index 0000000000..c9f25a0c36 --- /dev/null +++ b/stepmania/src/arch/InputHandler/InputHandler.h @@ -0,0 +1,30 @@ +#ifndef INPUT_HANDLER_H +#define INPUT_HANDLER_H 1 + +/* + * This is a simple class to handle special input devices. Update() + * will be called during the input update; the derived class should + * send appropriate events to InputHandler. + * + * Send input events for a specific type of device. Only one driver + * for a given set of InputDevice types should be loaded for a given + * arch. For example, any number of drivers may produce DEVICE_PUMPn + * events, but only one may be loaded at a time. + * + * DEVICE_KEYBOARD and DEVICE_JOYn are fed from SDL and should not + * be used by RageInputFeeders. + */ + +class RageInputFeeder +{ +public: + virtual void Update(float fDeltaTime) { } + virtual ~RageInputFeeder() { } +}; + +#endif + +/* + * Copyright (c) 2003 by the person(s) listed below. All rights reserved. + * Glenn Maynard + */ diff --git a/stepmania/src/arch/InputHandler/InputHandler_Win32_Pump.cpp b/stepmania/src/arch/InputHandler/InputHandler_Win32_Pump.cpp new file mode 100644 index 0000000000..68d7c25aa4 --- /dev/null +++ b/stepmania/src/arch/InputHandler/InputHandler_Win32_Pump.cpp @@ -0,0 +1,203 @@ +#include "stdafx.h" +#include "InputHandler_Win32_Pump.h" + +#include "RageLog.h" +#include "RageUtil.h" +#include "RageInputDevice.h" +#include "InputFilter.h" + +//----------------------------------------------------------------------------- +// In-line Links +//----------------------------------------------------------------------------- +#pragma comment(lib, "ddk/setupapi.lib") +#pragma comment(lib, "ddk/hid.lib") + +struct PumpPadDevice::dev_t { + dev_t(); + ~dev_t(); + HANDLE h; + OVERLAPPED ov; + long buf; + bool pending; + int GetPadEvent(); +}; + + +namespace USB { + char *GetUSBDevicePath (int num); + HANDLE OpenUSB (int VID, int PID, int num); +}; + +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; +} + + +PumpPadDevice::dev_t::dev_t() +{ + ZeroMemory( &ov, sizeof(ov) ); + pending=false; + h = INVALID_HANDLE_VALUE; +} + +PumpPadDevice::dev_t::~dev_t() +{ + if(h != INVALID_HANDLE_VALUE) + CloseHandle(h); +} + +PumpPadDevice::PumpPadDevice() +{ + const int pump_usb_vid = 0x0d2f, pump_usb_pid = 0x0001; + + dev = new dev_t[NUM_PUMPS]; + + for(int i = 0; i < NUM_PUMPS; ++i) + { + dev[i].h = USB::OpenUSB (pump_usb_vid, pump_usb_pid, i); + if(dev[i].h != INVALID_HANDLE_VALUE) + LOG->Info("Found Pump pad %i", i); + } +} + +PumpPadDevice::~PumpPadDevice() +{ + delete[] dev; +} + +int PumpPadDevice::dev_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 call): */ + 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 PumpPadDevice::Update() +{ + static const 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 i = 0; i < NUM_PUMPS; ++i) + { + int ret = dev[i].GetPadEvent(); + + if(ret == -1) + continue; /* no event */ + + InputDevice id = InputDevice(DEVICE_PUMP1 + i); + + for (int butno = 0 ; butno < NUM_PUMP_PAD_BUTTONS ; butno++) + INPUTFILTER->ButtonPressed(DeviceInput(id, butno), !(ret & bits[butno])); + } +} + diff --git a/stepmania/src/arch/InputHandler/InputHandler_Win32_Pump.h b/stepmania/src/arch/InputHandler/InputHandler_Win32_Pump.h new file mode 100644 index 0000000000..39fccc5ac4 --- /dev/null +++ b/stepmania/src/arch/InputHandler/InputHandler_Win32_Pump.h @@ -0,0 +1,20 @@ +#ifndef INPUT_HANDLER_WIN32_PUMP_H +#define INPUT_HANDLER_WIN32_PUMP_H 1 + +#include "InputHandler.h" + +class PumpPadDevice: RageInputFeeder +{ + struct dev_t; /* MYOB */ + + dev_t *dev; + +public: + void Update(); + PumpPadDevice(); + ~PumpPadDevice(); +}; + + + +#endif