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