adds in advanced gradient control to axis code (thanks to Yue Shi Lai)
git-svn-id: svn://svn.code.sf.net/p/qjoypad/code/trunk@116 c05e91a0-76c8-4ec0-b377-ef19ce7cc080
This commit is contained in:
committed by
virtuoussin13
parent
85dfc3ee90
commit
e7f4dfa748
100
src/axis.cpp
100
src/axis.cpp
@ -2,6 +2,9 @@
|
|||||||
#include "event.h"
|
#include "event.h"
|
||||||
#include "time.h"
|
#include "time.h"
|
||||||
#define sqr(a) ((a)*(a))
|
#define sqr(a) ((a)*(a))
|
||||||
|
#define cub(a) ((a)*(a)*(a))
|
||||||
|
#define clamp(a, a_low, a_high) \
|
||||||
|
((a) < (a_low) ? (a_low) : (a) > (a_high) ? (a_high) : (a))
|
||||||
|
|
||||||
|
|
||||||
Axis::Axis( int i ) {
|
Axis::Axis( int i ) {
|
||||||
@ -13,9 +16,6 @@ Axis::Axis( int i ) {
|
|||||||
toDefault();
|
toDefault();
|
||||||
tick = 0;
|
tick = 0;
|
||||||
timer = new QTimer(this);
|
timer = new QTimer(this);
|
||||||
a = 0;
|
|
||||||
b = 0;
|
|
||||||
c = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -36,7 +36,7 @@ bool Axis::read( QTextStream* stream ) {
|
|||||||
bool ok;
|
bool ok;
|
||||||
//int to store values derived from strings
|
//int to store values derived from strings
|
||||||
int val;
|
int val;
|
||||||
|
float fval;
|
||||||
//step through each word, check if it's a token we recognize
|
//step through each word, check if it's a token we recognize
|
||||||
for ( QStringList::Iterator it = words.begin(); it != words.end(); ++it ) {
|
for ( QStringList::Iterator it = words.begin(); it != words.end(); ++it ) {
|
||||||
if (*it == "maxspeed") {
|
if (*it == "maxspeed") {
|
||||||
@ -66,6 +66,21 @@ bool Axis::read( QTextStream* stream ) {
|
|||||||
if (ok && val >= 0 && val <= JOYMAX) xZone = val;
|
if (ok && val >= 0 && val <= JOYMAX) xZone = val;
|
||||||
else return false;
|
else return false;
|
||||||
}
|
}
|
||||||
|
else if (*it == "tcurve") {
|
||||||
|
++it;
|
||||||
|
if (it == words.end()) return false;
|
||||||
|
val = (*it).toInt(&ok);
|
||||||
|
if (ok && val >= 0 && val <= power_function) transferCurve = val;
|
||||||
|
else return false;
|
||||||
|
}
|
||||||
|
else if (*it == "sens") {
|
||||||
|
++it;
|
||||||
|
if (it == words.end()) return false;
|
||||||
|
fval = (*it).toFloat(&ok);
|
||||||
|
if (ok && fval >= SENSITIVITY_MIN && fval <= SENSITIVITY_MAX)
|
||||||
|
sensitivity = fval;
|
||||||
|
else return false;
|
||||||
|
}
|
||||||
//and for the positive keycode,
|
//and for the positive keycode,
|
||||||
else if (*it == "+key") {
|
else if (*it == "+key") {
|
||||||
++it;
|
++it;
|
||||||
@ -134,6 +149,10 @@ void Axis::write( QTextStream* stream ) {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (gradient) *stream << "maxSpeed " << maxSpeed << ", ";
|
if (gradient) *stream << "maxSpeed " << maxSpeed << ", ";
|
||||||
|
if (transferCurve != quadratic)
|
||||||
|
*stream << "tCurve " << transferCurve << ", ";
|
||||||
|
if (sensitivity != 1.0F)
|
||||||
|
*stream << "sens " << sensitivity << ", ";
|
||||||
*stream << "mouse";
|
*stream << "mouse";
|
||||||
if (mode == mousepv)
|
if (mode == mousepv)
|
||||||
*stream << "+v\n";
|
*stream << "+v\n";
|
||||||
@ -199,6 +218,8 @@ void Axis::toDefault() {
|
|||||||
gradient = false;
|
gradient = false;
|
||||||
throttle = 0;
|
throttle = 0;
|
||||||
maxSpeed = 100;
|
maxSpeed = 100;
|
||||||
|
transferCurve = quadratic;
|
||||||
|
sensitivity = 1.0F;
|
||||||
dZone = DZONE;
|
dZone = DZONE;
|
||||||
tick = 0;
|
tick = 0;
|
||||||
xZone = XZONE;
|
xZone = XZONE;
|
||||||
@ -275,13 +296,10 @@ void Axis::timerTick( int tick ) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Axis::adjustGradient() {
|
void Axis::adjustGradient() {
|
||||||
//create a nice quadratic curve fitting it to the points
|
inverseRange = 1.0F / (xZone - dZone);
|
||||||
//(dZone,0) and (xZone,MaxSpeed)
|
// This is also the convenient spot to initialize the dithering
|
||||||
a = (double) (maxSpeed) / sqr(xZone - dZone);
|
// accmulator.
|
||||||
b = -2 * a * dZone;
|
sumDist = 0;
|
||||||
c = a * sqr(dZone);
|
|
||||||
//actual equation for curve is: y = ax^2 + b
|
|
||||||
//where x is the state of the axis and y is the distance the mouse should move.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Axis::move( bool press ) {
|
void Axis::move( bool press ) {
|
||||||
@ -305,23 +323,51 @@ void Axis::move( bool press ) {
|
|||||||
//if using the mouse
|
//if using the mouse
|
||||||
else if (press) {
|
else if (press) {
|
||||||
int dist;
|
int dist;
|
||||||
if (gradient) {
|
|
||||||
//calculate our mouse speed curve based on calculations made in
|
|
||||||
//adjustGradient()
|
|
||||||
int absState = abs(state);
|
|
||||||
if (absState >= xZone) dist = maxSpeed;
|
|
||||||
else if (absState <= dZone) dist = 0;
|
|
||||||
else dist = (int) (a*sqr(absState) + b*absState + c);
|
|
||||||
}
|
|
||||||
//if not gradient, always go full speed.
|
|
||||||
else dist = maxSpeed;
|
|
||||||
|
|
||||||
//if we're on the negative side of the axis, must compensate for
|
if (gradient) {
|
||||||
//squaring and make distance negative.
|
const int absState = abs(state);
|
||||||
if (state < 0) dist = -dist;
|
float fdist; // Floating point movement distance
|
||||||
e.type = WARP;
|
|
||||||
if (mode == mousepv) {
|
if (absState >= xZone) fdist = 1.0F;
|
||||||
e.value1 = 0;
|
else if (absState <= dZone) fdist = 0.0F;
|
||||||
|
else {
|
||||||
|
const float u = inverseRange * (absState - dZone);
|
||||||
|
|
||||||
|
switch(transferCurve) {
|
||||||
|
case quadratic:
|
||||||
|
fdist = sqr(u);
|
||||||
|
break;
|
||||||
|
case cubic:
|
||||||
|
fdist = cub(u);
|
||||||
|
break;
|
||||||
|
case quadratic_extreme:
|
||||||
|
fdist = sqr(u);
|
||||||
|
if(u >= 0.95F) {
|
||||||
|
fdist *= 1.5F;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case power_function:
|
||||||
|
fdist = clamp(powf(u, 1.0F / clamp(
|
||||||
|
sensitivity, 1e-8F, 1e+3F)), 0.0F, 1.0F);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fdist = u;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fdist *= maxSpeed;
|
||||||
|
if (state < 0) fdist = -fdist;
|
||||||
|
// Accumulate the floating point distance and shift the
|
||||||
|
// mouse by the rounded magnitude
|
||||||
|
sumDist += fdist;
|
||||||
|
dist = static_cast<int>(rint(sumDist));
|
||||||
|
sumDist -= dist;
|
||||||
|
}
|
||||||
|
//if not gradient, always go full speed.
|
||||||
|
else dist = maxSpeed;
|
||||||
|
|
||||||
|
e.type = WARP;
|
||||||
|
if (mode == mousepv) {
|
||||||
|
e.value1 = 0;
|
||||||
e.value2 = dist;
|
e.value2 = dist;
|
||||||
}
|
}
|
||||||
else if (mode == mousenv) {
|
else if (mode == mousenv) {
|
||||||
|
22
src/axis.h
22
src/axis.h
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
//abs()
|
//abs()
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QTextStream>
|
#include <QTextStream>
|
||||||
@ -16,6 +17,8 @@
|
|||||||
|
|
||||||
//each axis can create a key press or move the mouse in one of four directions.
|
//each axis can create a key press or move the mouse in one of four directions.
|
||||||
enum AxisMode {keybd, mousepv, mousenv, mouseph, mousenh};
|
enum AxisMode {keybd, mousepv, mousenv, mouseph, mousenh};
|
||||||
|
enum TransferCurve {linear, quadratic, cubic, quadratic_extreme,
|
||||||
|
power_function};
|
||||||
|
|
||||||
//represents one joystick axis
|
//represents one joystick axis
|
||||||
class Axis : public QObject {
|
class Axis : public QObject {
|
||||||
@ -65,14 +68,17 @@ class Axis : public QObject {
|
|||||||
bool isDown;
|
bool isDown;
|
||||||
|
|
||||||
//variables for calculating quadratic used for gradient mouse axes
|
//variables for calculating quadratic used for gradient mouse axes
|
||||||
double a,b,c;
|
float inverseRange;
|
||||||
|
|
||||||
//actual axis settings:
|
//actual axis settings:
|
||||||
bool gradient;
|
bool gradient;
|
||||||
int maxSpeed; //0..MAXMOUSESPEED
|
int maxSpeed; //0..MAXMOUSESPEED
|
||||||
int throttle; //-1 (nkey), 0 (no throttle), 1 (pkey)
|
unsigned int transferCurve;
|
||||||
int dZone;//-32767 .. 32767
|
float sensitivity;
|
||||||
int xZone;//-32767 .. 32767
|
int throttle; //-1 (nkey), 0 (no throttle), 1 (pkey)
|
||||||
|
int dZone;//-32767 .. 32767
|
||||||
|
int xZone;//-32767 .. 32767
|
||||||
|
double sumDist;
|
||||||
AxisMode mode;
|
AxisMode mode;
|
||||||
//positive keycode
|
//positive keycode
|
||||||
int pkeycode;
|
int pkeycode;
|
||||||
|
@ -24,6 +24,7 @@ AxisEdit::AxisEdit( Axis* ax )
|
|||||||
v2->setSpacing(5);
|
v2->setSpacing(5);
|
||||||
CGradient = new QCheckBox("Gradient", this);
|
CGradient = new QCheckBox("Gradient", this);
|
||||||
CGradient->setChecked(axis->gradient);
|
CGradient->setChecked(axis->gradient);
|
||||||
|
connect(CGradient, SIGNAL(toggled(bool)), this, SLOT( CGradientChanged( bool )));
|
||||||
v2->addWidget(CGradient);
|
v2->addWidget(CGradient);
|
||||||
|
|
||||||
CMode = new QComboBox(this);
|
CMode = new QComboBox(this);
|
||||||
@ -35,6 +36,16 @@ AxisEdit::AxisEdit( Axis* ax )
|
|||||||
CMode->setCurrentIndex( axis->mode );
|
CMode->setCurrentIndex( axis->mode );
|
||||||
connect(CMode, SIGNAL(activated(int)), this, SLOT( CModeChanged( int )));
|
connect(CMode, SIGNAL(activated(int)), this, SLOT( CModeChanged( int )));
|
||||||
v2->addWidget(CMode);
|
v2->addWidget(CMode);
|
||||||
|
CTransferCurve = new QComboBox(this);
|
||||||
|
CTransferCurve->insertItem(linear, QString("Linear"), Qt::DisplayRole);
|
||||||
|
CTransferCurve->insertItem(quadratic, QString("Quadratic"),Qt::DisplayRole );
|
||||||
|
CTransferCurve->insertItem(cubic, QString("Cubic"),Qt::DisplayRole );
|
||||||
|
CTransferCurve->insertItem(quadratic_extreme, QString("Quadratic Extreme"), Qt::DisplayRole);
|
||||||
|
CTransferCurve->insertItem(power_function, QString("Power Function"), Qt::DisplayRole);
|
||||||
|
CTransferCurve->setCurrentIndex( axis->transferCurve );
|
||||||
|
CTransferCurve->setEnabled(axis->gradient);
|
||||||
|
connect(CTransferCurve, SIGNAL(activated(int)), this, SLOT( CTransferCurveChanged( int )));
|
||||||
|
v2->addWidget(CTransferCurve);
|
||||||
h->addLayout(v2);
|
h->addLayout(v2);
|
||||||
|
|
||||||
MouseBox = new QFrame(this);
|
MouseBox = new QFrame(this);
|
||||||
@ -50,6 +61,13 @@ AxisEdit::AxisEdit( Axis* ax )
|
|||||||
SSpeed->setSingleStep(1);
|
SSpeed->setSingleStep(1);
|
||||||
SSpeed->setValue(axis->maxSpeed);
|
SSpeed->setValue(axis->maxSpeed);
|
||||||
v2->addWidget(SSpeed);
|
v2->addWidget(SSpeed);
|
||||||
|
LSensitivity = new QLabel("Sensitivity", MouseBox);
|
||||||
|
v2->addWidget(LSensitivity);
|
||||||
|
SSensitivity = new QDoubleSpinBox(MouseBox);
|
||||||
|
SSensitivity->setRange(1e-3F, 1e+3F);
|
||||||
|
SSensitivity->setSingleStep(0.10);
|
||||||
|
SSensitivity->setValue(axis->sensitivity);
|
||||||
|
v2->addWidget(SSensitivity);
|
||||||
h->addWidget(MouseBox);
|
h->addWidget(MouseBox);
|
||||||
v->addLayout(h);
|
v->addLayout(h);
|
||||||
|
|
||||||
@ -87,6 +105,7 @@ AxisEdit::AxisEdit( Axis* ax )
|
|||||||
v->addLayout(h);
|
v->addLayout(h);
|
||||||
|
|
||||||
CModeChanged( axis->mode );
|
CModeChanged( axis->mode );
|
||||||
|
CTransferCurveChanged( axis->transferCurve );
|
||||||
CThrottleChanged( axis->throttle + 1 );
|
CThrottleChanged( axis->throttle + 1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,6 +117,16 @@ void AxisEdit::show() {
|
|||||||
void AxisEdit::setState( int val ) {
|
void AxisEdit::setState( int val ) {
|
||||||
Slider->setValue( val );
|
Slider->setValue( val );
|
||||||
}
|
}
|
||||||
|
void AxisEdit::CGradientChanged( bool on ) {
|
||||||
|
CTransferCurve->setEnabled(on);
|
||||||
|
if (on) {
|
||||||
|
CTransferCurveChanged( axis->transferCurve );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
LSensitivity->setEnabled(false);
|
||||||
|
SSensitivity->setEnabled(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void AxisEdit::CModeChanged( int index ) {
|
void AxisEdit::CModeChanged( int index ) {
|
||||||
if (index == keybd) {
|
if (index == keybd) {
|
||||||
@ -107,6 +136,21 @@ void AxisEdit::CModeChanged( int index ) {
|
|||||||
else {
|
else {
|
||||||
MouseBox->setEnabled(true);
|
MouseBox->setEnabled(true);
|
||||||
KeyBox->setEnabled(false);
|
KeyBox->setEnabled(false);
|
||||||
|
if (CGradient->isChecked()) {
|
||||||
|
CTransferCurve->setEnabled(true);
|
||||||
|
CTransferCurveChanged( axis->transferCurve );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AxisEdit::CTransferCurveChanged( int index ) {
|
||||||
|
if (index == power_function) {
|
||||||
|
LSensitivity->setEnabled(true);
|
||||||
|
SSensitivity->setEnabled(true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
LSensitivity->setEnabled(false);
|
||||||
|
SSensitivity->setEnabled(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,15 +173,10 @@ void AxisEdit::CThrottleChanged( int index ) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AxisEdit::accept() {
|
void AxisEdit::accept() {
|
||||||
//if the gradient status has changed, either request a timer or turn it down.
|
|
||||||
/*if (axis->gradient) {
|
|
||||||
if (!CGradient->isChecked()) tossTimer(axis);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (CGradient->isChecked()) takeTimer(axis);
|
|
||||||
}*/
|
|
||||||
axis->gradient = CGradient->isChecked();
|
axis->gradient = CGradient->isChecked();
|
||||||
axis->maxSpeed = SSpeed->value();
|
axis->maxSpeed = SSpeed->value();
|
||||||
|
axis->transferCurve = (TransferCurve)CTransferCurve->currentIndex();
|
||||||
|
axis->sensitivity = SSensitivity->value();
|
||||||
axis->throttle = CThrottle->currentIndex() - 1;
|
axis->throttle = CThrottle->currentIndex() - 1;
|
||||||
axis->dZone = Slider->dZone();
|
axis->dZone = Slider->dZone();
|
||||||
axis->xZone = Slider->xZone();
|
axis->xZone = Slider->xZone();
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include <QComboBox>
|
#include <QComboBox>
|
||||||
#include <QSpinBox>
|
#include <QSpinBox>
|
||||||
#include <QCheckBox>
|
#include <QCheckBox>
|
||||||
|
#include <QDoubleSpinBox>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
//for my home-brewed widgets
|
//for my home-brewed widgets
|
||||||
#include "joyslider.h"
|
#include "joyslider.h"
|
||||||
@ -22,7 +23,9 @@ class AxisEdit : public QDialog {
|
|||||||
void setState( int val );
|
void setState( int val );
|
||||||
protected slots:
|
protected slots:
|
||||||
//slots for GUI events
|
//slots for GUI events
|
||||||
void CModeChanged( int index );
|
void CGradientChanged( bool on );
|
||||||
|
void CModeChanged( int index );
|
||||||
|
void CTransferCurveChanged( int index );
|
||||||
void CThrottleChanged( int index );
|
void CThrottleChanged( int index );
|
||||||
void accept();
|
void accept();
|
||||||
protected:
|
protected:
|
||||||
@ -30,9 +33,11 @@ class AxisEdit : public QDialog {
|
|||||||
Axis *axis;
|
Axis *axis;
|
||||||
//the important parts of the dialog:
|
//the important parts of the dialog:
|
||||||
QCheckBox *CGradient;
|
QCheckBox *CGradient;
|
||||||
QComboBox *CMode, *CThrottle;
|
QComboBox *CMode, *CThrottle, *CTransferCurve;
|
||||||
QFrame *MouseBox, *KeyBox;
|
QFrame *MouseBox, *KeyBox;
|
||||||
QSpinBox *SSpeed;
|
QSpinBox *SSpeed;
|
||||||
|
QLabel *LSensitivity;
|
||||||
|
QDoubleSpinBox *SSensitivity;
|
||||||
KeyButton *BNeg, *BPos;
|
KeyButton *BNeg, *BPos;
|
||||||
JoySlider *Slider;
|
JoySlider *Slider;
|
||||||
QPushButton *BOkay, *BCancel;
|
QPushButton *BOkay, *BCancel;
|
||||||
|
@ -22,6 +22,9 @@
|
|||||||
//fastest the mouse can go. Completely arbitrary.
|
//fastest the mouse can go. Completely arbitrary.
|
||||||
#define MAXMOUSESPEED 5000
|
#define MAXMOUSESPEED 5000
|
||||||
|
|
||||||
|
#define SENSITIVITY_MIN 1e-8F
|
||||||
|
#define SENSITIVITY_MAX 1e+8F
|
||||||
|
|
||||||
#define NAME "QJoyPad 4.0"
|
#define NAME "QJoyPad 4.0"
|
||||||
|
|
||||||
#define MOUSE_OFFSET 400
|
#define MOUSE_OFFSET 400
|
||||||
|
Reference in New Issue
Block a user