Joypad Scol plugin
Joypad.cpp
Go to the documentation of this file.
1#include "Joypad.h"
2
3extern int JOYPAD_DATA_CB;
4
5#ifdef _WIN32
6#include <Oleauto.h>
7
8boost::mutex gMutex;
9
10std::set<GUID> lJoyId;
11LPDIRECTINPUT8 DIinterf;
12
13Joypad::Joypad(int index)
14{
15 mIsXInput = false;
16 pJoystick = NULL;
17 mTick = NULL;
18 mConnected = false;
19 mControllerId = -1;
20 mIndex = index;
21
22 mRumbleEffect = nullptr;
23
24 //XInput
25 ZeroMemory(&mRumbleState, sizeof(XINPUT_VIBRATION));
26 ZeroMemory(&mDIJoyState, sizeof(DIJOYSTATE2));
27
28 // Run thread
29 mIsrunning = true;
30 mThread = boost::thread(boost::bind(&Joypad::run, this));
31}
32
34{
35 mIsrunning = false;
36 mThread.join();
37}
38
39void Joypad::run()
40{
41 try
42 {
43 // get new data 30 time a second
44 while (mIsrunning)
45 {
46 boost::mutex::scoped_lock l(mMutex);
47 mTick = GetTickCount();
48
49 if (mIsrunning && !mConnected)
50 boost::this_thread::sleep_for(boost::chrono::milliseconds(200));
51
52 if (mIsrunning && !mConnected && SUCCEEDED(InitDirectInput()))
53 mConnected = true;
54
55 if (mConnected)
56 if (UpdateInputState() != S_OK)
57 mConnected = false;
58
59 if (!mConnected)
60 FreeDirectInput();
61
62 int elapsedTime = 33 - (int)(GetTickCount() - mTick);
63 if (elapsedTime > 0)
64 boost::this_thread::sleep_for(boost::chrono::milliseconds(elapsedTime));
65 }
66 FreeDirectInput();
67 }
68 catch (std::exception ex)
69 {
70 MMechostr(MSKDEBUG, "Joypad > error thread : %s \n", ex.what());
71 }
72}
73
75{
76 boost::mutex::scoped_lock l(mMutex);
77 return mConnected;
78}
79
81{
82 boost::mutex::scoped_lock l(mMutex);
83 return mIsrunning;
84}
85
86bool Joypad::StartRumble(float intensity)
87{
88 StopRumble();
89
90 if (mIsXInput)
91 {
92 mRumbleState.wLeftMotorSpeed = static_cast<WORD>(intensity * 65535.0f);
93 mRumbleState.wRightMotorSpeed = static_cast<WORD>(intensity * 65535.0f);
94
95 XInputSetState(mControllerId, &mRumbleState);
96 }
97 else if (pJoystick)
98 {
99 DIEFFECT effect = {};
100 effect.dwSize = sizeof(DIEFFECT);
101 effect.dwDuration = INFINITE;
102 effect.dwGain = DWORD(10000.0f * intensity);
103 effect.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS;
104 effect.cAxes = 2;
105 effect.rgdwAxes = new DWORD[2];
106 effect.rgdwAxes[0] = DIJOFS_X;
107 effect.rgdwAxes[1] = DIJOFS_Y;
108 effect.rglDirection = new LONG[2];
109 effect.rglDirection[0] = -200;
110 effect.rglDirection[1] = 200;
111
112 HRESULT hr = pJoystick->CreateEffect(GUID_Sine, &effect, &mRumbleEffect, nullptr);
113 if (FAILED(hr))
114 {
115 // Handle error
116 return false;
117 }
118
119 // Start the rumble effect
120 hr = mRumbleEffect->Start(1, 0);
121 if (FAILED(hr))
122 {
123 mRumbleEffect->Release(); // Release the effect
124 mRumbleEffect = nullptr;
125 // Handle error
126 return false;
127 }
128 }
129 else
130 return false;
131
132 return true;
133}
134
135
137{
138 if (mIsXInput)
139 {
140 ZeroMemory(&mRumbleState, sizeof(XINPUT_VIBRATION));
141 XInputSetState(mControllerId, &mRumbleState);
142 }
143 else
144 {
145 if (mRumbleEffect)
146 {
147 HRESULT hr = mRumbleEffect->Stop();
148 if (FAILED(hr))
149 {
150 // Handle error
151 return;
152 }
153
154 mRumbleEffect->Release(); // Release the effect
155 mRumbleEffect = nullptr;
156 }
157 }
158}
159
160//-----------------------------------------------------------------------------
161// Name: FreeDirectInput()
162// Desc: Initialize the DirectInput variables.
163//-----------------------------------------------------------------------------
164VOID Joypad::FreeDirectInput()
165{
166 boost::mutex::scoped_lock l(gMutex);
167
168 StopRumble();
169
170 // Unacquire the device one last time just in case
171 // the app tried to exit while the device is still acquired.
172 if (pJoystick)
173 pJoystick->Unacquire();
174
175 // Release any DirectInput objects.
176 SAFE_RELEASE(pJoystick);
177
178 std::set<GUID>::iterator iJoystickIdSearched = lJoyId.find(mInstanceId);
179 if (iJoystickIdSearched != lJoyId.end())
180 lJoyId.erase(iJoystickIdSearched);
181
182 if (lJoyId.empty())
183 SAFE_RELEASE(DIinterf);
184}
185
186
187//-----------------------------------------------------------------------------
188// Name: InitDirectInput()
189// Desc: Initialize the DirectInput variables.
190//-----------------------------------------------------------------------------
191HRESULT Joypad::InitDirectInput()
192{
193 boost::mutex::scoped_lock l(gMutex);
194 HRESULT hr;
195
196 // Register with the DirectInput subsystem and get a pointer
197 // to a IDirectInput interface we can use.
198 // Create a DInput object
199
200 if (DIinterf == NULL)
201 {
202 if (FAILED(hr = DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION,
203 IID_IDirectInput8, (VOID**)&DIinterf, NULL)))
204 return hr;
205 }
206
207 DIJOYCONFIG PreferredJoyCfg;
208 ZeroMemory((void*)&PreferredJoyCfg, sizeof(DIJOYCONFIG));
209 PreferredJoyCfg.dwSize = sizeof(DIJOYCONFIG) + 1;
210
211 pEnumContext.pPreferredJoyCfg = &PreferredJoyCfg;
212 pEnumContext.bPreferredJoyCfgValid = false;
213
214 IDirectInputJoyConfig8* pJoyConfig = NULL;
215 if (FAILED(hr = DIinterf->QueryInterface(IID_IDirectInputJoyConfig8, (void**)&pJoyConfig)))
216 return hr;
217
218 if (SUCCEEDED(pJoyConfig->GetConfig(0, &PreferredJoyCfg, DIJC_GUIDINSTANCE))) // This function is expected to fail if no joystick is attached
219 pEnumContext.bPreferredJoyCfgValid = true;
220 SAFE_RELEASE(pJoyConfig);
221
222 if (DIinterf == NULL)
223 return -1;
224
225 mControllerId = -1;
226
227 // Look for a simple joystick we can use for this sample program.
228 if (FAILED(hr = DIinterf->EnumDevices(DI8DEVCLASS_GAMECTRL, EnumJoysticksCallback, this, DIEDFL_ATTACHEDONLY)))
229 return hr;
230
231 // Make sure we got a joystick
232 if (NULL == pJoystick)
233 {
234 //MMechostr(MSKDEBUG, "Joystick not found.\n");
235 return -1;
236 }
237
238 // Set the data format to "simple joystick" - a predefined data format
239 //
240 // A data format specifies which controls on a device we are interested in,
241 // and how they should be reported. This tells DInput that we will be
242 // passing a DIJOYSTATE2 structure to IDirectInputDevice::GetDeviceState().
243 if (FAILED(hr = pJoystick->SetDataFormat(&c_dfDIJoystick2)))
244 return hr;
245
246 // Set the cooperative level to let DInput know how this device should
247 // interact with the system and with other DInput applications.
248 if (FAILED(hr = pJoystick->SetCooperativeLevel((HWND)SCgetExtra("hscol"), DISCL_EXCLUSIVE | DISCL_BACKGROUND)))
249 return hr;
250
251 // Enumerate the joystick objects. The callback function enabled user
252 // interface elements for objects that are found, and sets the min/max
253 // values property for discovered axes.
254 if (FAILED(hr = pJoystick->EnumObjects(EnumObjectsCallback, (VOID*)this, DIDFT_ALL)))
255 return hr;
256
257 //MMechostr(MSKDEBUG,"Joypad > InitDirectInput OK\n");
258 return S_OK;
259}
260
261
262//-----------------------------------------------------------------------------
263// Name: UpdateInputState()
264// Desc: Get the input device's state and display it.
265//-----------------------------------------------------------------------------
266HRESULT Joypad::UpdateInputState()
267{
268 HRESULT hr = S_OK;
269
270 if (NULL == pJoystick)
271 return S_FALSE;
272
273 // Poll the device to read the current state
274 hr = pJoystick->Poll();
275 if (FAILED(hr) && (DIinterf != NULL))
276 {
277 // DInput is telling us that the input stream has been
278 // interrupted. We aren't tracking any state between polls, so
279 // we don't have any special reset that needs to be done. We
280 // just re-acquire and try again.
281 hr = pJoystick->Acquire();
282 if (hr != DI_OK)
283 return S_FALSE;
284 }
285
286 // Get the input's device state
287 if ((pJoystick->GetDeviceState(sizeof(DIJOYSTATE2), &mDIJoyState)) != DI_OK)
288 return S_FALSE; // The device should have been acquired during the Poll()
289
290 DIJOYSTATE2* ndata = new DIJOYSTATE2;
291 *ndata = mDIJoyState;
292
293 // manage thrustmaster
294 /*
295 if (!mIsXInput)
296 {
297 if (ndata->lRz != 0.0 && ndata->lRx == 0.0)
298 ndata->lRx = ndata->lRz;
299 if (ndata->rglSlider[0] != 0.0 && ndata->lRy == 0.0)
300 ndata->lRy = ndata->rglSlider[0];
301 }*/
302
303 OBJpostEvent(JOYPAD_DATA_CB, SCOL_PTR this, SCOL_PTR ndata);
304 return S_OK;
305}
306
307//-----------------------------------------------------------------------------
308// Name: EnumJoysticksCallback()
309// Desc: Called once for each enumerated joystick. If we find one, create a
310// device interface on it so we can play with it.
311//-----------------------------------------------------------------------------
312BOOL CALLBACK EnumJoysticksCallback(const DIDEVICEINSTANCE* pdidInstance,
313 VOID* pContext)
314{
315 Joypad* joypad = (Joypad*)pContext;
316 if (joypad == 0)
317 return DIENUM_STOP;
318
319 HRESULT hr;
320
321 joypad->mControllerId++;
322
323 if (joypad->mIndex != 0 && ((joypad->mIndex - 1) != joypad->mControllerId))
324 return DIENUM_CONTINUE;
325
326 //MMechostr(MSKDEBUG, "EnumJoysticksCallback start %s : %i\n", pdidInstance->tszInstanceName, pdidInstance->guidInstance);
327
328 //use only gamepad if not already used by another isntance
329 std::set<GUID>::iterator iJoystickIdSearched = lJoyId.find(pdidInstance->guidInstance);
330 if (iJoystickIdSearched != lJoyId.end())
331 return DIENUM_CONTINUE;
332
333 if (DIinterf == NULL)
334 return DIENUM_STOP;
335
336 // Obtain an interface to the enumerated joystick.
337 hr = DIinterf->CreateDevice(pdidInstance->guidInstance, &joypad->pJoystick, NULL);
338
339 // If it failed, then we can't use this joystick. (Maybe the user unplugged
340 // it while we were in the middle of enumerating it.)
341 if (FAILED(hr))
342 return DIENUM_CONTINUE;
343
344 DIPROPDWORD dipdw; // DIPROPDWORD contains a DIPROPHEADER structure.
345 dipdw.diph.dwSize = sizeof(DIPROPDWORD);
346 dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
347 dipdw.diph.dwObj = 0; // device property
348 dipdw.diph.dwHow = DIPH_DEVICE;
349
350 hr = joypad->pJoystick->GetProperty(DIPROP_VIDPID, &dipdw.diph);
351 if (FAILED(hr))
352 {
353 SAFE_RELEASE(joypad->pJoystick);
354 joypad->pJoystick = NULL;
355 return DIENUM_CONTINUE;
356 }
357
358 DWORD vendorID = LOWORD(dipdw.dwData);
359 DWORD productID = HIWORD(dipdw.dwData);
360
361 // Ignore Nintendo devices
362 if (vendorID == 0x057e)
363 {
364 SAFE_RELEASE(joypad->pJoystick);
365 joypad->pJoystick = NULL;
366 return DIENUM_CONTINUE;
367 }
368
369 lJoyId.insert(pdidInstance->guidInstance);
370 joypad->mInstanceId = pdidInstance->guidInstance;
371
372 XINPUT_STATE xInputState;
373 joypad->mIsXInput = XInputGetState(joypad->mControllerId, &xInputState) == ERROR_SUCCESS;
374
375 //MMechostr(MSKDEBUG, "EnumJoysticksCallback end %s : %i\n", pdidInstance->tszInstanceName, pdidInstance->guidInstance);
376
377 // Stop enumeration. Note: we're just taking the first joystick we get.
378 return DIENUM_STOP;
379}
380
381
382//-----------------------------------------------------------------------------
383// Name: EnumObjectsCallback()
384// Desc: Callback function for enumerating objects (axes, buttons, POVs) on a
385// joystick. This function enables user interface elements for objects
386// that are found to exist, and scales axes min/max values.
387//-----------------------------------------------------------------------------
388BOOL CALLBACK EnumObjectsCallback(const DIDEVICEOBJECTINSTANCE* pdidoi,
389 VOID* pContext)
390{
391 Joypad * joypad = (Joypad *)pContext;
392
393 static int nSliderCount = 0; // Number of returned slider controls
394 static int nPOVCount = 0; // Number of returned POV controls
395
396 // For axes that are returned, set the DIPROP_RANGE property for the
397 // enumerated axis in order to scale min/max values.
398 if (pdidoi->dwType & DIDFT_AXIS)
399 {
400 DIPROPRANGE diprg;
401 diprg.diph.dwSize = sizeof(DIPROPRANGE);
402 diprg.diph.dwHeaderSize = sizeof(DIPROPHEADER);
403 diprg.diph.dwHow = DIPH_BYID;
404 diprg.diph.dwObj = pdidoi->dwType; // Specify the enumerated axis
405 diprg.lMin = -1000;
406 diprg.lMax = +1000;
407
408 // Set the range for the axis
409 if (FAILED(joypad->pJoystick->SetProperty(DIPROP_RANGE, &diprg.diph)))
410 return DIENUM_STOP;
411 }
412
413 return DIENUM_CONTINUE;
414}
415
416#elif defined(ANDROID)
417#include <android/input.h>
418
419extern AInputQueue* AndroidInputQueue;
420std::set<int> lJoyId;
421std::list<Joypad*> Joypad::lJoypad;
422
423void Joypad::updateInputEvent(AInputEvent* event)
424{
425 std::list<Joypad*>::iterator it;
426 for (it = lJoypad.begin(); it != lJoypad.end(); it++)
427 {
428 (*it)->updateEvent(event);
429 }
430}
431
432Joypad::Joypad(int index)
433{
434 mConnected = true;
435 mStickMode2 = false;
436 mDeviceId = -1;
437 mIndex = index;
438
439 mTick = 0;
440
441 for (size_t i = 0; i < 16; i++)
442 mDIJoyState.rgbButtons[i] = 0;
443
444 for (size_t i = 0; i < 4; i++)
445 mDIJoyState.rgdwPOV[i] = -1;
446
447 mDIJoyState.lX = 0;
448 mDIJoyState.lY = 0;
449 mDIJoyState.lRx = 0;
450 mDIJoyState.lRy = 0;
451 mDIJoyState.rglSlider[0] = 0;
452 mDIJoyState.rglSlider[1] = 0;
453
454 mIsrunning = true;
455 lJoypad.push_back(this);
456}
457
458Joypad::~Joypad(void)
459{
460 mIsrunning = false;
461
462 if (mDeviceId >= 0)
463 {
464 std::set<int>::iterator iJoystickIdSearched = lJoyId.find(mDeviceId);
465 if (iJoystickIdSearched != lJoyId.end())
466 lJoyId.erase(iJoystickIdSearched);
467 }
468
469 lJoypad.remove(this);
470}
471
472DIJOYSTATE2* Joypad::initData()
473{
474 DIJOYSTATE2* data = new DIJOYSTATE2;
475 for (size_t i = 0; i < 16; i++)
476 {
477 data->rgbButtons[i] = mDIJoyState.rgbButtons[i];
478 }
479
480 for (size_t i = 0; i < 4; i++)
481 data->rgdwPOV[i] = mDIJoyState.rgdwPOV[i];
482
483 data->lX = mDIJoyState.lX;
484 data->lY = mDIJoyState.lY;
485 data->lRx = mDIJoyState.lRx;
486 data->lRy = mDIJoyState.lRy;
487 data->rglSlider[0] = mDIJoyState.rglSlider[0];
488 data->rglSlider[1] = mDIJoyState.rglSlider[1];
489
490 return data;
491}
492
493void Joypad::configAxis()
494{
495 struct android_app* androidApp = (struct android_app*)SCgetExtra("this_inst");
496 if (androidApp)
497 {
498 // get screen orientation from java
499 JNIEnv* env;
500 ANativeActivity* nativeActivity = androidApp->activity;
501 nativeActivity->vm->AttachCurrentThread(&env, NULL);
502
503 //TODO setup axis
504 //"getDevice", "(I)Landroid/view/InputDevice;"
505 //"getMotionRanges", "()Ljava/util/List;"
506 //"getAxis", "()I"
507
508 jclass cInputDevice = env->FindClass("android/view/InputDevice");
509 jmethodID mGetInputDevice = env->GetStaticMethodID(cInputDevice, "getDevice", "(I)Landroid/view/InputDevice;");
510 jmethodID mGetMotionRanges = env->GetMethodID(cInputDevice, "getMotionRanges", "()Ljava/util/List;");
511
512 jclass cRange = env->FindClass("android/view/InputDevice$MotionRange");
513 jmethodID mGetAxis = env->GetMethodID(cRange, "getAxis", "()I");
514
515 jobject oDevice = (jobject)env->CallStaticObjectMethod(cInputDevice, mGetInputDevice, (jint)mDeviceId);
516 if (!env->ExceptionCheck() && oDevice)
517 {
518 jobject oMotionRanges = (jobject)env->CallObjectMethod(oDevice, mGetMotionRanges);
519 jclass cList = env->FindClass("java/util/List");
520 jmethodID mSize = env->GetMethodID(cList, "size", "()I");
521 jmethodID mGet = env->GetMethodID(cList, "get", "(I)Ljava/lang/Object;");
522
523 if (!env->ExceptionCheck() && oMotionRanges)
524 {
525 int length = env->CallIntMethod(oMotionRanges, mSize);
526 for (int i = 0; i < length; i++)
527 {
528 jobject oRange = (jobject)env->CallObjectMethod(oMotionRanges, mGet, (jint)i);
529 int axis = (int)env->CallIntMethod(oRange, mGetAxis);
530
531 if (axis == AMOTION_EVENT_AXIS_RX || axis == AMOTION_EVENT_AXIS_RY)
532 mStickMode2 = true;
533
534 env->DeleteLocalRef(oRange);
535 }
536
537 env->DeleteLocalRef(oMotionRanges);
538 }
539 env->DeleteLocalRef(oDevice);
540 }
541
542 if (env->ExceptionCheck())
543 env->ExceptionClear();
544
545 // release env
546 nativeActivity->vm->DetachCurrentThread();
547 }
548}
549
550void Joypad::updateEvent(AInputEvent* event)
551{
552 bool haveData = false;
553 int32_t source = AInputEvent_getSource(event);
554 int32_t eventType = AInputEvent_getType(event);
555 int deviceid = AInputEvent_getDeviceId(event);
556
557 switch (eventType)
558 {
559 case AINPUT_EVENT_TYPE_KEY:
560 {
561 int32_t keycode = AKeyEvent_getKeyCode(event);
562 int32_t action = AKeyEvent_getAction(event);
563
564 int state = (action == AKEY_EVENT_ACTION_DOWN) ? 1 : 0;
565 int pos = -1;
566
567 switch (keycode)
568 {
569 case AKEYCODE_BUTTON_A:
570 case AKEYCODE_BUTTON_1:
571 pos = 0;
572 break;
573 case AKEYCODE_BUTTON_B:
574 case AKEYCODE_BUTTON_2:
575 pos = 1;
576 break;
577 case AKEYCODE_BUTTON_X:
578 case AKEYCODE_BUTTON_3:
579 pos = 2;
580 break;
581 case AKEYCODE_BUTTON_Y:
582 case AKEYCODE_BUTTON_4:
583 pos = 3;
584 break;
585 case AKEYCODE_BUTTON_L1:
586 case AKEYCODE_BUTTON_5:
587 pos = 4;
588 break;
589 case AKEYCODE_BUTTON_L2:
590 case AKEYCODE_BUTTON_6:
591 pos = 5;
592 break;
593 case AKEYCODE_BUTTON_SELECT:
594 case AKEYCODE_BUTTON_7:
595 pos = 6;
596 break;
597 case AKEYCODE_BUTTON_START:
598 case AKEYCODE_BUTTON_8:
599 pos = 7;
600 break;
601 case AKEYCODE_BUTTON_THUMBL:
602 case AKEYCODE_BUTTON_9:
603 pos = 8;
604 break;
605 case AKEYCODE_BUTTON_THUMBR:
606 case AKEYCODE_BUTTON_10:
607 pos = 9;
608 break;
609 case AKEYCODE_BUTTON_C:
610 case AKEYCODE_BUTTON_11:
611 pos = 10;
612 break;
613 case AKEYCODE_BUTTON_Z:
614 case AKEYCODE_BUTTON_12:
615 pos = 11;
616 break;
617 case AKEYCODE_BUTTON_R1:
618 case AKEYCODE_BUTTON_13:
619 pos = 12;
620 break;
621 case AKEYCODE_BUTTON_R2:
622 case AKEYCODE_BUTTON_14:
623 pos = 13;
624 break;
625 case AKEYCODE_BUTTON_MODE:
626 case AKEYCODE_BUTTON_15:
627 pos = 14;
628 break;
629 case AKEYCODE_BUTTON_16:
630 pos = 15;
631 break;
632 }
633
634 if (pos >= 0)
635 {
636 //TODO use mIndex
637 std::set<int>::iterator iJoystickIdSearched = lJoyId.find(deviceid);
638 if (mDeviceId == -1 && iJoystickIdSearched == lJoyId.end())
639 {
640 mDeviceId = deviceid;
641 lJoyId.insert(mDeviceId);
642 configAxis();
643 }
644 else if (mDeviceId != deviceid)
645 return;
646
647 haveData = true;
648 mDIJoyState.rgbButtons[pos] = state;
649 }
650 break;
651 }
652 case AINPUT_EVENT_TYPE_MOTION:
653 {
654 if ((source != AINPUT_SOURCE_GAMEPAD) && (source != AINPUT_SOURCE_JOYSTICK))
655 return;
656
657 std::set<int>::iterator iJoystickIdSearched = lJoyId.find(deviceid);
658 if (mDeviceId == -1 && iJoystickIdSearched == lJoyId.end())
659 {
660 mDeviceId = deviceid;
661 lJoyId.insert(mDeviceId);
662 configAxis();
663 }
664 else if (mDeviceId != deviceid)
665 return;
666
667 haveData = true;
668 for (size_t p = 0; p < AMotionEvent_getPointerCount(event); p++)
669 {
670 mDIJoyState.lX = (int)(AMotionEvent_getAxisValue(event, AMOTION_EVENT_AXIS_X, p) * 1000.0f);
671 mDIJoyState.lY = (int)(AMotionEvent_getAxisValue(event, AMOTION_EVENT_AXIS_Y, p) * 1000.0f);
672
673 // XBOX 360 Wireless
674 if (mStickMode2)
675 {
676 mDIJoyState.lRx = (int)(AMotionEvent_getAxisValue(event, AMOTION_EVENT_AXIS_RX, p) * 1000.0f);
677 mDIJoyState.lRy = (int)(AMotionEvent_getAxisValue(event, AMOTION_EVENT_AXIS_RY, p) * 1000.0f);
678 mDIJoyState.rglSlider[0] = (int)(AMotionEvent_getAxisValue(event, AMOTION_EVENT_AXIS_Z, p) * 1000.0f);
679 mDIJoyState.rglSlider[1] = (int)(AMotionEvent_getAxisValue(event, AMOTION_EVENT_AXIS_RZ, p) * 1000.0f);
680 }
681 else
682 // XBOX 360 Wired
683 {
684 mDIJoyState.lRx = (int)(AMotionEvent_getAxisValue(event, AMOTION_EVENT_AXIS_Z, p) * 1000.0f);
685 mDIJoyState.lRy = (int)(AMotionEvent_getAxisValue(event, AMOTION_EVENT_AXIS_RZ, p) * 1000.0f);
686 mDIJoyState.rglSlider[0] = (int)(AMotionEvent_getAxisValue(event, AMOTION_EVENT_AXIS_LTRIGGER, p) * 1000.0f);
687 mDIJoyState.rglSlider[1] = (int)(AMotionEvent_getAxisValue(event, AMOTION_EVENT_AXIS_RTRIGGER, p) * 1000.0f);
688 }
689
690 //POV (sames values as windows)
691 DWORD pov = -1;
692 float px = (int)(AMotionEvent_getAxisValue(event, AMOTION_EVENT_AXIS_HAT_X, p) * 1000.0f);
693 float py = (int)(AMotionEvent_getAxisValue(event, AMOTION_EVENT_AXIS_HAT_Y, p) * 1000.0f);
694
695 if (px == 0.0f && py == 0.0f)
696 pov = -1;
697 else if (px == 0.0f && py < 0.0f)
698 pov = 0;
699 else if (px > 0.0f && py < 0.0f)
700 pov = 4500;
701 else if (px > 0.0f && py == 0.0f)
702 pov = 9000;
703 else if (px > 0.0f && py > 0.0f)
704 pov = 13500;
705 else if (px == 0.0f && py > 0.0f)
706 pov = 18000;
707 else if (px < 0.0f && py > 0.0f)
708 pov = 22500;
709 else if (px < 0.0f && py == 0.0f)
710 pov = 27000;
711 else if (px < 0.0f && py < 0.0f)
712 pov = 31500;
713
714 mDIJoyState.rgdwPOV[0] = pov;
715 }
716 break;
717 }
718 }
719
720 int elapsedTime = (GetTickCount() - mTick);
721 if (haveData && ((elapsedTime > 16) || mTick == 0))
722 {
723 //event
724 DIJOYSTATE2* ndata = initData();
725 mTick = GetTickCount();
726 OBJpostEvent(JOYPAD_DATA_CB, SCOL_PTR this, SCOL_PTR ndata);
727 }
728}
729
731{
732 return mConnected;
733}
734
736{
737 return mIsrunning;
738}
739
740bool Joypad::StartRumble(float intensity)
741{
742 //not implemented
743 return false;
744}
745
747{
748 //not implemented
749}
750
751#else // QT
752
753#ifdef SCOL_STATIC
754# include <QtPlugin>
755
756# if defined (_WIN32)
757Q_IMPORT_PLUGIN(QXInputGamepadBackendPlugin)
758# elif defined(ANDROID)
759Q_IMPORT_PLUGIN(QAndroidGamepadBackendPlugin)
760# elif defined (OSX) || defined(APPLE_IOS)
761Q_IMPORT_PLUGIN(QDarwinGamepadBackendPlugin)
762# else // LINUX
763Q_IMPORT_PLUGIN(QEvdevGamepadBackendPlugin)
764# endif
765
766#endif // SCOL_STATIC
767
768Joypad::Joypad(int index) : QObject(QCoreApplication::instance())
769{
770 mTick = 0;
771 mIndex = index;
772
773 for (size_t i = 0; i < 16; i++)
774 mDIJoyState.rgbButtons[i] = 0;
775
776 for (size_t i = 0; i < 4; i++)
777 mDIJoyState.rgdwPOV[i] = -1;
778
779 mDIJoyState.lX = 0;
780 mDIJoyState.lY = 0;
781 mDIJoyState.lRx = 0;
782 mDIJoyState.lRy = 0;
783 mDIJoyState.rglSlider[0] = 0;
784 mDIJoyState.rglSlider[1] = 0;
785
786 mGamepad = NULL;
787 mConnected = false;
788
789 // Run thread
790 mIsrunning = true;
791
792 //mThread = boost::thread(boost::bind(&Joypad::run, this));
793 run();
794}
795
797{
798 mIsrunning = false;
799 //mThread.join();
800
801 SAFE_DELETE(mGamepad);
802}
803
804void Joypad::initData()
805{
806 mConnected = mGamepad->isConnected();
807 if (mConnected)
808 {
809 mDIJoyState.rgbButtons[0] = mGamepad->buttonA();
810 mDIJoyState.rgbButtons[1] = mGamepad->buttonB();
811 mDIJoyState.rgbButtons[2] = mGamepad->buttonX();
812 mDIJoyState.rgbButtons[3] = mGamepad->buttonY();
813 mDIJoyState.rgbButtons[4] = mGamepad->buttonL1();
814 mDIJoyState.rgbButtons[5] = mGamepad->buttonL2();
815 mDIJoyState.rgbButtons[6] = mGamepad->buttonSelect();
816 mDIJoyState.rgbButtons[7] = mGamepad->buttonStart();
817 mDIJoyState.rgbButtons[8] = mGamepad->buttonL3();
818 mDIJoyState.rgbButtons[9] = mGamepad->buttonR3();
819 mDIJoyState.rgbButtons[10] = 0;
820 mDIJoyState.rgbButtons[11] = 0;
821 mDIJoyState.rgbButtons[12] = mGamepad->buttonR1();
822 mDIJoyState.rgbButtons[13] = mGamepad->buttonR2();
823 mDIJoyState.rgbButtons[14] = mGamepad->buttonGuide();
824
825 mDIJoyState.lX = (int)(mGamepad->axisLeftX() * 1000.0f);
826 mDIJoyState.lY = (int)(mGamepad->axisLeftY() * 1000.0f);
827 mDIJoyState.lRx = (int)(mGamepad->axisRightX() * 1000.0f);
828 mDIJoyState.lRy = (int)(mGamepad->axisRightY() * 1000.0f);
829
830 //POV (sames values as windows)
831 DWORD pov = -1;
832
833 if (mGamepad->buttonCenter())
834 pov = -1;
835 else if (!mGamepad->buttonLeft() && !mGamepad->buttonRight() && mGamepad->buttonUp())
836 pov = 0;
837 else if (mGamepad->buttonRight() && mGamepad->buttonUp())
838 pov = 4500;
839 else if (mGamepad->buttonRight() && !mGamepad->buttonDown() && !mGamepad->buttonUp())
840 pov = 9000;
841 else if (mGamepad->buttonRight() && mGamepad->buttonDown())
842 pov = 13500;
843 else if (!mGamepad->buttonLeft() && !mGamepad->buttonRight() && mGamepad->buttonDown())
844 pov = 18000;
845 else if (mGamepad->buttonLeft() && mGamepad->buttonDown())
846 pov = 22500;
847 else if (mGamepad->buttonLeft() && !mGamepad->buttonDown() && !mGamepad->buttonUp())
848 pov = 27000;
849 else if (mGamepad->buttonLeft() && mGamepad->buttonUp())
850 pov = 31500;
851
852 mDIJoyState.rgdwPOV[0] = pov;
853
854 DIJOYSTATE2* data = new DIJOYSTATE2;
855 for (size_t i = 0; i < 16; i++)
856 {
857 data->rgbButtons[i] = mDIJoyState.rgbButtons[i];
858 }
859
860 for (size_t i = 0; i < 4; i++)
861 data->rgdwPOV[i] = mDIJoyState.rgdwPOV[i];
862
863 data->lX = mDIJoyState.lX;
864 data->lY = mDIJoyState.lY;
865 data->lRx = mDIJoyState.lRx;
866 data->lRy = mDIJoyState.lRy;
867 data->rglSlider[0] = mDIJoyState.rglSlider[0];
868 data->rglSlider[1] = mDIJoyState.rglSlider[1];
869
870 //event
871 OBJpostEvent(JOYPAD_DATA_CB, SCOL_PTR this, SCOL_PTR data);
872 }
873}
874
875void Joypad::updateDoubleData(double value)
876{
877 initData();
878}
879
880void Joypad::updateBoolData(bool value)
881{
882 initData();
883}
884
886{
887 if (!mGamepad)
888 {
889 const QList<int> gamepads = QGamepadManager::instance()->connectedGamepads();
890 if (gamepads.isEmpty())
891 {
892 mConnected = false;
893 }
894 else
895 {
896 //TODO use mIndex
897 mGamepad = new QGamepad(*gamepads.begin(), this);
898
899 connect(mGamepad, SIGNAL(connectedChanged(bool)), this, SLOT(updateBoolData(double)));
900 connect(mGamepad, SIGNAL(axisLeftXChanged(double)), this, SLOT(updateDoubleData(double)));
901 connect(mGamepad, SIGNAL(axisLeftYChanged(double)), this, SLOT(updateDoubleData(double)));
902 connect(mGamepad, SIGNAL(axisRightXChanged(double)), this, SLOT(updateDoubleData(double)));
903 connect(mGamepad, SIGNAL(axisRightYChanged(double)), this, SLOT(updateDoubleData(double)));
904 connect(mGamepad, SIGNAL(buttonAChanged(bool)), this, SLOT(updateBoolData(bool)));
905 connect(mGamepad, SIGNAL(buttonBChanged(bool)), this, SLOT(updateBoolData(bool)));
906 connect(mGamepad, SIGNAL(buttonYChanged(bool)), this, SLOT(updateBoolData(bool)));
907 connect(mGamepad, SIGNAL(buttonL1Changed(bool)), this, SLOT(updateBoolData(bool)));
908 connect(mGamepad, SIGNAL(buttonR1Changed(bool)), this, SLOT(updateBoolData(bool)));
909 connect(mGamepad, SIGNAL(buttonL2Changed(double)), this, SLOT(updateDoubleData(double)));
910 connect(mGamepad, SIGNAL(buttonR2Changed(double)), this, SLOT(updateDoubleData(double)));
911 connect(mGamepad, SIGNAL(buttonL3Changed(bool)), this, SLOT(updateBoolData(bool)));
912 connect(mGamepad, SIGNAL(buttonR3Changed(bool)), this, SLOT(updateBoolData(bool)));
913 connect(mGamepad, SIGNAL(buttonSelectChanged(bool)), this, SLOT(updateBoolData(bool)));
914 connect(mGamepad, SIGNAL(buttonStartChanged(bool)), this, SLOT(updateBoolData(bool)));
915 connect(mGamepad, SIGNAL(buttonGuideChanged(bool)), this, SLOT(updateBoolData(bool)));
916 connect(mGamepad, SIGNAL(buttonUpChanged(bool)), this, SLOT(updateBoolData(bool)));
917 connect(mGamepad, SIGNAL(buttonDownChanged(bool)), this, SLOT(updateBoolData(bool)));
918 connect(mGamepad, SIGNAL(buttonLeftChanged(bool)), this, SLOT(updateBoolData(bool)));
919 connect(mGamepad, SIGNAL(buttonRightChanged(bool)), this, SLOT(updateBoolData(bool)));
920 connect(mGamepad, SIGNAL(buttonCenterChanged(bool)), this, SLOT(updateBoolData(bool)));
921 }
922 }
923}
924/*
925void Joypad::run()
926{
927 try
928 {
929 // get new data 30 time a second
930 while(mIsrunning)
931 {
932 boost::mutex::scoped_lock l(mMutex);
933 mTick = GetTickCount();
934
935 if (!mGamepad)
936 {
937 const QList<int> gamepads = QGamepadManager::instance()->connectedGamepads();
938 if (gamepads.isEmpty())
939 {
940 mConnected = false;
941 }
942 else
943 {
944 mGamepad = new QGamepad(*gamepads.begin(), QCoreApplication::instance());
945 mConnected = mGamepad->isConnected();
946 }
947 }
948
949 if(mGamepad && !mGamepad->isConnected())
950 boost::this_thread::sleep_for(boost::chrono::milliseconds(200));
951
952 mConnected = (mGamepad) ? mGamepad->isConnected() : false;
953 if (mConnected)
954 {
955 mDIJoyState.rgbButtons[0] = mGamepad->buttonA();
956 mDIJoyState.rgbButtons[1] = mGamepad->buttonB();
957 mDIJoyState.rgbButtons[2] = mGamepad->buttonX();
958 mDIJoyState.rgbButtons[3] = mGamepad->buttonY();
959 mDIJoyState.rgbButtons[4] = mGamepad->buttonL1();
960 mDIJoyState.rgbButtons[5] = mGamepad->buttonL2();
961 mDIJoyState.rgbButtons[6] = mGamepad->buttonSelect();
962 mDIJoyState.rgbButtons[7] = mGamepad->buttonStart();
963 mDIJoyState.rgbButtons[8] = mGamepad->buttonL3();
964 mDIJoyState.rgbButtons[9] = mGamepad->buttonR3();
965 mDIJoyState.rgbButtons[10] = 0;
966 mDIJoyState.rgbButtons[11] = 0;
967 mDIJoyState.rgbButtons[12] = mGamepad->buttonR1();
968 mDIJoyState.rgbButtons[13] = mGamepad->buttonR2();
969 mDIJoyState.rgbButtons[14] = mGamepad->buttonGuide();
970
971 mDIJoyState.lX = (int)(mGamepad->axisLeftX() * 1000.0f);
972 mDIJoyState.lY = (int)(mGamepad->axisLeftY() * 1000.0f);
973 mDIJoyState.lRx= (int)(mGamepad->axisRightX() * 1000.0f);
974 mDIJoyState.lRy = (int)(mGamepad->axisRightY() * 1000.0f);
975
976 //POV (sames values as windows)
977 DWORD pov = -1;
978
979 if (mGamepad->buttonCenter())
980 pov = -1;
981 else if (!mGamepad->buttonDown() && !mGamepad->buttonUp() && mGamepad->buttonLeft())
982 pov = 0;
983 else if (mGamepad->buttonRight() && mGamepad->buttonDown())
984 pov = 4500;
985 else if (mGamepad->buttonRight() && !mGamepad->buttonDown() && !mGamepad->buttonUp())
986 pov = 9000;
987 else if (mGamepad->buttonRight() && mGamepad->buttonUp())
988 pov = 13500;
989 else if (mGamepad->buttonLeft() && mGamepad->buttonRight() && mGamepad->buttonUp())
990 pov = 18000;
991 else if (mGamepad->buttonLeft() && mGamepad->buttonUp())
992 pov = 22500;
993 else if (mGamepad->buttonLeft() && !mGamepad->buttonDown() && !mGamepad->buttonUp())
994 pov = 27000;
995 else if (mGamepad->buttonLeft() && mGamepad->buttonDown())
996 pov = 31500;
997
998 mDIJoyState.rgdwPOV[0] = pov;
999 }
1000
1001 int elapsedTime = (GetTickCount() - mTick);
1002 if ((elapsedTime > 16) || mTick == 0)
1003 {
1004 //event
1005 DIJOYSTATE2* ndata = initData();
1006 mTick = GetTickCount();
1007 OBJpostEvent(JOYPAD_DATA_CB, SCOL_PTR this, SCOL_PTR ndata);
1008 }
1009
1010 elapsedTime = 33 - (GetTickCount() - mTick);
1011 if (elapsedTime > 0)
1012 boost::this_thread::sleep_for(boost::chrono::milliseconds(elapsedTime));
1013 }
1014 }
1015 catch(std::exception ex)
1016 {
1017 MMechostr(MSKDEBUG,"Joypad > error thread : %s \n", ex.what());
1018 }
1019}
1020*/
1022{
1023 //boost::mutex::scoped_lock l(mMutex);
1024 return mConnected;
1025}
1026
1028{
1029 //boost::mutex::scoped_lock l(mMutex);
1030 return mIsrunning;
1031}
1032
1033bool Joypad::StartRumble(float intensity)
1034{
1035 //not implemented
1036 return false;
1037}
1038
1040{
1041 //not implemented
1042}
1043
1044#endif
int JOYPAD_DATA_CB
Joypad(int index=0)
Definition Joypad.cpp:768
void run()
Definition Joypad.cpp:885
bool IsConnected()
Definition Joypad.cpp:1021
unsigned long mTick
Definition Joypad.h:103
bool StartRumble(float intensity)
Definition Joypad.cpp:1033
void StopRumble()
Definition Joypad.cpp:1039
bool IsRunning()
Definition Joypad.cpp:1027
int mIndex
Definition Joypad.h:104
~Joypad(void)
Definition Joypad.cpp:796
LONG lRy
Definition Joypad.h:52
LONG lRx
Definition Joypad.h:51
DWORD rgdwPOV[4]
Definition Joypad.h:55
LONG lX
Definition Joypad.h:48
LONG rglSlider[2]
Definition Joypad.h:54
LONG lY
Definition Joypad.h:49
int rgbButtons[16]
Definition Joypad.h:56