947 lines
26 KiB
C++
947 lines
26 KiB
C++
|
|
/* VisualBoyAdvance S - GB & GBA emulator
|
|
Copyright (C) 2006 Spacy
|
|
|
|
Original VBA Credits:
|
|
Copyright (C) 1999-2003 Forgotten
|
|
Copyright (C) 2004-2006 VBA development team
|
|
|
|
This program 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 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program 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 this program; if not, write to the Free Software Foundation, Inc.,
|
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*/
|
|
|
|
#include "stdafx.h"
|
|
#include "VBA.h"
|
|
#include "Input.h"
|
|
#include "Reg.h"
|
|
#include "WinResUtil.h"
|
|
|
|
#define DIRECTINPUT_VERSION 0x0800
|
|
#include <Dinput.h>
|
|
#pragma comment(lib, "Dinput8")
|
|
|
|
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
extern void directXMessage(const char *);
|
|
extern void winlog(const char *msg,...);
|
|
|
|
#define POV_UP 1
|
|
#define POV_DOWN 2
|
|
#define POV_RIGHT 4
|
|
#define POV_LEFT 8
|
|
|
|
class DirectInput : public Input {
|
|
public:
|
|
virtual void checkDevices();
|
|
DirectInput();
|
|
virtual ~DirectInput();
|
|
|
|
virtual bool initialize();
|
|
virtual bool readDevices();
|
|
virtual u32 readDevice(int which);
|
|
virtual CString getKeyName(LONG_PTR key);
|
|
virtual void checkKeys();
|
|
virtual void checkMotionKeys();
|
|
virtual void activate();
|
|
virtual void loadSettings();
|
|
virtual void saveSettings();
|
|
};
|
|
|
|
struct deviceInfo {
|
|
LPDIRECTINPUTDEVICE8 device;
|
|
BOOL isPolled;
|
|
int nButtons;
|
|
int nAxes;
|
|
int nPovs;
|
|
BOOL first;
|
|
struct {
|
|
DWORD offset;
|
|
LONG center;
|
|
LONG negative;
|
|
LONG positive;
|
|
} axis[8];
|
|
int needed;
|
|
union {
|
|
UCHAR data[256];
|
|
DIJOYSTATE state;
|
|
};
|
|
};
|
|
|
|
static deviceInfo *currentDevice = NULL;
|
|
static int numDevices = 1;
|
|
static deviceInfo *pDevices = NULL;
|
|
static LPDIRECTINPUT8 pDirectInput = NULL;
|
|
static int axisNumber = 0;
|
|
|
|
|
|
|
|
|
|
LONG_PTR defvalues[JOYPADS * KEYS_PER_PAD + MOTION_KEYS] =
|
|
{
|
|
DIK_LEFT, DIK_RIGHT,
|
|
DIK_UP, DIK_DOWN,
|
|
DIK_Z, DIK_X,
|
|
DIK_RETURN,DIK_BACK,
|
|
DIK_A, DIK_S,
|
|
DIK_SPACE, DIK_F12,
|
|
DIK_C,
|
|
0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
DIK_NUMPAD4, DIK_NUMPAD6, DIK_NUMPAD8, DIK_NUMPAD2
|
|
};
|
|
|
|
|
|
void winReadKey(const char *name, KeyList& Keys)
|
|
{
|
|
CString TxtKeyList = regQueryStringValue(name, "");
|
|
int curPos= 0;
|
|
|
|
CString resToken=TxtKeyList.Tokenize(",",curPos);
|
|
while (resToken != "")
|
|
{
|
|
Keys.AddTail(atoi(resToken));
|
|
resToken= TxtKeyList.Tokenize(",",curPos);
|
|
};
|
|
}
|
|
|
|
void winReadKey(const char *name, int num, KeyList& Keys)
|
|
{
|
|
char buffer[80];
|
|
|
|
sprintf(buffer, "Joy%d_%s", num, name);
|
|
winReadKey(buffer, Keys);
|
|
}
|
|
|
|
|
|
void winReadKeys()
|
|
{
|
|
|
|
for(int i = 0; i < JOYPADS; i++) {
|
|
winReadKey("Left", i, theApp.input->joypaddata[JOYPAD(i,KEY_LEFT)]);
|
|
winReadKey("Right", i, theApp.input->joypaddata[JOYPAD(i, KEY_RIGHT)]);
|
|
winReadKey("Up", i, theApp.input->joypaddata[JOYPAD(i,KEY_UP)]);
|
|
winReadKey("Down", i, theApp.input->joypaddata[JOYPAD(i,KEY_DOWN)]);
|
|
winReadKey("A", i, theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_A)]);
|
|
winReadKey("B", i, theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_B)]);
|
|
winReadKey("L", i, theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_L)]);
|
|
winReadKey("R", i, theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_R)]);
|
|
winReadKey("Start", i, theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_START)]);
|
|
winReadKey("Select", i, theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_SELECT)]);
|
|
winReadKey("Speed", i, theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_SPEED)]);
|
|
winReadKey("Capture", i, theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_CAPTURE)]);
|
|
winReadKey("GS", i, theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_GS)]);
|
|
}
|
|
winReadKey("Motion_Left", theApp.input->joypaddata[MOTION(KEY_LEFT)]);
|
|
winReadKey("Motion_Right", theApp.input->joypaddata[MOTION(KEY_RIGHT)]);
|
|
winReadKey("Motion_Up", theApp.input->joypaddata[MOTION(KEY_UP)]);
|
|
winReadKey("Motion_Down", theApp.input->joypaddata[MOTION(KEY_DOWN)]);
|
|
}
|
|
|
|
void winSaveKey(char *name, KeyList& value)
|
|
{
|
|
CString txtKeys;
|
|
|
|
POSITION p = value.GetHeadPosition();
|
|
while(p!=NULL)
|
|
{
|
|
CString tmp;
|
|
tmp.Format("%d", value.GetNext(p));
|
|
txtKeys+=tmp;
|
|
if (p!=NULL)
|
|
txtKeys+=",";
|
|
}
|
|
regSetStringValue(name, txtKeys);
|
|
}
|
|
|
|
static void winSaveKey(char *name, int num, KeyList& value)
|
|
{
|
|
char buffer[80];
|
|
|
|
sprintf(buffer, "Joy%d_%s", num, name);
|
|
winSaveKey(buffer, value);
|
|
}
|
|
|
|
void winSaveKeys()
|
|
{
|
|
for(int i = 0; i < JOYPADS; i++) {
|
|
winSaveKey("Left", i, theApp.input->joypaddata[JOYPAD(i,KEY_LEFT)]);
|
|
winSaveKey("Right", i, theApp.input->joypaddata[JOYPAD(i,KEY_RIGHT)]);
|
|
winSaveKey("Up", i, theApp.input->joypaddata[JOYPAD(i,KEY_UP)]);
|
|
winSaveKey("Speed", i, theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_SPEED)]);
|
|
winSaveKey("Capture", i, theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_CAPTURE)]);
|
|
winSaveKey("GS", i, theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_GS)]);
|
|
winSaveKey("Down", i, theApp.input->joypaddata[JOYPAD(i,KEY_DOWN)]);
|
|
winSaveKey("A", i, theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_A)]);
|
|
winSaveKey("B", i, theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_B)]);
|
|
winSaveKey("L", i, theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_L)]);
|
|
winSaveKey("R", i, theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_R)]);
|
|
winSaveKey("Start", i, theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_START)]);
|
|
winSaveKey("Select", i, theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_SELECT)]);
|
|
}
|
|
regSetDwordValue("joyVersion", 1);
|
|
|
|
winSaveKey("Motion_Left",
|
|
theApp.input->joypaddata[MOTION(KEY_LEFT)]);
|
|
winSaveKey("Motion_Right",
|
|
theApp.input->joypaddata[MOTION(KEY_RIGHT)]);
|
|
winSaveKey("Motion_Up",
|
|
theApp.input->joypaddata[MOTION(KEY_UP)]);
|
|
winSaveKey("Motion_Down",
|
|
theApp.input->joypaddata[MOTION(KEY_DOWN)]);
|
|
}
|
|
|
|
static BOOL CALLBACK EnumAxesCallback( const DIDEVICEOBJECTINSTANCE* pdidoi,
|
|
VOID* pContext )
|
|
{
|
|
DIPROPRANGE diprg;
|
|
diprg.diph.dwSize = sizeof(DIPROPRANGE);
|
|
diprg.diph.dwHeaderSize = sizeof(DIPROPHEADER);
|
|
diprg.diph.dwHow = DIPH_BYOFFSET;
|
|
diprg.diph.dwObj = pdidoi->dwOfs; // Specify the enumerated axis
|
|
|
|
diprg.lMin = -32768;
|
|
diprg.lMax = 32767;
|
|
// try to set the range
|
|
if (FAILED(currentDevice->device->SetProperty(DIPROP_RANGE, &diprg.diph))) {
|
|
// Get the range for the axis
|
|
if ( FAILED(currentDevice->device->
|
|
GetProperty( DIPROP_RANGE, &diprg.diph ) ) ) {
|
|
return DIENUM_STOP;
|
|
}
|
|
}
|
|
|
|
DIPROPDWORD didz;
|
|
|
|
didz.diph.dwSize = sizeof(didz);
|
|
didz.diph.dwHeaderSize = sizeof(DIPROPHEADER);
|
|
didz.diph.dwHow = DIPH_BYOFFSET;
|
|
didz.diph.dwObj = pdidoi->dwOfs;
|
|
|
|
didz.dwData = 5000;
|
|
|
|
currentDevice->device->SetProperty(DIPROP_DEADZONE, &didz.diph);
|
|
|
|
LONG center = (diprg.lMin + diprg.lMax)/2;
|
|
LONG threshold = (diprg.lMax - center)/2;
|
|
|
|
// only 8 axis supported
|
|
if (axisNumber < 8) {
|
|
currentDevice->axis[axisNumber].center = center;
|
|
currentDevice->axis[axisNumber].negative = center - threshold;
|
|
currentDevice->axis[axisNumber].positive = center + threshold;
|
|
currentDevice->axis[axisNumber].offset = pdidoi->dwOfs;
|
|
}
|
|
axisNumber++;
|
|
return DIENUM_CONTINUE;
|
|
}
|
|
|
|
static BOOL CALLBACK EnumPovsCallback( const DIDEVICEOBJECTINSTANCE* pdidoi,
|
|
VOID* pContext )
|
|
{
|
|
return DIENUM_CONTINUE;
|
|
}
|
|
|
|
static BOOL CALLBACK DIEnumDevicesCallback(LPCDIDEVICEINSTANCE pInst,
|
|
LPVOID lpvContext)
|
|
{
|
|
ZeroMemory(&pDevices[numDevices],sizeof(deviceInfo));
|
|
|
|
HRESULT hRet = pDirectInput->CreateDevice(pInst->guidInstance,
|
|
&pDevices[numDevices].device,
|
|
NULL);
|
|
|
|
if (hRet != DI_OK)
|
|
return DIENUM_STOP;
|
|
|
|
DIDEVCAPS caps;
|
|
caps.dwSize=sizeof(DIDEVCAPS);
|
|
|
|
hRet = pDevices[numDevices].device->GetCapabilities(&caps);
|
|
|
|
if (hRet == DI_OK) {
|
|
if (caps.dwFlags & DIDC_POLLEDDATAFORMAT ||
|
|
caps.dwFlags & DIDC_POLLEDDEVICE)
|
|
pDevices[numDevices].isPolled = TRUE;
|
|
|
|
pDevices[numDevices].nButtons = caps.dwButtons;
|
|
pDevices[numDevices].nAxes = caps.dwAxes;
|
|
pDevices[numDevices].nPovs = caps.dwPOVs;
|
|
|
|
for (int i = 0; i < 6; i++) {
|
|
pDevices[numDevices].axis[i].center = 0x8000;
|
|
pDevices[numDevices].axis[i].negative = 0x4000;
|
|
pDevices[numDevices].axis[i].positive = 0xc000;
|
|
}
|
|
}
|
|
|
|
|
|
numDevices++;
|
|
|
|
|
|
return DIENUM_CONTINUE;
|
|
}
|
|
|
|
BOOL CALLBACK DIEnumDevicesCallback2(LPCDIDEVICEINSTANCE pInst,
|
|
LPVOID lpvContext)
|
|
{
|
|
numDevices++;
|
|
|
|
return DIENUM_CONTINUE;
|
|
}
|
|
|
|
static int getPovState(DWORD value)
|
|
{
|
|
int state = 0;
|
|
if (LOWORD(value) != 0xFFFF) {
|
|
if (value < 9000 || value > 27000)
|
|
state |= POV_UP;
|
|
if (value > 0 && value < 18000)
|
|
state |= POV_RIGHT;
|
|
if (value > 9000 && value < 27000)
|
|
state |= POV_DOWN;
|
|
if (value > 18000)
|
|
state |= POV_LEFT;
|
|
}
|
|
return state;
|
|
}
|
|
|
|
static void checkKeys()
|
|
{
|
|
LONG_PTR dev = 0;
|
|
int i;
|
|
|
|
for(i = 0; i < (sizeof(theApp.input->joypaddata) / sizeof(theApp.input->joypaddata[0])); i++)
|
|
{
|
|
if (theApp.input->joypaddata[i].IsEmpty() && defvalues[i])
|
|
theApp.input->joypaddata[i].AddTail(defvalues[i]);
|
|
POSITION p = theApp.input->joypaddata[i].GetHeadPosition();
|
|
while(p!=NULL)
|
|
{
|
|
LONG_PTR k = theApp.input->joypaddata[i].GetNext(p);
|
|
if (k > 0 && DEVICEOF(k) < numDevices)
|
|
pDevices[DEVICEOF(k)].needed = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
#define KEYDOWN(buffer,key) (buffer[key] & 0x80)
|
|
|
|
static bool readKeyboard()
|
|
{
|
|
if (pDevices[0].needed) {
|
|
HRESULT hret = pDevices[0].device->
|
|
GetDeviceState(256,
|
|
(LPVOID)pDevices[0].data);
|
|
|
|
if (hret == DIERR_INPUTLOST || hret == DIERR_NOTACQUIRED) {
|
|
hret = pDevices[0].device->Acquire();
|
|
if (hret != DI_OK)
|
|
return false;
|
|
hret = pDevices[0].device->GetDeviceState(256,(LPVOID)pDevices[0].data);
|
|
}
|
|
|
|
return hret == DI_OK;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static bool readJoystick(int joy)
|
|
{
|
|
if (pDevices[joy].needed) {
|
|
if (pDevices[joy].isPolled)
|
|
((LPDIRECTINPUTDEVICE2)pDevices[joy].device)->Poll();
|
|
|
|
HRESULT hret = pDevices[joy].device->
|
|
GetDeviceState(sizeof(DIJOYSTATE),
|
|
(LPVOID)&pDevices[joy].state);
|
|
|
|
if (hret == DIERR_INPUTLOST || hret == DIERR_NOTACQUIRED) {
|
|
hret = pDevices[joy].device->Acquire();
|
|
|
|
if (hret == DI_OK) {
|
|
|
|
if (pDevices[joy].isPolled)
|
|
((LPDIRECTINPUTDEVICE2)pDevices[joy].device)->Poll();
|
|
|
|
hret = pDevices[joy].device->
|
|
GetDeviceState(sizeof(DIJOYSTATE),
|
|
(LPVOID)&pDevices[joy].state);
|
|
}
|
|
}
|
|
|
|
return hret == DI_OK;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static void checkKeyboard()
|
|
{
|
|
// mham fix. Patch #1378104
|
|
UCHAR keystate[256];
|
|
HRESULT hret = pDevices[0].device->Acquire();
|
|
|
|
if (pDevices[0].first) {
|
|
pDevices[0].device->GetDeviceState(256, (LPVOID)pDevices[0].data);
|
|
pDevices[0].first = FALSE;
|
|
return;
|
|
}
|
|
|
|
hret = pDevices[0].device->
|
|
GetDeviceState(256, (LPVOID)keystate);
|
|
|
|
if (hret == DIERR_INPUTLOST || hret == DIERR_NOTACQUIRED) {
|
|
return;
|
|
}
|
|
|
|
if (hret == DI_OK) {
|
|
for (int i = 0; i < 256; i++) {
|
|
if (keystate[i] == pDevices[0].data[i]) continue;
|
|
if (KEYDOWN(keystate, i)) {
|
|
SendMessage(GetFocus(), JOYCONFIG_MESSAGE,0,i);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
memcpy(pDevices[0].data, keystate, sizeof(UCHAR) * 256);
|
|
}
|
|
|
|
static void checkJoypads()
|
|
{
|
|
DIDEVICEOBJECTINSTANCE di;
|
|
|
|
ZeroMemory(&di,sizeof(DIDEVICEOBJECTINSTANCE));
|
|
|
|
di.dwSize = sizeof(DIDEVICEOBJECTINSTANCE);
|
|
|
|
int i =0;
|
|
|
|
DIJOYSTATE joystick;
|
|
|
|
for (i = 1; i < numDevices; i++) {
|
|
HRESULT hret = pDevices[i].device->Acquire();
|
|
|
|
|
|
if (pDevices[i].isPolled)
|
|
((LPDIRECTINPUTDEVICE2)pDevices[i].device)->Poll();
|
|
|
|
hret = pDevices[i].device->GetDeviceState(sizeof(joystick), &joystick);
|
|
|
|
int j;
|
|
|
|
if (pDevices[i].first) {
|
|
memcpy(&pDevices[i].state, &joystick, sizeof(joystick));
|
|
pDevices[i].first = FALSE;
|
|
continue;
|
|
}
|
|
|
|
for (j = 0; j < pDevices[i].nButtons; j++) {
|
|
if (((pDevices[i].state.rgbButtons[j] ^ joystick.rgbButtons[j])
|
|
& joystick.rgbButtons[j]) & 0x80) {
|
|
HWND focus = GetFocus();
|
|
|
|
SendMessage(focus, JOYCONFIG_MESSAGE, i,j+128);
|
|
}
|
|
}
|
|
|
|
for (j = 0; j < pDevices[i].nAxes && j < 8; j++) {
|
|
LONG value = pDevices[i].axis[j].center;
|
|
LONG old = 0;
|
|
switch (pDevices[i].axis[j].offset) {
|
|
case DIJOFS_X:
|
|
value = joystick.lX;
|
|
old = pDevices[i].state.lX;
|
|
break;
|
|
case DIJOFS_Y:
|
|
value = joystick.lY;
|
|
old = pDevices[i].state.lY;
|
|
break;
|
|
case DIJOFS_Z:
|
|
value = joystick.lZ;
|
|
old = pDevices[i].state.lZ;
|
|
break;
|
|
case DIJOFS_RX:
|
|
value = joystick.lRx;
|
|
old = pDevices[i].state.lRx;
|
|
break;
|
|
case DIJOFS_RY:
|
|
value = joystick.lRy;
|
|
old = pDevices[i].state.lRy;
|
|
break;
|
|
case DIJOFS_RZ:
|
|
value = joystick.lRz;
|
|
old = pDevices[i].state.lRz;
|
|
break;
|
|
case DIJOFS_SLIDER(0):
|
|
value = joystick.rglSlider[0];
|
|
old = pDevices[i].state.rglSlider[0];
|
|
break;
|
|
case DIJOFS_SLIDER(1):
|
|
value = joystick.rglSlider[1];
|
|
old = pDevices[i].state.rglSlider[1];
|
|
break;
|
|
}
|
|
if (value != old) {
|
|
if (value < pDevices[i].axis[j].negative)
|
|
SendMessage(GetFocus(), JOYCONFIG_MESSAGE, i, (j<<1));
|
|
else if (value > pDevices[i].axis[j].positive)
|
|
SendMessage(GetFocus(), JOYCONFIG_MESSAGE, i, (j<<1)+1);
|
|
}
|
|
}
|
|
|
|
for (j = 0;j < 4 && j < pDevices[i].nPovs; j++) {
|
|
if (LOWORD(pDevices[i].state.rgdwPOV[j]) != LOWORD(joystick.rgdwPOV[j])) {
|
|
int state = getPovState(joystick.rgdwPOV[j]);
|
|
|
|
if (state & POV_UP)
|
|
SendMessage(GetFocus(), JOYCONFIG_MESSAGE, i, (j<<2)+0x20);
|
|
else if (state & POV_DOWN)
|
|
SendMessage(GetFocus(), JOYCONFIG_MESSAGE, i, (j<<2)+0x21);
|
|
else if (state & POV_RIGHT)
|
|
SendMessage(GetFocus(), JOYCONFIG_MESSAGE, i, (j<<2)+0x22);
|
|
else if (state & POV_LEFT)
|
|
SendMessage(GetFocus(), JOYCONFIG_MESSAGE, i, (j<<2)+0x23);
|
|
}
|
|
}
|
|
|
|
memcpy(&pDevices[i].state, &joystick, sizeof(joystick));
|
|
}
|
|
}
|
|
|
|
BOOL checkKey(LONG_PTR key)
|
|
{
|
|
LONG_PTR dev = (key >> 8);
|
|
|
|
LONG_PTR k = (key & 255);
|
|
|
|
if (dev == 0) {
|
|
return KEYDOWN(pDevices[0].data,k);
|
|
} else if (dev >= numDevices) {
|
|
return FALSE;
|
|
} else {
|
|
if (k < 16) {
|
|
LONG_PTR axis = k >> 1;
|
|
LONG value = pDevices[dev].axis[axis].center;
|
|
switch (pDevices[dev].axis[axis].offset) {
|
|
case DIJOFS_X:
|
|
value = pDevices[dev].state.lX;
|
|
break;
|
|
case DIJOFS_Y:
|
|
value = pDevices[dev].state.lY;
|
|
break;
|
|
case DIJOFS_Z:
|
|
value = pDevices[dev].state.lZ;
|
|
break;
|
|
case DIJOFS_RX:
|
|
value = pDevices[dev].state.lRx;
|
|
break;
|
|
case DIJOFS_RY:
|
|
value = pDevices[dev].state.lRy;
|
|
break;
|
|
case DIJOFS_RZ:
|
|
value = pDevices[dev].state.lRz;
|
|
break;
|
|
case DIJOFS_SLIDER(0):
|
|
value = pDevices[dev].state.rglSlider[0];
|
|
break;
|
|
case DIJOFS_SLIDER(1):
|
|
value = pDevices[dev].state.rglSlider[1];
|
|
break;
|
|
}
|
|
|
|
if (k & 1)
|
|
return value > pDevices[dev].axis[axis].positive;
|
|
return value < pDevices[dev].axis[axis].negative;
|
|
} else if (k < 48) {
|
|
LONG_PTR hat = (k >> 2) & 3;
|
|
int state = getPovState(pDevices[dev].state.rgdwPOV[hat]);
|
|
BOOL res = FALSE;
|
|
switch (k & 3) {
|
|
case 0:
|
|
res = state & POV_UP;
|
|
break;
|
|
case 1:
|
|
res = state & POV_DOWN;
|
|
break;
|
|
case 2:
|
|
res = state & POV_RIGHT;
|
|
break;
|
|
case 3:
|
|
res = state & POV_LEFT;
|
|
break;
|
|
}
|
|
return res;
|
|
} else if (k >= 128) {
|
|
return pDevices[dev].state.rgbButtons[k-128] & 0x80;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL checkKey(KeyList &k)
|
|
{
|
|
POSITION p = k.GetHeadPosition();
|
|
while(p!=NULL)
|
|
{
|
|
if (checkKey(k.GetNext(p)))
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
DirectInput::DirectInput()
|
|
{}
|
|
|
|
DirectInput::~DirectInput()
|
|
{
|
|
saveSettings();
|
|
if (pDirectInput != NULL) {
|
|
if (pDevices) {
|
|
for (int i = 0; i < numDevices ; i++) {
|
|
if (pDevices[i].device) {
|
|
pDevices[i].device->Unacquire();
|
|
pDevices[i].device->Release();
|
|
pDevices[i].device = NULL;
|
|
}
|
|
}
|
|
free(pDevices);
|
|
pDevices = NULL;
|
|
}
|
|
|
|
pDirectInput->Release();
|
|
pDirectInput = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
bool DirectInput::initialize()
|
|
{
|
|
|
|
HRESULT hr;
|
|
|
|
hr = DirectInput8Create(
|
|
AfxGetInstanceHandle(),
|
|
DIRECTINPUT_VERSION,
|
|
IID_IDirectInput8,
|
|
(LPVOID*)&pDirectInput,
|
|
NULL );
|
|
|
|
if ( hr != DI_OK ) {
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
|
|
hr = pDirectInput->EnumDevices(DI8DEVCLASS_GAMECTRL,
|
|
DIEnumDevicesCallback2,
|
|
NULL,
|
|
DIEDFL_ATTACHEDONLY);
|
|
|
|
|
|
|
|
pDevices = (deviceInfo *)calloc(numDevices, sizeof(deviceInfo));
|
|
|
|
hr = pDirectInput->CreateDevice(GUID_SysKeyboard,&pDevices[0].device,NULL);
|
|
pDevices[0].isPolled = false;
|
|
pDevices[0].needed = true;
|
|
pDevices[0].first = true;
|
|
|
|
if (hr != DI_OK) {
|
|
return false;
|
|
}
|
|
|
|
|
|
numDevices = 1;
|
|
|
|
hr = pDirectInput->EnumDevices(DI8DEVCLASS_GAMECTRL,
|
|
DIEnumDevicesCallback,
|
|
NULL,
|
|
DIEDFL_ATTACHEDONLY);
|
|
|
|
|
|
if (hr != DI_OK) {
|
|
return false;
|
|
}
|
|
|
|
hr = pDevices[0].device->SetDataFormat(&c_dfDIKeyboard);
|
|
|
|
if (hr != DI_OK) {
|
|
return false;
|
|
}
|
|
|
|
int i;
|
|
for (i = 1; i < numDevices; i++) {
|
|
pDevices[i].device->SetDataFormat(&c_dfDIJoystick);
|
|
pDevices[i].needed = false;
|
|
pDevices[i].first = true;
|
|
currentDevice = &pDevices[i];
|
|
axisNumber = 0;
|
|
currentDevice->device->EnumObjects(EnumAxesCallback, NULL, DIDFT_AXIS);
|
|
currentDevice->device->EnumObjects(EnumPovsCallback, NULL, DIDFT_POV);
|
|
|
|
|
|
currentDevice = NULL;
|
|
}
|
|
|
|
for (i = 0; i < numDevices; i++)
|
|
pDevices[i].device->Acquire();
|
|
|
|
return true;
|
|
}
|
|
|
|
bool DirectInput::readDevices()
|
|
{
|
|
bool ok = true;
|
|
for (int i = 0; i < numDevices; i++) {
|
|
if (pDevices[i].needed) {
|
|
if (i) {
|
|
ok = readJoystick(i);
|
|
} else
|
|
ok = readKeyboard();
|
|
}
|
|
}
|
|
return ok;
|
|
}
|
|
|
|
u32 DirectInput::readDevice(int which)
|
|
{
|
|
u32 res = 0;
|
|
int i = theApp.joypadDefault;
|
|
if(which >= 0 && which <= 3)
|
|
i = which;
|
|
|
|
if(checkKey(theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_A)]))
|
|
res |= 1;
|
|
if(checkKey(theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_B)]))
|
|
res |= 2;
|
|
if(checkKey(theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_SELECT)]))
|
|
res |= 4;
|
|
if(checkKey(theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_START)]))
|
|
res |= 8;
|
|
if(checkKey(theApp.input->joypaddata[JOYPAD(i,KEY_RIGHT)]))
|
|
res |= 16;
|
|
if(checkKey(theApp.input->joypaddata[JOYPAD(i,KEY_LEFT)]))
|
|
res |= 32;
|
|
if(checkKey(theApp.input->joypaddata[JOYPAD(i,KEY_UP)]))
|
|
res |= 64;
|
|
if(checkKey(theApp.input->joypaddata[JOYPAD(i,KEY_DOWN)]))
|
|
res |= 128;
|
|
if(checkKey(theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_R)]))
|
|
res |= 256;
|
|
if(checkKey(theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_L)]))
|
|
res |= 512;
|
|
|
|
if(checkKey(theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_GS)]))
|
|
res |= 4096;
|
|
|
|
if(theApp.autoFire) {
|
|
res &= (~theApp.autoFire);
|
|
if(theApp.autoFireToggle)
|
|
res |= theApp.autoFire;
|
|
theApp.autoFireToggle = !theApp.autoFireToggle;
|
|
}
|
|
|
|
// disallow L+R or U+D of being pressed at the same time
|
|
if((res & 48) == 48)
|
|
res &= ~16;
|
|
if((res & 192) == 192)
|
|
res &= ~128;
|
|
|
|
if(theApp.movieRecording) {
|
|
if(i == theApp.joypadDefault) {
|
|
if(res != theApp.movieLastJoypad) {
|
|
fwrite(&theApp.movieFrame, 1, sizeof(theApp.movieFrame), theApp.movieFile);
|
|
fwrite(&res, 1, sizeof(res), theApp.movieFile);
|
|
theApp.movieLastJoypad = res;
|
|
}
|
|
}
|
|
}
|
|
if(theApp.moviePlaying) {
|
|
if(theApp.movieFrame == theApp.moviePlayFrame) {
|
|
theApp.movieLastJoypad = theApp.movieNextJoypad;
|
|
theApp.movieReadNext();
|
|
}
|
|
res = theApp.movieLastJoypad;
|
|
}
|
|
// we don't record speed up or screen capture buttons
|
|
if(checkKey(theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_SPEED)]) || theApp.speedupToggle)
|
|
res |= 1024;
|
|
if(checkKey(theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_CAPTURE)]))
|
|
res |= 2048;
|
|
|
|
return res;
|
|
}
|
|
|
|
CString DirectInput::getKeyName(LONG_PTR key)
|
|
{
|
|
LONG_PTR d = (key >> 8);
|
|
LONG_PTR k = key & 255;
|
|
|
|
DIDEVICEOBJECTINSTANCE di;
|
|
|
|
ZeroMemory(&di,sizeof(DIDEVICEOBJECTINSTANCE));
|
|
|
|
di.dwSize = sizeof(DIDEVICEOBJECTINSTANCE);
|
|
|
|
CString winBuffer = winResLoadString(IDS_ERROR);
|
|
|
|
if (d == 0) {
|
|
pDevices[0].device->GetObjectInfo( &di, (DWORD)key, DIPH_BYOFFSET );
|
|
winBuffer = di.tszName;
|
|
} else if (d < numDevices) {
|
|
if (k < 16) {
|
|
if (k < 4) {
|
|
switch (k) {
|
|
case 0:
|
|
winBuffer.Format(winResLoadString(IDS_JOY_LEFT), d);
|
|
break;
|
|
case 1:
|
|
winBuffer.Format(winResLoadString(IDS_JOY_RIGHT), d);
|
|
break;
|
|
case 2:
|
|
winBuffer.Format(winResLoadString(IDS_JOY_UP), d);
|
|
break;
|
|
case 3:
|
|
winBuffer.Format(winResLoadString(IDS_JOY_DOWN), d);
|
|
break;
|
|
}
|
|
} else {
|
|
pDevices[d].device->GetObjectInfo(&di,
|
|
pDevices[d].axis[k>>1].offset,
|
|
DIPH_BYOFFSET);
|
|
if (k & 1)
|
|
winBuffer.Format("Joy %d %s +", d, di.tszName);
|
|
else
|
|
winBuffer.Format("Joy %d %s -", d, di.tszName);
|
|
}
|
|
} else if (k < 48) {
|
|
LONG_PTR hat = (k >> 2) & 3;
|
|
pDevices[d].device->GetObjectInfo(&di,
|
|
(DWORD)DIJOFS_POV(hat),
|
|
DIPH_BYOFFSET);
|
|
char *dir = "up";
|
|
LONG_PTR dd = k & 3;
|
|
if (dd == 1)
|
|
dir = "down";
|
|
else if (dd == 2)
|
|
dir = "right";
|
|
else if (dd == 3)
|
|
dir = "left";
|
|
winBuffer.Format("Joy %d %s %s", d, di.tszName, dir);
|
|
} else {
|
|
pDevices[d].device->GetObjectInfo(&di,
|
|
(DWORD)DIJOFS_BUTTON(k-128),
|
|
DIPH_BYOFFSET);
|
|
winBuffer.Format(winResLoadString(IDS_JOY_BUTTON),d,di.tszName);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Joystick isn't plugged in. We can't decipher k, so just show its value.
|
|
winBuffer.Format("Joy %d (%d)", d, k);
|
|
}
|
|
|
|
return winBuffer;
|
|
}
|
|
|
|
void DirectInput::checkKeys()
|
|
{
|
|
::checkKeys();
|
|
}
|
|
|
|
void DirectInput::checkMotionKeys()
|
|
{
|
|
if(checkKey(theApp.input->joypaddata[MOTION(KEY_LEFT)])) {
|
|
theApp.sensorX += 3;
|
|
if(theApp.sensorX > 2197)
|
|
theApp.sensorX = 2197;
|
|
if(theApp.sensorX < 2047)
|
|
theApp.sensorX = 2057;
|
|
} else if(checkKey(theApp.input->joypaddata[MOTION(KEY_RIGHT)])) {
|
|
theApp.sensorX -= 3;
|
|
if(theApp.sensorX < 1897)
|
|
theApp.sensorX = 1897;
|
|
if(theApp.sensorX > 2047)
|
|
theApp.sensorX = 2037;
|
|
} else if(theApp.sensorX > 2047) {
|
|
theApp.sensorX -= 2;
|
|
if(theApp.sensorX < 2047)
|
|
theApp.sensorX = 2047;
|
|
} else {
|
|
theApp.sensorX += 2;
|
|
if(theApp.sensorX > 2047)
|
|
theApp.sensorX = 2047;
|
|
}
|
|
|
|
if(checkKey(theApp.input->joypaddata[MOTION(KEY_UP)])) {
|
|
theApp.sensorY += 3;
|
|
if(theApp.sensorY > 2197)
|
|
theApp.sensorY = 2197;
|
|
if(theApp.sensorY < 2047)
|
|
theApp.sensorY = 2057;
|
|
} else if(checkKey(theApp.input->joypaddata[MOTION(KEY_DOWN)])) {
|
|
theApp.sensorY -= 3;
|
|
if(theApp.sensorY < 1897)
|
|
theApp.sensorY = 1897;
|
|
if(theApp.sensorY > 2047)
|
|
theApp.sensorY = 2037;
|
|
} else if(theApp.sensorY > 2047) {
|
|
theApp.sensorY -= 2;
|
|
if(theApp.sensorY < 2047)
|
|
theApp.sensorY = 2047;
|
|
} else {
|
|
theApp.sensorY += 2;
|
|
if(theApp.sensorY > 2047)
|
|
theApp.sensorY = 2047;
|
|
}
|
|
}
|
|
|
|
Input *newDirectInput()
|
|
{
|
|
return new DirectInput;
|
|
}
|
|
|
|
|
|
void DirectInput::checkDevices()
|
|
{
|
|
checkJoypads();
|
|
checkKeyboard();
|
|
}
|
|
|
|
void DirectInput::activate()
|
|
{
|
|
for (int i = 0; i < numDevices; i++) {
|
|
if (pDevices != NULL && pDevices[i].device != NULL)
|
|
pDevices[i].device->Acquire();
|
|
}
|
|
}
|
|
|
|
void DirectInput::loadSettings()
|
|
{
|
|
winReadKeys();
|
|
}
|
|
|
|
void DirectInput::saveSettings()
|
|
{
|
|
winSaveKeys();
|
|
}
|