1 /* antimicro Gamepad to KB+M event mapper
2 * Copyright (C) 2015 Travis Nickles <nickles.travis@gmail.com>
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 //#include <QDebug>
19 #include <QThread>
20 #include <QStringList>
21 #include <cmath>
22
23 #include "setjoystick.h"
24 #include "inputdevice.h"
25 #include "joybutton.h"
26 #include "vdpad.h"
27 #include "event.h"
28 #include "logger.h"
29
30 #ifdef Q_OS_WIN
31 #include "eventhandlerfactory.h"
32 #endif
33
34 const QString JoyButton::xmlName = "button";
35
36 // Set default values for many properties.
37 const int JoyButton::ENABLEDTURBODEFAULT = 100;
38 const double JoyButton::DEFAULTMOUSESPEEDMOD = 1.0;
39 double JoyButton::mouseSpeedModifier = JoyButton::DEFAULTMOUSESPEEDMOD;
40 const unsigned int JoyButton::DEFAULTKEYREPEATDELAY = 600; // 600 ms
41 const unsigned int JoyButton::DEFAULTKEYREPEATRATE = 40; // 40 ms. 25 times per second
42 const JoyButton::JoyMouseCurve JoyButton::DEFAULTMOUSECURVE = JoyButton::EnhancedPrecisionCurve;
43 const bool JoyButton::DEFAULTTOGGLE = false;
44 const int JoyButton::DEFAULTTURBOINTERVAL = 0;
45 const bool JoyButton::DEFAULTUSETURBO = false;
46 const int JoyButton::DEFAULTMOUSESPEEDX = 50;
47 const int JoyButton::DEFAULTMOUSESPEEDY = 50;
48 const int JoyButton::DEFAULTSETSELECTION = -1;
49 const JoyButton::SetChangeCondition JoyButton::DEFAULTSETCONDITION = JoyButton::SetChangeDisabled;
50 const JoyButton::JoyMouseMovementMode JoyButton::DEFAULTMOUSEMODE = JoyButton::MouseCursor;
51 const int JoyButton::DEFAULTSPRINGWIDTH = 0;
52 const int JoyButton::DEFAULTSPRINGHEIGHT = 0;
53 const double JoyButton::DEFAULTSENSITIVITY = 1.0;
54 const int JoyButton::DEFAULTWHEELX = 20;
55 const int JoyButton::DEFAULTWHEELY = 20;
56 const bool JoyButton::DEFAULTCYCLERESETACTIVE = false;
57 const int JoyButton::DEFAULTCYCLERESET = 0;
58 const bool JoyButton::DEFAULTRELATIVESPRING = false;
59 const JoyButton::TurboMode JoyButton::DEFAULTTURBOMODE = JoyButton::NormalTurbo;
60 const double JoyButton::DEFAULTEASINGDURATION = 0.5;
61 const double JoyButton::MINIMUMEASINGDURATION = 0.2;
62 const double JoyButton::MAXIMUMEASINGDURATION = 5.0;
63 const unsigned int JoyButton::MINCYCLERESETTIME = 10;
64 const unsigned int JoyButton::MAXCYCLERESETTIME = 60000;
65
66 const int JoyButton::DEFAULTMOUSEHISTORYSIZE = 10;
67 const double JoyButton::DEFAULTWEIGHTMODIFIER = 0.2;
68 const int JoyButton::MAXIMUMMOUSEHISTORYSIZE = 100;
69 const double JoyButton::MAXIMUMWEIGHTMODIFIER = 1.0;
70 const int JoyButton::MAXIMUMMOUSEREFRESHRATE = 16;
71 int JoyButton::IDLEMOUSEREFRESHRATE = (5 * 20);
72 const int JoyButton::DEFAULTIDLEMOUSEREFRESHRATE = 100;
73 const double JoyButton::DEFAULTEXTRACCELVALUE = 2.0;
74 const double JoyButton::DEFAULTMINACCELTHRESHOLD = 10.0;
75 const double JoyButton::DEFAULTMAXACCELTHRESHOLD = 100.0;
76 const double JoyButton::DEFAULTSTARTACCELMULTIPLIER = 0.0;
77 const double JoyButton::DEFAULTACCELEASINGDURATION = 0.1;
78 const JoyButton::JoyExtraAccelerationCurve
79 JoyButton::DEFAULTEXTRAACCELCURVE = JoyButton::LinearAccelCurve;
80
81 const int JoyButton::DEFAULTSPRINGRELEASERADIUS = 0;
82
83 // Keep references to active keys and mouse buttons.
84 QHash<unsigned int, int> JoyButton::activeKeys;
85 QHash<unsigned int, int> JoyButton::activeMouseButtons;
86 JoyButtonSlot* JoyButton::lastActiveKey = 0;
87
88 // Keep track of active Mouse Speed Mod slots.
89 QList<JoyButtonSlot*> JoyButton::mouseSpeedModList;
90
91 // Lists used for cursor mode calculations.
92 QList<JoyButton::mouseCursorInfo> JoyButton::cursorXSpeeds;
93 QList<JoyButton::mouseCursorInfo> JoyButton::cursorYSpeeds;
94
95 // Lists used for spring mode calculations.
96 QList<PadderCommon::springModeInfo> JoyButton::springXSpeeds;
97 QList<PadderCommon::springModeInfo> JoyButton::springYSpeeds;
98
99 // Keeps timestamp of last mouse event.
100 //QElapsedTimer JoyButton::lastMouseTime;
101 // Temporary test object to test old mouse time behavior.
102 QTime JoyButton::testOldMouseTime;
103
104 // Helper object to have a single mouse event for all JoyButton
105 // instances.
106 JoyButtonMouseHelper JoyButton::mouseHelper;
107
108 QTimer JoyButton::staticMouseEventTimer;
109 QList<JoyButton*> JoyButton::pendingMouseButtons;
110
111 // History buffers used for mouse smoothing routine.
112 QList<double> JoyButton::mouseHistoryX;
113 QList<double> JoyButton::mouseHistoryY;
114
115 // Carry over remainder of a cursor move for the next mouse event.
116 double JoyButton::cursorRemainderX = 0.0;
117 double JoyButton::cursorRemainderY = 0.0;
118
119 double JoyButton::weightModifier = 0;
120 int JoyButton::mouseHistorySize = 1;
121
122 int JoyButton::mouseRefreshRate = 5;
123 int JoyButton::springModeScreen = -1;
124 int JoyButton::gamepadRefreshRate = 10;
125
126 #ifdef Q_OS_WIN
127 JoyKeyRepeatHelper JoyButton::repeatHelper;
128 #endif
129
130 static const double PI = acos(-1.0);
131
JoyButton(int index,int originset,SetJoystick * parentSet,QObject * parent)132 JoyButton::JoyButton(int index, int originset, SetJoystick *parentSet,
133 QObject *parent) :
134 QObject(parent)
135 {
136 vdpad = 0;
137 slotiter = 0;
138
139 turboTimer.setParent(this);
140 pauseTimer.setParent(this);
141 holdTimer.setParent(this);
142 pauseWaitTimer.setParent(this);
143 createDeskTimer.setParent(this);
144 releaseDeskTimer.setParent(this);
145 mouseWheelVerticalEventTimer.setParent(this);
146 mouseWheelHorizontalEventTimer.setParent(this);
147 setChangeTimer.setParent(this);
148 keyPressTimer.setParent(this);
149 delayTimer.setParent(this);
150 slotSetChangeTimer.setParent(this);
151 activeZoneTimer.setParent(this);
152
153 setChangeTimer.setSingleShot(true);
154 slotSetChangeTimer.setSingleShot(true);
155 this->parentSet = parentSet;
156
157 connect(&pauseWaitTimer, SIGNAL(timeout()), this, SLOT(pauseWaitEvent()));
158 connect(&keyPressTimer, SIGNAL(timeout()), this, SLOT(keyPressEvent()));
159 connect(&holdTimer, SIGNAL(timeout()), this, SLOT(holdEvent()));
160 connect(&delayTimer, SIGNAL(timeout()), this, SLOT(delayEvent()));
161 connect(&createDeskTimer, SIGNAL(timeout()), this, SLOT(waitForDeskEvent()));
162 connect(&releaseDeskTimer, SIGNAL(timeout()), this, SLOT(waitForReleaseDeskEvent()));
163 connect(&turboTimer, SIGNAL(timeout()), this, SLOT(turboEvent()));
164 connect(&mouseWheelVerticalEventTimer, SIGNAL(timeout()), this, SLOT(wheelEventVertical()));
165 connect(&mouseWheelHorizontalEventTimer, SIGNAL(timeout()), this, SLOT(wheelEventHorizontal()));
166 connect(&setChangeTimer, SIGNAL(timeout()), this, SLOT(checkForSetChange()));
167 connect(&slotSetChangeTimer, SIGNAL(timeout()), this, SLOT(slotSetChange()));
168 connect(&activeZoneTimer, SIGNAL(timeout()), this, SLOT(buildActiveZoneSummaryString()));
169
170 activeZoneTimer.setInterval(0);
171 activeZoneTimer.setSingleShot(true);
172
173 // Will only matter on the first call
174 establishMouseTimerConnections();
175
176 // Make sure to call before calling reset
177 this->resetProperties();
178
179 this->index = index;
180 this->originset = originset;
181
182 quitEvent = true;
183 }
184
~JoyButton()185 JoyButton::~JoyButton()
186 {
187 reset();
188 }
189
queuePendingEvent(bool pressed,bool ignoresets)190 void JoyButton::queuePendingEvent(bool pressed, bool ignoresets)
191 {
192 pendingEvent = false;
193 pendingPress = false;
194 pendingIgnoreSets = false;
195
196 if (this->vdpad)
197 {
198 vdpadPassEvent(pressed, ignoresets);
199 }
200 else
201 {
202 pendingEvent = true;
203 pendingPress = pressed;
204 pendingIgnoreSets = ignoresets;
205 }
206 }
207
activatePendingEvent()208 void JoyButton::activatePendingEvent()
209 {
210 if (pendingEvent)
211 {
212 joyEvent(pendingPress, pendingIgnoreSets);
213
214 pendingEvent = false;
215 pendingPress = false;
216 pendingIgnoreSets = false;
217 }
218 }
219
hasPendingEvent()220 bool JoyButton::hasPendingEvent()
221 {
222 return pendingEvent;
223 }
224
clearPendingEvent()225 void JoyButton::clearPendingEvent()
226 {
227 pendingEvent = false;
228 pendingPress = false;
229 pendingIgnoreSets = false;
230 }
231
vdpadPassEvent(bool pressed,bool ignoresets)232 void JoyButton::vdpadPassEvent(bool pressed, bool ignoresets)
233 {
234 if (this->vdpad && pressed != isButtonPressed)
235 {
236 isButtonPressed = pressed;
237 if (isButtonPressed)
238 {
239 emit clicked(index);
240 }
241 else
242 {
243 emit released(index);
244 }
245
246 if (!ignoresets)
247 {
248 this->vdpad->queueJoyEvent(ignoresets);
249 }
250 else
251 {
252 this->vdpad->joyEvent(pressed, ignoresets);
253 }
254 }
255 }
256
joyEvent(bool pressed,bool ignoresets)257 void JoyButton::joyEvent(bool pressed, bool ignoresets)
258 {
259 if (this->vdpad && !pendingEvent)
260 {
261 vdpadPassEvent(pressed, ignoresets);
262 }
263 else if (ignoreEvents)
264 {
265 if (pressed != isButtonPressed)
266 {
267 isButtonPressed = pressed;
268 if (isButtonPressed)
269 {
270 emit clicked(index);
271 }
272 else
273 {
274 emit released(index);
275 }
276 }
277 }
278 else
279 {
280 if (pressed != isDown)
281 {
282 if (pressed)
283 {
284 emit clicked(index);
285 if (updateInitAccelValues)
286 {
287 oldAccelMulti = updateOldAccelMulti = 0.0;
288 accelTravel = 0.0;
289 }
290 }
291 else
292 {
293 emit released(index);
294 }
295
296 bool activePress = pressed;
297 setChangeTimer.stop();
298
299 if (toggle && pressed)
300 {
301 isDown = true;
302 toggleActiveState = !toggleActiveState;
303
304 if (!isButtonPressed)
305 {
306 this->ignoresets = ignoresets;
307 isButtonPressed = !isButtonPressed;
308
309 ignoreSetQueue.enqueue(ignoresets);
310 isButtonPressedQueue.enqueue(isButtonPressed);
311 }
312 else
313 {
314 activePress = false;
315 }
316 }
317 else if (toggle && !pressed && isDown)
318 {
319 isDown = false;
320
321 if (!toggleActiveState)
322 {
323 this->ignoresets = ignoresets;
324 isButtonPressed = !isButtonPressed;
325
326 ignoreSetQueue.enqueue(ignoresets);
327 isButtonPressedQueue.enqueue(isButtonPressed);
328 }
329 }
330 else
331 {
332 this->ignoresets = ignoresets;
333 isButtonPressed = isDown = pressed;
334
335 ignoreSetQueue.enqueue(ignoresets);
336 isButtonPressedQueue.enqueue(isButtonPressed);
337 }
338
339 if (useTurbo)
340 {
341 if (isButtonPressed && activePress && !turboTimer.isActive())
342 {
343 if (cycleResetActive &&
344 cycleResetHold.elapsed() >= cycleResetInterval && slotiter)
345 {
346 slotiter->toFront();
347 currentCycle = 0;
348 previousCycle = 0;
349 }
350
351 buttonHold.restart();
352 buttonHeldRelease.restart();
353 keyPressHold.restart();
354 cycleResetHold.restart();
355 turboTimer.start();
356
357 // Newly activated button. Just entered safe zone.
358 if (updateInitAccelValues)
359 {
360 initializeDistanceValues();
361 }
362 currentAccelerationDistance = getAccelerationDistance();
363
364 Logger::LogDebug(tr("Processing turbo for #%1 - %2")
365 .arg(parentSet->getInputDevice()->getRealJoyNumber())
366 .arg(getPartialName()));
367
368 turboEvent();
369 }
370 else if (!isButtonPressed && !activePress && turboTimer.isActive())
371 {
372 turboTimer.stop();
373 Logger::LogDebug(tr("Finishing turbo for button #%1 - %2")
374 .arg(parentSet->getInputDevice()->getRealJoyNumber())
375 .arg(getPartialName()));
376
377 if (isKeyPressed)
378 {
379 turboEvent();
380 }
381 else
382 {
383 lastDistance = getMouseDistanceFromDeadZone();
384 }
385
386 activeZoneTimer.start();
387 }
388 }
389 // Toogle is enabled and a controller button change has occurred.
390 // Switch to a different distance zone if appropriate
391 else if (toggle && !activePress && isButtonPressed)
392 {
393 bool releasedCalled = distanceEvent();
394 if (releasedCalled)
395 {
396 quitEvent = true;
397 buttonHold.restart();
398 buttonHeldRelease.restart();
399 keyPressHold.restart();
400 //createDeskTimer.start(0);
401 releaseDeskTimer.stop();
402 if (!keyPressTimer.isActive())
403 {
404 waitForDeskEvent();
405 }
406 }
407 }
408 else if (isButtonPressed && activePress)
409 {
410 if (cycleResetActive &&
411 cycleResetHold.elapsed() >= cycleResetInterval && slotiter)
412 {
413 slotiter->toFront();
414 currentCycle = 0;
415 previousCycle = 0;
416 }
417
418 buttonHold.restart();
419 buttonHeldRelease.restart();
420 cycleResetHold.restart();
421 keyPressHold.restart();
422 //createDeskTimer.start(0);
423 releaseDeskTimer.stop();
424
425 // Newly activated button. Just entered safe zone.
426 if (updateInitAccelValues)
427 {
428 initializeDistanceValues();
429 }
430
431 currentAccelerationDistance = getAccelerationDistance();
432
433 Logger::LogDebug(tr("Processing press for button #%1 - %2")
434 .arg(parentSet->getInputDevice()->getRealJoyNumber())
435 .arg(getPartialName()));
436
437 if (!keyPressTimer.isActive())
438 {
439 checkForPressedSetChange();
440 if (!setChangeTimer.isActive())
441 {
442 waitForDeskEvent();
443 }
444 }
445
446
447 }
448 else if (!isButtonPressed && !activePress)
449 {
450 Logger::LogDebug(tr("Processing release for button #%1 - %2")
451 .arg(parentSet->getInputDevice()->getRealJoyNumber())
452 .arg(getPartialName()));
453
454 waitForReleaseDeskEvent();
455 }
456
457 if (updateInitAccelValues)
458 {
459 updateLastMouseDistance = false;
460 updateStartingMouseDistance = false;
461 updateOldAccelMulti = 0.0;
462 }
463
464 }
465 else if (!useTurbo && isButtonPressed)
466 {
467 resetAccelerationDistances();
468 currentAccelerationDistance = getAccelerationDistance();
469
470 if (!setChangeTimer.isActive())
471 {
472 bool releasedCalled = distanceEvent();
473 if (releasedCalled)
474 {
475 Logger::LogDebug(tr("Distance change for button #%1 - %2")
476 .arg(parentSet->getInputDevice()->getRealJoyNumber())
477 .arg(getPartialName()));
478
479 quitEvent = true;
480 buttonHold.restart();
481 buttonHeldRelease.restart();
482 keyPressHold.restart();
483 //createDeskTimer.start(0);
484 releaseDeskTimer.stop();
485 if (!keyPressTimer.isActive())
486 {
487 waitForDeskEvent();
488 }
489 }
490 }
491 }
492 }
493
494 updateInitAccelValues = true;
495 }
496
497 /**
498 * @brief Get 0 indexed number of button
499 * @return 0 indexed button index number
500 */
getJoyNumber()501 int JoyButton::getJoyNumber()
502 {
503 return index;
504 }
505
506 /**
507 * @brief Get a 1 indexed number of button
508 * @return 1 indexed button index number
509 */
getRealJoyNumber()510 int JoyButton::getRealJoyNumber()
511 {
512 return index + 1;
513 }
514
setJoyNumber(int index)515 void JoyButton::setJoyNumber(int index)
516 {
517 this->index = index;
518 }
519
setToggle(bool toggle)520 void JoyButton::setToggle(bool toggle)
521 {
522 if (toggle != this->toggle)
523 {
524 this->toggle = toggle;
525 emit toggleChanged(toggle);
526 emit propertyUpdated();
527 }
528 }
529
setTurboInterval(int interval)530 void JoyButton::setTurboInterval(int interval)
531 {
532 if (interval >= 10 && interval != this->turboInterval)
533 {
534 this->turboInterval = interval;
535 emit turboIntervalChanged(interval);
536 emit propertyUpdated();
537 }
538 else if (interval < 10 && interval != this->turboInterval)
539 {
540 interval = 0;
541 this->setUseTurbo(false);
542 this->turboInterval = interval;
543 emit turboIntervalChanged(interval);
544 emit propertyUpdated();
545 }
546 }
547
reset()548 void JoyButton::reset()
549 {
550 disconnectPropertyUpdatedConnections();
551
552 turboTimer.stop();
553 pauseWaitTimer.stop();
554 createDeskTimer.stop();
555 releaseDeskTimer.stop();
556 holdTimer.stop();
557 mouseWheelVerticalEventTimer.stop();
558 mouseWheelHorizontalEventTimer.stop();
559 setChangeTimer.stop();
560 keyPressTimer.stop();
561 delayTimer.stop();
562
563 #ifdef Q_OS_WIN
564 repeatHelper.getRepeatTimer()->stop();
565 #endif
566
567 slotSetChangeTimer.stop();
568
569 if (slotiter)
570 {
571 delete slotiter;
572 slotiter = 0;
573 }
574
575 releaseActiveSlots();
576 clearAssignedSlots();
577
578 isButtonPressedQueue.clear();
579 ignoreSetQueue.clear();
580 mouseEventQueue.clear();
581 mouseWheelVerticalEventQueue.clear();
582 mouseWheelHorizontalEventQueue.clear();
583
584 resetProperties(); // quitEvent changed here
585 }
586
reset(int index)587 void JoyButton::reset(int index)
588 {
589 JoyButton::reset();
590 this->index = index;
591 }
592
getToggleState()593 bool JoyButton::getToggleState()
594 {
595 return toggle;
596 }
597
getTurboInterval()598 int JoyButton::getTurboInterval()
599 {
600 return turboInterval;
601 }
602
turboEvent()603 void JoyButton::turboEvent()
604 {
605 if (!isKeyPressed)
606 {
607 if (!isButtonPressedQueue.isEmpty())
608 {
609 ignoreSetQueue.clear();
610 isButtonPressedQueue.clear();
611
612 ignoreSetQueue.enqueue(false);
613 isButtonPressedQueue.enqueue(isButtonPressed);
614 }
615
616 createDeskEvent();
617 isKeyPressed = true;
618 if (turboTimer.isActive())
619 {
620 int tempInterval = turboInterval / 2;
621 if (turboTimer.interval() != tempInterval)
622 {
623 turboTimer.start(tempInterval);
624 }
625 }
626 }
627 else
628 {
629 if (!isButtonPressedQueue.isEmpty())
630 {
631 ignoreSetQueue.enqueue(false);
632 isButtonPressedQueue.enqueue(!isButtonPressed);
633 }
634
635 releaseDeskEvent();
636
637 isKeyPressed = false;
638 if (turboTimer.isActive())
639 {
640 int tempInterval = turboInterval / 2;
641 if (turboTimer.interval() != tempInterval)
642 {
643 turboTimer.start(tempInterval);
644 }
645
646 }
647
648 }
649 }
650
distanceEvent()651 bool JoyButton::distanceEvent()
652 {
653 bool released = false;
654
655 if (slotiter)
656 {
657 QReadLocker tempLocker(&assignmentsLock);
658
659 bool distanceFound = containsDistanceSlots();
660
661 if (distanceFound)
662 {
663 double currentDistance = getDistanceFromDeadZone();
664 double tempDistance = 0.0;
665 JoyButtonSlot *previousDistanceSlot = 0;
666 QListIterator<JoyButtonSlot*> iter(assignments);
667 if (previousCycle)
668 {
669 iter.findNext(previousCycle);
670 }
671
672 while (iter.hasNext())
673 {
674 JoyButtonSlot *slot = iter.next();
675 int tempcode = slot->getSlotCode();
676 if (slot->getSlotMode() == JoyButtonSlot::JoyDistance)
677 {
678 tempDistance += tempcode / 100.0;
679
680 if (currentDistance < tempDistance)
681 {
682 iter.toBack();
683 }
684 else
685 {
686 previousDistanceSlot = slot;
687 }
688 }
689 else if (slot->getSlotMode() == JoyButtonSlot::JoyCycle)
690 {
691 tempDistance = 0.0;
692 iter.toBack();
693 }
694 }
695
696 // No applicable distance slot
697 if (!previousDistanceSlot)
698 {
699 if (this->currentDistance)
700 {
701 // Distance slot is currently active.
702 // Release slots, return iterator to
703 // the front, and nullify currentDistance
704 pauseWaitTimer.stop();
705 holdTimer.stop();
706
707 // Release stuff
708 releaseActiveSlots();
709 currentPause = currentHold = 0;
710 //quitEvent = true;
711
712 slotiter->toFront();
713 if (previousCycle)
714 {
715 slotiter->findNext(previousCycle);
716 }
717
718 this->currentDistance = 0;
719 released = true;
720 }
721 }
722 // An applicable distance slot was found
723 else if (previousDistanceSlot)
724 {
725 if (this->currentDistance != previousDistanceSlot)
726 {
727 // Active distance slot is not the applicable slot.
728 // Deactive slots in previous distance range and
729 // activate new slots. Set currentDistance to
730 // new slot.
731 pauseWaitTimer.stop();
732 holdTimer.stop();
733
734 // Release stuff
735 releaseActiveSlots();
736 currentPause = currentHold = 0;
737 //quitEvent = true;
738
739 slotiter->toFront();
740 if (previousCycle)
741 {
742 slotiter->findNext(previousCycle);
743 }
744
745 slotiter->findNext(previousDistanceSlot);
746
747 this->currentDistance = previousDistanceSlot;
748 released = true;
749 }
750 }
751 }
752 }
753
754 return released;
755 }
756
createDeskEvent()757 void JoyButton::createDeskEvent()
758 {
759 quitEvent = false;
760
761 if (!slotiter)
762 {
763 assignmentsLock.lockForRead();
764 slotiter = new QListIterator<JoyButtonSlot*>(assignments);
765 assignmentsLock.unlock();
766
767 distanceEvent();
768 }
769 else if (!slotiter->hasPrevious())
770 {
771 distanceEvent();
772 }
773 else if (currentCycle)
774 {
775 currentCycle = 0;
776 distanceEvent();
777 }
778
779 assignmentsLock.lockForRead();
780 activateSlots();
781 assignmentsLock.unlock();
782
783 if (currentCycle)
784 {
785 quitEvent = true;
786 }
787 else if (!currentPause && !currentHold && !keyPressTimer.isActive())
788 {
789 quitEvent = true;
790 }
791 }
792
activateSlots()793 void JoyButton::activateSlots()
794 {
795 if (slotiter)
796 {
797 QWriteLocker tempLocker(&activeZoneLock);
798
799 bool exit = false;
800 //bool delaySequence = checkForDelaySequence();
801 bool delaySequence = false;
802 bool changeRepeatState = false;
803
804 while (slotiter->hasNext() && !exit)
805 {
806 JoyButtonSlot *slot = slotiter->next();
807 int tempcode = slot->getSlotCode();
808 JoyButtonSlot::JoySlotInputAction mode = slot->getSlotMode();
809
810 if (mode == JoyButtonSlot::JoyKeyboard)
811 {
812 sendevent(slot, true);
813 activeSlots.append(slot);
814 int oldvalue = activeKeys.value(tempcode, 0) + 1;
815 activeKeys.insert(tempcode, oldvalue);
816 if (!slot->isModifierKey())
817 {
818 lastActiveKey = slot;
819 changeRepeatState = true;
820 }
821 else
822 {
823 lastActiveKey = 0;
824 changeRepeatState = true;
825 }
826 }
827 else if (mode == JoyButtonSlot::JoyMouseButton)
828 {
829 if (tempcode == JoyButtonSlot::MouseWheelUp ||
830 tempcode == JoyButtonSlot::MouseWheelDown)
831 {
832 slot->getMouseInterval()->restart();
833 wheelVerticalTime.restart();
834 currentWheelVerticalEvent = slot;
835 activeSlots.append(slot);
836 wheelEventVertical();
837 currentWheelVerticalEvent = 0;
838 }
839 else if (tempcode == JoyButtonSlot::MouseWheelLeft ||
840 tempcode == JoyButtonSlot::MouseWheelRight)
841 {
842 slot->getMouseInterval()->restart();
843 wheelHorizontalTime.restart();
844 currentWheelHorizontalEvent = slot;
845 activeSlots.append(slot);
846 wheelEventHorizontal();
847 currentWheelHorizontalEvent = 0;
848 }
849 else
850 {
851 sendevent(slot, true);
852 activeSlots.append(slot);
853 int oldvalue = activeMouseButtons.value(tempcode, 0) + 1;
854 activeMouseButtons.insert(tempcode, oldvalue);
855 }
856 }
857 else if (mode == JoyButtonSlot::JoyMouseMovement)
858 {
859 slot->getMouseInterval()->restart();
860 //currentMouseEvent = slot;
861 activeSlots.append(slot);
862 //mouseEventQueue.enqueue(slot);
863 //mouseEvent();
864 if (pendingMouseButtons.size() == 0)
865 {
866 mouseHelper.setFirstSpringStatus(true);
867 }
868
869 pendingMouseButtons.append(this);
870 mouseEventQueue.enqueue(slot);
871 //currentMouseEvent = 0;
872
873 // Temporarily lower timer interval. Helps improve mouse control
874 // precision on the lower end of an axis.
875 if (!staticMouseEventTimer.isActive() || staticMouseEventTimer.interval() != 0)
876 {
877 if (!staticMouseEventTimer.isActive() || staticMouseEventTimer.interval() == IDLEMOUSEREFRESHRATE)
878 {
879 int tempRate = qBound(0, mouseRefreshRate - gamepadRefreshRate, MAXIMUMMOUSEREFRESHRATE);
880 //Logger::LogInfo(QString("STARTING OVER: %1 %2").arg(QTime::currentTime().toString("hh:mm:ss.zzz")).arg(tempRate));
881 staticMouseEventTimer.start(tempRate);
882
883 //lastMouseTime.restart();
884 testOldMouseTime.restart();
885 accelExtraDurationTime.restart();
886 }
887 }
888 }
889 else if (mode == JoyButtonSlot::JoyPause)
890 {
891 if (!activeSlots.isEmpty())
892 {
893 if (slotiter->hasPrevious())
894 {
895 slotiter->previous();
896 }
897 delaySequence = true;
898 exit = true;
899 }
900 // Segment can be ignored on a 0 interval pause
901 else if (tempcode > 0)
902 {
903 currentPause = slot;
904 pauseHold.restart();
905 inpauseHold.restart();
906 pauseWaitTimer.start(0);
907 exit = true;
908 }
909 }
910 else if (mode == JoyButtonSlot::JoyHold)
911 {
912 currentHold = slot;
913 holdTimer.start(0);
914 exit = true;
915 }
916 else if (mode == JoyButtonSlot::JoyDelay)
917 {
918 currentDelay = slot;
919 buttonDelay.restart();
920 delayTimer.start(0);
921 exit = true;
922 }
923 else if (mode == JoyButtonSlot::JoyCycle)
924 {
925 currentCycle = slot;
926 exit = true;
927 }
928 else if (mode == JoyButtonSlot::JoyDistance)
929 {
930 exit = true;
931 }
932 else if (mode == JoyButtonSlot::JoyRelease)
933 {
934 if (!currentRelease)
935 {
936 findReleaseEventEnd();
937 }
938 /*else
939 {
940 currentRelease = 0;
941 exit = true;
942 }*/
943
944 else if (currentRelease && activeSlots.isEmpty())
945 {
946 //currentRelease = 0;
947 exit = true;
948 }
949 else if (currentRelease && !activeSlots.isEmpty())
950 {
951 if (slotiter->hasPrevious())
952 {
953 slotiter->previous();
954 }
955 delaySequence = true;
956 exit = true;
957 }
958 }
959 else if (mode == JoyButtonSlot::JoyMouseSpeedMod)
960 {
961 mouseSpeedModifier = tempcode * 0.01;
962 mouseSpeedModList.append(slot);
963 activeSlots.append(slot);
964 }
965 else if (mode == JoyButtonSlot::JoyKeyPress)
966 {
967 if (activeSlots.isEmpty())
968 {
969 delaySequence = true;
970 currentKeyPress = slot;
971 }
972 else
973 {
974 if (slotiter->hasPrevious())
975 {
976 slotiter->previous();
977 }
978 delaySequence = true;
979 exit = true;
980 }
981 }
982 else if (mode == JoyButtonSlot::JoyLoadProfile)
983 {
984 releaseActiveSlots();
985 slotiter->toBack();
986 exit = true;
987
988 QString location = slot->getTextData();
989 if (!location.isEmpty())
990 {
991 parentSet->getInputDevice()->sendLoadProfileRequest(location);
992 }
993 }
994 else if (mode == JoyButtonSlot::JoySetChange)
995 {
996 activeSlots.append(slot);
997 }
998 else if (mode == JoyButtonSlot::JoyTextEntry)
999 {
1000 sendevent(slot, true);
1001 }
1002 else if (mode == JoyButtonSlot::JoyExecute)
1003 {
1004 sendevent(slot, true);
1005 }
1006 }
1007
1008 #ifdef Q_OS_WIN
1009 BaseEventHandler *handler = EventHandlerFactory::getInstance()->handler();
1010 #endif
1011
1012 if (delaySequence && !activeSlots.isEmpty())
1013 {
1014 keyPressHold.restart();
1015 keyPressEvent();
1016 }
1017
1018 #ifdef Q_OS_WIN
1019 else if (handler && handler->getIdentifier() == "sendinput" &&
1020 changeRepeatState && !useTurbo)
1021 {
1022 InputDevice *device = getParentSet()->getInputDevice();
1023 if (device->isKeyRepeatEnabled())
1024 {
1025 if (lastActiveKey && activeSlots.contains(lastActiveKey))
1026 {
1027 repeatHelper.setLastActiveKey(lastActiveKey);
1028 repeatHelper.setKeyRepeatRate(device->getKeyRepeatRate());
1029 repeatHelper.getRepeatTimer()->start(device->getKeyRepeatDelay());
1030 }
1031 else if (repeatHelper.getRepeatTimer()->isActive())
1032 {
1033 repeatHelper.setLastActiveKey(0);
1034 repeatHelper.getRepeatTimer()->stop();
1035 }
1036 }
1037 }
1038 #endif
1039
1040 //emit activeZoneChanged();
1041 activeZoneTimer.start();
1042 }
1043 }
1044
slotSetChange()1045 void JoyButton::slotSetChange()
1046 {
1047 if (currentSetChangeSlot)
1048 {
1049 // Get set change slot and then remove reference.
1050 unsigned int setChangeIndex = currentSetChangeSlot->getSlotCode();
1051 currentSetChangeSlot = 0;
1052
1053 // Ensure that a change to the current set is not attempted.
1054 if (setChangeIndex != originset)
1055 {
1056 emit released(index);
1057 emit setChangeActivated(setChangeIndex);
1058 }
1059 }
1060 }
1061
1062 /**
1063 * @brief Calculate mouse movement coordinates for mouse movement slots
1064 * currently active.
1065 */
mouseEvent()1066 void JoyButton::mouseEvent()
1067 {
1068 JoyButtonSlot *buttonslot = 0;
1069 bool singleShot = false;
1070 if (currentMouseEvent)
1071 {
1072 buttonslot = currentMouseEvent;
1073 singleShot = true;
1074 }
1075
1076 if (buttonslot || !mouseEventQueue.isEmpty())
1077 {
1078 updateLastMouseDistance = true;
1079 updateStartingMouseDistance = true;
1080 updateOldAccelMulti = 0.0;
1081
1082 QQueue<JoyButtonSlot*> tempQueue;
1083
1084 if (!buttonslot)
1085 {
1086 buttonslot = mouseEventQueue.dequeue();
1087 }
1088
1089 //unsigned int timeElapsed = lastMouseTime.elapsed();
1090 unsigned int timeElapsed = testOldMouseTime.elapsed();
1091 //unsigned int nanoTimeElapsed = lastMouseTime.nsecsElapsed();
1092
1093 // Presumed initial mouse movement. Use full duration rather than
1094 // partial.
1095 if (staticMouseEventTimer.interval() < mouseRefreshRate)
1096 {
1097 //unsigned int nanoRemainder = nanoTimeElapsed - (timeElapsed * 1000000);
1098 timeElapsed = getMouseRefreshRate() + (timeElapsed - staticMouseEventTimer.interval());
1099 //nanoTimeElapsed = (timeElapsed * 1000000) + (nanoRemainder);
1100 }
1101
1102 while (buttonslot)
1103 {
1104 QElapsedTimer* mouseInterval = buttonslot->getMouseInterval();
1105
1106 int mousedirection = buttonslot->getSlotCode();
1107 JoyButton::JoyMouseMovementMode mousemode = getMouseMode();
1108 int mousespeed = 0;
1109
1110 bool isActive = activeSlots.contains(buttonslot);
1111 if (isActive)
1112 {
1113 if (mousemode == JoyButton::MouseCursor)
1114 {
1115 if (mousedirection == JoyButtonSlot::MouseRight)
1116 {
1117 mousespeed = mouseSpeedX;
1118 }
1119 else if (mousedirection == JoyButtonSlot::MouseLeft)
1120 {
1121 mousespeed = mouseSpeedX;
1122 }
1123 else if (mousedirection == JoyButtonSlot::MouseDown)
1124 {
1125 mousespeed = mouseSpeedY;
1126 }
1127 else if (mousedirection == JoyButtonSlot::MouseUp)
1128 {
1129 mousespeed = mouseSpeedY;
1130 }
1131
1132 double difference = getMouseDistanceFromDeadZone();
1133
1134 double mouse1 = 0;
1135 double mouse2 = 0;
1136 double sumDist = buttonslot->getMouseDistance();
1137 JoyMouseCurve currentCurve = getMouseCurve();
1138
1139 switch (currentCurve)
1140 {
1141 case LinearCurve:
1142 {
1143 break;
1144 }
1145 case QuadraticCurve:
1146 {
1147 difference = difference * difference;
1148 break;
1149 }
1150 case CubicCurve:
1151 {
1152 difference = difference * difference * difference;
1153 break;
1154 }
1155 case QuadraticExtremeCurve:
1156 {
1157 double temp = difference;
1158 difference = difference * difference;
1159 difference = (temp >= 0.95) ? (difference * 1.5) : difference;
1160 break;
1161 }
1162 case PowerCurve:
1163 {
1164 double tempsensitive = qMin(qMax(sensitivity, 1.0e-3), 1.0e+3);
1165 double temp = qMin(qMax(pow(difference, 1.0 / tempsensitive), 0.0), 1.0);
1166 difference = temp;
1167 break;
1168 }
1169 case EnhancedPrecisionCurve:
1170 {
1171 // Perform different forms of acceleration depending on
1172 // the range of the element from its assigned dead zone.
1173 // Useful for more precise controls with an axis.
1174 double temp = difference;
1175 if (temp <= 0.4)
1176 {
1177 // Low slope value for really slow acceleration
1178 difference = difference * 0.37;
1179 }
1180 else if (temp <= 0.75)
1181 {
1182 // Perform Linear accleration with an appropriate
1183 // offset.
1184 difference = difference - 0.252;
1185 }
1186 else if (temp > 0.75)
1187 {
1188 // Perform mouse acceleration. Make up the difference
1189 // due to the previous two segments. Maxes out at 1.0.
1190 difference = (difference * 2.008) - 1.008;
1191 }
1192
1193 break;
1194 }
1195 case EasingQuadraticCurve:
1196 case EasingCubicCurve:
1197 {
1198 // Perform different forms of acceleration depending on
1199 // the range of the element from its assigned dead zone.
1200 // Useful for more precise controls with an axis.
1201 double temp = difference;
1202 if (temp <= 0.4)
1203 {
1204 // Low slope value for really slow acceleration
1205 difference = difference * 0.38;
1206
1207 // Out of high end. Reset easing status.
1208 if (buttonslot->isEasingActive())
1209 {
1210 buttonslot->setEasingStatus(false);
1211 buttonslot->getEasingTime()->restart();
1212 }
1213 }
1214 else if (temp <= 0.75)
1215 {
1216 // Perform Linear accleration with an appropriate
1217 // offset.
1218 difference = difference - 0.248;
1219
1220 // Out of high end. Reset easing status.
1221 if (buttonslot->isEasingActive())
1222 {
1223 buttonslot->setEasingStatus(false);
1224 buttonslot->getEasingTime()->restart();
1225 }
1226 }
1227 else if (temp > 0.75)
1228 {
1229 // Gradually increase the mouse speed until the specified elapsed duration
1230 // time has passed.
1231 unsigned int easingElapsed = buttonslot->getEasingTime()->elapsed();
1232 double easingDuration = this->easingDuration; // Time in seconds
1233 if (!buttonslot->isEasingActive())
1234 {
1235 buttonslot->setEasingStatus(true);
1236 buttonslot->getEasingTime()->restart();
1237 easingElapsed = 0;
1238 }
1239
1240 // Determine the multiplier to use for the current maximum mouse speed
1241 // based on how much time has passed.
1242 double elapsedDiff = 1.0;
1243 if (easingDuration > 0.0 && (easingElapsed * .001) < easingDuration)
1244 {
1245 elapsedDiff = ((easingElapsed * .001) / easingDuration);
1246 if (currentCurve == EasingQuadraticCurve)
1247 {
1248 // Range 1.0 - 1.5
1249 elapsedDiff = (1.5 - 1.0) * elapsedDiff * elapsedDiff + 1.0;
1250 }
1251 else
1252 {
1253 // Range 1.0 - 1.5
1254 elapsedDiff = (1.5 - 1.0) * (elapsedDiff * elapsedDiff
1255 * elapsedDiff) + 1.0;
1256 }
1257 }
1258 else
1259 {
1260 elapsedDiff = 1.5;
1261 }
1262
1263 // Allow gradient control on the high end of an axis.
1264 difference = elapsedDiff * difference;
1265 // Range 0.502 - 1.5
1266 difference = difference * 1.33067 - 0.496005;
1267 }
1268 break;
1269 }
1270 }
1271
1272 double distance = 0;
1273 difference = (mouseSpeedModifier == 1.0) ? difference : (difference * mouseSpeedModifier);
1274
1275 double mintravel = minMouseDistanceAccelThreshold * 0.01;
1276 double minstop = qMax(0.05, mintravel);
1277 //double currentTravel = getAccelerationDistance() - lastAccelerationDistance;
1278
1279 // Last check ensures that acceleration is only applied for the same direction.
1280 if (extraAccelerationEnabled && isPartRealAxis() &&
1281 fabs(getAccelerationDistance() - lastAccelerationDistance) >= mintravel &&
1282 (getAccelerationDistance() - lastAccelerationDistance >= 0) == (getAccelerationDistance() >= 0))
1283 {
1284 double magfactor = extraAccelerationMultiplier;
1285 double minfactor = qMax((DEFAULTSTARTACCELMULTIPLIER * 0.001) + 1.0, magfactor * (startAccelMultiplier * 0.01));
1286 double maxtravel = maxMouseDistanceAccelThreshold * 0.01;
1287 double slope = (magfactor - minfactor)/(maxtravel - mintravel);
1288 double intercept = minfactor - (slope * mintravel);
1289
1290 double intermediateTravel = qMin(maxtravel, fabs(getAccelerationDistance() - lastAccelerationDistance));
1291 if (currentAccelMulti > 1.0 && oldAccelMulti == 0.0)
1292 {
1293 intermediateTravel = qMin(maxtravel, intermediateTravel + mintravel);
1294 }
1295
1296 double currentAccelMultiTemp = (slope * intermediateTravel + intercept);
1297 if (extraAccelCurve == EaseOutSineCurve)
1298 {
1299 double getMultiDiff2 = ((currentAccelMultiTemp - minfactor) / (extraAccelerationMultiplier - minfactor));
1300 currentAccelMultiTemp = (extraAccelerationMultiplier - minfactor) * sin(getMultiDiff2 * (PI/2.0)) + minfactor;
1301 }
1302 else if (extraAccelCurve == EaseOutQuadAccelCurve)
1303 {
1304 double getMultiDiff2 = ((currentAccelMultiTemp - minfactor) / (extraAccelerationMultiplier - minfactor));
1305 currentAccelMultiTemp = -(extraAccelerationMultiplier - minfactor) * (getMultiDiff2 * (getMultiDiff2 - 2)) + minfactor;
1306 }
1307 else if (extraAccelCurve == EaseOutCubicAccelCurve)
1308 {
1309 double getMultiDiff = ((currentAccelMultiTemp - minfactor) / (extraAccelerationMultiplier - minfactor)) - 1;
1310 currentAccelMultiTemp = (extraAccelerationMultiplier - minfactor) * ((getMultiDiff) * (getMultiDiff) * (getMultiDiff) + 1) + minfactor;
1311 }
1312
1313 difference = difference * currentAccelMultiTemp;
1314 currentAccelMulti = currentAccelMultiTemp;
1315 updateOldAccelMulti = currentAccelMulti;
1316 accelTravel = intermediateTravel;
1317 accelExtraDurationTime.restart();
1318 }
1319 else if (extraAccelerationEnabled && isPartRealAxis() && accelDuration > 0.0 &&
1320 currentAccelMulti > 0.0 &&
1321 fabs(getAccelerationDistance() - startingAccelerationDistance) < minstop)
1322 {
1323 //qDebug() << "Keep Trying: " << fabs(getAccelerationDistance() - lastAccelerationDistance);
1324 //qDebug() << "MIN TRAVEL: " << mintravel;
1325
1326 updateStartingMouseDistance = true;
1327 double magfactor = extraAccelerationMultiplier;
1328 double minfactor = qMax((DEFAULTSTARTACCELMULTIPLIER * 0.001) + 1.0, magfactor * (startAccelMultiplier * 0.01));
1329 double maxtravel = maxMouseDistanceAccelThreshold * 0.01;
1330 double slope = (magfactor - minfactor)/(maxtravel - mintravel);
1331 double intercept = minfactor - (slope * mintravel);
1332
1333 unsigned int elapsedElapsed = accelExtraDurationTime.elapsed();
1334
1335 double intermediateTravel = accelTravel;
1336 if ((getAccelerationDistance() - startingAccelerationDistance >= 0) != (getAccelerationDistance() >= 0))
1337 {
1338 // Travelling towards dead zone. Decrease acceleration and duration.
1339 intermediateTravel = qMax(intermediateTravel - fabs(getAccelerationDistance() - startingAccelerationDistance), mintravel);
1340 }
1341
1342 // Linear case
1343 double currentAccelMultiTemp = (slope * intermediateTravel + intercept);
1344 double elapsedDuration = accelDuration *
1345 ((currentAccelMultiTemp - minfactor) / (extraAccelerationMultiplier - minfactor));
1346
1347 if (extraAccelCurve == EaseOutSineCurve)
1348 {
1349 double multiDiff = ((currentAccelMultiTemp - minfactor) / (extraAccelerationMultiplier - minfactor));
1350 double temp = sin(multiDiff * (PI/2.0));
1351 elapsedDuration = accelDuration * temp + 0;
1352 currentAccelMultiTemp = (extraAccelerationMultiplier - minfactor) * sin(multiDiff * (PI/2.0)) + minfactor;
1353 }
1354 else if (extraAccelCurve == EaseOutQuadAccelCurve)
1355 {
1356 double getMultiDiff2 = ((currentAccelMultiTemp - minfactor) / (extraAccelerationMultiplier - minfactor));
1357 double temp = (getMultiDiff2 * (getMultiDiff2 - 2));
1358 elapsedDuration = -accelDuration * temp + 0;
1359 currentAccelMultiTemp = -(extraAccelerationMultiplier - minfactor) * temp + minfactor;
1360 }
1361 else if (extraAccelCurve == EaseOutCubicAccelCurve)
1362 {
1363 double getMultiDiff = ((currentAccelMultiTemp - minfactor) / (extraAccelerationMultiplier - minfactor)) - 1;
1364 double temp = ((getMultiDiff) * (getMultiDiff) * (getMultiDiff) + 1);
1365 elapsedDuration = accelDuration * temp + 0;
1366 currentAccelMultiTemp = (extraAccelerationMultiplier - minfactor) * temp + minfactor;
1367 }
1368
1369 double tempAccel = currentAccelMultiTemp;
1370 double elapsedDiff = 1.0;
1371 if (elapsedDuration > 0.0 && (elapsedElapsed * 0.001) < elapsedDuration)
1372 {
1373 elapsedDiff = ((elapsedElapsed * 0.001) / elapsedDuration);
1374 elapsedDiff = (1.0 - tempAccel) * (elapsedDiff * elapsedDiff * elapsedDiff) + tempAccel;
1375
1376 difference = elapsedDiff * difference;
1377
1378 // As acceleration is applied, do not update last
1379 // distance values when not necessary.
1380 updateStartingMouseDistance = false;
1381 updateOldAccelMulti = currentAccelMulti;
1382 }
1383 else
1384 {
1385 elapsedDiff = 1.0;
1386 currentAccelMulti = 0.0;
1387 updateOldAccelMulti = 0.0;
1388 accelTravel = 0.0;
1389 }
1390 }
1391 else if (extraAccelerationEnabled && isPartRealAxis())
1392 {
1393 currentAccelMulti = 0.0;
1394 updateStartingMouseDistance = true;
1395 oldAccelMulti = updateOldAccelMulti = 0.0;
1396 accelTravel = 0.0;
1397 }
1398
1399 sumDist += difference * (mousespeed * JoyButtonSlot::JOYSPEED * timeElapsed) * 0.001;
1400 //sumDist = difference * (nanoTimeElapsed * 0.000000001) * mousespeed * JoyButtonSlot::JOYSPEED;
1401 distance = sumDist;
1402
1403 if (mousedirection == JoyButtonSlot::MouseRight)
1404 {
1405 mouse1 = distance;
1406 }
1407 else if (mousedirection == JoyButtonSlot::MouseLeft)
1408 {
1409 mouse1 = -distance;
1410 }
1411 else if (mousedirection == JoyButtonSlot::MouseDown)
1412 {
1413 mouse2 = distance;
1414 }
1415 else if (mousedirection == JoyButtonSlot::MouseUp)
1416 {
1417 mouse2 = -distance;
1418 }
1419
1420 mouseCursorInfo infoX;
1421 infoX.code = mouse1;
1422 infoX.slot = buttonslot;
1423 cursorXSpeeds.append(infoX);
1424
1425 mouseCursorInfo infoY;
1426 infoY.code = mouse2;
1427 infoY.slot = buttonslot;
1428 cursorYSpeeds.append(infoY);
1429 sumDist = 0;
1430
1431 buttonslot->setDistance(sumDist);
1432 }
1433 else if (mousemode == JoyButton::MouseSpring)
1434 {
1435 double mouse1 = -2.0;
1436 double mouse2 = -2.0;
1437 double difference = getMouseDistanceFromDeadZone();
1438
1439 if (mousedirection == JoyButtonSlot::MouseRight)
1440 {
1441 mouse1 = difference;
1442 if (mouseHelper.getFirstSpringStatus())
1443 {
1444 mouse2 = 0.0;
1445 mouseHelper.setFirstSpringStatus(false);
1446 }
1447 }
1448 else if (mousedirection == JoyButtonSlot::MouseLeft)
1449 {
1450 mouse1 = -difference;
1451 if (mouseHelper.getFirstSpringStatus())
1452 {
1453 mouse2 = 0.0;
1454 mouseHelper.setFirstSpringStatus(false);
1455 }
1456 }
1457 else if (mousedirection == JoyButtonSlot::MouseDown)
1458 {
1459 if (mouseHelper.getFirstSpringStatus())
1460 {
1461 mouse1 = 0.0;
1462 mouseHelper.setFirstSpringStatus(false);
1463 }
1464
1465 mouse2 = difference;
1466 }
1467 else if (mousedirection == JoyButtonSlot::MouseUp)
1468 {
1469 if (mouseHelper.getFirstSpringStatus())
1470 {
1471 mouse1 = 0.0;
1472 mouseHelper.setFirstSpringStatus(false);
1473 }
1474
1475 mouse2 = -difference;
1476 }
1477
1478 PadderCommon::springModeInfo infoX;
1479 infoX.displacementX = mouse1;
1480 infoX.springDeadX = 0.0;
1481 infoX.width = springWidth;
1482 infoX.height = springHeight;
1483 infoX.relative = relativeSpring;
1484 infoX.screen = springModeScreen;
1485 springXSpeeds.append(infoX);
1486
1487 PadderCommon::springModeInfo infoY;
1488 infoY.displacementY = mouse2;
1489 infoY.springDeadY = 0.0;
1490 infoY.width = springWidth;
1491 infoY.height = springHeight;
1492 infoY.relative = relativeSpring;
1493 infoY.screen = springModeScreen;
1494 springYSpeeds.append(infoY);
1495
1496 mouseInterval->restart();
1497 }
1498
1499 tempQueue.enqueue(buttonslot);
1500 }
1501
1502 if (!mouseEventQueue.isEmpty() && !singleShot)
1503 {
1504 buttonslot = mouseEventQueue.dequeue();
1505 }
1506 else
1507 {
1508 buttonslot = 0;
1509 }
1510 }
1511
1512 if (!tempQueue.isEmpty())
1513 {
1514 while (!tempQueue.isEmpty())
1515 {
1516 JoyButtonSlot *tempslot = tempQueue.dequeue();
1517 mouseEventQueue.enqueue(tempslot);
1518 }
1519 }
1520 }
1521 }
1522
wheelEventVertical()1523 void JoyButton::wheelEventVertical()
1524 {
1525 JoyButtonSlot *buttonslot = 0;
1526 if (currentWheelVerticalEvent)
1527 {
1528 buttonslot = currentWheelVerticalEvent;
1529 }
1530
1531 if (buttonslot && wheelSpeedY != 0)
1532 {
1533 bool isActive = activeSlots.contains(buttonslot);
1534 if (isActive)
1535 {
1536 sendevent(buttonslot, true);
1537 sendevent(buttonslot, false);
1538 mouseWheelVerticalEventQueue.enqueue(buttonslot);
1539 mouseWheelVerticalEventTimer.start(1000 / wheelSpeedY);
1540 }
1541 else
1542 {
1543 mouseWheelVerticalEventTimer.stop();
1544 }
1545 }
1546 else if (!mouseWheelVerticalEventQueue.isEmpty() && wheelSpeedY != 0)
1547 {
1548 QQueue<JoyButtonSlot*> tempQueue;
1549 while (!mouseWheelVerticalEventQueue.isEmpty())
1550 {
1551 buttonslot = mouseWheelVerticalEventQueue.dequeue();
1552 bool isActive = activeSlots.contains(buttonslot);
1553 if (isActive)
1554 {
1555 sendevent(buttonslot, true);
1556 sendevent(buttonslot, false);
1557 tempQueue.enqueue(buttonslot);
1558 }
1559 }
1560
1561 if (!tempQueue.isEmpty())
1562 {
1563 mouseWheelVerticalEventQueue = tempQueue;
1564 mouseWheelVerticalEventTimer.start(1000 / wheelSpeedY);
1565 }
1566 else
1567 {
1568 mouseWheelVerticalEventTimer.stop();
1569 }
1570 }
1571 else
1572 {
1573 mouseWheelVerticalEventTimer.stop();
1574 }
1575 }
1576
wheelEventHorizontal()1577 void JoyButton::wheelEventHorizontal()
1578 {
1579 JoyButtonSlot *buttonslot = 0;
1580 if (currentWheelHorizontalEvent)
1581 {
1582 buttonslot = currentWheelHorizontalEvent;
1583 }
1584
1585 if (buttonslot && wheelSpeedX != 0)
1586 {
1587 bool isActive = activeSlots.contains(buttonslot);
1588 if (isActive)
1589 {
1590 sendevent(buttonslot, true);
1591 sendevent(buttonslot, false);
1592 mouseWheelHorizontalEventQueue.enqueue(buttonslot);
1593 mouseWheelHorizontalEventTimer.start(1000 / wheelSpeedX);
1594 }
1595 else
1596 {
1597 mouseWheelHorizontalEventTimer.stop();
1598 }
1599 }
1600 else if (!mouseWheelHorizontalEventQueue.isEmpty() && wheelSpeedX != 0)
1601 {
1602 QQueue<JoyButtonSlot*> tempQueue;
1603 while (!mouseWheelHorizontalEventQueue.isEmpty())
1604 {
1605 buttonslot = mouseWheelHorizontalEventQueue.dequeue();
1606 bool isActive = activeSlots.contains(buttonslot);
1607 if (isActive)
1608 {
1609 sendevent(buttonslot, true);
1610 sendevent(buttonslot, false);
1611 tempQueue.enqueue(buttonslot);
1612 }
1613 }
1614
1615 if (!tempQueue.isEmpty())
1616 {
1617 mouseWheelHorizontalEventQueue = tempQueue;
1618 mouseWheelHorizontalEventTimer.start(1000 / wheelSpeedX);
1619 }
1620 else
1621 {
1622 mouseWheelHorizontalEventTimer.stop();
1623 }
1624 }
1625 else
1626 {
1627 mouseWheelHorizontalEventTimer.stop();
1628 }
1629 }
1630
setUseTurbo(bool useTurbo)1631 void JoyButton::setUseTurbo(bool useTurbo)
1632 {
1633 bool initialState = this->useTurbo;
1634
1635 if (useTurbo != this->useTurbo)
1636 {
1637 if (useTurbo && this->containsSequence())
1638 {
1639 this->useTurbo = false;
1640 }
1641 else
1642 {
1643 this->useTurbo = useTurbo;
1644 }
1645
1646 if (initialState != this->useTurbo)
1647 {
1648 emit turboChanged(this->useTurbo);
1649 emit propertyUpdated();
1650
1651 if (this->useTurbo && this->turboInterval == 0)
1652 {
1653 this->setTurboInterval(ENABLEDTURBODEFAULT);
1654 }
1655 }
1656 }
1657 }
1658
isUsingTurbo()1659 bool JoyButton::isUsingTurbo()
1660 {
1661 return useTurbo;
1662 }
1663
getXmlName()1664 QString JoyButton::getXmlName()
1665 {
1666 return this->xmlName;
1667 }
1668
readConfig(QXmlStreamReader * xml)1669 void JoyButton::readConfig(QXmlStreamReader *xml)
1670 {
1671 if (xml->isStartElement() && xml->name() == getXmlName())
1672 {
1673 xml->readNextStartElement();
1674 while (!xml->atEnd() && (!xml->isEndElement() && xml->name() != getXmlName()))
1675 {
1676 bool found = readButtonConfig(xml);
1677 if (!found)
1678 {
1679 xml->skipCurrentElement();
1680 }
1681 else
1682 {
1683 buildActiveZoneSummaryString();
1684 }
1685
1686 xml->readNextStartElement();
1687 }
1688 }
1689 }
1690
writeConfig(QXmlStreamWriter * xml)1691 void JoyButton::writeConfig(QXmlStreamWriter *xml)
1692 {
1693 if (!isDefault())
1694 {
1695 xml->writeStartElement(getXmlName());
1696 xml->writeAttribute("index", QString::number(getRealJoyNumber()));
1697
1698 if (toggle != DEFAULTTOGGLE)
1699 {
1700 xml->writeTextElement("toggle", toggle ? "true" : "false");
1701 }
1702
1703 if (turboInterval != DEFAULTTURBOINTERVAL)
1704 {
1705 xml->writeTextElement("turbointerval", QString::number(turboInterval));
1706 }
1707
1708 if (currentTurboMode != DEFAULTTURBOMODE)
1709 {
1710 if (currentTurboMode == GradientTurbo)
1711 {
1712 xml->writeTextElement("turbomode", "gradient");
1713 }
1714 else if (currentTurboMode == PulseTurbo)
1715 {
1716 xml->writeTextElement("turbomode", "pulse");
1717 }
1718 }
1719
1720 if (useTurbo != DEFAULTUSETURBO)
1721 {
1722 xml->writeTextElement("useturbo", useTurbo ? "true" : "false");
1723 }
1724
1725 if (mouseSpeedX != DEFAULTMOUSESPEEDX)
1726 {
1727 xml->writeTextElement("mousespeedx", QString::number(mouseSpeedX));
1728 }
1729
1730 if (mouseSpeedY != DEFAULTMOUSESPEEDY)
1731 {
1732 xml->writeTextElement("mousespeedy", QString::number(mouseSpeedY));
1733 }
1734
1735
1736 if (mouseMode != DEFAULTMOUSEMODE)
1737 {
1738 if (mouseMode == MouseCursor)
1739 {
1740 xml->writeTextElement("mousemode", "cursor");
1741 }
1742 else if (mouseMode == MouseSpring)
1743 {
1744 xml->writeTextElement("mousemode", "spring");
1745 xml->writeTextElement("mousespringwidth", QString::number(springWidth));
1746 xml->writeTextElement("mousespringheight", QString::number(springHeight));
1747 }
1748 }
1749
1750 if (mouseCurve != DEFAULTMOUSECURVE)
1751 {
1752 if (mouseCurve == LinearCurve)
1753 {
1754 xml->writeTextElement("mouseacceleration", "linear");
1755 }
1756 else if (mouseCurve == QuadraticCurve)
1757 {
1758 xml->writeTextElement("mouseacceleration", "quadratic");
1759 }
1760 else if (mouseCurve == CubicCurve)
1761 {
1762 xml->writeTextElement("mouseacceleration", "cubic");
1763 }
1764 else if (mouseCurve == QuadraticExtremeCurve)
1765 {
1766 xml->writeTextElement("mouseacceleration", "quadratic-extreme");
1767 }
1768 else if (mouseCurve == PowerCurve)
1769 {
1770 xml->writeTextElement("mouseacceleration", "power");
1771 xml->writeTextElement("mousesensitivity", QString::number(sensitivity));
1772 }
1773 else if (mouseCurve == EnhancedPrecisionCurve)
1774 {
1775 xml->writeTextElement("mouseacceleration", "precision");
1776 }
1777 else if (mouseCurve == EasingQuadraticCurve)
1778 {
1779 xml->writeTextElement("mouseacceleration", "easing-quadratic");
1780 }
1781 else if (mouseCurve == EasingCubicCurve)
1782 {
1783 xml->writeTextElement("mouseacceleration", "easing-cubic");
1784 }
1785 }
1786
1787 if (wheelSpeedX != DEFAULTWHEELX)
1788 {
1789 xml->writeTextElement("wheelspeedx", QString::number(wheelSpeedX));
1790 }
1791
1792 if (wheelSpeedY != DEFAULTWHEELY)
1793 {
1794 xml->writeTextElement("wheelspeedy", QString::number(wheelSpeedY));
1795 }
1796
1797 if (!isModifierButton())
1798 {
1799 if (setSelectionCondition != SetChangeDisabled)
1800 {
1801 xml->writeTextElement("setselect", QString::number(setSelection+1));
1802
1803 QString temptext;
1804 if (setSelectionCondition == SetChangeOneWay)
1805 {
1806 temptext = "one-way";
1807 }
1808 else if (setSelectionCondition == SetChangeTwoWay)
1809 {
1810 temptext = "two-way";
1811 }
1812 else if (setSelectionCondition == SetChangeWhileHeld)
1813 {
1814 temptext = "while-held";
1815 }
1816 xml->writeTextElement("setselectcondition", temptext);
1817 }
1818 }
1819
1820 if (!actionName.isEmpty())
1821 {
1822 xml->writeTextElement("actionname", actionName);
1823 }
1824
1825 if (cycleResetActive)
1826 {
1827 xml->writeTextElement("cycleresetactive", "true");
1828 }
1829
1830 if (cycleResetInterval >= MINCYCLERESETTIME)
1831 {
1832 xml->writeTextElement("cycleresetinterval", QString::number(cycleResetInterval));
1833 }
1834
1835 if (relativeSpring == true)
1836 {
1837 xml->writeTextElement("relativespring", "true");
1838 }
1839
1840 if (easingDuration != DEFAULTEASINGDURATION)
1841 {
1842 xml->writeTextElement("easingduration", QString::number(easingDuration));
1843 }
1844
1845 if (extraAccelerationEnabled)
1846 {
1847 xml->writeTextElement("extraacceleration", "true");
1848 }
1849
1850 if (extraAccelerationMultiplier != DEFAULTEXTRACCELVALUE)
1851 {
1852 xml->writeTextElement("accelerationmultiplier", QString::number(extraAccelerationMultiplier));
1853 }
1854
1855 if (startAccelMultiplier != DEFAULTSTARTACCELMULTIPLIER)
1856 {
1857 xml->writeTextElement("startaccelmultiplier", QString::number(startAccelMultiplier));
1858 }
1859
1860 if (minMouseDistanceAccelThreshold != DEFAULTMINACCELTHRESHOLD)
1861 {
1862 xml->writeTextElement("minaccelthreshold", QString::number(minMouseDistanceAccelThreshold));
1863 }
1864
1865 if (maxMouseDistanceAccelThreshold != DEFAULTMAXACCELTHRESHOLD)
1866 {
1867 xml->writeTextElement("maxaccelthreshold", QString::number(maxMouseDistanceAccelThreshold));
1868 }
1869
1870 if (accelDuration != DEFAULTACCELEASINGDURATION)
1871 {
1872 xml->writeTextElement("accelextraduration", QString::number(accelDuration));
1873 }
1874
1875 if (springDeadCircleMultiplier != DEFAULTSPRINGRELEASERADIUS)
1876 {
1877 xml->writeTextElement("springreleaseradius", QString::number(springDeadCircleMultiplier));
1878 }
1879
1880 if (extraAccelCurve != DEFAULTEXTRAACCELCURVE)
1881 {
1882 QString temp;
1883 if (extraAccelCurve == LinearAccelCurve)
1884 {
1885 temp = "linear";
1886 }
1887 else if (extraAccelCurve == EaseOutSineCurve)
1888 {
1889 temp = "easeoutsine";
1890 }
1891 else if (extraAccelCurve == EaseOutQuadAccelCurve)
1892 {
1893 temp = "easeoutquad";
1894 }
1895 else if (extraAccelCurve == EaseOutCubicAccelCurve)
1896 {
1897 temp = "easeoutcubic";
1898 }
1899
1900 if (!temp.isEmpty())
1901 {
1902 xml->writeTextElement("extraaccelerationcurve", temp);
1903 }
1904 }
1905
1906 // Write information about assigned slots.
1907 if (!assignments.isEmpty())
1908 {
1909 xml->writeStartElement("slots");
1910 QListIterator<JoyButtonSlot*> iter(assignments);
1911 while (iter.hasNext())
1912 {
1913 JoyButtonSlot *buttonslot = iter.next();
1914 buttonslot->writeConfig(xml);
1915 }
1916 xml->writeEndElement();
1917 }
1918
1919
1920 xml->writeEndElement();
1921 }
1922 }
1923
readButtonConfig(QXmlStreamReader * xml)1924 bool JoyButton::readButtonConfig(QXmlStreamReader *xml)
1925 {
1926 bool found = false;
1927
1928 if (xml->name() == "toggle" && xml->isStartElement())
1929 {
1930 found = true;
1931 QString temptext = xml->readElementText();
1932 if (temptext == "true")
1933 {
1934 this->setToggle(true);
1935 }
1936 }
1937 else if (xml->name() == "turbointerval" && xml->isStartElement())
1938 {
1939 found = true;
1940 QString temptext = xml->readElementText();
1941 int tempchoice = temptext.toInt();
1942 this->setTurboInterval(tempchoice);
1943 }
1944 else if (xml->name() == "turbomode" && xml->isStartElement())
1945 {
1946 found = true;
1947 QString temptext = xml->readElementText();
1948 if (temptext == "normal")
1949 {
1950 this->setTurboMode(NormalTurbo);
1951 }
1952 else if (temptext == "gradient")
1953 {
1954 this->setTurboMode(GradientTurbo);
1955 }
1956 else if (temptext == "pulse")
1957 {
1958 this->setTurboMode(PulseTurbo);
1959 }
1960 }
1961 else if (xml->name() == "useturbo" && xml->isStartElement())
1962 {
1963 found = true;
1964 QString temptext = xml->readElementText();
1965 if (temptext == "true")
1966 {
1967 this->setUseTurbo(true);
1968 }
1969 }
1970 else if (xml->name() == "mousespeedx" && xml->isStartElement())
1971 {
1972 found = true;
1973 QString temptext = xml->readElementText();
1974 int tempchoice = temptext.toInt();
1975 this->setMouseSpeedX(tempchoice);
1976 }
1977 else if (xml->name() == "mousespeedy" && xml->isStartElement())
1978 {
1979 found = true;
1980 QString temptext = xml->readElementText();
1981 int tempchoice = temptext.toInt();
1982 this->setMouseSpeedY(tempchoice);
1983 }
1984 else if (xml->name() == "cycleresetactive" && xml->isStartElement())
1985 {
1986 found = true;
1987 QString temptext = xml->readElementText();
1988 if (temptext == "true")
1989 {
1990 this->setCycleResetStatus(true);
1991 }
1992 }
1993 else if (xml->name() == "cycleresetinterval" && xml->isStartElement())
1994 {
1995 found = true;
1996 QString temptext = xml->readElementText();
1997 unsigned int tempchoice = temptext.toInt();
1998 if (tempchoice >= MINCYCLERESETTIME)
1999 {
2000 this->setCycleResetTime(tempchoice);
2001 }
2002 }
2003 else if (xml->name() == "slots" && xml->isStartElement())
2004 {
2005 found = true;
2006 xml->readNextStartElement();
2007 while (!xml->atEnd() && (!xml->isEndElement() && xml->name() != "slots"))
2008 {
2009 if (xml->name() == "slot" && xml->isStartElement())
2010 {
2011 JoyButtonSlot *buttonslot = new JoyButtonSlot(this);
2012 buttonslot->readConfig(xml);
2013 bool validSlot = buttonslot->isValidSlot();
2014 if (validSlot)
2015 {
2016 bool inserted = insertAssignedSlot(buttonslot, false);
2017 if (!inserted)
2018 {
2019 delete buttonslot;
2020 buttonslot = 0;
2021 }
2022 }
2023 else
2024 {
2025 delete buttonslot;
2026 buttonslot = 0;
2027 }
2028 }
2029 else
2030 {
2031 xml->skipCurrentElement();
2032 }
2033
2034 xml->readNextStartElement();
2035 }
2036 }
2037 else if (xml->name() == "setselect" && xml->isStartElement())
2038 {
2039 if (!isModifierButton())
2040 {
2041 found = true;
2042 QString temptext = xml->readElementText();
2043 int tempchoice = temptext.toInt();
2044 if (tempchoice >= 0 && tempchoice <= InputDevice::NUMBER_JOYSETS)
2045 {
2046 this->setChangeSetSelection(tempchoice - 1, false);
2047 }
2048 }
2049 }
2050 else if (xml->name() == "setselectcondition" && xml->isStartElement())
2051 {
2052 if (!isModifierButton())
2053 {
2054 found = true;
2055 QString temptext = xml->readElementText();
2056 SetChangeCondition tempcondition = SetChangeDisabled;
2057 if (temptext == "one-way")
2058 {
2059 tempcondition = SetChangeOneWay;
2060 }
2061 else if (temptext == "two-way")
2062 {
2063 tempcondition = SetChangeTwoWay;
2064 }
2065 else if (temptext == "while-held")
2066 {
2067 tempcondition = SetChangeWhileHeld;
2068 }
2069
2070 if (tempcondition != SetChangeDisabled)
2071 {
2072 this->setChangeSetCondition(tempcondition, false, false);
2073 }
2074 }
2075 }
2076 else if (xml->name() == "mousemode" && xml->isStartElement())
2077 {
2078 found = true;
2079 QString temptext = xml->readElementText();
2080 if (temptext == "cursor")
2081 {
2082 setMouseMode(MouseCursor);
2083 }
2084 else if (temptext == "spring")
2085 {
2086 setMouseMode(MouseSpring);
2087 }
2088 }
2089 else if (xml->name() == "mouseacceleration" && xml->isStartElement())
2090 {
2091 found = true;
2092 QString temptext = xml->readElementText();
2093 if (temptext == "linear")
2094 {
2095 setMouseCurve(LinearCurve);
2096 }
2097 else if (temptext == "quadratic")
2098 {
2099 setMouseCurve(QuadraticCurve);
2100 }
2101 else if (temptext == "cubic")
2102 {
2103 setMouseCurve(CubicCurve);
2104 }
2105 else if (temptext == "quadratic-extreme")
2106 {
2107 setMouseCurve(QuadraticExtremeCurve);
2108 }
2109 else if (temptext == "power")
2110 {
2111 setMouseCurve(PowerCurve);
2112 }
2113 else if (temptext == "precision")
2114 {
2115 setMouseCurve(EnhancedPrecisionCurve);
2116 }
2117 else if (temptext == "easing-quadratic")
2118 {
2119 setMouseCurve(EasingQuadraticCurve);
2120 }
2121 else if (temptext == "easing-cubic")
2122 {
2123 setMouseCurve(EasingCubicCurve);
2124 }
2125 }
2126 else if (xml->name() == "mousespringwidth" && xml->isStartElement())
2127 {
2128 found = true;
2129 QString temptext = xml->readElementText();
2130 int tempchoice = temptext.toInt();
2131 setSpringWidth(tempchoice);
2132 }
2133 else if (xml->name() == "mousespringheight" && xml->isStartElement())
2134 {
2135 found = true;
2136 QString temptext = xml->readElementText();
2137 int tempchoice = temptext.toInt();
2138 setSpringHeight(tempchoice);
2139 }
2140 else if (xml->name() == "mousesensitivity" && xml->isStartElement())
2141 {
2142 found = true;
2143 QString temptext = xml->readElementText();
2144 double tempchoice = temptext.toDouble();
2145 setSensitivity(tempchoice);
2146 }
2147 else if (xml->name() == "actionname" && xml->isStartElement())
2148 {
2149 found = true;
2150 QString temptext = xml->readElementText();
2151 if (!temptext.isEmpty())
2152 {
2153 setActionName(temptext);
2154 }
2155 }
2156 else if (xml->name() == "wheelspeedx" && xml->isStartElement())
2157 {
2158 found = true;
2159 QString temptext = xml->readElementText();
2160 int tempchoice = temptext.toInt();
2161 setWheelSpeedX(tempchoice);
2162 }
2163 else if (xml->name() == "wheelspeedy" && xml->isStartElement())
2164 {
2165 found = true;
2166 QString temptext = xml->readElementText();
2167 int tempchoice = temptext.toInt();
2168 setWheelSpeedY(tempchoice);
2169 }
2170 else if (xml->name() == "relativespring" && xml->isStartElement())
2171 {
2172 found = true;
2173 QString temptext = xml->readElementText();
2174 if (temptext == "true")
2175 {
2176 this->setSpringRelativeStatus(true);
2177 }
2178 }
2179 else if (xml->name() == "easingduration" && xml->isStartElement())
2180 {
2181 found = true;
2182 QString temptext = xml->readElementText();
2183 double tempchoice = temptext.toDouble();
2184 setEasingDuration(tempchoice);
2185 }
2186 else if (xml->name() == "extraacceleration" && xml->isStartElement())
2187 {
2188 found = true;
2189 QString temptext = xml->readElementText();
2190 if (temptext == "true")
2191 {
2192 setExtraAccelerationStatus(true);
2193 }
2194 }
2195 else if (xml->name() == "accelerationmultiplier" && xml->isStartElement())
2196 {
2197 found = true;
2198 QString temptext = xml->readElementText();
2199 double tempchoice = temptext.toDouble();
2200 setExtraAccelerationMultiplier(tempchoice);
2201 }
2202 else if (xml->name() == "startaccelmultiplier" && xml->isStartElement())
2203 {
2204 found = true;
2205 QString temptext = xml->readElementText();
2206 double tempchoice = temptext.toDouble();
2207 setStartAccelMultiplier(tempchoice);
2208 }
2209 else if (xml->name() == "minaccelthreshold" && xml->isStartElement())
2210 {
2211 found = true;
2212 QString temptext = xml->readElementText();
2213 double tempchoice = temptext.toDouble();
2214 setMinAccelThreshold(tempchoice);
2215 }
2216 else if (xml->name() == "maxaccelthreshold" && xml->isStartElement())
2217 {
2218 found = true;
2219 QString temptext = xml->readElementText();
2220 double tempchoice = temptext.toDouble();
2221 setMaxAccelThreshold(tempchoice);
2222 }
2223 else if (xml->name() == "accelextraduration" && xml->isStartElement())
2224 {
2225 found = true;
2226 QString temptext = xml->readElementText();
2227 double tempchoice = temptext.toDouble();
2228 setAccelExtraDuration(tempchoice);
2229 }
2230 else if (xml->name() == "extraaccelerationcurve" && xml->isStartElement())
2231 {
2232 found = true;
2233
2234 QString temptext = xml->readElementText();
2235 JoyExtraAccelerationCurve tempcurve = DEFAULTEXTRAACCELCURVE;
2236 if (temptext == "linear")
2237 {
2238 tempcurve = LinearAccelCurve;
2239 }
2240 else if (temptext == "easeoutsine")
2241 {
2242 tempcurve = EaseOutSineCurve;
2243 }
2244 else if (temptext == "easeoutquad")
2245 {
2246 tempcurve = EaseOutQuadAccelCurve;
2247 }
2248 else if (temptext == "easeoutcubic")
2249 {
2250 tempcurve = EaseOutCubicAccelCurve;
2251 }
2252
2253 setExtraAccelerationCurve(tempcurve);
2254 }
2255 else if (xml->name() == "springreleaseradius" && xml->isStartElement())
2256 {
2257 found = true;
2258 QString temptext = xml->readElementText();
2259 int tempchoice = temptext.toInt();
2260 if (!relativeSpring)
2261 {
2262 setSpringDeadCircleMultiplier(tempchoice);
2263 }
2264 }
2265
2266 return found;
2267 }
2268
getName(bool forceFullFormat,bool displayNames)2269 QString JoyButton::getName(bool forceFullFormat, bool displayNames)
2270 {
2271 QString newlabel = getPartialName(forceFullFormat, displayNames);
2272 newlabel.append(": ");
2273 if (!actionName.isEmpty() && displayNames)
2274 {
2275 newlabel.append(actionName);
2276 }
2277 else
2278 {
2279 newlabel.append(getCalculatedActiveZoneSummary());
2280 }
2281 return newlabel;
2282 }
2283
getPartialName(bool forceFullFormat,bool displayNames)2284 QString JoyButton::getPartialName(bool forceFullFormat, bool displayNames)
2285 {
2286 QString temp;
2287 if (!buttonName.isEmpty() && displayNames)
2288 {
2289 if (forceFullFormat)
2290 {
2291 temp.append(tr("Button")).append(" ");
2292 }
2293 temp.append(buttonName);
2294 }
2295 else if (!defaultButtonName.isEmpty())
2296 {
2297 if (forceFullFormat)
2298 {
2299 temp.append(tr("Button")).append(" ");
2300 }
2301 temp.append(defaultButtonName);
2302 }
2303 else
2304 {
2305 temp.append(tr("Button")).append(" ").append(QString::number(getRealJoyNumber()));
2306 }
2307
2308 return temp;
2309 }
2310
2311 /**
2312 * @brief Generate a string representing a summary of the slots currently
2313 * assigned to a button
2314 * @return String of currently assigned slots
2315 */
getSlotsSummary()2316 QString JoyButton::getSlotsSummary()
2317 {
2318 QString newlabel;
2319 int slotCount = assignments.size();
2320
2321 if (slotCount > 0)
2322 {
2323 QListIterator<JoyButtonSlot*> iter(assignments);
2324 QStringList stringlist;
2325
2326 int i = 0;
2327 while (iter.hasNext())
2328 {
2329 JoyButtonSlot *slot = iter.next();
2330 stringlist.append(slot->getSlotString());
2331 i++;
2332
2333 if (i > 4 && iter.hasNext())
2334 {
2335 stringlist.append(" ...");
2336 iter.toBack();
2337 }
2338 }
2339
2340 newlabel = stringlist.join(", ");
2341 }
2342 else
2343 {
2344 newlabel = newlabel.append(tr("[NO KEY]"));
2345 }
2346
2347 return newlabel;
2348 }
2349
2350 /**
2351 * @brief Generate a string that represents slots that will be activated or
2352 * slots that are currently active if a button is pressed
2353 * @return String of currently applicable slots for a button
2354 */
getActiveZoneSummary()2355 QString JoyButton::getActiveZoneSummary()
2356 {
2357 QList<JoyButtonSlot*> tempList = getActiveZoneList();
2358 QString temp = buildActiveZoneSummary(tempList);
2359 return temp;
2360 }
2361
getCalculatedActiveZoneSummary()2362 QString JoyButton::getCalculatedActiveZoneSummary()
2363 {
2364 activeZoneStringLock.lockForRead();
2365 QString temp = this->activeZoneString;
2366 activeZoneStringLock.unlock();
2367 return temp;
2368 }
2369
2370 /**
2371 * @brief Generate active zone string and notify other objects.
2372 */
buildActiveZoneSummaryString()2373 void JoyButton::buildActiveZoneSummaryString()
2374 {
2375 activeZoneStringLock.lockForWrite();
2376 this->activeZoneString = getActiveZoneSummary();
2377 activeZoneStringLock.unlock();
2378
2379 emit activeZoneChanged();
2380 }
2381
2382 /**
2383 * @brief Generate active zone string but do not notify any other object.
2384 */
localBuildActiveZoneSummaryString()2385 void JoyButton::localBuildActiveZoneSummaryString()
2386 {
2387 activeZoneStringLock.lockForWrite();
2388 this->activeZoneString = getActiveZoneSummary();
2389 activeZoneStringLock.unlock();
2390 }
2391
buildActiveZoneSummary(QList<JoyButtonSlot * > & tempList)2392 QString JoyButton::buildActiveZoneSummary(QList<JoyButtonSlot *> &tempList)
2393 {
2394 QString newlabel;
2395 QListIterator<JoyButtonSlot*> iter(tempList);
2396 QStringList stringlist;
2397 int i = 0;
2398 bool slotsActive = !activeSlots.isEmpty();
2399
2400 if (setSelectionCondition == SetChangeOneWay)
2401 {
2402 newlabel.append(tr("[Set %1 1W]").arg(setSelection+1));
2403 if (iter.hasNext())
2404 {
2405 newlabel.append(" ");
2406 }
2407 }
2408 else if (setSelectionCondition == SetChangeTwoWay)
2409 {
2410 newlabel = newlabel.append(tr("[Set %1 2W]").arg(setSelection+1));
2411 if (iter.hasNext())
2412 {
2413 newlabel.append(" ");
2414 }
2415 }
2416
2417 if (setSelectionCondition == SetChangeWhileHeld)
2418 {
2419 newlabel.append(tr("[Set %1 WH]").arg(setSelection+1));
2420 }
2421 else if (iter.hasNext())
2422 {
2423 bool behindHold = false;
2424 while (iter.hasNext())
2425 {
2426 JoyButtonSlot *slot = iter.next();
2427 JoyButtonSlot::JoySlotInputAction mode = slot->getSlotMode();
2428 switch (mode)
2429 {
2430 case JoyButtonSlot::JoyKeyboard:
2431 case JoyButtonSlot::JoyMouseButton:
2432 case JoyButtonSlot::JoyMouseMovement:
2433 {
2434 QString temp = slot->getSlotString();
2435 if (behindHold)
2436 {
2437 temp.prepend("[H] ");
2438 behindHold = false;
2439 }
2440
2441 stringlist.append(temp);
2442 i++;
2443 break;
2444 }
2445 case JoyButtonSlot::JoyKeyPress:
2446 {
2447 // Skip slot if a press time slot was inserted.
2448 break;
2449 }
2450 case JoyButtonSlot::JoyHold:
2451 {
2452 if (!slotsActive && i == 0)
2453 {
2454 // If button is not active and first slot is a hold,
2455 // keep processing slots but take note of the hold.
2456 behindHold = true;
2457 }
2458 else
2459 {
2460 // Move iter to back so loop will end.
2461 iter.toBack();
2462 }
2463
2464 break;
2465 }
2466 case JoyButtonSlot::JoyLoadProfile:
2467 case JoyButtonSlot::JoySetChange:
2468 case JoyButtonSlot::JoyTextEntry:
2469 case JoyButtonSlot::JoyExecute:
2470 {
2471 QString temp = slot->getSlotString();
2472 if (behindHold)
2473 {
2474 temp.prepend("[H] ");
2475 behindHold = false;
2476 }
2477
2478 stringlist.append(temp);
2479 i++;
2480 break;
2481 }
2482 /*case JoyButtonSlot::JoyRelease:
2483 {
2484 if (!currentRelease)
2485 {
2486 findReleaseEventIterEnd(iter);
2487 }
2488
2489 break;
2490 }
2491 */
2492 /*case JoyButtonSlot::JoyDistance:
2493 {
2494 iter->toBack();
2495 break;
2496 }
2497 */
2498 case JoyButtonSlot::JoyDelay:
2499 {
2500 iter.toBack();
2501 break;
2502 }
2503 case JoyButtonSlot::JoyCycle:
2504 {
2505 iter.toBack();
2506 break;
2507 }
2508 }
2509
2510 if (i > 4 && iter.hasNext())
2511 {
2512 stringlist.append(" ...");
2513 iter.toBack();
2514 }
2515 }
2516
2517 newlabel.append(stringlist.join(", "));
2518 }
2519 else if (setSelectionCondition == SetChangeDisabled)
2520 {
2521 newlabel.append(tr("[NO KEY]"));
2522 }
2523
2524 return newlabel;
2525 }
2526
getActiveZoneList()2527 QList<JoyButtonSlot*> JoyButton::getActiveZoneList()
2528 {
2529 QListIterator<JoyButtonSlot*> activeSlotsIter(activeSlots);
2530 QListIterator<JoyButtonSlot*> assignmentsIter(assignments);
2531
2532 QListIterator<JoyButtonSlot*> *iter = 0;
2533 QReadWriteLock *tempLock = 0;
2534
2535 activeZoneLock.lockForRead();
2536 int numActiveSlots = activeSlots.size();
2537 activeZoneLock.unlock();
2538
2539 if (numActiveSlots > 0)
2540 {
2541 tempLock = &activeZoneLock;
2542 iter = &activeSlotsIter;
2543 }
2544 else
2545 {
2546 tempLock = &assignmentsLock;
2547 iter = &assignmentsIter;
2548 }
2549
2550 QReadLocker tempLocker(tempLock);
2551 Q_UNUSED(tempLocker);
2552
2553 if (tempLock == &assignmentsLock)
2554 {
2555 if (previousCycle)
2556 {
2557 iter->findNext(previousCycle);
2558 }
2559 }
2560
2561 QList<JoyButtonSlot*> tempSlotList;
2562
2563 if (setSelectionCondition != SetChangeWhileHeld && iter->hasNext())
2564 {
2565 while (iter->hasNext())
2566 {
2567 JoyButtonSlot *slot = iter->next();
2568 JoyButtonSlot::JoySlotInputAction mode = slot->getSlotMode();
2569 switch (mode)
2570 {
2571 case JoyButtonSlot::JoyKeyboard:
2572 case JoyButtonSlot::JoyMouseButton:
2573 case JoyButtonSlot::JoyMouseMovement:
2574 {
2575 tempSlotList.append(slot);
2576 break;
2577 }
2578 case JoyButtonSlot::JoyKeyPress:
2579 case JoyButtonSlot::JoyHold:
2580 case JoyButtonSlot::JoyLoadProfile:
2581 case JoyButtonSlot::JoySetChange:
2582 case JoyButtonSlot::JoyTextEntry:
2583 case JoyButtonSlot::JoyExecute:
2584 {
2585 tempSlotList.append(slot);
2586 break;
2587 }
2588 case JoyButtonSlot::JoyRelease:
2589 {
2590 if (!currentRelease)
2591 {
2592 findReleaseEventIterEnd(iter);
2593 }
2594
2595 break;
2596 }
2597 case JoyButtonSlot::JoyDistance:
2598 {
2599 iter->toBack();
2600 break;
2601 }
2602 case JoyButtonSlot::JoyCycle:
2603 {
2604 iter->toBack();
2605 break;
2606 }
2607 }
2608 }
2609 }
2610
2611 return tempSlotList;
2612 }
2613
2614 /**
2615 * @brief Generate a string representing all the currently assigned slots for
2616 * a button
2617 * @return String representing all assigned slots for a button
2618 */
getSlotsString()2619 QString JoyButton::getSlotsString()
2620 {
2621 QString label;
2622
2623 if (assignments.size() > 0)
2624 {
2625 QListIterator<JoyButtonSlot*> iter(assignments);
2626 QStringList stringlist;
2627
2628 while (iter.hasNext())
2629 {
2630 JoyButtonSlot *slot = iter.next();
2631 stringlist.append(slot->getSlotString());
2632 }
2633
2634 label = stringlist.join(", ");
2635 }
2636 else
2637 {
2638 label = label.append(tr("[NO KEY]"));
2639 }
2640
2641 return label;
2642 }
2643
setCustomName(QString name)2644 void JoyButton::setCustomName(QString name)
2645 {
2646 customName = name;
2647 }
2648
getCustomName()2649 QString JoyButton::getCustomName()
2650 {
2651 return customName;
2652 }
2653
2654 /**
2655 * @brief Create new JoyButtonSlot with data provided and append the new slot
2656 * an existing to the assignment list.
2657 * @param Native virtual code being used.
2658 * @param Mode of the slot.
2659 * @return Whether the new slot was successfully added to the assignment list.
2660 */
setAssignedSlot(int code,JoyButtonSlot::JoySlotInputAction mode)2661 bool JoyButton::setAssignedSlot(int code, JoyButtonSlot::JoySlotInputAction mode)
2662 {
2663 bool slotInserted = false;
2664 JoyButtonSlot *slot = new JoyButtonSlot(code, mode, this);
2665 if (slot->getSlotMode() == JoyButtonSlot::JoyDistance)
2666 {
2667 if (slot->getSlotCode() >= 1 && slot->getSlotCode() <= 100)
2668 {
2669 double tempDistance = getTotalSlotDistance(slot);
2670 if (tempDistance <= 1.0)
2671 {
2672 assignmentsLock.lockForWrite();
2673 assignments.append(slot);
2674 assignmentsLock.unlock();
2675
2676 buildActiveZoneSummaryString();
2677 slotInserted = true;
2678 }
2679 }
2680 }
2681 else if (slot->getSlotCode() >= 0)
2682 {
2683 assignmentsLock.lockForWrite();
2684 assignments.append(slot);
2685 assignmentsLock.unlock();
2686
2687 buildActiveZoneSummaryString();
2688 slotInserted = true;
2689 }
2690
2691 if (slotInserted)
2692 {
2693 checkTurboCondition(slot);
2694 emit slotsChanged();
2695 }
2696 else
2697 {
2698 if (slot)
2699 {
2700 delete slot;
2701 slot = 0;
2702 }
2703 }
2704
2705 return slotInserted;
2706 }
2707
2708 /**
2709 * @brief Create new JoyButtonSlot with data provided and append the new slot
2710 * an existing to the assignment list.
2711 * @param Native virtual code being used.
2712 * @param Qt key alias used for abstracting native virtual code.
2713 * @param Mode of the slot.
2714 * @return Whether the new slot was successfully added to the assignment list.
2715 */
setAssignedSlot(int code,unsigned int alias,JoyButtonSlot::JoySlotInputAction mode)2716 bool JoyButton::setAssignedSlot(int code, unsigned int alias,
2717 JoyButtonSlot::JoySlotInputAction mode)
2718 {
2719 bool slotInserted = false;
2720 JoyButtonSlot *slot = new JoyButtonSlot(code, alias, mode, this);
2721 if (slot->getSlotMode() == JoyButtonSlot::JoyDistance)
2722 {
2723 if (slot->getSlotCode() >= 1 && slot->getSlotCode() <= 100)
2724 {
2725 double tempDistance = getTotalSlotDistance(slot);
2726 if (tempDistance <= 1.0)
2727 {
2728 assignmentsLock.lockForWrite();
2729 assignments.append(slot);
2730 assignmentsLock.unlock();
2731
2732 buildActiveZoneSummaryString();
2733 slotInserted = true;
2734 }
2735 }
2736 }
2737 else if (slot->getSlotCode() >= 0)
2738 {
2739 assignmentsLock.lockForWrite();
2740 assignments.append(slot);
2741 assignmentsLock.unlock();
2742
2743 buildActiveZoneSummaryString();
2744 slotInserted = true;
2745 }
2746
2747 if (slotInserted)
2748 {
2749 checkTurboCondition(slot);
2750 emit slotsChanged();
2751 }
2752 else
2753 {
2754 if (slot)
2755 {
2756 delete slot;
2757 slot = 0;
2758 }
2759 }
2760
2761 return slotInserted;
2762 }
2763
2764 /**
2765 * @brief Create new JoyButtonSlot with data provided and replace an existing
2766 * slot in the assignment list if one exists.
2767 * @param Native virtual code being used.
2768 * @param Qt key alias used for abstracting native virtual code.
2769 * @param Index number in the list.
2770 * @param Mode of the slot.
2771 * @return Whether the new slot was successfully added to the assignment list.
2772 */
setAssignedSlot(int code,unsigned int alias,int index,JoyButtonSlot::JoySlotInputAction mode)2773 bool JoyButton::setAssignedSlot(int code, unsigned int alias, int index,
2774 JoyButtonSlot::JoySlotInputAction mode)
2775 {
2776 bool permitSlot = true;
2777
2778 JoyButtonSlot *slot = new JoyButtonSlot(code, alias, mode, this);
2779 if (slot->getSlotMode() == JoyButtonSlot::JoyDistance)
2780 {
2781 if (slot->getSlotCode() >= 1 && slot->getSlotCode() <= 100)
2782 {
2783 double tempDistance = getTotalSlotDistance(slot);
2784 if (tempDistance > 1.0)
2785 {
2786 permitSlot = false;
2787 }
2788 }
2789 else
2790 {
2791 permitSlot = false;
2792 }
2793 }
2794 else if (slot->getSlotCode() < 0)
2795 {
2796 permitSlot = false;
2797 }
2798
2799 if (permitSlot)
2800 {
2801 assignmentsLock.lockForWrite();
2802
2803 if (index >= 0 && index < assignments.count())
2804 {
2805 // Insert slot and move existing slots.
2806 JoyButtonSlot *temp = assignments.at(index);
2807 if (temp)
2808 {
2809 delete temp;
2810 temp = 0;
2811 }
2812
2813 assignments.replace(index, slot);
2814 }
2815 else if (index >= assignments.count())
2816 {
2817 // Append code into a new slot
2818 assignments.append(slot);
2819 }
2820
2821 checkTurboCondition(slot);
2822 assignmentsLock.unlock();
2823
2824 buildActiveZoneSummaryString();
2825
2826 emit slotsChanged();
2827 }
2828 else
2829 {
2830 if (slot)
2831 {
2832 delete slot;
2833 slot = 0;
2834 }
2835 }
2836
2837 return permitSlot;
2838 }
2839
2840 /**
2841 * @brief Create new JoyButtonSlot with data provided and insert it into
2842 * assignments list if it is valid.
2843 * @param Native virtual code being used.
2844 * @param Qt key alias used for abstracting native virtual code.
2845 * @param Index number in the list.
2846 * @param Mode of the slot.
2847 * @return Whether the new slot was successfully added to the assignment list.
2848 */
insertAssignedSlot(int code,unsigned int alias,int index,JoyButtonSlot::JoySlotInputAction mode)2849 bool JoyButton::insertAssignedSlot(int code, unsigned int alias, int index,
2850 JoyButtonSlot::JoySlotInputAction mode)
2851 {
2852 bool permitSlot = true;
2853
2854 JoyButtonSlot *slot = new JoyButtonSlot(code, alias, mode, this);
2855 if (slot->getSlotMode() == JoyButtonSlot::JoyDistance)
2856 {
2857 if (slot->getSlotCode() >= 1 && slot->getSlotCode() <= 100)
2858 {
2859 double tempDistance = getTotalSlotDistance(slot);
2860 if (tempDistance > 1.0)
2861 {
2862 permitSlot = false;
2863 }
2864 }
2865 else
2866 {
2867 permitSlot = false;
2868 }
2869 }
2870 else if (slot->getSlotCode() < 0)
2871 {
2872 permitSlot = false;
2873 }
2874
2875 if (permitSlot)
2876 {
2877 assignmentsLock.lockForWrite();
2878
2879 if (index >= 0 && index < assignments.count())
2880 {
2881 // Insert new slot into list. Move old slots if needed.
2882 assignments.insert(index, slot);
2883 }
2884 else if (index >= assignments.count())
2885 {
2886 // Append new slot into list.
2887 assignments.append(slot);
2888 }
2889
2890 checkTurboCondition(slot);
2891 assignmentsLock.unlock();
2892
2893 buildActiveZoneSummaryString();
2894
2895 emit slotsChanged();
2896 }
2897 else
2898 {
2899 if (slot)
2900 {
2901 delete slot;
2902 slot = 0;
2903 }
2904 }
2905
2906 return permitSlot;
2907 }
2908
insertAssignedSlot(JoyButtonSlot * newSlot,bool updateActiveString)2909 bool JoyButton::insertAssignedSlot(JoyButtonSlot *newSlot, bool updateActiveString)
2910 {
2911 bool permitSlot = false;
2912
2913 if (newSlot->getSlotMode() == JoyButtonSlot::JoyDistance)
2914 {
2915 if (newSlot->getSlotCode() >= 1 && newSlot->getSlotCode() <= 100)
2916 {
2917 double tempDistance = getTotalSlotDistance(newSlot);
2918 if (tempDistance <= 1.0)
2919 {
2920 permitSlot = true;
2921 }
2922 }
2923 }
2924 else if (newSlot->getSlotMode() == JoyButtonSlot::JoyLoadProfile)
2925 {
2926 permitSlot = true;
2927 }
2928 else if (newSlot->getSlotMode() == JoyButtonSlot::JoyTextEntry &&
2929 !newSlot->getTextData().isEmpty())
2930 {
2931 permitSlot = true;
2932 }
2933 else if (newSlot->getSlotMode() == JoyButtonSlot::JoyExecute &&
2934 !newSlot->getTextData().isEmpty())
2935 {
2936 permitSlot = true;
2937 }
2938 else if (newSlot->getSlotCode() >= 0)
2939 {
2940 permitSlot = true;
2941 }
2942
2943 if (permitSlot)
2944 {
2945 assignmentsLock.lockForWrite();
2946 checkTurboCondition(newSlot);
2947 assignments.append(newSlot);
2948 assignmentsLock.unlock();
2949
2950 if (updateActiveString)
2951 {
2952 buildActiveZoneSummaryString();
2953 }
2954
2955
2956 emit slotsChanged();
2957 }
2958
2959 return permitSlot;
2960 }
2961
setAssignedSlot(JoyButtonSlot * otherSlot,int index)2962 bool JoyButton::setAssignedSlot(JoyButtonSlot *otherSlot, int index)
2963 {
2964 bool permitSlot = false;
2965 JoyButtonSlot *newslot = new JoyButtonSlot(otherSlot, this);
2966
2967 if (newslot->getSlotMode() == JoyButtonSlot::JoyDistance)
2968 {
2969 if (newslot->getSlotCode() >= 1 && newslot->getSlotCode() <= 100)
2970 {
2971 double tempDistance = getTotalSlotDistance(newslot);
2972 if (tempDistance <= 1.0)
2973 {
2974 permitSlot = true;
2975 }
2976 }
2977 }
2978 else if (newslot->getSlotMode() == JoyButtonSlot::JoyLoadProfile)
2979 {
2980 permitSlot = true;
2981 }
2982 else if (newslot->getSlotMode() == JoyButtonSlot::JoyTextEntry &&
2983 !newslot->getTextData().isEmpty())
2984 {
2985 permitSlot = true;
2986 }
2987 else if (newslot->getSlotMode() == JoyButtonSlot::JoyExecute &&
2988 !newslot->getTextData().isEmpty())
2989 {
2990 permitSlot = true;
2991 }
2992 else if (newslot->getSlotCode() >= 0)
2993 {
2994 permitSlot = true;
2995 }
2996
2997 if (permitSlot)
2998 {
2999 assignmentsLock.lockForWrite();
3000
3001 checkTurboCondition(newslot);
3002
3003 if (index >= 0 && index < assignments.count())
3004 {
3005 // Slot already exists. Override code and place into desired slot
3006 JoyButtonSlot *temp = assignments.at(index);
3007 if (temp)
3008 {
3009 delete temp;
3010 temp = 0;
3011 //assignments.insert(index, temp);
3012 }
3013
3014 assignments.replace(index, newslot);
3015 }
3016 else if (index >= assignments.count())
3017 {
3018 // Append code into a new slot
3019 assignments.append(newslot);
3020 }
3021
3022 assignmentsLock.unlock();
3023
3024 buildActiveZoneSummaryString();
3025
3026 emit slotsChanged();
3027 }
3028 else
3029 {
3030 delete newslot;
3031 newslot = 0;
3032 }
3033
3034 return permitSlot;
3035 }
3036
getAssignedSlots()3037 QList<JoyButtonSlot*>* JoyButton::getAssignedSlots()
3038 {
3039 QList<JoyButtonSlot*> *newassign = &assignments;
3040 return newassign;
3041 }
3042
setMouseSpeedX(int speed)3043 void JoyButton::setMouseSpeedX(int speed)
3044 {
3045 if (speed >= 1 && speed <= 300)
3046 {
3047 mouseSpeedX = speed;
3048 emit propertyUpdated();
3049 }
3050 }
3051
getMouseSpeedX()3052 int JoyButton::getMouseSpeedX()
3053 {
3054 return mouseSpeedX;
3055 }
3056
setMouseSpeedY(int speed)3057 void JoyButton::setMouseSpeedY(int speed)
3058 {
3059 if (speed >= 1 && speed <= 300)
3060 {
3061 mouseSpeedY = speed;
3062 emit propertyUpdated();
3063 }
3064 }
3065
getMouseSpeedY()3066 int JoyButton::getMouseSpeedY()
3067 {
3068 return mouseSpeedY;
3069 }
3070
setChangeSetSelection(int index,bool updateActiveString)3071 void JoyButton::setChangeSetSelection(int index, bool updateActiveString)
3072 {
3073 if (index >= -1 && index <= 7)
3074 {
3075 setSelection = index;
3076
3077 if (updateActiveString)
3078 {
3079 buildActiveZoneSummaryString();
3080 }
3081
3082 emit propertyUpdated();
3083 }
3084 }
3085
getSetSelection()3086 int JoyButton::getSetSelection()
3087 {
3088 return setSelection;
3089 }
3090
setChangeSetCondition(SetChangeCondition condition,bool passive,bool updateActiveString)3091 void JoyButton::setChangeSetCondition(SetChangeCondition condition,
3092 bool passive, bool updateActiveString)
3093 {
3094 SetChangeCondition oldCondition = setSelectionCondition;
3095
3096 if (condition != setSelectionCondition && !passive)
3097 {
3098 if (condition == SetChangeWhileHeld || condition == SetChangeTwoWay)
3099 {
3100 // Set new condition
3101 emit setAssignmentChanged(index, setSelection, condition);
3102 }
3103 else if (setSelectionCondition == SetChangeWhileHeld || setSelectionCondition == SetChangeTwoWay)
3104 {
3105 // Remove old condition
3106 emit setAssignmentChanged(index, setSelection, SetChangeDisabled);
3107 }
3108
3109 setSelectionCondition = condition;
3110 }
3111 else if (passive)
3112 {
3113 setSelectionCondition = condition;
3114 }
3115
3116 if (setSelectionCondition == SetChangeDisabled)
3117 {
3118 setChangeSetSelection(-1);
3119 }
3120
3121 if (setSelectionCondition != oldCondition)
3122 {
3123 if (updateActiveString)
3124 {
3125 buildActiveZoneSummaryString();
3126 }
3127
3128 emit propertyUpdated();
3129 }
3130 }
3131
getChangeSetCondition()3132 JoyButton::SetChangeCondition JoyButton::getChangeSetCondition()
3133 {
3134 return setSelectionCondition;
3135 }
3136
getButtonState()3137 bool JoyButton::getButtonState()
3138 {
3139 return isButtonPressed;
3140 }
3141
getOriginSet()3142 int JoyButton::getOriginSet()
3143 {
3144 return originset;
3145 }
3146
pauseWaitEvent()3147 void JoyButton::pauseWaitEvent()
3148 {
3149 if (currentPause)
3150 {
3151 if (!isButtonPressedQueue.isEmpty() && createDeskTimer.isActive())
3152 {
3153 if (slotiter)
3154 {
3155 slotiter->toBack();
3156
3157 bool lastIgnoreSetState = ignoreSetQueue.last();
3158 bool lastIsButtonPressed = isButtonPressedQueue.last();
3159 ignoreSetQueue.clear();
3160 isButtonPressedQueue.clear();
3161
3162 ignoreSetQueue.enqueue(lastIgnoreSetState);
3163 isButtonPressedQueue.enqueue(lastIsButtonPressed);
3164 currentPause = 0;
3165 //JoyButtonSlot *oldCurrentRelease = currentRelease;
3166 currentRelease = 0;
3167 //createDeskTimer.stop();
3168 releaseDeskTimer.stop();
3169 pauseWaitTimer.stop();
3170
3171 slotiter->toFront();
3172 if (previousCycle)
3173 {
3174 slotiter->findNext(previousCycle);
3175 }
3176 quitEvent = true;
3177 keyPressHold.restart();
3178 //waitForDeskEvent();
3179 // Assuming that if this is the case, a pause from
3180 // a release slot was previously active. setChangeTimer
3181 // should not be active at this point.
3182 //if (oldCurrentRelease && setChangeTimer.isActive())
3183 //{
3184 // setChangeTimer.stop();
3185 //}
3186 }
3187 }
3188 }
3189
3190 if (currentPause)
3191 {
3192 // If release timer is active, temporarily
3193 // disable it
3194 if (releaseDeskTimer.isActive())
3195 {
3196 releaseDeskTimer.stop();
3197 }
3198
3199 if (inpauseHold.elapsed() < currentPause->getSlotCode())
3200 {
3201 int proposedInterval = currentPause->getSlotCode() - inpauseHold.elapsed();
3202 proposedInterval = proposedInterval > 0 ? proposedInterval : 0;
3203 int newTimerInterval = qMin(10, proposedInterval);
3204 pauseWaitTimer.start(newTimerInterval);
3205 }
3206 else
3207 {
3208 pauseWaitTimer.stop();
3209 createDeskTimer.stop();
3210 currentPause = 0;
3211 createDeskEvent();
3212
3213 // If release timer was disabled but if the button
3214 // is not pressed, restart the release timer.
3215 if (!releaseDeskTimer.isActive() && (isButtonPressedQueue.isEmpty() || !isButtonPressedQueue.last()))
3216 {
3217 waitForReleaseDeskEvent();
3218 }
3219 }
3220 }
3221 else
3222 {
3223 pauseWaitTimer.stop();
3224 }
3225 }
3226
checkForSetChange()3227 void JoyButton::checkForSetChange()
3228 {
3229 if (!ignoreSetQueue.isEmpty() && !isButtonPressedQueue.isEmpty())
3230 {
3231 bool tempFinalState = isButtonPressedQueue.last();
3232 bool tempFinalIgnoreSetsState = ignoreSetQueue.last();
3233
3234 if (!tempFinalIgnoreSetsState)
3235 {
3236 if (!tempFinalState && setSelectionCondition == SetChangeOneWay && setSelection > -1)
3237 {
3238 // If either timer is currently active,
3239 // stop the timer
3240 if (createDeskTimer.isActive())
3241 {
3242 createDeskTimer.stop();
3243 }
3244
3245 if (releaseDeskTimer.isActive())
3246 {
3247 releaseDeskTimer.stop();
3248 }
3249
3250 isButtonPressedQueue.clear();
3251 ignoreSetQueue.clear();
3252
3253 emit released(index);
3254 emit setChangeActivated(setSelection);
3255 }
3256 else if (!tempFinalState && setSelectionCondition == SetChangeTwoWay && setSelection > -1)
3257 {
3258 // If either timer is currently active,
3259 // stop the timer
3260 if (createDeskTimer.isActive())
3261 {
3262 createDeskTimer.stop();
3263 }
3264
3265 if (releaseDeskTimer.isActive())
3266 {
3267 releaseDeskTimer.stop();
3268 }
3269
3270 isButtonPressedQueue.clear();
3271 ignoreSetQueue.clear();
3272
3273 emit released(index);
3274 emit setChangeActivated(setSelection);
3275 }
3276 else if (setSelectionCondition == SetChangeWhileHeld && setSelection > -1)
3277 {
3278 if (tempFinalState)
3279 {
3280 whileHeldStatus = true;
3281 }
3282 else if (!tempFinalState)
3283 {
3284 whileHeldStatus = false;
3285 }
3286
3287 // If either timer is currently active,
3288 // stop the timer
3289 if (createDeskTimer.isActive())
3290 {
3291 createDeskTimer.stop();
3292 }
3293
3294 if (releaseDeskTimer.isActive())
3295 {
3296 releaseDeskTimer.stop();
3297 }
3298
3299 isButtonPressedQueue.clear();
3300 ignoreSetQueue.clear();
3301
3302 emit released(index);
3303 emit setChangeActivated(setSelection);
3304 }
3305 }
3306
3307 // Clear queue except for a press if it is last in
3308 if (!isButtonPressedQueue.isEmpty())
3309 {
3310 isButtonPressedQueue.clear();
3311 if (tempFinalState)
3312 {
3313 isButtonPressedQueue.enqueue(tempFinalState);
3314 }
3315 }
3316
3317 // Clear queue except for a press if it is last in
3318 if (!ignoreSetQueue.isEmpty())
3319 {
3320 bool tempFinalIgnoreSetsState = ignoreSetQueue.last();
3321 ignoreSetQueue.clear();
3322 if (tempFinalState)
3323 {
3324 ignoreSetQueue.enqueue(tempFinalIgnoreSetsState);
3325 }
3326 }
3327 }
3328 }
3329
waitForDeskEvent()3330 void JoyButton::waitForDeskEvent()
3331 {
3332 if (quitEvent && !isButtonPressedQueue.isEmpty() && isButtonPressedQueue.last())
3333 {
3334 if (createDeskTimer.isActive())
3335 {
3336 keyPressTimer.stop();
3337 createDeskTimer.stop();
3338 releaseDeskTimer.stop();
3339 createDeskEvent();
3340 }
3341 else
3342 {
3343 keyPressTimer.stop();
3344 releaseDeskTimer.stop();
3345 createDeskEvent();
3346 }
3347 /*else
3348 {
3349 createDeskTimer.start(0);
3350 releaseDeskTimer.stop();
3351 keyDelayHold.restart();
3352 }*/
3353 }
3354 else if (!createDeskTimer.isActive())
3355 {
3356 #ifdef Q_CC_MSVC
3357 createDeskTimer.start(5);
3358 releaseDeskTimer.stop();
3359 #else
3360 createDeskTimer.start(0);
3361 releaseDeskTimer.stop();
3362 #endif
3363 }
3364 else if (createDeskTimer.isActive())
3365 {
3366 // Decrease timer interval of active timer.
3367 createDeskTimer.start(0);
3368 releaseDeskTimer.stop();
3369 }
3370 }
3371
waitForReleaseDeskEvent()3372 void JoyButton::waitForReleaseDeskEvent()
3373 {
3374 if (quitEvent && !keyPressTimer.isActive())
3375 {
3376 if (releaseDeskTimer.isActive())
3377 {
3378 releaseDeskTimer.stop();
3379 }
3380 createDeskTimer.stop();
3381 keyPressTimer.stop();
3382 releaseDeskEvent();
3383 }
3384 else if (!releaseDeskTimer.isActive())
3385 {
3386 #ifdef Q_CC_MSVC
3387 releaseDeskTimer.start(1);
3388 createDeskTimer.stop();
3389 #else
3390 releaseDeskTimer.start(1);
3391 createDeskTimer.stop();
3392 #endif
3393 }
3394 else if (releaseDeskTimer.isActive())
3395 {
3396 createDeskTimer.stop();
3397 }
3398 }
3399
containsSequence()3400 bool JoyButton::containsSequence()
3401 {
3402 bool result = false;
3403
3404 assignmentsLock.lockForRead();
3405 QListIterator<JoyButtonSlot*> tempiter(assignments);
3406 while (tempiter.hasNext())
3407 {
3408 JoyButtonSlot *slot = tempiter.next();
3409 JoyButtonSlot::JoySlotInputAction mode = slot->getSlotMode();
3410 if (mode == JoyButtonSlot::JoyPause ||
3411 mode == JoyButtonSlot::JoyHold ||
3412 mode == JoyButtonSlot::JoyDistance
3413 )
3414 {
3415 result = true;
3416 tempiter.toBack();
3417 }
3418 }
3419 assignmentsLock.unlock();
3420
3421 return result;
3422 }
3423
holdEvent()3424 void JoyButton::holdEvent()
3425 {
3426 if (currentHold)
3427 {
3428 bool currentlyPressed = false;
3429 if (!isButtonPressedQueue.isEmpty())
3430 {
3431 currentlyPressed = isButtonPressedQueue.last();
3432 }
3433
3434 // Activate hold event
3435 if (currentlyPressed && buttonHold.elapsed() > currentHold->getSlotCode())
3436 {
3437 releaseActiveSlots();
3438 currentHold = 0;
3439 holdTimer.stop();
3440 buttonHold.restart();
3441 createDeskEvent();
3442 }
3443 // Elapsed time has not occurred
3444 else if (currentlyPressed)
3445 {
3446 unsigned int holdTime = currentHold->getSlotCode();
3447 int proposedInterval = holdTime - buttonHold.elapsed();
3448 proposedInterval = proposedInterval > 0 ? proposedInterval : 0;
3449 int newTimerInterval = qMin(10, proposedInterval);
3450 holdTimer.start(newTimerInterval);
3451 }
3452 // Pre-emptive release
3453 else
3454 {
3455 currentHold = 0;
3456 holdTimer.stop();
3457
3458 if (slotiter)
3459 {
3460 findHoldEventEnd();
3461 createDeskEvent();
3462 }
3463 }
3464 }
3465 else
3466 {
3467 holdTimer.stop();
3468 }
3469 }
3470
delayEvent()3471 void JoyButton::delayEvent()
3472 {
3473 if (currentDelay)
3474 {
3475 bool currentlyPressed = false;
3476 if (!isButtonPressedQueue.isEmpty())
3477 {
3478 currentlyPressed = isButtonPressedQueue.last();
3479 }
3480
3481 // Delay time has elapsed. Continue processing slots.
3482 if (currentDelay && buttonDelay.elapsed() > currentDelay->getSlotCode())
3483 {
3484 currentDelay = 0;
3485 delayTimer.stop();
3486 buttonDelay.restart();
3487 createDeskEvent();
3488 }
3489 // Elapsed time has not occurred
3490 else if (currentlyPressed)
3491 {
3492 unsigned int delayTime = currentDelay->getSlotCode();
3493 int proposedInterval = delayTime - buttonDelay.elapsed();
3494 proposedInterval = proposedInterval > 0 ? proposedInterval : 0;
3495 int newTimerInterval = qMin(10, proposedInterval);
3496 delayTimer.start(newTimerInterval);
3497 }
3498 // Pre-emptive release
3499 else
3500 {
3501 currentDelay = 0;
3502 delayTimer.stop();
3503 }
3504 }
3505 else
3506 {
3507 delayTimer.stop();
3508 }
3509 }
3510
releaseDeskEvent(bool skipsetchange)3511 void JoyButton::releaseDeskEvent(bool skipsetchange)
3512 {
3513 quitEvent = false;
3514
3515 pauseWaitTimer.stop();
3516 holdTimer.stop();
3517 createDeskTimer.stop();
3518 keyPressTimer.stop();
3519 delayTimer.stop();
3520 #ifdef Q_OS_WIN
3521 repeatHelper.getRepeatTimer()->stop();
3522 #endif
3523 setChangeTimer.stop();
3524
3525 releaseActiveSlots();
3526 if (!isButtonPressedQueue.isEmpty() && !currentRelease)
3527 {
3528 releaseSlotEvent();
3529 }
3530 else if (currentRelease)
3531 {
3532 currentRelease = 0;
3533 }
3534
3535 if (!skipsetchange && setSelectionCondition != SetChangeDisabled &&
3536 !isButtonPressedQueue.isEmpty() && !currentRelease)
3537 {
3538 bool tempButtonPressed = isButtonPressedQueue.last();
3539 bool tempFinalIgnoreSetsState = ignoreSetQueue.last();
3540
3541 if (!tempButtonPressed && !tempFinalIgnoreSetsState)
3542 {
3543 if (setSelectionCondition == SetChangeWhileHeld && whileHeldStatus)
3544 {
3545 setChangeTimer.start(0);
3546 }
3547 else if (setSelectionCondition != SetChangeWhileHeld)
3548 {
3549 setChangeTimer.start();
3550 }
3551 }
3552 else
3553 {
3554 bool tempFinalState = false;
3555 if (!isButtonPressedQueue.isEmpty())
3556 {
3557 tempFinalState = isButtonPressedQueue.last();
3558 isButtonPressedQueue.clear();
3559 if (tempFinalState)
3560 {
3561 isButtonPressedQueue.enqueue(tempFinalState);
3562 }
3563 }
3564
3565 if (!ignoreSetQueue.isEmpty())
3566 {
3567 bool tempFinalIgnoreSetsState = ignoreSetQueue.last();
3568 ignoreSetQueue.clear();
3569 if (tempFinalState)
3570 {
3571 ignoreSetQueue.enqueue(tempFinalIgnoreSetsState);
3572 }
3573 }
3574 }
3575 }
3576 else
3577 {
3578 bool tempFinalState = false;
3579 if (!isButtonPressedQueue.isEmpty())
3580 {
3581 tempFinalState = isButtonPressedQueue.last();
3582 isButtonPressedQueue.clear();
3583 if (tempFinalState || currentRelease)
3584 {
3585 isButtonPressedQueue.enqueue(tempFinalState);
3586 }
3587 }
3588
3589 if (!ignoreSetQueue.isEmpty())
3590 {
3591 bool tempFinalIgnoreSetsState = ignoreSetQueue.last();
3592 ignoreSetQueue.clear();
3593 if (tempFinalState || currentRelease)
3594 {
3595 ignoreSetQueue.enqueue(tempFinalIgnoreSetsState);
3596 }
3597 }
3598 }
3599
3600 if (!currentRelease)
3601 {
3602 lastAccelerationDistance = 0.0;
3603 currentAccelMulti = 0.0;
3604 currentAccelerationDistance = 0.0;
3605 startingAccelerationDistance = 0.0;
3606 oldAccelMulti = updateOldAccelMulti = 0.0;
3607 accelTravel = 0.0;
3608 accelExtraDurationTime.restart();
3609
3610 lastMouseDistance = 0.0;
3611 currentMouseDistance = 0.0;
3612 updateStartingMouseDistance = true;
3613
3614 if (slotiter && !slotiter->hasNext())
3615 {
3616 // At the end of the list of assignments.
3617 currentCycle = 0;
3618 previousCycle = 0;
3619 slotiter->toFront();
3620 }
3621 else if (slotiter && slotiter->hasNext() && currentCycle)
3622 {
3623 // Cycle at the end of a segment.
3624 slotiter->toFront();
3625 slotiter->findNext(currentCycle);
3626 }
3627 else if (slotiter && slotiter->hasPrevious() && slotiter->hasNext() && !currentCycle)
3628 {
3629 // Check if there is a cycle action slot after
3630 // current slot. Useful after dealing with pause
3631 // actions.
3632 JoyButtonSlot *tempslot = 0;
3633 bool exit = false;
3634 while (slotiter->hasNext() && !exit)
3635 {
3636 tempslot = slotiter->next();
3637 if (tempslot->getSlotMode() == JoyButtonSlot::JoyCycle)
3638 {
3639 currentCycle = tempslot;
3640 exit = true;
3641 }
3642 }
3643
3644 // Didn't find any cycle. Move iterator
3645 // to the front.
3646 if (!currentCycle)
3647 {
3648 slotiter->toFront();
3649 previousCycle = 0;
3650 }
3651 }
3652
3653 if (currentCycle)
3654 {
3655 previousCycle = currentCycle;
3656 currentCycle = 0;
3657 }
3658 else if (slotiter && slotiter->hasNext() && containsReleaseSlots())
3659 {
3660 currentCycle = 0;
3661 previousCycle = 0;
3662 slotiter->toFront();
3663 }
3664
3665 this->currentDistance = 0;
3666 this->currentKeyPress = 0;
3667 quitEvent = true;
3668 }
3669
3670
3671 }
3672
3673 /**
3674 * @brief Get the distance that an element is away from its assigned
3675 * dead zone
3676 * @return Normalized distance away from dead zone
3677 */
getDistanceFromDeadZone()3678 double JoyButton::getDistanceFromDeadZone()
3679 {
3680 double distance = 0.0;
3681 if (isButtonPressed)
3682 {
3683 distance = 1.0;
3684 }
3685
3686 return distance;
3687 }
3688
getAccelerationDistance()3689 double JoyButton::getAccelerationDistance()
3690 {
3691 return this->getDistanceFromDeadZone();
3692 }
3693
3694 /**
3695 * @brief Get the distance factor that should be used for mouse movement
3696 * @return Distance factor that should be used for mouse movement
3697 */
getMouseDistanceFromDeadZone()3698 double JoyButton::getMouseDistanceFromDeadZone()
3699 {
3700 return this->getDistanceFromDeadZone();
3701 }
3702
getTotalSlotDistance(JoyButtonSlot * slot)3703 double JoyButton::getTotalSlotDistance(JoyButtonSlot *slot)
3704 {
3705 double tempDistance = 0.0;
3706
3707 QListIterator<JoyButtonSlot*> iter(assignments);
3708 while (iter.hasNext())
3709 {
3710 JoyButtonSlot *currentSlot = iter.next();
3711 int tempcode = currentSlot->getSlotCode();
3712 JoyButtonSlot::JoySlotInputAction mode = currentSlot->getSlotMode();
3713 if (mode == JoyButtonSlot::JoyDistance)
3714 {
3715 tempDistance += tempcode / 100.0;
3716 if (slot == currentSlot)
3717 {
3718 // Current slot found. Go to end of iterator
3719 // so loop will exit
3720 iter.toBack();
3721 }
3722 }
3723 // Reset tempDistance
3724 else if (mode == JoyButtonSlot::JoyCycle)
3725 {
3726 tempDistance = 0.0;
3727 }
3728 }
3729
3730 return tempDistance;
3731 }
3732
containsDistanceSlots()3733 bool JoyButton::containsDistanceSlots()
3734 {
3735 bool result = false;
3736 QListIterator<JoyButtonSlot*> iter(assignments);
3737 while (iter.hasNext())
3738 {
3739 JoyButtonSlot *slot = iter.next();
3740 if (slot->getSlotMode() == JoyButtonSlot::JoyDistance)
3741 {
3742 result = true;
3743 iter.toBack();
3744 }
3745 }
3746
3747 return result;
3748 }
3749
clearAssignedSlots(bool signalEmit)3750 void JoyButton::clearAssignedSlots(bool signalEmit)
3751 {
3752 QListIterator<JoyButtonSlot*> iter(assignments);
3753 while (iter.hasNext())
3754 {
3755 JoyButtonSlot *slot = iter.next();
3756 if (slot)
3757 {
3758 delete slot;
3759 slot = 0;
3760 }
3761 }
3762
3763 assignments.clear();
3764 if (signalEmit)
3765 {
3766 emit slotsChanged();
3767 }
3768 }
3769
removeAssignedSlot(int index)3770 void JoyButton::removeAssignedSlot(int index)
3771 {
3772 QWriteLocker tempAssignLocker(&assignmentsLock);
3773
3774 if (index >= 0 && index < assignments.size())
3775 {
3776 JoyButtonSlot *slot = assignments.takeAt(index);
3777 if (slot)
3778 {
3779 delete slot;
3780 slot = 0;
3781 }
3782
3783 tempAssignLocker.unlock();
3784
3785 buildActiveZoneSummaryString();
3786 emit slotsChanged();
3787 }
3788 }
3789
clearSlotsEventReset(bool clearSignalEmit)3790 void JoyButton::clearSlotsEventReset(bool clearSignalEmit)
3791 {
3792 QWriteLocker tempAssignLocker(&assignmentsLock);
3793
3794 turboTimer.stop();
3795 pauseWaitTimer.stop();
3796 createDeskTimer.stop();
3797 releaseDeskTimer.stop();
3798 holdTimer.stop();
3799 mouseWheelVerticalEventTimer.stop();
3800 mouseWheelHorizontalEventTimer.stop();
3801 setChangeTimer.stop();
3802 keyPressTimer.stop();
3803 delayTimer.stop();
3804 activeZoneTimer.stop();
3805 #ifdef Q_OS_WIN
3806 repeatHelper.getRepeatTimer()->stop();
3807 #endif
3808
3809 if (slotiter)
3810 {
3811 delete slotiter;
3812 slotiter = 0;
3813 }
3814
3815 releaseActiveSlots();
3816 clearAssignedSlots(clearSignalEmit);
3817
3818 isButtonPressedQueue.clear();
3819 ignoreSetQueue.clear();
3820 mouseEventQueue.clear();
3821 mouseWheelVerticalEventQueue.clear();
3822 mouseWheelHorizontalEventQueue.clear();
3823
3824 currentCycle = 0;
3825 previousCycle = 0;
3826 currentPause = 0;
3827 currentHold = 0;
3828 currentDistance = 0;
3829 currentRawValue = 0;
3830 currentMouseEvent = 0;
3831 currentRelease = 0;
3832 currentWheelVerticalEvent = 0;
3833 currentWheelHorizontalEvent = 0;
3834 currentKeyPress = 0;
3835 currentDelay = 0;
3836
3837 isKeyPressed = isButtonPressed = false;
3838
3839 //buildActiveZoneSummaryString();
3840 activeZoneTimer.start();
3841 quitEvent = true;
3842 }
3843
eventReset()3844 void JoyButton::eventReset()
3845 {
3846 QWriteLocker tempAssignLocker(&assignmentsLock);
3847
3848 turboTimer.stop();
3849 pauseWaitTimer.stop();
3850 createDeskTimer.stop();
3851 releaseDeskTimer.stop();
3852 holdTimer.stop();
3853 mouseWheelVerticalEventTimer.stop();
3854 mouseWheelHorizontalEventTimer.stop();
3855 setChangeTimer.stop();
3856 keyPressTimer.stop();
3857 delayTimer.stop();
3858 activeZoneTimer.stop();
3859 #ifdef Q_OS_WIN
3860 repeatHelper.getRepeatTimer()->stop();
3861 #endif
3862
3863 if (slotiter)
3864 {
3865 delete slotiter;
3866 slotiter = 0;
3867 }
3868
3869 isButtonPressedQueue.clear();
3870 ignoreSetQueue.clear();
3871 mouseEventQueue.clear();
3872 mouseWheelVerticalEventQueue.clear();
3873 mouseWheelHorizontalEventQueue.clear();
3874
3875 currentCycle = 0;
3876 previousCycle = 0;
3877 currentPause = 0;
3878 currentHold = 0;
3879 currentDistance = 0;
3880 currentRawValue = 0;
3881 currentMouseEvent = 0;
3882 currentRelease = 0;
3883 currentWheelVerticalEvent = 0;
3884 currentWheelHorizontalEvent = 0;
3885 currentKeyPress = 0;
3886 currentDelay = 0;
3887
3888 isKeyPressed = isButtonPressed = false;
3889
3890 releaseActiveSlots();
3891
3892 quitEvent = true;
3893 }
3894
releaseActiveSlots()3895 void JoyButton::releaseActiveSlots()
3896 {
3897 if (!activeSlots.isEmpty())
3898 {
3899 QWriteLocker tempLocker(&activeZoneLock);
3900
3901 bool changeRepeatState = false;
3902 QListIterator<JoyButtonSlot*> iter(activeSlots);
3903
3904 iter.toBack();
3905 while (iter.hasPrevious())
3906 {
3907 JoyButtonSlot *slot = iter.previous();
3908 int tempcode = slot->getSlotCode();
3909 JoyButtonSlot::JoySlotInputAction mode = slot->getSlotMode();
3910
3911 if (mode == JoyButtonSlot::JoyKeyboard)
3912 {
3913 int referencecount = activeKeys.value(tempcode, 1) - 1;
3914 if (referencecount <= 0)
3915 {
3916 sendevent(slot, false);
3917 activeKeys.remove(tempcode);
3918 changeRepeatState = true;
3919 }
3920 else
3921 {
3922 activeKeys.insert(tempcode, referencecount);
3923 }
3924
3925 if (lastActiveKey == slot && referencecount <= 0)
3926 {
3927 lastActiveKey = 0;
3928 }
3929 }
3930 else if (mode == JoyButtonSlot::JoyMouseButton)
3931 {
3932 if (tempcode != JoyButtonSlot::MouseWheelUp &&
3933 tempcode != JoyButtonSlot::MouseWheelDown &&
3934 tempcode != JoyButtonSlot::MouseWheelLeft &&
3935 tempcode != JoyButtonSlot::MouseWheelRight)
3936 {
3937 int referencecount = activeMouseButtons.value(tempcode, 1) - 1;
3938 if (referencecount <= 0)
3939 {
3940 sendevent(slot, false);
3941 activeMouseButtons.remove(tempcode);
3942 }
3943 else
3944 {
3945 activeMouseButtons.insert(tempcode, referencecount);
3946 }
3947 }
3948 else if (tempcode == JoyButtonSlot::MouseWheelUp ||
3949 tempcode == JoyButtonSlot::MouseWheelDown)
3950 {
3951 mouseWheelVerticalEventQueue.removeAll(slot);
3952 }
3953 else if (tempcode == JoyButtonSlot::MouseWheelLeft ||
3954 tempcode == JoyButtonSlot::MouseWheelRight)
3955 {
3956 mouseWheelHorizontalEventQueue.removeAll(slot);
3957 }
3958
3959 slot->setDistance(0.0);
3960 slot->getMouseInterval()->restart();
3961 }
3962 else if (mode == JoyButtonSlot::JoyMouseMovement)
3963 {
3964 JoyMouseMovementMode mousemode = getMouseMode();
3965 if (mousemode == MouseCursor)
3966 {
3967 QListIterator<mouseCursorInfo> iterX(cursorXSpeeds);
3968 unsigned int i = cursorXSpeeds.length();
3969
3970 QList<int> indexesToRemove;
3971 while (iterX.hasNext())
3972 {
3973 mouseCursorInfo info = iterX.next();
3974 if (info.slot == slot)
3975 {
3976 indexesToRemove.append(i);
3977 }
3978
3979 i++;
3980 }
3981
3982 QListIterator<int> removeXIter(indexesToRemove);
3983 while (removeXIter.hasPrevious())
3984 {
3985 int index = removeXIter.previous();
3986 cursorXSpeeds.removeAt(index);
3987 }
3988 indexesToRemove.clear();
3989
3990 i = cursorYSpeeds.length();
3991
3992 QListIterator<mouseCursorInfo> iterY(cursorYSpeeds);
3993 while (iterY.hasNext())
3994 {
3995 mouseCursorInfo info = iterY.next();
3996 if (info.slot == slot)
3997 {
3998 indexesToRemove.append(i);
3999 }
4000 i++;
4001 }
4002
4003 QListIterator<int> removeYIter(indexesToRemove);
4004 while (removeYIter.hasPrevious())
4005 {
4006 int index = removeYIter.previous();
4007 cursorYSpeeds.removeAt(index);
4008 }
4009 indexesToRemove.clear();
4010
4011 slot->getEasingTime()->restart();
4012 slot->setEasingStatus(false);
4013 }
4014 else if (mousemode == JoyButton::MouseSpring)
4015 {
4016 double mouse1 = (tempcode == JoyButtonSlot::MouseLeft ||
4017 tempcode == JoyButtonSlot::MouseRight) ? 0.0 : -2.0;
4018 double mouse2 = (tempcode == JoyButtonSlot::MouseUp ||
4019 tempcode == JoyButtonSlot::MouseDown) ? 0.0 : -2.0;
4020
4021 double springDeadCircleX = 0.0;
4022 if (getSpringDeadCircleMultiplier() > 0)
4023 {
4024 if (tempcode == JoyButtonSlot::MouseLeft)
4025 {
4026 double temp = getCurrentSpringDeadCircle();
4027 if (temp > getLastMouseDistanceFromDeadZone())
4028 {
4029 springDeadCircleX = -getLastMouseDistanceFromDeadZone();
4030 }
4031 else
4032 {
4033 springDeadCircleX = -temp;
4034 }
4035 }
4036 else if (tempcode == JoyButtonSlot::MouseRight)
4037 {
4038 double temp = getCurrentSpringDeadCircle();
4039 if (temp > getLastMouseDistanceFromDeadZone())
4040 {
4041 springDeadCircleX = getLastMouseDistanceFromDeadZone();
4042 }
4043 else
4044 {
4045 springDeadCircleX = temp;
4046 }
4047 }
4048 }
4049
4050 double springDeadCircleY = 0.0;
4051 if (getSpringDeadCircleMultiplier() > 0)
4052 {
4053 if (tempcode == JoyButtonSlot::MouseUp)
4054 {
4055 double temp = getCurrentSpringDeadCircle();
4056 if (temp > getLastMouseDistanceFromDeadZone())
4057 {
4058 springDeadCircleY = -getLastMouseDistanceFromDeadZone();
4059 }
4060 else
4061 {
4062 springDeadCircleY = -temp;
4063 }
4064 }
4065 else if (tempcode == JoyButtonSlot::MouseDown)
4066 {
4067 double temp = getCurrentSpringDeadCircle();
4068 if (temp > getLastMouseDistanceFromDeadZone())
4069 {
4070 springDeadCircleY = getLastMouseDistanceFromDeadZone();
4071 }
4072 else
4073 {
4074 springDeadCircleY = temp;
4075 }
4076 }
4077 }
4078
4079 PadderCommon::springModeInfo infoX;
4080 infoX.displacementX = mouse1;
4081 infoX.displacementY = -2.0;
4082 infoX.springDeadX = springDeadCircleX;
4083 infoX.springDeadY = springDeadCircleY;
4084 infoX.width = springWidth;
4085 infoX.height = springHeight;
4086 infoX.relative = relativeSpring;
4087 infoX.screen = springModeScreen;
4088 springXSpeeds.append(infoX);
4089
4090 PadderCommon::springModeInfo infoY;
4091 infoY.displacementX = -2.0;
4092 infoY.displacementY = mouse2;
4093 infoY.springDeadX = springDeadCircleX;
4094 infoY.springDeadY = springDeadCircleY;
4095 infoY.width = springWidth;
4096 infoY.height = springHeight;
4097 infoY.relative = relativeSpring;
4098 infoY.screen = springModeScreen;
4099 springYSpeeds.append(infoY);
4100 }
4101
4102 mouseEventQueue.removeAll(slot);
4103 slot->setDistance(0.0);
4104 slot->getMouseInterval()->restart();
4105 }
4106 else if (mode == JoyButtonSlot::JoyMouseSpeedMod)
4107 {
4108 int queueLength = mouseSpeedModList.length();
4109 if (!mouseSpeedModList.isEmpty())
4110 {
4111 mouseSpeedModList.removeAll(slot);
4112 queueLength -= 1;
4113 }
4114
4115 if (queueLength <= 0)
4116 {
4117 mouseSpeedModifier = DEFAULTMOUSESPEEDMOD;
4118 }
4119 }
4120 else if (mode == JoyButtonSlot::JoySetChange)
4121 {
4122 currentSetChangeSlot = slot;
4123 slotSetChangeTimer.start();
4124 }
4125 }
4126
4127 activeSlots.clear();
4128
4129 currentMouseEvent = 0;
4130 if (!mouseEventQueue.isEmpty())
4131 {
4132 mouseEventQueue.clear();
4133 }
4134
4135 pendingMouseButtons.removeAll(this);
4136 currentWheelVerticalEvent = 0;
4137 currentWheelHorizontalEvent = 0;
4138 mouseWheelVerticalEventTimer.stop();
4139 mouseWheelHorizontalEventTimer.stop();
4140
4141 if (!mouseWheelVerticalEventQueue.isEmpty())
4142 {
4143 mouseWheelVerticalEventQueue.clear();
4144 lastWheelVerticalDistance = getMouseDistanceFromDeadZone();
4145 wheelVerticalTime.restart();
4146 }
4147
4148 if (!mouseWheelHorizontalEventQueue.isEmpty())
4149 {
4150 mouseWheelHorizontalEventQueue.clear();
4151 lastWheelHorizontalDistance = getMouseDistanceFromDeadZone();
4152 wheelHorizontalTime.restart();
4153 }
4154
4155 // Check if mouse remainder should be zero.
4156 // Only need to check one list from cursor speeds and spring speeds
4157 // since the correspond Y lists will be the same size.
4158 if (pendingMouseButtons.length() == 0 && cursorXSpeeds.length() == 0 &&
4159 springXSpeeds.length() == 0)
4160 {
4161 //staticMouseEventTimer.setInterval(IDLEMOUSEREFRESHRATE);
4162 cursorRemainderX = 0;
4163 cursorRemainderY = 0;
4164 }
4165
4166 //emit activeZoneChanged();
4167 activeZoneTimer.start();
4168
4169 #ifdef Q_OS_WIN
4170 BaseEventHandler *handler = EventHandlerFactory::getInstance()->handler();
4171
4172 if (handler && handler->getIdentifier() == "sendinput" &&
4173 changeRepeatState && lastActiveKey && !useTurbo)
4174 {
4175 InputDevice *device = getParentSet()->getInputDevice();
4176 if (device->isKeyRepeatEnabled())
4177 {
4178 if (lastActiveKey)
4179 {
4180 repeatHelper.setLastActiveKey(lastActiveKey);
4181 repeatHelper.setKeyRepeatRate(device->getKeyRepeatRate());
4182 repeatHelper.getRepeatTimer()->start(device->getKeyRepeatDelay());
4183 }
4184 else if (repeatHelper.getRepeatTimer()->isActive())
4185 {
4186 repeatHelper.setLastActiveKey(0);
4187 repeatHelper.getRepeatTimer()->stop();
4188 }
4189 }
4190 }
4191
4192 #endif
4193 }
4194 }
4195
containsReleaseSlots()4196 bool JoyButton::containsReleaseSlots()
4197 {
4198 bool result = false;
4199 QListIterator<JoyButtonSlot*> iter(assignments);
4200 while (iter.hasNext())
4201 {
4202 JoyButtonSlot *slot = iter.next();
4203 if (slot->getSlotMode() == JoyButtonSlot::JoyRelease)
4204 {
4205 result = true;
4206 iter.toBack();
4207 }
4208 }
4209
4210 return result;
4211 }
4212
releaseSlotEvent()4213 void JoyButton::releaseSlotEvent()
4214 {
4215 JoyButtonSlot *temp = 0;
4216
4217 int timeElapsed = buttonHeldRelease.elapsed();
4218 int tempElapsed = 0;
4219
4220 if (containsReleaseSlots())
4221 {
4222 QListIterator<JoyButtonSlot*> iter(assignments);
4223 if (previousCycle)
4224 {
4225 iter.findNext(previousCycle);
4226 }
4227
4228 while (iter.hasNext())
4229 {
4230 JoyButtonSlot *currentSlot = iter.next();
4231 int tempcode = currentSlot->getSlotCode();
4232 JoyButtonSlot::JoySlotInputAction mode = currentSlot->getSlotMode();
4233 if (mode == JoyButtonSlot::JoyRelease)
4234 {
4235 tempElapsed += tempcode;
4236 if (tempElapsed <= timeElapsed)
4237 {
4238 temp = currentSlot;
4239 }
4240 else if (tempElapsed > timeElapsed)
4241 {
4242 iter.toBack();
4243 }
4244 }
4245 else if (mode == JoyButtonSlot::JoyCycle)
4246 {
4247 tempElapsed = 0;
4248 iter.toBack();
4249 }
4250 }
4251
4252 if (temp && slotiter)
4253 {
4254 slotiter->toFront();
4255 slotiter->findNext(temp);
4256 currentRelease = temp;
4257
4258 activateSlots();
4259 if (!keyPressTimer.isActive() && !pauseWaitTimer.isActive())
4260 {
4261 releaseActiveSlots();
4262 currentRelease = 0;
4263 }
4264
4265 // Stop hold timer here to be sure that
4266 // a hold timer that could be activated
4267 // during a release event is stopped.
4268 holdTimer.stop();
4269 if (currentHold)
4270 {
4271 currentHold = 0;
4272 }
4273 }
4274 }
4275 }
4276
4277
4278
findReleaseEventEnd()4279 void JoyButton::findReleaseEventEnd()
4280 {
4281 bool found = false;
4282 while (!found && slotiter->hasNext())
4283 {
4284 JoyButtonSlot *currentSlot = slotiter->next();
4285 JoyButtonSlot::JoySlotInputAction mode = currentSlot->getSlotMode();
4286
4287 if (mode == JoyButtonSlot::JoyRelease)
4288 {
4289 found = true;
4290 }
4291 else if (mode == JoyButtonSlot::JoyCycle)
4292 {
4293 found = true;
4294 }
4295 else if (mode == JoyButtonSlot::JoyHold)
4296 {
4297 found = true;
4298 }
4299 }
4300
4301 if (found && slotiter->hasPrevious())
4302 {
4303 slotiter->previous();
4304 }
4305 }
4306
findReleaseEventIterEnd(QListIterator<JoyButtonSlot * > * tempiter)4307 void JoyButton::findReleaseEventIterEnd(QListIterator<JoyButtonSlot*> *tempiter)
4308 {
4309 bool found = false;
4310 if (tempiter)
4311 {
4312 while (!found && tempiter->hasNext())
4313 {
4314 JoyButtonSlot *currentSlot = tempiter->next();
4315 JoyButtonSlot::JoySlotInputAction mode = currentSlot->getSlotMode();
4316
4317 if (mode == JoyButtonSlot::JoyRelease)
4318 {
4319 found = true;
4320 }
4321 else if (mode == JoyButtonSlot::JoyCycle)
4322 {
4323 found = true;
4324 }
4325 else if (mode == JoyButtonSlot::JoyHold)
4326 {
4327 found = true;
4328 }
4329 }
4330
4331 if (found && tempiter->hasPrevious())
4332 {
4333 tempiter->previous();
4334 }
4335 }
4336 }
4337
findHoldEventEnd()4338 void JoyButton::findHoldEventEnd()
4339 {
4340 bool found = false;
4341
4342 while (!found && slotiter->hasNext())
4343 {
4344 JoyButtonSlot *currentSlot = slotiter->next();
4345 JoyButtonSlot::JoySlotInputAction mode = currentSlot->getSlotMode();
4346
4347 if (mode == JoyButtonSlot::JoyRelease)
4348 {
4349 found = true;
4350 }
4351 else if (mode == JoyButtonSlot::JoyCycle)
4352 {
4353 found = true;
4354 }
4355 else if (mode == JoyButtonSlot::JoyHold)
4356 {
4357 found = true;
4358 }
4359 }
4360
4361 if (found && slotiter->hasPrevious())
4362 {
4363 slotiter->previous();
4364 }
4365 }
4366
setVDPad(VDPad * vdpad)4367 void JoyButton::setVDPad(VDPad *vdpad)
4368 {
4369 joyEvent(false, true);
4370 this->vdpad = vdpad;
4371 emit propertyUpdated();
4372 }
4373
isPartVDPad()4374 bool JoyButton::isPartVDPad()
4375 {
4376 return (this->vdpad != 0);
4377 }
4378
getVDPad()4379 VDPad* JoyButton::getVDPad()
4380 {
4381 return this->vdpad;
4382 }
4383
removeVDPad()4384 void JoyButton::removeVDPad()
4385 {
4386 this->vdpad = 0;
4387 emit propertyUpdated();
4388 }
4389
4390 /**
4391 * @brief Check if button properties are at their default values
4392 * @return Status of possible property edits
4393 */
isDefault()4394 bool JoyButton::isDefault()
4395 {
4396 bool value = true;
4397 value = value && (toggle == DEFAULTTOGGLE);
4398 value = value && (turboInterval == DEFAULTTURBOINTERVAL);
4399 value = value && (currentTurboMode == NormalTurbo);
4400 value = value && (useTurbo == DEFAULTUSETURBO);
4401 value = value && (mouseSpeedX == DEFAULTMOUSESPEEDX);
4402 value = value && (mouseSpeedY == DEFAULTMOUSESPEEDY);
4403 value = value && (setSelection == DEFAULTSETSELECTION);
4404 value = value && (setSelectionCondition == DEFAULTSETCONDITION);
4405 value = value && (assignments.isEmpty());
4406 value = value && (mouseMode == DEFAULTMOUSEMODE);
4407 value = value && (mouseCurve == DEFAULTMOUSECURVE);
4408 value = value && (springWidth == DEFAULTSPRINGWIDTH);
4409 value = value && (springHeight == DEFAULTSPRINGHEIGHT);
4410 value = value && (sensitivity == DEFAULTSENSITIVITY);
4411 value = value && (actionName.isEmpty());
4412 //value = value && (buttonName.isEmpty());
4413 value = value && (wheelSpeedX == DEFAULTWHEELX);
4414 value = value && (wheelSpeedY == DEFAULTWHEELY);
4415 value = value && (cycleResetActive == DEFAULTCYCLERESETACTIVE);
4416 value = value && (cycleResetInterval == DEFAULTCYCLERESET);
4417 value = value && (relativeSpring == DEFAULTRELATIVESPRING);
4418 value = value && (easingDuration == DEFAULTEASINGDURATION);
4419
4420 value = value && (extraAccelerationEnabled == false);
4421 value = value && (extraAccelerationMultiplier == DEFAULTEXTRACCELVALUE);
4422 value = value && (minMouseDistanceAccelThreshold == DEFAULTMINACCELTHRESHOLD);
4423 value = value && (maxMouseDistanceAccelThreshold == DEFAULTMAXACCELTHRESHOLD);
4424 value = value && (startAccelMultiplier == DEFAULTSTARTACCELMULTIPLIER);
4425 value = value && (accelDuration == DEFAULTACCELEASINGDURATION);
4426 value = value && (springDeadCircleMultiplier == DEFAULTSPRINGRELEASERADIUS);
4427 value = value && (extraAccelCurve == DEFAULTEXTRAACCELCURVE);
4428 return value;
4429 }
4430
setIgnoreEventState(bool ignore)4431 void JoyButton::setIgnoreEventState(bool ignore)
4432 {
4433 ignoreEvents = ignore;
4434 }
4435
getIgnoreEventState()4436 bool JoyButton::getIgnoreEventState()
4437 {
4438 return ignoreEvents;
4439 }
4440
setMouseMode(JoyMouseMovementMode mousemode)4441 void JoyButton::setMouseMode(JoyMouseMovementMode mousemode)
4442 {
4443 this->mouseMode = mousemode;
4444 emit propertyUpdated();
4445 }
4446
getMouseMode()4447 JoyButton::JoyMouseMovementMode JoyButton::getMouseMode()
4448 {
4449 return mouseMode;
4450 }
4451
setMouseCurve(JoyMouseCurve selectedCurve)4452 void JoyButton::setMouseCurve(JoyMouseCurve selectedCurve)
4453 {
4454 mouseCurve = selectedCurve;
4455 emit propertyUpdated();
4456 }
4457
getMouseCurve()4458 JoyButton::JoyMouseCurve JoyButton::getMouseCurve()
4459 {
4460 return mouseCurve;
4461 }
4462
setSpringWidth(int value)4463 void JoyButton::setSpringWidth(int value)
4464 {
4465 if (value >= 0)
4466 {
4467 springWidth = value;
4468 emit propertyUpdated();
4469 }
4470 }
4471
getSpringWidth()4472 int JoyButton::getSpringWidth()
4473 {
4474 return springWidth;
4475 }
4476
setSpringHeight(int value)4477 void JoyButton::setSpringHeight(int value)
4478 {
4479 if (springHeight >= 0)
4480 {
4481 springHeight = value;
4482 emit propertyUpdated();
4483 }
4484 }
4485
getSpringHeight()4486 int JoyButton::getSpringHeight()
4487 {
4488 return springHeight;
4489 }
4490
setSensitivity(double value)4491 void JoyButton::setSensitivity(double value)
4492 {
4493 if (value >= 0.001 && value <= 1000)
4494 {
4495 sensitivity = value;
4496 emit propertyUpdated();
4497 }
4498 }
4499
getSensitivity()4500 double JoyButton::getSensitivity()
4501 {
4502 return sensitivity;
4503 }
4504
getWhileHeldStatus()4505 bool JoyButton::getWhileHeldStatus()
4506 {
4507 return whileHeldStatus;
4508 }
4509
setWhileHeldStatus(bool status)4510 void JoyButton::setWhileHeldStatus(bool status)
4511 {
4512 whileHeldStatus = status;
4513 }
4514
setActionName(QString tempName)4515 void JoyButton::setActionName(QString tempName)
4516 {
4517 if (tempName.length() <= 50 && tempName != actionName)
4518 {
4519 actionName = tempName;
4520 emit actionNameChanged();
4521 emit propertyUpdated();
4522 }
4523 }
4524
getActionName()4525 QString JoyButton::getActionName()
4526 {
4527 return actionName;
4528 }
4529
setButtonName(QString tempName)4530 void JoyButton::setButtonName(QString tempName)
4531 {
4532 if (tempName.length() <= 20 && tempName != buttonName)
4533 {
4534 buttonName = tempName;
4535 emit buttonNameChanged();
4536 emit propertyUpdated();
4537 }
4538 }
4539
getButtonName()4540 QString JoyButton::getButtonName()
4541 {
4542 return buttonName;
4543 }
4544
setWheelSpeedX(int speed)4545 void JoyButton::setWheelSpeedX(int speed)
4546 {
4547 if (speed >= 1 && speed <= 100)
4548 {
4549 wheelSpeedX = speed;
4550 emit propertyUpdated();
4551 }
4552 }
4553
setWheelSpeedY(int speed)4554 void JoyButton::setWheelSpeedY(int speed)
4555 {
4556 if (speed >= 1 && speed <= 100)
4557 {
4558 wheelSpeedY = speed;
4559 emit propertyUpdated();
4560 }
4561 }
4562
getWheelSpeedX()4563 int JoyButton::getWheelSpeedX()
4564 {
4565 return wheelSpeedX;
4566 }
4567
getWheelSpeedY()4568 int JoyButton::getWheelSpeedY()
4569 {
4570 return wheelSpeedY;
4571 }
4572
setDefaultButtonName(QString tempname)4573 void JoyButton::setDefaultButtonName(QString tempname)
4574 {
4575 defaultButtonName = tempname;
4576 }
4577
getDefaultButtonName()4578 QString JoyButton::getDefaultButtonName()
4579 {
4580 return defaultButtonName;
4581 }
4582
4583 /**
4584 * @brief Take cursor mouse information provided by all buttons and
4585 * send a cursor mode mouse event to the display server.
4586 */
moveMouseCursor(int & movedX,int & movedY,int & movedElapsed)4587 void JoyButton::moveMouseCursor(int &movedX, int &movedY, int &movedElapsed)
4588 {
4589 movedX = 0;
4590 movedY = 0;
4591 double finalx = 0.0;
4592 double finaly = 0.0;
4593 //int elapsedTime = lastMouseTime.elapsed();
4594 int elapsedTime = testOldMouseTime.elapsed();
4595 movedElapsed = elapsedTime;
4596 if (staticMouseEventTimer.interval() < mouseRefreshRate)
4597 {
4598 elapsedTime = mouseRefreshRate + (elapsedTime - staticMouseEventTimer.interval());
4599 movedElapsed = elapsedTime;
4600 }
4601
4602 if (mouseHistoryX.size() >= mouseHistorySize)
4603 {
4604 mouseHistoryX.removeLast();
4605 }
4606
4607 if (mouseHistoryY.size() >= mouseHistorySize)
4608 {
4609 mouseHistoryY.removeLast();
4610 }
4611
4612 /*
4613 * Combine all mouse events to find the distance to move the mouse
4614 * along the X and Y axis. If necessary, perform mouse smoothing.
4615 * The mouse smoothing technique used is an interpretation of the method
4616 * outlined at http://flipcode.net/archives/Smooth_Mouse_Filtering.shtml.
4617 */
4618 if (cursorXSpeeds.length() == cursorYSpeeds.length() &&
4619 cursorXSpeeds.length() > 0)
4620 {
4621 int queueLength = cursorXSpeeds.length();
4622 for (int i=0; i < queueLength; i++)
4623 {
4624 mouseCursorInfo infoX = cursorXSpeeds.takeFirst();
4625 mouseCursorInfo infoY = cursorYSpeeds.takeFirst();
4626 if (infoX.code != 0)
4627 {
4628 finalx = (infoX.code < 0) ? qMin(infoX.code, finalx) :
4629 qMax(infoX.code, finalx);
4630 }
4631
4632 if (infoY.code != 0)
4633 {
4634 finaly = (infoY.code < 0) ? qMin(infoY.code, finaly) :
4635 qMax(infoY.code, finaly);
4636 }
4637
4638 infoX.slot->getMouseInterval()->restart();
4639 infoY.slot->getMouseInterval()->restart();
4640 }
4641
4642 // Only apply remainder if both current displacement and remainder
4643 // follow the same direction.
4644 if ((cursorRemainderX >= 0) == (finalx >= 0))
4645 {
4646 finalx += cursorRemainderX;
4647 }
4648
4649 // Cap maximum relative mouse movement.
4650 if (abs(finalx) > 127)
4651 {
4652 finalx = (finalx < 0) ? -127 : 127;
4653 }
4654
4655 mouseHistoryX.prepend(finalx);
4656
4657 // Only apply remainder if both current displacement and remainder
4658 // follow the same direction.
4659 if ((cursorRemainderY >= 0) == (finaly >= 0))
4660 {
4661 finaly += cursorRemainderY;
4662 }
4663
4664 // Cap maximum relative mouse movement.
4665 if (abs(finaly) > 127)
4666 {
4667 finaly = (finaly < 0) ? -127 : 127;
4668 }
4669
4670 mouseHistoryY.prepend(finaly);
4671
4672 cursorRemainderX = 0;
4673 cursorRemainderY = 0;
4674
4675 double adjustedX = 0;
4676 double adjustedY = 0;
4677
4678 QListIterator<double> iterX(mouseHistoryX);
4679 double currentWeight = 1.0;
4680 double weightModifier = JoyButton::weightModifier;
4681 double finalWeight = 0.0;
4682
4683 while (iterX.hasNext())
4684 {
4685 double temp = iterX.next();
4686 adjustedX += temp * currentWeight;
4687 finalWeight += currentWeight;
4688 currentWeight *= weightModifier;
4689 }
4690
4691 if (fabs(adjustedX) > 0)
4692 {
4693 adjustedX = adjustedX / static_cast<double>(finalWeight);
4694
4695 if (adjustedX > 0)
4696 {
4697 double oldX = adjustedX;
4698 adjustedX = static_cast<int>(floor(adjustedX));
4699 //adjustedX = (int)floor(adjustedX + 0.5); // Old rounding behavior
4700 cursorRemainderX = oldX - adjustedX;
4701 }
4702 else
4703 {
4704 double oldX = adjustedX;
4705 adjustedX = static_cast<int>(ceil(adjustedX));
4706 //adjustedX = (int)ceil(adjustedX - 0.5); // Old rounding behavior
4707 cursorRemainderX = oldX - adjustedX;
4708 }
4709
4710 }
4711
4712 QListIterator<double> iterY(mouseHistoryY);
4713 currentWeight = 1.0;
4714 finalWeight = 0.0;
4715
4716 while (iterY.hasNext())
4717 {
4718 double temp = iterY.next();
4719 adjustedY += temp * currentWeight;
4720 finalWeight += currentWeight;
4721 currentWeight *= weightModifier;
4722 }
4723
4724 if (fabs(adjustedY) > 0)
4725 {
4726 adjustedY = adjustedY / static_cast<double>(finalWeight);
4727 if (adjustedY > 0)
4728 {
4729 double oldY = adjustedY;
4730 adjustedY = static_cast<int>(floor(adjustedY));
4731 //adjustedY = (int)floor(adjustedY + 0.5); // Old rounding behavior
4732 cursorRemainderY = oldY - adjustedY;
4733 }
4734 else
4735 {
4736 double oldY = adjustedY;
4737 adjustedY = static_cast<int>(ceil(adjustedY));
4738 //adjustedY = (int)ceil(adjustedY - 0.5); // Old rounding behavior
4739 cursorRemainderY = oldY - adjustedY;
4740 }
4741 }
4742
4743 // This check is more of a precaution than anything. No need to cause
4744 // a sync to happen when not needed.
4745 if (adjustedX != 0 || adjustedY != 0)
4746 {
4747 sendevent(adjustedX, adjustedY);
4748 }
4749
4750 //Logger::LogInfo(QString("FINAL X: %1").arg(adjustedX));
4751 //Logger::LogInfo(QString("FINAL Y: %1\n").arg(adjustedY));
4752 //Logger::LogInfo(QString("ELAPSED: %1\n").arg(elapsedTime));
4753 //Logger::LogInfo(QString("REMAINDER X: %1").arg(cursorRemainderX));
4754
4755 movedX = static_cast<int>(adjustedX);
4756 movedY = static_cast<int>(adjustedY);
4757 }
4758 else
4759 {
4760 mouseHistoryX.prepend(0);
4761 mouseHistoryY.prepend(0);
4762 }
4763
4764 //lastMouseTime.restart();
4765
4766 // Check if mouse event timer should use idle time.
4767 if (pendingMouseButtons.length() == 0)
4768 {
4769 if (staticMouseEventTimer.interval() != IDLEMOUSEREFRESHRATE)
4770 {
4771 staticMouseEventTimer.start(IDLEMOUSEREFRESHRATE);
4772
4773 // Clear current mouse history
4774 mouseHistoryX.clear();
4775 mouseHistoryY.clear();
4776
4777 // Fill history with zeroes.
4778 for (int i=0; i < mouseHistorySize; i++)
4779 {
4780 mouseHistoryX.append(0);
4781 mouseHistoryY.append(0);
4782 }
4783 }
4784
4785 cursorRemainderX = 0;
4786 cursorRemainderY = 0;
4787 }
4788 else
4789 {
4790 if (staticMouseEventTimer.interval() != mouseRefreshRate)
4791 {
4792 // Restore intended QTimer interval.
4793 staticMouseEventTimer.start(mouseRefreshRate);
4794 }
4795 }
4796
4797
4798 cursorXSpeeds.clear();
4799 cursorYSpeeds.clear();
4800 }
4801
4802 /**
4803 * @brief Take spring mouse information provided by all buttons and
4804 * send a spring mode mouse event to the display server.
4805 */
moveSpringMouse(int & movedX,int & movedY,bool & hasMoved)4806 void JoyButton::moveSpringMouse(int &movedX, int &movedY, bool &hasMoved)
4807 {
4808 PadderCommon::springModeInfo fullSpring = {
4809 -2.0, -2.0, 0, 0, false, springModeScreen, 0.0, 0.0
4810 };
4811 PadderCommon::springModeInfo relativeSpring = {
4812 -2.0, -2.0, 0, 0, false, springModeScreen, 0.0, 0.0
4813 };
4814
4815 int realMouseX = movedX = 0;
4816 int realMouseY = movedY = 0;
4817 hasMoved = false;
4818
4819 if (springXSpeeds.length() == springYSpeeds.length() &&
4820 springXSpeeds.length() > 0)
4821 {
4822 int queueLength = springXSpeeds.length();
4823 bool complete = false;
4824 for (int i=queueLength-1; i >= 0 && !complete; i--)
4825 {
4826 double tempx = -2.0;
4827 double tempy = -2.0;
4828
4829 double tempSpringDeadX = 0.0;
4830 double tempSpringDeadY = 0.0;
4831
4832 PadderCommon::springModeInfo infoX;
4833 PadderCommon::springModeInfo infoY;
4834
4835 infoX = springXSpeeds.takeLast();
4836 infoY = springYSpeeds.takeLast();
4837
4838 tempx = infoX.displacementX;
4839 tempy = infoY.displacementY;
4840
4841 tempSpringDeadX = infoX.springDeadX;
4842 tempSpringDeadY = infoY.springDeadY;
4843
4844 if (infoX.relative)
4845 {
4846 if (relativeSpring.displacementX == -2.0)
4847 {
4848 relativeSpring.displacementX = tempx;
4849 }
4850 relativeSpring.relative = true;
4851
4852 // Use largest found width for spring
4853 // mode dimensions.
4854 relativeSpring.width = qMax(infoX.width, relativeSpring.width);
4855 }
4856 else
4857 {
4858 if (fullSpring.displacementX == -2.0)
4859 {
4860 fullSpring.displacementX = tempx;
4861 }
4862
4863 if (fullSpring.springDeadX == 0.0)
4864 {
4865 fullSpring.springDeadX = tempSpringDeadX;
4866 }
4867
4868 // Use largest found width for spring
4869 // mode dimensions.
4870 fullSpring.width = qMax(infoX.width, fullSpring.width);
4871 }
4872
4873 if (infoY.relative)
4874 {
4875 if (relativeSpring.displacementY == -2.0)
4876 {
4877 relativeSpring.displacementY = tempy;
4878 }
4879
4880 relativeSpring.relative = true;
4881
4882 // Use largest found height for spring
4883 // mode dimensions.
4884 relativeSpring.height = qMax(infoX.height, relativeSpring.height);
4885 }
4886 else
4887 {
4888 if (fullSpring.displacementY == -2.0)
4889 {
4890 fullSpring.displacementY = tempy;
4891 }
4892
4893 if (fullSpring.springDeadY == 0.0)
4894 {
4895 fullSpring.springDeadY = tempSpringDeadY;
4896 }
4897
4898 // Use largest found height for spring
4899 // mode dimensions.
4900 fullSpring.height = qMax(infoX.height, fullSpring.height);
4901 }
4902
4903 if ((relativeSpring.displacementX != -2.0 && relativeSpring.displacementY != -2.0) &&
4904 (fullSpring.displacementX != -2.0 && fullSpring.displacementY != -2.0))
4905 {
4906 complete = true;
4907 }
4908 else if ((relativeSpring.springDeadX != 0.0 && relativeSpring.springDeadY != 0.0) &&
4909 (fullSpring.springDeadX != 0.0 && fullSpring.springDeadY != 0.0))
4910 {
4911 complete = true;
4912 }
4913 }
4914
4915 fullSpring.screen = springModeScreen;
4916 relativeSpring.screen = springModeScreen;
4917
4918 if (relativeSpring.relative)
4919 {
4920 sendSpringEvent(&fullSpring, &relativeSpring, &realMouseX, &realMouseY);
4921 }
4922 else
4923 {
4924 if (!hasFutureSpringEvents())
4925 {
4926 if (fullSpring.springDeadX != 0.0)
4927 {
4928 fullSpring.displacementX = fullSpring.springDeadX;
4929 }
4930
4931 if (fullSpring.springDeadY != 0.0)
4932 {
4933 fullSpring.displacementY = fullSpring.springDeadY;
4934 }
4935
4936 sendSpringEvent(&fullSpring, 0, &realMouseX, &realMouseY);
4937 }
4938 else
4939 {
4940 sendSpringEvent(&fullSpring, 0, &realMouseX, &realMouseY);
4941 }
4942
4943 }
4944
4945 movedX = realMouseX;
4946 movedY = realMouseY;
4947 hasMoved = true;
4948 }
4949
4950 //lastMouseTime.restart();
4951
4952 // Check if mouse event timer should use idle time.
4953 if (pendingMouseButtons.length() == 0)
4954 {
4955 staticMouseEventTimer.start(IDLEMOUSEREFRESHRATE);
4956 }
4957 else
4958 {
4959 if (staticMouseEventTimer.interval() != mouseRefreshRate)
4960 {
4961 // Restore intended QTimer interval.
4962 staticMouseEventTimer.start(mouseRefreshRate);
4963 }
4964 }
4965
4966 springXSpeeds.clear();
4967 springYSpeeds.clear();
4968 }
4969
keyPressEvent()4970 void JoyButton::keyPressEvent()
4971 {
4972 //qDebug() << "RADIO EDIT: " << keyDelayHold.elapsed();
4973 if (keyPressTimer.isActive() && keyPressHold.elapsed() >= getPreferredKeyPressTime())
4974 {
4975 currentKeyPress = 0;
4976
4977 keyPressTimer.stop();
4978 keyPressHold.restart();
4979 releaseActiveSlots();
4980
4981 createDeskTimer.stop();
4982
4983 if (currentRelease)
4984 {
4985 releaseDeskTimer.stop();
4986
4987 createDeskEvent();
4988 waitForReleaseDeskEvent();
4989 }
4990 else
4991 {
4992 createDeskEvent();
4993 }
4994 }
4995 else
4996 {
4997 createDeskTimer.stop();
4998 //releaseDeskTimer.stop();
4999
5000 unsigned int preferredDelay = getPreferredKeyPressTime();
5001 int proposedInterval = preferredDelay - keyPressHold.elapsed();
5002 proposedInterval = proposedInterval > 0 ? proposedInterval : 0;
5003 int newTimerInterval = qMin(10, proposedInterval);
5004 keyPressTimer.start(newTimerInterval);
5005 // If release timer is active, push next run until
5006 // after keyDelayTimer will timeout again. Helps
5007 // reduce CPU usage of an excessively repeating timer.
5008 if (releaseDeskTimer.isActive())
5009 {
5010 releaseDeskTimer.start(proposedInterval);
5011 }
5012 }
5013 }
5014
5015 /**
5016 * @brief TODO: CHECK IF METHOD WOULD BE USEFUL. CURRENTLY NOT USED.
5017 * @return Result
5018 */
checkForDelaySequence()5019 bool JoyButton::checkForDelaySequence()
5020 {
5021 bool result = false;
5022
5023 QListIterator<JoyButtonSlot*> tempiter(assignments);
5024
5025 // Move iterator to start of cycle.
5026 if (previousCycle)
5027 {
5028 tempiter.findNext(previousCycle);
5029 }
5030
5031 while (tempiter.hasNext())
5032 {
5033 JoyButtonSlot *slot = tempiter.next();
5034 JoyButtonSlot::JoySlotInputAction mode = slot->getSlotMode();
5035 if (mode == JoyButtonSlot::JoyPause || mode == JoyButtonSlot::JoyRelease)
5036 {
5037 result = true;
5038 tempiter.toBack();
5039 }
5040 else if (mode == JoyButtonSlot::JoyCycle)
5041 {
5042 result = false;
5043 tempiter.toBack();
5044 }
5045 }
5046
5047 return result;
5048 }
5049
getParentSet()5050 SetJoystick* JoyButton::getParentSet()
5051 {
5052 return parentSet;
5053 }
5054
checkForPressedSetChange()5055 void JoyButton::checkForPressedSetChange()
5056 {
5057 if (!isButtonPressedQueue.isEmpty())
5058 {
5059 bool tempButtonPressed = isButtonPressedQueue.last();
5060 bool tempFinalIgnoreSetsState = ignoreSetQueue.last();
5061
5062 if (!whileHeldStatus)
5063 {
5064 if (tempButtonPressed && !tempFinalIgnoreSetsState &&
5065 setSelectionCondition == SetChangeWhileHeld && !currentRelease)
5066 {
5067 setChangeTimer.start(0);
5068 quitEvent = true;
5069 }
5070 }
5071 }
5072 }
5073
5074 /**
5075 * @brief Obtain the appropriate key press time for the current event.
5076 * Order of preference: active key press time slot value ->
5077 * profile value -> program default value.
5078 * @return Appropriate key press time for current event.
5079 */
getPreferredKeyPressTime()5080 unsigned int JoyButton::getPreferredKeyPressTime()
5081 {
5082 unsigned int tempPressTime = InputDevice::DEFAULTKEYPRESSTIME;
5083 if (currentKeyPress && currentKeyPress->getSlotCode() > 0)
5084 {
5085 tempPressTime = static_cast<unsigned int>(currentKeyPress->getSlotCode());
5086 }
5087 else if (parentSet->getInputDevice()->getDeviceKeyPressTime() > 0)
5088 {
5089 tempPressTime = parentSet->getInputDevice()->getDeviceKeyPressTime();
5090 }
5091
5092 return tempPressTime;
5093 }
5094
setCycleResetTime(unsigned int interval)5095 void JoyButton::setCycleResetTime(unsigned int interval)
5096 {
5097 if (interval >= MINCYCLERESETTIME)
5098 {
5099 unsigned int ceiling = MAXCYCLERESETTIME;
5100 unsigned int temp = qBound(MINCYCLERESETTIME, interval, ceiling);
5101 cycleResetInterval = temp;
5102 emit propertyUpdated();
5103 }
5104 else
5105 {
5106 interval = 0;
5107 cycleResetActive = false;
5108 emit propertyUpdated();
5109 }
5110 }
5111
getCycleResetTime()5112 unsigned int JoyButton::getCycleResetTime()
5113 {
5114 return cycleResetInterval;
5115 }
5116
setCycleResetStatus(bool enabled)5117 void JoyButton::setCycleResetStatus(bool enabled)
5118 {
5119 cycleResetActive = enabled;
5120 emit propertyUpdated();
5121 }
5122
isCycleResetActive()5123 bool JoyButton::isCycleResetActive()
5124 {
5125 return cycleResetActive;
5126 }
5127
establishPropertyUpdatedConnections()5128 void JoyButton::establishPropertyUpdatedConnections()
5129 {
5130 connect(this, SIGNAL(slotsChanged()), parentSet->getInputDevice(), SLOT(profileEdited()));
5131 connect(this, SIGNAL(propertyUpdated()), parentSet->getInputDevice(), SLOT(profileEdited()));
5132 }
5133
disconnectPropertyUpdatedConnections()5134 void JoyButton::disconnectPropertyUpdatedConnections()
5135 {
5136 disconnect(this, SIGNAL(slotsChanged()), 0, 0);
5137 disconnect(this, SIGNAL(propertyUpdated()), parentSet->getInputDevice(), SLOT(profileEdited()));
5138 }
5139
5140 /**
5141 * @brief Change initial settings used for mouse event timer being used by
5142 * the application.
5143 */
establishMouseTimerConnections()5144 void JoyButton::establishMouseTimerConnections()
5145 {
5146 #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
5147 if (staticMouseEventTimer.timerType() != Qt::PreciseTimer)
5148 {
5149 staticMouseEventTimer.setTimerType(Qt::PreciseTimer);
5150 }
5151 #endif
5152
5153 // Only one connection will be made for each.
5154 connect(&staticMouseEventTimer, SIGNAL(timeout()), &mouseHelper,
5155 SLOT(mouseEvent()), Qt::UniqueConnection);
5156
5157 if (staticMouseEventTimer.interval() != IDLEMOUSEREFRESHRATE)
5158 {
5159 staticMouseEventTimer.setInterval(IDLEMOUSEREFRESHRATE);
5160 }
5161
5162 /*if (!staticMouseEventTimer.isActive())
5163 {
5164 lastMouseTime.start();
5165 staticMouseEventTimer.start(IDLEMOUSEREFRESHRATE);
5166 }
5167 */
5168 }
5169
setSpringRelativeStatus(bool value)5170 void JoyButton::setSpringRelativeStatus(bool value)
5171 {
5172 if (value != relativeSpring)
5173 {
5174 if (value)
5175 {
5176 setSpringDeadCircleMultiplier(0);
5177 }
5178
5179 relativeSpring = value;
5180 emit propertyUpdated();
5181 }
5182 }
5183
isRelativeSpring()5184 bool JoyButton::isRelativeSpring()
5185 {
5186 return relativeSpring;
5187 }
5188
5189 /**
5190 * @brief Copy assignments and properties from one button to another.
5191 * Used for set copying.
5192 * @param Button instance that should be modified.
5193 */
copyAssignments(JoyButton * destButton)5194 void JoyButton::copyAssignments(JoyButton *destButton)
5195 {
5196 destButton->eventReset();
5197 destButton->assignmentsLock.lockForWrite();
5198 destButton->assignments.clear();
5199 destButton->assignmentsLock.unlock();
5200
5201 assignmentsLock.lockForWrite();
5202 QListIterator<JoyButtonSlot*> iter(assignments);
5203 while (iter.hasNext())
5204 {
5205 JoyButtonSlot *slot = iter.next();
5206 JoyButtonSlot *newslot = new JoyButtonSlot(slot, destButton);
5207 destButton->insertAssignedSlot(newslot, false);
5208 }
5209 assignmentsLock.unlock();
5210
5211 destButton->toggle = toggle;
5212 destButton->turboInterval = turboInterval;
5213 destButton->useTurbo = useTurbo;
5214 destButton->mouseSpeedX = mouseSpeedX;
5215 destButton->mouseSpeedY = mouseSpeedY;
5216 destButton->wheelSpeedX = wheelSpeedX;
5217 destButton->wheelSpeedY = wheelSpeedY;
5218 destButton->mouseMode = mouseMode;
5219 destButton->mouseCurve = mouseCurve;
5220 destButton->springWidth = springWidth;
5221 destButton->springHeight = springHeight;
5222 destButton->sensitivity = sensitivity;
5223 //destButton->setSelection = setSelection;
5224 //destButton->setSelectionCondition = setSelectionCondition;
5225 destButton->buttonName = buttonName;
5226 destButton->actionName = actionName;
5227 destButton->cycleResetActive = cycleResetActive;
5228 destButton->cycleResetInterval = cycleResetInterval;
5229 destButton->relativeSpring = relativeSpring;
5230 destButton->currentTurboMode = currentTurboMode;
5231 destButton->easingDuration = easingDuration;
5232 destButton->extraAccelerationEnabled = extraAccelerationEnabled;
5233 destButton->extraAccelerationMultiplier = extraAccelerationMultiplier;
5234 destButton->minMouseDistanceAccelThreshold = minMouseDistanceAccelThreshold;
5235 destButton->maxMouseDistanceAccelThreshold = maxMouseDistanceAccelThreshold;
5236 destButton->startAccelMultiplier = startAccelMultiplier;
5237 destButton->springDeadCircleMultiplier = springDeadCircleMultiplier;
5238 destButton->extraAccelCurve = extraAccelCurve;
5239
5240 destButton->buildActiveZoneSummaryString();
5241 if (!destButton->isDefault())
5242 {
5243 emit propertyUpdated();
5244 }
5245 }
5246
5247 /**
5248 * @brief Set the turbo mode that the button should use
5249 * @param Mode that should be used
5250 */
setTurboMode(TurboMode mode)5251 void JoyButton::setTurboMode(TurboMode mode)
5252 {
5253 currentTurboMode = mode;
5254 }
5255
5256 /**
5257 * @brief Get currently assigned turbo mode
5258 * @return Currently assigned turbo mode
5259 */
getTurboMode()5260 JoyButton::TurboMode JoyButton::getTurboMode()
5261 {
5262 return currentTurboMode;
5263 }
5264
5265 /**
5266 * @brief Check if button should be considered a part of a real controller
5267 * axis. Needed for some dialogs so the program won't have to resort to
5268 * type checking.
5269 * @return Status of being part of a real controller axis
5270 */
isPartRealAxis()5271 bool JoyButton::isPartRealAxis()
5272 {
5273 return false;
5274 }
5275
5276 /**
5277 * @brief Calculate maximum mouse speed when using a given mouse curve.
5278 * @param Mouse curve
5279 * @param Mouse speed value
5280 * @return Final mouse speed
5281 */
calculateFinalMouseSpeed(JoyMouseCurve curve,int value)5282 int JoyButton::calculateFinalMouseSpeed(JoyMouseCurve curve, int value)
5283 {
5284 int result = JoyAxis::JOYSPEED * value;
5285 switch (curve)
5286 {
5287 case QuadraticExtremeCurve:
5288 case EasingQuadraticCurve:
5289 case EasingCubicCurve:
5290 {
5291 result *= 1.5;
5292 break;
5293 }
5294 }
5295
5296 return result;
5297 }
5298
setEasingDuration(double value)5299 void JoyButton::setEasingDuration(double value)
5300 {
5301 if (value >= MINIMUMEASINGDURATION && value <= MAXIMUMEASINGDURATION &&
5302 value != easingDuration)
5303 {
5304 easingDuration = value;
5305 emit propertyUpdated();
5306 }
5307 }
5308
getEasingDuration()5309 double JoyButton::getEasingDuration()
5310 {
5311 return easingDuration;
5312 }
5313
getMouseHelper()5314 JoyButtonMouseHelper* JoyButton::getMouseHelper()
5315 {
5316 return &mouseHelper;
5317 }
5318
5319 /**
5320 * @brief Get the list of buttons that have a pending mouse movement event.
5321 * @return QList<JoyButton*>*
5322 */
getPendingMouseButtons()5323 QList<JoyButton*>* JoyButton::getPendingMouseButtons()
5324 {
5325 return &pendingMouseButtons;
5326 }
5327
hasCursorEvents()5328 bool JoyButton::hasCursorEvents()
5329 {
5330 return (cursorXSpeeds.length() != 0) || (cursorYSpeeds.length() != 0);
5331 }
5332
hasSpringEvents()5333 bool JoyButton::hasSpringEvents()
5334 {
5335 return (springXSpeeds.length() != 0) || (springYSpeeds.length() != 0);
5336 }
5337
5338 /**
5339 * @brief Get the weight modifier being used for mouse smoothing.
5340 * @return Weight modifier in the range of 0.0 - 1.0.
5341 */
getWeightModifier()5342 double JoyButton::getWeightModifier()
5343 {
5344 return weightModifier;
5345 }
5346
5347 /**
5348 * @brief Set the weight modifier to use for mouse smoothing.
5349 * @param Weight modifier in the range of 0.0 - 1.0.
5350 */
setWeightModifier(double modifier)5351 void JoyButton::setWeightModifier(double modifier)
5352 {
5353 if (modifier >= 0.0 && modifier <= MAXIMUMWEIGHTMODIFIER)
5354 {
5355 weightModifier = modifier;
5356 }
5357 }
5358
5359 /**
5360 * @brief Get mouse history buffer size.
5361 * @return Mouse history buffer size
5362 */
getMouseHistorySize()5363 int JoyButton::getMouseHistorySize()
5364 {
5365 return mouseHistorySize;
5366 }
5367
5368 /**
5369 * @brief Set mouse history buffer size used for mouse smoothing.
5370 * @param Mouse history buffer size
5371 */
setMouseHistorySize(int size)5372 void JoyButton::setMouseHistorySize(int size)
5373 {
5374 if (size >= 1 && size <= MAXIMUMMOUSEHISTORYSIZE)
5375 {
5376 mouseHistoryX.clear();
5377 mouseHistoryY.clear();
5378
5379 mouseHistorySize = size;
5380 }
5381 }
5382
5383 /**
5384 * @brief Get active mouse movement refresh rate.
5385 * @return
5386 */
getMouseRefreshRate()5387 int JoyButton::getMouseRefreshRate()
5388 {
5389 return mouseRefreshRate;
5390 }
5391
5392 /**
5393 * @brief Set the mouse refresh rate when a mouse slot is active.
5394 * @param Refresh rate in ms.
5395 */
setMouseRefreshRate(int refresh)5396 void JoyButton::setMouseRefreshRate(int refresh)
5397 {
5398 if (refresh >= 1 && refresh <= 16)
5399 {
5400 mouseRefreshRate = refresh;
5401 int temp = IDLEMOUSEREFRESHRATE;
5402 //IDLEMOUSEREFRESHRATE = mouseRefreshRate * 20;
5403
5404 if (staticMouseEventTimer.isActive())
5405 {
5406 testOldMouseTime.restart();
5407 //lastMouseTime.restart();
5408 int tempInterval = staticMouseEventTimer.interval();
5409
5410 if (tempInterval != temp &&
5411 tempInterval != 0)
5412 {
5413 QMetaObject::invokeMethod(&staticMouseEventTimer, "start",
5414 Q_ARG(int, mouseRefreshRate));
5415 }
5416 else
5417 {
5418 // Restart QTimer to keep QTimer in line with QTime
5419 QMetaObject::invokeMethod(&staticMouseEventTimer, "start",
5420 Q_ARG(int, temp));
5421 }
5422
5423 // Clear current mouse history
5424 mouseHistoryX.clear();
5425 mouseHistoryY.clear();
5426 }
5427 else
5428 {
5429 staticMouseEventTimer.setInterval(IDLEMOUSEREFRESHRATE);
5430 }
5431
5432 mouseHelper.carryMouseRefreshRateUpdate(mouseRefreshRate);
5433 }
5434 }
5435
5436 /**
5437 * @brief Get the gamepad poll rate used by the application.
5438 * @return Poll rate in ms.
5439 */
getGamepadRefreshRate()5440 int JoyButton::getGamepadRefreshRate()
5441 {
5442 return gamepadRefreshRate;
5443 }
5444
5445 /**
5446 * @brief Set the gamepad poll rate to be used in the application.
5447 * @param Poll rate in ms.
5448 */
setGamepadRefreshRate(int refresh)5449 void JoyButton::setGamepadRefreshRate(int refresh)
5450 {
5451 if (refresh >= 1 && refresh <= 16)
5452 {
5453 gamepadRefreshRate = refresh;
5454 mouseHelper.carryGamePollRateUpdate(gamepadRefreshRate);
5455 }
5456 }
5457
5458 /**
5459 * @brief Check if turbo should be disabled for a slot
5460 * @param JoyButtonSlot to check
5461 */
checkTurboCondition(JoyButtonSlot * slot)5462 void JoyButton::checkTurboCondition(JoyButtonSlot *slot)
5463 {
5464 JoyButtonSlot::JoySlotInputAction mode = slot->getSlotMode();
5465 switch (mode)
5466 {
5467 case JoyButtonSlot::JoyPause:
5468 case JoyButtonSlot::JoyHold:
5469 case JoyButtonSlot::JoyDistance:
5470 case JoyButtonSlot::JoyRelease:
5471 case JoyButtonSlot::JoyLoadProfile:
5472 case JoyButtonSlot::JoySetChange:
5473 {
5474 setUseTurbo(false);
5475 break;
5476 }
5477 }
5478 }
5479
resetProperties()5480 void JoyButton::resetProperties()
5481 {
5482 currentCycle = 0;
5483 previousCycle = 0;
5484 currentPause = 0;
5485 currentHold = 0;
5486 currentDistance = 0;
5487 currentRawValue = 0;
5488 currentMouseEvent = 0;
5489 currentRelease = 0;
5490 currentWheelVerticalEvent = 0;
5491 currentWheelHorizontalEvent = 0;
5492 currentKeyPress = 0;
5493 currentDelay = 0;
5494 currentSetChangeSlot = 0;
5495
5496 isKeyPressed = isButtonPressed = false;
5497 quitEvent = true;
5498
5499 toggle = false;
5500 turboInterval = 0;
5501 isDown = false;
5502 toggleActiveState = false;
5503 useTurbo = false;
5504 mouseSpeedX = 50;
5505 mouseSpeedY = 50;
5506 wheelSpeedX = 20;
5507 wheelSpeedY = 20;
5508 mouseMode = MouseCursor;
5509 mouseCurve = DEFAULTMOUSECURVE;
5510 springWidth = 0;
5511 springHeight = 0;
5512 sensitivity = 1.0;
5513 setSelection = -1;
5514 setSelectionCondition = SetChangeDisabled;
5515 ignoresets = false;
5516 ignoreEvents = false;
5517 whileHeldStatus = false;
5518 buttonName.clear();
5519 actionName.clear();
5520 cycleResetActive = false;
5521 cycleResetInterval = 0;
5522 relativeSpring = false;
5523 lastDistance = 0.0;
5524 currentAccelMulti = 0.0;
5525 lastAccelerationDistance = 0.0;
5526 lastMouseDistance = 0.0;
5527 currentMouseDistance = 0.0;
5528 updateLastMouseDistance = false;
5529 updateStartingMouseDistance = false;
5530 updateOldAccelMulti = 0.0;
5531 updateInitAccelValues = true;
5532
5533 currentAccelerationDistance = 0.0;
5534 startingAccelerationDistance = 0.0;
5535 lastWheelVerticalDistance = 0.0;
5536 lastWheelHorizontalDistance = 0.0;
5537 tempTurboInterval = 0;
5538 //currentTurboMode = GradientTurbo;
5539 oldAccelMulti = 0.0;
5540 accelTravel = 0.0;
5541 currentTurboMode = DEFAULTTURBOMODE;
5542 easingDuration = DEFAULTEASINGDURATION;
5543 springDeadCircleMultiplier = DEFAULTSPRINGRELEASERADIUS;
5544
5545 pendingEvent = false;
5546 pendingPress = false;
5547 pendingIgnoreSets = false;
5548
5549 extraAccelerationEnabled = false;
5550 extraAccelerationMultiplier = DEFAULTEXTRACCELVALUE;
5551 minMouseDistanceAccelThreshold = DEFAULTMINACCELTHRESHOLD;
5552 maxMouseDistanceAccelThreshold = DEFAULTMAXACCELTHRESHOLD;
5553 startAccelMultiplier = DEFAULTSTARTACCELMULTIPLIER;
5554 accelDuration = DEFAULTACCELEASINGDURATION;
5555 extraAccelCurve = LinearAccelCurve;
5556
5557 activeZoneStringLock.lockForWrite();
5558 activeZoneString = tr("[NO KEY]");
5559 activeZoneStringLock.unlock();
5560 }
5561
isModifierButton()5562 bool JoyButton::isModifierButton()
5563 {
5564 return false;
5565 }
5566
resetActiveButtonMouseDistances()5567 void JoyButton::resetActiveButtonMouseDistances()
5568 {
5569 mouseHelper.resetButtonMouseDistances();
5570 }
5571
resetAccelerationDistances()5572 void JoyButton::resetAccelerationDistances()
5573 {
5574 if (updateLastMouseDistance)
5575 {
5576 lastAccelerationDistance = currentAccelerationDistance;
5577 lastMouseDistance = currentMouseDistance;
5578 updateLastMouseDistance = false;
5579 }
5580
5581 if (updateStartingMouseDistance)
5582 {
5583 startingAccelerationDistance = lastAccelerationDistance;
5584 updateStartingMouseDistance = false;
5585 }
5586
5587 if (updateOldAccelMulti >= 0.0)
5588 {
5589 oldAccelMulti = updateOldAccelMulti;
5590 updateOldAccelMulti = 0.0;
5591 }
5592
5593 currentAccelerationDistance = getAccelerationDistance();
5594 currentMouseDistance = getMouseDistanceFromDeadZone();
5595 }
5596
initializeDistanceValues()5597 void JoyButton::initializeDistanceValues()
5598 {
5599 lastAccelerationDistance = getLastAccelerationDistance();
5600 currentAccelerationDistance = getAccelerationDistance();
5601 startingAccelerationDistance = lastAccelerationDistance;
5602
5603 lastMouseDistance = getLastMouseDistanceFromDeadZone();
5604 currentMouseDistance = getMouseDistanceFromDeadZone();
5605 }
5606
getLastMouseDistanceFromDeadZone()5607 double JoyButton::getLastMouseDistanceFromDeadZone()
5608 {
5609 return lastMouseDistance;
5610 }
5611
getLastAccelerationDistance()5612 double JoyButton::getLastAccelerationDistance()
5613 {
5614 return lastAccelerationDistance;
5615 }
5616
copyLastMouseDistanceFromDeadZone(JoyButton * srcButton)5617 void JoyButton::copyLastMouseDistanceFromDeadZone(JoyButton *srcButton)
5618 {
5619 this->lastMouseDistance = srcButton->lastMouseDistance;
5620 }
5621
copyLastAccelerationDistance(JoyButton * srcButton)5622 void JoyButton::copyLastAccelerationDistance(JoyButton *srcButton)
5623 {
5624 this->lastAccelerationDistance = srcButton->lastAccelerationDistance;
5625 }
5626
isExtraAccelerationEnabled()5627 bool JoyButton::isExtraAccelerationEnabled()
5628 {
5629 return extraAccelerationEnabled;
5630 }
5631
getExtraAccelerationMultiplier()5632 double JoyButton::getExtraAccelerationMultiplier()
5633 {
5634 return extraAccelerationMultiplier;
5635 }
5636
setExtraAccelerationStatus(bool status)5637 void JoyButton::setExtraAccelerationStatus(bool status)
5638 {
5639 if (isPartRealAxis())
5640 {
5641 extraAccelerationEnabled = status;
5642 emit propertyUpdated();
5643 }
5644 else
5645 {
5646 extraAccelerationEnabled = false;
5647 }
5648 }
5649
setExtraAccelerationMultiplier(double value)5650 void JoyButton::setExtraAccelerationMultiplier(double value)
5651 {
5652 if (value >= 1.0 && value <= 200.0)
5653 {
5654 extraAccelerationMultiplier = value;
5655 emit propertyUpdated();
5656 }
5657 }
5658
setMinAccelThreshold(double value)5659 void JoyButton::setMinAccelThreshold(double value)
5660 {
5661 if (value >= 1.0 && value <= 100.0 && value <= maxMouseDistanceAccelThreshold)
5662 {
5663 minMouseDistanceAccelThreshold = value;
5664 emit propertyUpdated();
5665 }
5666 }
5667
getMinAccelThreshold()5668 double JoyButton::getMinAccelThreshold()
5669 {
5670 return minMouseDistanceAccelThreshold;
5671 }
5672
setMaxAccelThreshold(double value)5673 void JoyButton::setMaxAccelThreshold(double value)
5674 {
5675 if (value >= 1.0 && value <= 100.0 && value >= minMouseDistanceAccelThreshold)
5676 {
5677 maxMouseDistanceAccelThreshold = value;
5678 emit propertyUpdated();
5679 }
5680 }
5681
getMaxAccelThreshold()5682 double JoyButton::getMaxAccelThreshold()
5683 {
5684 return maxMouseDistanceAccelThreshold;
5685 }
5686
setStartAccelMultiplier(double value)5687 void JoyButton::setStartAccelMultiplier(double value)
5688 {
5689 if (value >= 0.0 && value <= 100.0)
5690 {
5691 startAccelMultiplier = value;
5692 emit propertyUpdated();
5693 }
5694 }
5695
getStartAccelMultiplier()5696 double JoyButton::getStartAccelMultiplier()
5697 {
5698 return startAccelMultiplier;
5699 }
5700
getSpringModeScreen()5701 int JoyButton::getSpringModeScreen()
5702 {
5703 return springModeScreen;
5704 }
5705
setSpringModeScreen(int screen)5706 void JoyButton::setSpringModeScreen(int screen)
5707 {
5708 if (screen >= -1)
5709 {
5710 springModeScreen = screen;
5711 }
5712 }
5713
setAccelExtraDuration(double value)5714 void JoyButton::setAccelExtraDuration(double value)
5715 {
5716 if (value >= 0.0 && value <= 5.0)
5717 {
5718 accelDuration = value;
5719 emit propertyUpdated();
5720 }
5721 }
5722
getAccelExtraDuration()5723 double JoyButton::getAccelExtraDuration()
5724 {
5725 return accelDuration;
5726 }
5727
hasFutureSpringEvents()5728 bool JoyButton::hasFutureSpringEvents()
5729 {
5730 bool result = false;
5731 QListIterator<JoyButton*> iter(pendingMouseButtons);
5732 while (iter.hasNext())
5733 {
5734 JoyButton *temp = iter.next();
5735 if (temp->getMouseMode() == MouseSpring)
5736 {
5737 result = true;
5738 iter.toBack();
5739 }
5740 }
5741
5742 return result;
5743 }
5744
setSpringDeadCircleMultiplier(int value)5745 void JoyButton::setSpringDeadCircleMultiplier(int value)
5746 {
5747 if (value >= 0 && value <= 100)
5748 {
5749 springDeadCircleMultiplier = value;
5750 emit propertyUpdated();
5751 }
5752 }
5753
getSpringDeadCircleMultiplier()5754 int JoyButton::getSpringDeadCircleMultiplier()
5755 {
5756 return springDeadCircleMultiplier;
5757 }
5758
getCurrentSpringDeadCircle()5759 double JoyButton::getCurrentSpringDeadCircle()
5760 {
5761 return (springDeadCircleMultiplier * 0.01);
5762 }
5763
restartLastMouseTime()5764 void JoyButton::restartLastMouseTime()
5765 {
5766 testOldMouseTime.restart();
5767 //lastMouseTime.restart();
5768 }
5769
setStaticMouseThread(QThread * thread)5770 void JoyButton::setStaticMouseThread(QThread *thread)
5771 {
5772 int oldInterval = staticMouseEventTimer.interval();
5773 if (oldInterval == 0)
5774 {
5775 oldInterval = IDLEMOUSEREFRESHRATE;
5776 }
5777
5778 staticMouseEventTimer.moveToThread(thread);
5779 mouseHelper.moveToThread(thread);
5780
5781 QMetaObject::invokeMethod(&staticMouseEventTimer, "start",
5782 Q_ARG(int, oldInterval));
5783
5784 //lastMouseTime.start();
5785 testOldMouseTime.start();
5786
5787 #ifdef Q_OS_WIN
5788 repeatHelper.moveToThread(thread);
5789 #endif
5790 }
5791
indirectStaticMouseThread(QThread * thread)5792 void JoyButton::indirectStaticMouseThread(QThread *thread)
5793 {
5794 QMetaObject::invokeMethod(&staticMouseEventTimer, "stop");
5795 #ifdef Q_OS_WIN
5796 QMetaObject::invokeMethod(repeatHelper.getRepeatTimer(), "stop");
5797 #endif
5798 QMetaObject::invokeMethod(&mouseHelper, "changeThread",
5799 Q_ARG(QThread*, thread));
5800 }
5801
shouldInvokeMouseEvents()5802 bool JoyButton::shouldInvokeMouseEvents()
5803 {
5804 bool result = false;
5805
5806 if (pendingMouseButtons.size() > 0 && staticMouseEventTimer.isActive())
5807 {
5808 int timerInterval = staticMouseEventTimer.interval();
5809 if (timerInterval == 0)
5810 {
5811 result = true;
5812 }
5813 //else if (lastMouseTime.elapsed() >= timerInterval)
5814 //else if (lastMouseTime.hasExpired(timerInterval))
5815 else if (testOldMouseTime.elapsed() >= timerInterval)
5816 {
5817 result = true;
5818 }
5819 }
5820
5821 return result;
5822 }
5823
invokeMouseEvents()5824 void JoyButton::invokeMouseEvents()
5825 {
5826 mouseHelper.mouseEvent();
5827 }
5828
hasActiveSlots()5829 bool JoyButton::hasActiveSlots()
5830 {
5831 return !activeSlots.isEmpty();
5832 }
5833
setExtraAccelerationCurve(JoyExtraAccelerationCurve curve)5834 void JoyButton::setExtraAccelerationCurve(JoyExtraAccelerationCurve curve)
5835 {
5836 extraAccelCurve = curve;
5837 emit propertyUpdated();
5838 }
5839
getExtraAccelerationCurve()5840 JoyButton::JoyExtraAccelerationCurve JoyButton::getExtraAccelerationCurve()
5841 {
5842 return extraAccelCurve;
5843 }
5844
copyExtraAccelerationState(JoyButton * srcButton)5845 void JoyButton::copyExtraAccelerationState(JoyButton *srcButton)
5846 {
5847 this->currentAccelMulti = srcButton->currentAccelMulti;
5848 this->oldAccelMulti = srcButton->oldAccelMulti;
5849 this->accelTravel = srcButton->accelTravel;
5850
5851 this->startingAccelerationDistance = srcButton->startingAccelerationDistance;
5852 this->lastAccelerationDistance = srcButton->lastAccelerationDistance;
5853 this->lastMouseDistance = srcButton->lastMouseDistance;
5854
5855 this->accelExtraDurationTime.setHMS(srcButton->accelExtraDurationTime.hour(),
5856 srcButton->accelExtraDurationTime.minute(),
5857 srcButton->accelExtraDurationTime.second(),
5858 srcButton->accelExtraDurationTime.msec());
5859
5860 this->updateOldAccelMulti = srcButton->updateOldAccelMulti;
5861 this->updateStartingMouseDistance = srcButton->updateStartingMouseDistance;
5862 this->updateLastMouseDistance = srcButton->lastMouseDistance;
5863 }
5864
setUpdateInitAccel(bool state)5865 void JoyButton::setUpdateInitAccel(bool state)
5866 {
5867 this->updateInitAccelValues = state;
5868 }
5869