/* 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 #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(); }