1 /* Copyright 2006,2013 Theo Berkau
2
3 This file is part of Yabause.
4
5 Yabause is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 Yabause is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with Yabause; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 /*! \file perdx.c
21 \brief Direct X peripheral interface.
22 */
23
24 #include <windows.h>
25 #ifdef __MINGW32__
26 #undef HAVE_XINPUT
27 #endif
28 #define COBJMACROS
29 #ifdef HAVE_XINPUT
30 #include <wbemidl.h>
31 #include <wbemcli.h>
32 #include <oleauto.h>
33 #include <xinput.h>
34 #endif
35 #include "debug.h"
36 #include "peripheral.h"
37 #include "perdx.h"
38 #include "vdp1.h"
39 #include "vdp2.h"
40 #include "yui.h"
41 #include "movie.h"
42 #include "error.h"
43
44 enum {
45 EMUTYPE_NONE=0,
46 EMUTYPE_STANDARDPAD,
47 EMUTYPE_ANALOGPAD,
48 EMUTYPE_STUNNER,
49 EMUTYPE_MOUSE,
50 EMUTYPE_KEYBOARD
51 };
52
53 #define DX_PADOFFSET 24
54 #define DX_STICKOFFSET 8
55 #define DX_MAKEKEY(p, s, a) ( ((p) << DX_PADOFFSET) | ((s) << DX_STICKOFFSET) | (a) )
56 #define DX_PerAxisValue(p, s, a, v) PerAxisValue(DX_MAKEKEY(p, s, a), (v))
57 #define DX_PerKeyUp(p, s, a) PerKeyUp(DX_MAKEKEY(p, s, a) )
58 #define DX_PerKeyDown(p, s, a) PerKeyDown(DX_MAKEKEY(p, s, a) )
59
60 int Check_Skip_Key();
61
62 PerInterface_struct PERDIRECTX = {
63 PERCORE_DIRECTX,
64 #ifdef HAVE_XINPUT
65 "DirectX/XInput Input Interface",
66 #else
67 "DirectX Input Interface",
68 #endif
69 PERDXInit,
70 PERDXDeInit,
71 PERDXHandleEvents,
72 PERDXScan,
73 TRUE,
74 PERDXFlush,
75 };
76
77 LPDIRECTINPUT8 lpDI8 = NULL;
78 struct
79 {
80 BOOL is_xinput_device;
81 int user_index;
82 LPDIRECTINPUTDEVICE8 lpDIDevice;
83 } dev_list[256]; // I hope that's enough
84
85 u32 num_devices=0;
86
87 static unsigned int PERCORE_INITIALIZED = 0;
88
89 const char *mouse_names[] = {
90 "A",
91 "B",
92 "C",
93 "Start",
94 NULL
95 };
96
97 #define PAD_DIR_AXISLEFT 0
98 #define PAD_DIR_AXISRIGHT 1
99 #define PAD_DIR_AXISUP 2
100 #define PAD_DIR_AXISDOWN 3
101 #define PAD_DIR_POVUP 0
102 #define PAD_DIR_POVRIGHT 1
103 #define PAD_DIR_POVDOWN 2
104 #define PAD_DIR_POVLEFT 3
105
106 HWND DXGetWindow ();
107
108 #ifdef HAVE_XINPUT
109 #define SAFE_RELEASE(p) { if(p) { (p)->lpVtbl->Release((p)); (p)=NULL; } }
110 #define SAFE_DELETE(p) { if(p) { free (p); (p)=NULL; } }
111
112 typedef struct
113 {
114 DWORD dwVidPid;
115 struct XINPUT_DEVICE_NODE* pNext;
116 } XINPUT_DEVICE_NODE;
117
118 XINPUT_DEVICE_NODE *g_pXInputDeviceList = NULL;
119 BOOL bCleanupCOM=FALSE;
120
121 //////////////////////////////////////////////////////////////////////////////
122
SetupForIsXInputDevice()123 HRESULT SetupForIsXInputDevice()
124 {
125 IWbemLocator * pIWbemLocator = NULL;
126 IEnumWbemClassObject * pEnumDevices = NULL;
127 IWbemClassObject * pDevices[20] = {0};
128 IWbemServices * pIWbemServices = NULL;
129 BSTR bstrNamespace = NULL;
130 BSTR bstrDeviceID = NULL;
131 BSTR bstrClassName = NULL;
132 DWORD uReturned = 0;
133 BOOL bIsXinputDevice = FALSE;
134 UINT iDevice = 0;
135 VARIANT var;
136 HRESULT hr;
137
138 hr = CoInitialize(NULL);
139 bCleanupCOM = SUCCEEDED(hr);
140
141 hr = CoCreateInstance(&CLSID_WbemLocator,
142 NULL,
143 CLSCTX_INPROC_SERVER,
144 &IID_IWbemLocator,
145 (LPVOID *) &pIWbemLocator);
146 if (FAILED(hr) || pIWbemLocator == NULL) {
147 YabSetError(YAB_ERR_CANNOTINIT, "pIWbemLocator");
148 goto bail;
149 }
150
151 bstrNamespace = SysAllocString(L"\\\\.\\root\\cimv2"); if (bstrNamespace == NULL) {goto bail;}
152 bstrClassName = SysAllocString(L"Win32_PNPEntity"); if (bstrClassName == NULL) {goto bail;}
153 bstrDeviceID = SysAllocString(L"DeviceID"); if (bstrDeviceID == NULL) {goto bail;}
154
155 hr = IWbemLocator_ConnectServer(pIWbemLocator, bstrNamespace, NULL, NULL, 0L,
156 0L, NULL, NULL, &pIWbemServices);
157 if (FAILED(hr) || pIWbemServices == NULL)
158 {
159 YabSetError(YAB_ERR_CANNOTINIT, "pIWbemServices");
160 goto bail;
161 }
162
163 CoSetProxyBlanket((IUnknown *) pIWbemServices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL,
164 RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE);
165
166 hr = IWbemServices_CreateInstanceEnum(pIWbemServices, bstrClassName, 0, NULL, &pEnumDevices);
167 if (FAILED(hr) || pEnumDevices == NULL)
168 {
169 YabSetError(YAB_ERR_CANNOTINIT, "pEnumDevices");
170 goto bail;
171 }
172
173 for (;;)
174 {
175 // Get 20 at a time
176 hr = IEnumWbemClassObject_Next(pEnumDevices, 10000, 20, pDevices, &uReturned);
177 if( FAILED(hr) ||
178 uReturned == 0 )
179 break;
180 for (iDevice = 0; iDevice < uReturned; iDevice++)
181 {
182 hr = IWbemClassObject_Get(pDevices[iDevice], bstrDeviceID, 0L, &var, NULL, NULL);
183 if (SUCCEEDED(hr) && var.vt == VT_BSTR && var.bstrVal != NULL) {
184 if (wcsstr(var.bstrVal, L"IG_")) {
185 // If it does, then get the VID/PID from var.bstrVal
186 DWORD dwPid = 0, dwVid = 0;
187 WCHAR* strVid;
188 WCHAR* strPid;
189 DWORD dwVidPid;
190 XINPUT_DEVICE_NODE* pNewNode;
191
192 strVid = wcsstr( var.bstrVal, L"VID_" );
193 if( strVid && swscanf( strVid, L"VID_%4X", &dwVid ) != 1 )
194 dwVid = 0;
195 strPid = wcsstr( var.bstrVal, L"PID_" );
196 if( strPid && swscanf( strPid, L"PID_%4X", &dwPid ) != 1 )
197 dwPid = 0;
198
199 dwVidPid = MAKELONG( dwVid, dwPid );
200
201 // Add the VID/PID to a linked list
202 pNewNode = malloc(sizeof(XINPUT_DEVICE_NODE));
203 if( pNewNode )
204 {
205 pNewNode->dwVidPid = dwVidPid;
206 pNewNode->pNext = (struct XINPUT_DEVICE_NODE *)g_pXInputDeviceList;
207 g_pXInputDeviceList = pNewNode;
208 }
209 }
210 }
211 SAFE_RELEASE( pDevices[iDevice] );
212 }
213 }
214
215 bail:
216 if(bstrNamespace)
217 SysFreeString(bstrNamespace);
218 if(bstrDeviceID)
219 SysFreeString(bstrDeviceID);
220 if(bstrClassName)
221 SysFreeString(bstrClassName);
222 for( iDevice=0; iDevice<20; iDevice++ )
223 SAFE_RELEASE( pDevices[iDevice] );
224 SAFE_RELEASE( pEnumDevices );
225 SAFE_RELEASE( pIWbemLocator );
226 SAFE_RELEASE( pIWbemServices );
227
228 return hr;
229 }
230
231 //////////////////////////////////////////////////////////////////////////////
232
CleanupForIsXInputDevice()233 void CleanupForIsXInputDevice()
234 {
235 // Cleanup linked list
236 XINPUT_DEVICE_NODE* pNode = g_pXInputDeviceList;
237 while( pNode )
238 {
239 XINPUT_DEVICE_NODE* pDelete = pNode;
240 pNode = (XINPUT_DEVICE_NODE *)pNode->pNext;
241 SAFE_DELETE( pDelete );
242 }
243 g_pXInputDeviceList = NULL;
244
245 if( bCleanupCOM )
246 CoUninitialize();
247 }
248
249 //////////////////////////////////////////////////////////////////////////////
250
IsXInputDevice(const GUID * guidProduct)251 BOOL IsXInputDevice( const GUID* guidProduct )
252 {
253 // Check each xinput device to see if this device's vid/pid matches
254 XINPUT_DEVICE_NODE* pNode = g_pXInputDeviceList;
255 while( pNode )
256 {
257 if( pNode->dwVidPid == guidProduct->Data1 )
258 return TRUE;
259 pNode = (XINPUT_DEVICE_NODE*)pNode->pNext;
260 }
261
262 return FALSE;
263 }
264 #endif
265
266 //////////////////////////////////////////////////////////////////////////////
267
EnumPeripheralsCallback(LPCDIDEVICEINSTANCE lpddi,LPVOID pvRef)268 BOOL CALLBACK EnumPeripheralsCallback (LPCDIDEVICEINSTANCE lpddi, LPVOID pvRef)
269 {
270 if (GET_DIDEVICE_TYPE(lpddi->dwDevType) == DI8DEVTYPE_GAMEPAD ||
271 GET_DIDEVICE_TYPE(lpddi->dwDevType) == DI8DEVTYPE_JOYSTICK ||
272 GET_DIDEVICE_TYPE(lpddi->dwDevType) == DI8DEVTYPE_1STPERSON)//xbox one controller uses this type
273 {
274 #ifdef HAVE_XINPUT
275 if (IsXInputDevice(&lpddi->guidProduct))
276 {
277 dev_list[num_devices].lpDIDevice = NULL;
278 dev_list[num_devices].is_xinput_device = TRUE;
279 dev_list[num_devices].user_index=((int *)pvRef)[0];
280 ((int *)pvRef)[0]++;
281 num_devices++;
282 }
283 else
284 #endif
285 {
286 dev_list[num_devices].is_xinput_device = FALSE;
287 if (SUCCEEDED(IDirectInput8_CreateDevice(lpDI8, &lpddi->guidInstance, &dev_list[num_devices].lpDIDevice,
288 NULL) ))
289 num_devices++;
290 }
291 }
292
293 return DIENUM_CONTINUE;
294 }
295
296 //////////////////////////////////////////////////////////////////////////////
297
PERDXInit(void)298 int PERDXInit(void)
299 {
300 char tempstr[512];//sprintf(tempstr, "Input. DirectInput8Create error: %s - %s", DXGetErrorString8(ret), DXGetErrorDescription8(ret));
301 HRESULT ret;
302 int user_index=0;
303 u32 i;
304
305 if (PERCORE_INITIALIZED)
306 return 0;
307
308 if (FAILED((ret = DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION,
309 &IID_IDirectInput8, (LPVOID *)&lpDI8, NULL)) ))
310 {
311 sprintf(tempstr, "Input. DirectInput8Create error: %s - %s", DXGetErrorString8(ret), DXGetErrorDescription8(ret));
312 YabSetError(YAB_ERR_CANNOTINIT, tempstr);
313 return -1;
314 }
315
316 #ifdef HAVE_XINPUT
317 SetupForIsXInputDevice();
318 #endif
319 num_devices = 0;
320 IDirectInput8_EnumDevices(lpDI8, DI8DEVCLASS_ALL, EnumPeripheralsCallback,
321 &user_index, DIEDFL_ATTACHEDONLY);
322
323 #ifdef HAVE_XINPUT
324 CleanupForIsXInputDevice();
325 #endif
326
327 for (i = 0; i < num_devices; i++)
328 {
329 if (!dev_list[i].is_xinput_device)
330 {
331 if( FAILED( ret = IDirectInputDevice8_SetDataFormat(dev_list[i].lpDIDevice, &c_dfDIJoystick2 ) ) )
332 return -1;
333
334 // Set the cooperative level to let DInput know how this device should
335 // interact with the system and with other DInput applications.
336 if( FAILED( ret = IDirectInputDevice8_SetCooperativeLevel( dev_list[i].lpDIDevice, DXGetWindow(),
337 DISCL_NONEXCLUSIVE | DISCL_BACKGROUND
338 /* DISCL_EXCLUSIVE |
339 DISCL_FOREGROUND */ ) ) )
340 return -1;
341 }
342 }
343
344 //LoadDefaultPort1A();
345 PERCORE_INITIALIZED = 1;
346 return 0;
347 }
348
349 //////////////////////////////////////////////////////////////////////////////
350
PERDXDeInit(void)351 void PERDXDeInit(void)
352 {
353 u32 i;
354
355 for (i = 0; i < num_devices; i++)
356 {
357 if (dev_list[i].lpDIDevice)
358 {
359 IDirectInputDevice8_Unacquire(dev_list[i].lpDIDevice);
360 IDirectInputDevice8_Release(dev_list[i].lpDIDevice);
361 dev_list[i].lpDIDevice = NULL;
362 }
363 }
364
365 if (lpDI8)
366 {
367 IDirectInput8_Release(lpDI8);
368 lpDI8 = NULL;
369 }
370 PERCORE_INITIALIZED = 0;
371 }
372
373 //////////////////////////////////////////////////////////////////////////////
374
PollAxisAsButton(u32 pad,int min_id,int max_id,int deadzone,int val)375 void PollAxisAsButton(u32 pad, int min_id, int max_id, int deadzone, int val)
376 {
377 //deadzone is part of the id
378 if ( val < -deadzone )
379 {
380 DX_PerKeyUp( pad, deadzone, max_id );
381 DX_PerKeyDown( pad, deadzone, min_id );
382 }
383 else if ( val > deadzone )
384 {
385 DX_PerKeyUp( pad, deadzone, min_id );
386 DX_PerKeyDown( pad, deadzone, max_id );
387 }
388 else
389 {
390 DX_PerKeyUp( pad, deadzone, min_id );
391 DX_PerKeyUp( pad, deadzone, max_id );
392 }
393 }
394
395 //////////////////////////////////////////////////////////////////////////////
396
PollTriggerAsButton(u32 pad,int min_id,int max_id,int deadzone,int val)397 void PollTriggerAsButton(u32 pad, int min_id, int max_id, int deadzone, int val)
398 {
399 #ifdef HAVE_XINPUT
400 //stick value is set to this PollKeys
401 u32 stick = XINPUT_GAMEPAD_TRIGGER_THRESHOLD;
402 if (val > deadzone)
403 {
404 DX_PerKeyUp(pad, stick, max_id);
405 DX_PerKeyDown(pad, stick, min_id);
406 }
407 else
408 {
409 DX_PerKeyUp(pad, stick, min_id);
410 DX_PerKeyUp(pad, stick, max_id);
411 }
412 #endif
413 }
414
415 //////////////////////////////////////////////////////////////////////////////
416
417 #ifdef HAVE_XINPUT
PollXInputButtons(u32 pad,XINPUT_STATE * state)418 void PollXInputButtons(u32 pad, XINPUT_STATE *state)
419 {
420 int i;
421
422 // Check buttons
423 for ( i = 0; i < 16; i++ )
424 {
425 WORD mask = 1 << i;
426
427 if ( (state->Gamepad.wButtons & mask) == mask )
428 DX_PerKeyDown( pad, 0, DIJOFS_BUTTON(i) );
429 else
430 DX_PerKeyUp( pad, 0, DIJOFS_BUTTON(i) );
431 }
432 }
433 #endif
434
435 //////////////////////////////////////////////////////////////////////////////
436
PollKeys(void)437 void PollKeys(void)
438 {
439 u32 i, j;
440 DWORD size=8;
441 HRESULT hr;
442
443 for (i = 0; i < num_devices; i++)
444 {
445 LPDIRECTINPUTDEVICE8 curdevice;
446 DIJOYSTATE2 js;
447
448 #ifdef HAVE_XINPUT
449 if (dev_list[i].is_xinput_device)
450 {
451 XINPUT_STATE state;
452 u8 axislx, axisly, axisrx, axisry;
453 ZeroMemory( &state, sizeof(XINPUT_STATE) );
454 if (XInputGetState(dev_list[i].user_index, &state) == ERROR_DEVICE_NOT_CONNECTED)
455 continue;
456
457 //convert signed values to 0-255
458 axislx = ((state.Gamepad.sThumbLX >> 8) - 0x80) & 0xff;
459 axisly = ~(((state.Gamepad.sThumbLY >> 8) - 0x80) & 0xff);//invert so that up == 0x00
460 axisrx = ((state.Gamepad.sThumbRX >> 8) - 0x80) & 0xff;
461 axisry = ~(((state.Gamepad.sThumbRY >> 8) - 0x80) & 0xff);
462
463 // Handle axis
464 DX_PerAxisValue(i, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, XI_THUMBLX + PAD_DIR_AXISLEFT, axislx);
465 DX_PerAxisValue(i, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, XI_THUMBLY + PAD_DIR_AXISDOWN, axisly);
466 DX_PerAxisValue(i, XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE, XI_THUMBRX + PAD_DIR_AXISLEFT, axisrx);
467 DX_PerAxisValue(i, XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE, XI_THUMBRY + PAD_DIR_AXISDOWN, axisry);
468 DX_PerAxisValue(i, XINPUT_GAMEPAD_TRIGGER_THRESHOLD, XI_TRIGGERL, state.Gamepad.bLeftTrigger);
469 DX_PerAxisValue(i, XINPUT_GAMEPAD_TRIGGER_THRESHOLD, XI_TRIGGERR, state.Gamepad.bRightTrigger);
470
471 // Left Stick
472 PollAxisAsButton(i, XI_THUMBLX+PAD_DIR_AXISLEFT, XI_THUMBLX+PAD_DIR_AXISRIGHT,
473 XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, state.Gamepad.sThumbLX);
474 PollAxisAsButton(i, XI_THUMBLY+PAD_DIR_AXISUP, XI_THUMBLY+PAD_DIR_AXISDOWN,
475 XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, state.Gamepad.sThumbLY);
476
477 // Right Stick
478 PollAxisAsButton(i, XI_THUMBRX+PAD_DIR_AXISLEFT, XI_THUMBRX+PAD_DIR_AXISRIGHT,
479 XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE, state.Gamepad.sThumbRX);
480 PollAxisAsButton(i, XI_THUMBRY+PAD_DIR_AXISUP, XI_THUMBRY+PAD_DIR_AXISDOWN,
481 XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE, state.Gamepad.sThumbRY);
482
483 PollXInputButtons(i, &state);
484 PollTriggerAsButton(i, XI_TRIGGERL, XI_TRIGGERL, XINPUT_GAMEPAD_TRIGGER_THRESHOLD, state.Gamepad.bLeftTrigger);
485 PollTriggerAsButton(i, XI_TRIGGERR, XI_TRIGGERR, XINPUT_GAMEPAD_TRIGGER_THRESHOLD, state.Gamepad.bRightTrigger);
486 continue;
487 }
488 else if (dev_list[i].lpDIDevice == NULL)
489 continue;
490 #else
491 if (dev_list[i].lpDIDevice == NULL)
492 continue;
493 #endif
494
495 curdevice=dev_list[i].lpDIDevice;
496
497 // Poll the device to read the current state
498 hr = IDirectInputDevice8_Poll(curdevice);
499 if( FAILED( hr ) )
500 {
501 hr = IDirectInputDevice8_Acquire(curdevice);
502 while( hr == DIERR_INPUTLOST)
503 hr = IDirectInputDevice8_Acquire(curdevice);
504
505 continue;
506 }
507
508 // Get the input's device state
509 if( FAILED( hr = IDirectInputDevice8_GetDeviceState( curdevice, sizeof( DIJOYSTATE2 ), &js ) ) )
510 continue;
511
512
513 // Handle axis
514 DX_PerAxisValue(i, 0x3FFF, XI_THUMBLX, (u8)((js.lX) >> 8));
515 DX_PerAxisValue(i, 0x3FFF, XI_THUMBLY, (u8)((js.lY) >> 8));
516 DX_PerAxisValue(i, 0x3FFF, XI_THUMBRX, (u8)((js.lRx) >> 8));
517 DX_PerAxisValue(i, 0x3FFF, XI_THUMBRY, (u8)((js.lRy) >> 8));
518
519 // Left Stick
520 PollAxisAsButton(i, XI_THUMBL+PAD_DIR_AXISLEFT, XI_THUMBL+PAD_DIR_AXISRIGHT,
521 0x3FFF, js.lX-0x7FFF);
522 PollAxisAsButton(i, XI_THUMBL+PAD_DIR_AXISUP, XI_THUMBL+PAD_DIR_AXISDOWN,
523 0x3FFF, js.lY-0x7FFF);
524
525 // Right Stick
526 PollAxisAsButton(i, XI_THUMBR+PAD_DIR_AXISLEFT, XI_THUMBR+PAD_DIR_AXISRIGHT,
527 0x3FFF, js.lRx-0x7FFF);
528 PollAxisAsButton(i, XI_THUMBR+PAD_DIR_AXISUP, XI_THUMBR+PAD_DIR_AXISDOWN,
529 0x3FFF, js.lRy-0x7FFF);
530
531 for (j = 0; j < 4; j++)
532 {
533 if (LOWORD(js.rgdwPOV[j]) == 0xFFFF)
534 {
535 DX_PerKeyUp(i, 0, DIJOFS_POV(j)+PAD_DIR_POVUP);
536 DX_PerKeyUp(i, 0, DIJOFS_POV(j)+PAD_DIR_POVRIGHT);
537 DX_PerKeyUp(i, 0, DIJOFS_POV(j)+PAD_DIR_POVDOWN);
538 DX_PerKeyUp(i, 0, DIJOFS_POV(j)+PAD_DIR_POVLEFT);
539 }
540 // POV Up
541 else if (js.rgdwPOV[j] < 4500)
542 {
543 DX_PerKeyDown(i, 0, DIJOFS_POV(j)+PAD_DIR_POVUP);
544 DX_PerKeyUp(i, 0, DIJOFS_POV(j)+PAD_DIR_POVRIGHT);
545 DX_PerKeyUp(i, 0, DIJOFS_POV(j)+PAD_DIR_POVLEFT);
546 }
547 // POV Up-right
548 else if (js.rgdwPOV[j] < 9000)
549 {
550 DX_PerKeyDown(i, 0, DIJOFS_POV(j)+PAD_DIR_POVUP);
551 DX_PerKeyDown(i, 0, DIJOFS_POV(j)+PAD_DIR_POVRIGHT);
552 }
553 // POV Right
554 else if (js.rgdwPOV[j] < 13500)
555 {
556 DX_PerKeyDown(i, 0, DIJOFS_POV(j)+PAD_DIR_POVRIGHT);
557 DX_PerKeyUp(i, 0, DIJOFS_POV(j)+PAD_DIR_POVDOWN);
558 DX_PerKeyUp(i, 0, DIJOFS_POV(j)+PAD_DIR_POVUP);
559 }
560 // POV Right-down
561 else if (js.rgdwPOV[j] < 18000)
562 {
563 DX_PerKeyDown(i, 0, DIJOFS_POV(j)+PAD_DIR_POVRIGHT);
564 DX_PerKeyDown(i, 0, DIJOFS_POV(j)+PAD_DIR_POVDOWN);
565 }
566 // POV Down
567 else if (js.rgdwPOV[j] < 22500)
568 {
569 DX_PerKeyDown(i, 0, DIJOFS_POV(j)+PAD_DIR_POVDOWN);
570 DX_PerKeyUp(i, 0, DIJOFS_POV(j)+PAD_DIR_POVLEFT);
571 DX_PerKeyUp(i, 0, DIJOFS_POV(j)+PAD_DIR_POVRIGHT);
572 }
573 // POV Down-left
574 else if (js.rgdwPOV[j] < 27000)
575 {
576 DX_PerKeyDown(i, 0, DIJOFS_POV(j)+PAD_DIR_POVDOWN);
577 DX_PerKeyDown(i, 0, DIJOFS_POV(j)+PAD_DIR_POVLEFT);
578 }
579 // POV Left
580 else if (js.rgdwPOV[j] < 31500)
581 {
582 DX_PerKeyDown(i, 0, DIJOFS_POV(j)+PAD_DIR_POVLEFT);
583 DX_PerKeyUp(i, 0, DIJOFS_POV(j)+PAD_DIR_POVUP);
584 DX_PerKeyUp(i, 0, DIJOFS_POV(j)+PAD_DIR_POVDOWN);
585 }
586 // POV Left-up
587 else if (js.rgdwPOV[j] < 36000)
588 {
589 DX_PerKeyDown(i, 0, DIJOFS_POV(j)+PAD_DIR_POVLEFT);
590 DX_PerKeyDown(i, 0, DIJOFS_POV(j)+PAD_DIR_POVUP);
591 }
592 }
593
594 for (j = 0; j < 32; j++)
595 {
596 if (js.rgbButtons[j] & 0x80)
597 DX_PerKeyDown(i,0,DIJOFS_BUTTON(j));
598 else
599 DX_PerKeyUp(i,0,DIJOFS_BUTTON(j));
600 }
601 }
602 }
603
604 //////////////////////////////////////////////////////////////////////////////
605
PERDXHandleEvents(void)606 int PERDXHandleEvents(void)
607 {
608 PollKeys();
609
610 if (YabauseExec() != 0)
611 return -1;
612
613 return 0;
614 }
615
616 //////////////////////////////////////////////////////////////////////////////
617
ScanXInputAxis(int pad,LONG axis,LONG deadzone,SHORT stick,int min_id,int max_id)618 u32 ScanXInputAxis(int pad, LONG axis, LONG deadzone, SHORT stick, int min_id, int max_id)
619 {
620 if (axis < -deadzone)
621 return DX_MAKEKEY(pad, stick, min_id);
622 else if (axis > deadzone)
623 return DX_MAKEKEY(pad, stick, max_id);
624 else
625 return 0;
626 }
627
628 //////////////////////////////////////////////////////////////////////////////
629
ScanXInputTrigger(int pad,BYTE value,BYTE deadzone,SHORT stick,int id)630 u32 ScanXInputTrigger(int pad, BYTE value, BYTE deadzone, SHORT stick, int id)
631 {
632 if (value > deadzone)
633 return DX_MAKEKEY(pad, stick, id);
634 else
635 return 0;
636 }
637
638 //////////////////////////////////////////////////////////////////////////////
639
PERDXScan(u32 flags)640 u32 PERDXScan(u32 flags)
641 {
642 int i, j;
643 HRESULT hr;
644
645 for (i = 0; i < num_devices; i++)
646 {
647 LPDIRECTINPUTDEVICE8 curdevice;
648 DIJOYSTATE2 js;
649 u32 scan;
650
651 #ifdef HAVE_XINPUT
652 if (dev_list[i].is_xinput_device)
653 {
654 XINPUT_STATE state;
655 ZeroMemory( &state, sizeof(XINPUT_STATE) );
656 if (XInputGetState(dev_list[i].user_index, &state) == ERROR_DEVICE_NOT_CONNECTED)
657 continue;
658
659 //min_id max_id have to match for scan and poll
660 // Handle axis
661 if (flags & PERSF_AXIS)
662 {
663 // L Thumb
664 if ((scan = ScanXInputAxis(i, state.Gamepad.sThumbLX,
665 XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE,
666 XI_THUMBLX + PAD_DIR_AXISLEFT, XI_THUMBLX + PAD_DIR_AXISRIGHT)) != 0)
667 return scan;
668 if ((scan = ScanXInputAxis(i, state.Gamepad.sThumbLY,
669 XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE,
670 XI_THUMBLY + PAD_DIR_AXISUP, XI_THUMBLY + PAD_DIR_AXISDOWN)) != 0)
671 return scan;
672
673 // R Thumb
674 if ((scan = ScanXInputAxis(i, state.Gamepad.sThumbRX,
675 XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE, XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE,
676 XI_THUMBRX + PAD_DIR_AXISLEFT, XI_THUMBRX + PAD_DIR_AXISRIGHT)) != 0)
677 return scan;
678
679 if ((scan = ScanXInputAxis(i, state.Gamepad.sThumbRY,
680 XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE, XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE,
681 XI_THUMBRY + PAD_DIR_AXISUP, XI_THUMBRY + PAD_DIR_AXISDOWN)) != 0)
682 return scan;
683
684 // L Trigger
685 if ((scan = ScanXInputTrigger(i, state.Gamepad.bLeftTrigger, XINPUT_GAMEPAD_TRIGGER_THRESHOLD,
686 XINPUT_GAMEPAD_TRIGGER_THRESHOLD, XI_TRIGGERL)) != 0)
687 return scan;
688
689 // R Trigger
690 if ((scan = ScanXInputTrigger(i, state.Gamepad.bRightTrigger, XINPUT_GAMEPAD_TRIGGER_THRESHOLD,
691 XINPUT_GAMEPAD_TRIGGER_THRESHOLD, XI_TRIGGERR)) != 0)
692 return scan;
693 }
694
695 if (flags & PERSF_HAT)
696 {
697 // L Thumb
698 if ((scan = ScanXInputAxis(i, state.Gamepad.sThumbLX,
699 XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, 0,
700 XI_THUMBL+PAD_DIR_AXISLEFT, XI_THUMBL+PAD_DIR_AXISRIGHT)) != 0)
701 return scan;
702 if ((scan = ScanXInputAxis(i, state.Gamepad.sThumbLY,
703 XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, 0,
704 XI_THUMBL+PAD_DIR_AXISUP, XI_THUMBL+PAD_DIR_AXISDOWN)) != 0)
705 return scan;
706
707 // R Thumb
708 if ((scan = ScanXInputAxis(i, state.Gamepad.sThumbRX,
709 XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE, 0,
710 XI_THUMBR+PAD_DIR_AXISLEFT, XI_THUMBR+PAD_DIR_AXISRIGHT)) != 0)
711 return scan;
712 if ((scan = ScanXInputAxis(i, state.Gamepad.sThumbRY,
713 XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE, 0,
714 XI_THUMBR+PAD_DIR_AXISUP, XI_THUMBR+PAD_DIR_AXISDOWN)) != 0)
715 return scan;
716
717 if (state.Gamepad.wButtons & 0xF)
718 {
719 // Return lowest bit
720 for (j = 0; j < 16; j++)
721 {
722 if (state.Gamepad.wButtons & (1 << j))
723 return DX_MAKEKEY(i, 0, DIJOFS_BUTTON(j));
724 }
725 }
726 }
727
728 if (flags & PERSF_BUTTON)
729 {
730 if (state.Gamepad.wButtons & 0xF3F0)
731 {
732 // Return lowest bit
733 for (j = 0; j < 16; j++)
734 {
735 if (state.Gamepad.wButtons & (1 << j))
736 return DX_MAKEKEY(i, 0, DIJOFS_BUTTON(j));
737 }
738 }
739 }
740
741 continue;
742 }
743 else if (dev_list[i].lpDIDevice == NULL)
744 continue;
745 #else
746 if (dev_list[i].lpDIDevice == NULL)
747 continue;
748 #endif
749
750 curdevice=dev_list[i].lpDIDevice;
751
752 // Poll the device to read the current state
753 hr = IDirectInputDevice8_Poll(curdevice);
754 if( FAILED( hr ) )
755 {
756 hr = IDirectInputDevice8_Acquire(curdevice);
757 while( hr == DIERR_INPUTLOST)
758 hr = IDirectInputDevice8_Acquire(curdevice);
759
760 continue;
761 }
762
763 // Get the input's device state
764 if( FAILED( hr = IDirectInputDevice8_GetDeviceState( curdevice, sizeof( DIJOYSTATE2 ), &js ) ) )
765 continue;
766
767 if (flags & PERSF_AXIS)
768 {
769 // Left Stick
770 if ((scan = ScanXInputAxis(i, js.lX-0x7FFF, 0x3FFF, 0x3FFF, XI_THUMBLX, XI_THUMBLX)) != 0)
771 return scan;
772 if ((scan = ScanXInputAxis(i, js.lY-0x7FFF, 0x3FFF, 0x3FFF, XI_THUMBLY, XI_THUMBLY)) != 0)
773 return scan;
774
775 // Right Stick
776 if ((scan = ScanXInputAxis(i, js.lRx-0x7FFF, 0x3FFF, 0x3FFF, XI_THUMBRX, XI_THUMBRX)) != 0)
777 return scan;
778 if ((scan = ScanXInputAxis(i, js.lRy-0x7FFF, 0x3FFF, 0x3FFF, XI_THUMBRY, XI_THUMBRY)) != 0)
779 return scan;
780 }
781
782 if (flags & PERSF_HAT)
783 {
784 // L Thumb
785 if ((scan = ScanXInputAxis(i, js.lX-0x7FFF, 0x3FFF, 0,
786 XI_THUMBL+PAD_DIR_AXISLEFT, XI_THUMBL+PAD_DIR_AXISRIGHT)) != 0)
787 return scan;
788 if ((scan = ScanXInputAxis(i, js.lY-0x7FFF, 0x3FFF, 0,
789 XI_THUMBL+PAD_DIR_AXISUP, XI_THUMBL+PAD_DIR_AXISDOWN)) != 0)
790 return scan;
791
792 // R Thumb
793 if ((scan = ScanXInputAxis(i, js.lRx-0x7FFF, 0x3FFF, 0,
794 XI_THUMBR+PAD_DIR_AXISLEFT, XI_THUMBR+PAD_DIR_AXISRIGHT)) != 0)
795 return scan;
796 if ((scan = ScanXInputAxis(i, js.lRy-0x7FFF, 0x3FFF, 0,
797 XI_THUMBR+PAD_DIR_AXISUP, XI_THUMBR+PAD_DIR_AXISDOWN)) != 0)
798 return scan;
799
800 for (j = 0; j < 4; j++)
801 {
802 // POV Up
803 if (js.rgdwPOV[j] < 4500)
804 return DX_MAKEKEY(i,0,DIJOFS_POV(j)+PAD_DIR_POVUP);
805 // POV Right
806 else if (js.rgdwPOV[j] < 13500)
807 return DX_MAKEKEY(i,0,DIJOFS_POV(j)+PAD_DIR_POVRIGHT);
808 // POV Down
809 else if (js.rgdwPOV[j] < 22500)
810 return DX_MAKEKEY(i,0,DIJOFS_POV(j)+PAD_DIR_POVDOWN);
811 // POV Left
812 else if (js.rgdwPOV[j] < 31500)
813 return DX_MAKEKEY(i,0,DIJOFS_POV(j)+PAD_DIR_POVLEFT);
814 }
815 }
816
817 if (flags & PERSF_BUTTON)
818 {
819 for (j = 0; j < 32; j++)
820 {
821 if (js.rgbButtons[j] & 0x80)
822 return DX_MAKEKEY(i,0,DIJOFS_BUTTON(j));
823 }
824 }
825 }
826
827 return 0;
828 }
829
830 //////////////////////////////////////////////////////////////////////////////
831
PERDXFlush(void)832 void PERDXFlush(void)
833 {
834 }
835
836 //////////////////////////////////////////////////////////////////////////////