summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSascha Hlusiak <saschahlusiak@arcor.de>2009-02-19 23:40:58 +0100
committerSascha Hlusiak <saschahlusiak@arcor.de>2009-02-19 23:40:58 +0100
commit4978e78e7c49bc0aabf5c7ade4223c2529a9f046 (patch)
treebec93c47658cd1cb730b055c796ad024f5b0e70c
parentd4bb86ddb0ba570de0f501cd0edb13861456b711 (diff)
Add PWM key generation when axis in accelerated mode
When axis is in accelerated mode and keyhigh/keylow is set, the deflection of the axis will be linked to the _percent of time_ the key will be down. Full deflection will set the key permanently down (old behaviour). 50% deflection will result in the key being 50ms down and 50ms up. 75% deflection will result in the key being 150ms down and 50ms up. etc. Minimum interval is 50ms, maximum is 600ms.
-rw-r--r--src/jstk.c24
-rw-r--r--src/jstk.h4
-rw-r--r--src/jstk_axis.c167
-rw-r--r--src/jstk_axis.h1
4 files changed, 183 insertions, 13 deletions
diff --git a/src/jstk.c b/src/jstk.c
index a5ea298..155bf2c 100644
--- a/src/jstk.c
+++ b/src/jstk.c
@@ -283,20 +283,9 @@ jstkReadProc(LocalDevicePtr local)
case JSTK_MAPPING_KEY: if (priv->keys_enabled == TRUE) {
if (priv->axis[number].type == JSTK_TYPE_ACCELERATED) {
- if ((priv->axis[number].value > 0) !=
- (priv->axis[number].oldvalue > 0))
- jstkGenerateKeys(priv->keyboard_device,
- priv->axis[number].keys_high,
- (priv->axis[number].value > 0) ? 1:0);
-
- if ((priv->axis[number].value < 0) !=
- (priv->axis[number].oldvalue < 0))
- jstkGenerateKeys(priv->keyboard_device,
- priv->axis[number].keys_low,
- (priv->axis[number].value < 0) ? 1:0);
+ jstkHandlePWMAxis(local, number);
} else if (priv->axis[number].type == JSTK_TYPE_BYVALUE) {
- if (priv->keys_enabled == TRUE)
- jstkStartAxisTimer(local, number);
+ jstkStartAxisTimer(local, number);
}
break;
}
@@ -449,6 +438,12 @@ jstkDeviceControlProc(DeviceIntPtr pJstk,
priv->timerrunning = FALSE;
TimerCancel(priv->timer);
}
+ for (i = 0; i < MAXAXES; i++)
+ if (priv->axis[i].timerrunning)
+ {
+ priv->axis[i].timerrunning = FALSE;
+ TimerCancel(priv->axis[i].timer);
+ }
if (local->fd >= 0)
RemoveEnabledDevice(local->fd);
@@ -552,6 +547,9 @@ jstkCorePreInit(InputDriverPtr drv, IDevPtr dev, int flags)
priv->axis[i].amplify = 1.0f;
priv->axis[i].valuator = -1;
priv->axis[i].subpixel = 0.0f;
+ priv->axis[i].timer = NULL;
+ priv->axis[i].timerrunning = FALSE;
+ priv->axis[i].key_isdown = 0;
for (j=0; j<MAXKEYSPERBUTTON; j++)
priv->axis[i].keys_low[j] = priv->axis[i].keys_high[j] = 0;
}
diff --git a/src/jstk.h b/src/jstk.h
index 694ae45..1d97937 100644
--- a/src/jstk.h
+++ b/src/jstk.h
@@ -81,7 +81,11 @@ typedef struct _AXIS {
float previousposition; /* TYPE_ABSOLUTE */
float amplify;
float subpixel; /* Pending subpixel movement */
+
KEYSCANCODES keys_low, keys_high; /* MAPPING_KEY */
+ int key_isdown;
+ OsTimerPtr timer;
+ Bool timerrunning;
} AXIS;
typedef struct _BUTTON {
diff --git a/src/jstk_axis.c b/src/jstk_axis.c
index 7e59e97..b314122 100644
--- a/src/jstk_axis.c
+++ b/src/jstk_axis.c
@@ -384,3 +384,170 @@ jstkHandleAbsoluteAxis(LocalDevicePtr device, int number)
xf86PostMotionEvent(device->dev, 0, 0, 2, x, y);
}
}
+
+
+
+
+
+/***********************************************************************
+ *
+ * jstkPWMAxisTimer --
+ *
+ * The timer that will generate Key events.
+ * The deflection of the axis will control the PERCENT OF TIME the key is
+ * down, not the amount of impulses.
+ * Return 0, when timer can be stopped.
+ *
+ ***********************************************************************
+ */
+static CARD32
+jstkPWMAxisTimer(OsTimerPtr timer,
+ CARD32 atime,
+ pointer arg)
+{
+ DeviceIntPtr device = (DeviceIntPtr)arg;
+ JoystickDevPtr priv = (JoystickDevPtr)XI_PRIVATE(device);
+
+ int sigstate, i;
+ int nexttimer;
+
+ nexttimer = 0;
+
+ sigstate = xf86BlockSIGIO();
+
+ for (i=0; i<MAXAXES; i++)
+ if (priv->axis[i].timer == timer) /* The timer handles only one axis! Find it. */
+ {
+ AXIS *axis;
+ axis = &priv->axis[i];
+
+ DBG(8, ErrorF("PWM Axis %d value %d (old %d)\n", i, axis->value, axis->oldvalue));
+
+ /* Force key_high down if centered */
+ if ((axis->value <= 0) &&
+ (axis->oldvalue > 0) &&
+ (axis->key_isdown))
+ {
+ DBG(7, ErrorF("PWM Axis %d jumped over. Forcing keys_high up.\n", i));
+ jstkGenerateKeys(priv->keyboard_device,
+ axis->keys_high,
+ 0);
+ axis->key_isdown = 0;
+ }
+
+ /* Force key_low down if centered */
+ if ((axis->value >= 0) &&
+ (axis->oldvalue < 0) &&
+ (axis->key_isdown))
+ {
+ DBG(7, ErrorF("PWM Axis %d jumped over. Forcing keys_low up.\n", i));
+ jstkGenerateKeys(priv->keyboard_device,
+ axis->keys_low,
+ 0);
+ axis->key_isdown = 0;
+ }
+
+ if (axis->value == 0)
+ nexttimer = 0;
+ else {
+ float time_on, time_off;
+ float scale;
+ KEYSCANCODES *keys;
+
+ if (axis->value < 0)
+ keys = &axis->keys_low;
+ else keys = &axis->keys_high;
+
+ /* Calculate next timer */
+ time_on = (float)(abs(axis->value) - axis->deadzone) / 32768.0;
+ time_on *= (32768.0f / (float)(32768 - axis->deadzone));
+
+ time_off = 1.0f - time_on;
+
+ time_on += 0.01f; /* Ugly but ensures we don't divide by 0 */
+ time_off += 0.01f;
+
+ /* Scale both durations, so the smaller always is 50ms */
+ scale = 50.0f * axis->amplify;
+
+ if (time_on < time_off)
+ scale /= time_on;
+ else scale /= time_off;
+
+ time_on *= scale;
+ time_off *= scale;
+
+
+ if (time_off > 600.0f) {
+ /* Might as well just have it down forever */
+ DBG(7, ErrorF("PWM Axis %d up time too long (%.0fms). Forcing up)\n", i, time_off));
+ if (axis->key_isdown == 1) {
+ axis->key_isdown = 0;
+ jstkGenerateKeys(priv->keyboard_device,
+ *keys,
+ axis->key_isdown);
+ }
+ nexttimer = 0;
+ } else if (time_on > 600.0f) {
+ /* Might as well just have it up forever */
+ DBG(7, ErrorF("PWM Axis %d down time too long (%.0fms). Forcing down)\n", i, time_on));
+ if (axis->key_isdown == 0) {
+ axis->key_isdown = 1;
+ jstkGenerateKeys(priv->keyboard_device,
+ *keys,
+ axis->key_isdown);
+ }
+ nexttimer = 0;
+ } else {
+ /* Flip key state */
+ axis->key_isdown = 1 - axis->key_isdown;
+ jstkGenerateKeys(priv->keyboard_device,
+ *keys,
+ axis->key_isdown);
+
+ DBG(7, ErrorF("PWM Axis %d state=%d (%.0fms down, %.0fms up).\n", i, axis->key_isdown, time_on, time_off));
+
+ nexttimer = axis->key_isdown ? (int)time_on : (int)time_off;
+ }
+ }
+
+ if (nexttimer == 0) { /* No next timer, stop */
+ axis->timerrunning = FALSE;
+
+ DBG(2, ErrorF("Stopping PWM Axis %d Timer\n", i));
+ }
+ axis->oldvalue = axis->value;
+ break;
+ }
+
+ xf86UnblockSIGIO (sigstate);
+ return nexttimer;
+}
+
+
+/***********************************************************************
+ *
+ * jstkStartAxisTimer --
+ *
+ * Starts the timer for the movement.
+ * Will already prepare for moving one pixel, for "tipping" the stick
+ *
+ ***********************************************************************
+ */
+void
+jstkHandlePWMAxis(LocalDevicePtr device, int number)
+{
+ JoystickDevPtr priv = device->private;
+ if (priv->axis[number].timerrunning) return;
+
+ priv->axis[number].timerrunning = TRUE;
+
+ DBG(2, ErrorF("Starting PWM Axis Timer (triggered by axis %d, value %d)\n",
+ number, priv->axis[number].value));
+ priv->axis[number].timer = TimerSet(
+ priv->axis[number].timer,
+ 0, /* Relative */
+ 1, /* What about NOW? */
+ jstkPWMAxisTimer,
+ device->dev);
+}
diff --git a/src/jstk_axis.h b/src/jstk_axis.h
index e759f39..028c65f 100644
--- a/src/jstk_axis.h
+++ b/src/jstk_axis.h
@@ -27,5 +27,6 @@
void jstkStartAxisTimer(LocalDevicePtr device, int number);
void jstkStartButtonAxisTimer(LocalDevicePtr device, int number);
void jstkHandleAbsoluteAxis(LocalDevicePtr device, int number);
+void jstkHandlePWMAxis(LocalDevicePtr device, int number);
#endif