summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Gerecke <killertofu@gmail.com>2011-12-21 09:26:46 -0800
committerJason Gerecke <killertofu@gmail.com>2011-12-29 11:23:31 -0800
commit477a261ef79172d6378613fc4cab0026ed49d02f (patch)
tree2dac1d22fecdd796b390c264950ee9ac7482d4b4
parenta60e59a4730d6a11f999085aa8754fd0de5dfbaf (diff)
De-duplicate code for wheel/strip scrolling
Replaces sendWheelStripEvents and getWheelButton with several small functions to reduce unnecessary code duplication. As a side-effect, it is now possible for the driver to handle simultaneous scrolls on multiple axes. Previously, getWheelButton would go through all the axes but was limited to returning a single button/action. Signed-off-by: Jason Gerecke <killertofu@gmail.com> Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
-rw-r--r--src/wcmCommon.c177
-rw-r--r--src/xf86WacomDefs.h2
-rw-r--r--test/wacom-tests.c84
3 files changed, 200 insertions, 63 deletions
diff --git a/src/wcmCommon.c b/src/wcmCommon.c
index e85c6d8..e6eb958 100644
--- a/src/wcmCommon.c
+++ b/src/wcmCommon.c
@@ -317,73 +317,106 @@ static void sendAButton(InputInfoPtr pInfo, int button, int mask,
first_val, num_val, valuators);
}
-/*****************************************************************************
- * getWheelButton --
- * Get the wheel button to be sent for the current device state.
- ****************************************************************************/
-
-static int getWheelButton(InputInfoPtr pInfo, const WacomDeviceState* ds,
- unsigned int **fakeKey)
+/**
+ * Get the distance an axis was scrolled. This function is aware
+ * of the different ways different scrolling axes work and strives
+ * to produce a common representation of relative change.
+ *
+ * @param current Current value of the axis
+ * @param old Previous value of the axis
+ * @param wrap Maximum value before wraparound occurs (0 if axis does not wrap)
+ * @param flags Flags defining axis attributes: AXIS_INVERT and AXIS_BITWISE
+ * @return Relative change in axis value
+ */
+static int getScrollDelta(int current, int old, int wrap, int flags)
{
- WacomDevicePtr priv = (WacomDevicePtr) pInfo->private;
- int fakeButton = 0, value = 0;
+ int delta;
- /* emulate events for relative wheel */
- if ( ds->relwheel )
+ if (flags & AXIS_BITWISE)
{
- value = ds->relwheel;
- fakeButton = (value > 0) ? priv->relup : priv->reldn;
- *fakeKey = (value > 0) ? priv->wheel_keys[0+1] : priv->wheel_keys[1+1];
+ current = (int)log2((current << 1) | 0x01);
+ old = (int)log2((old << 1) | 0x01);
+ wrap = (int)log2((wrap << 1) | 0x01);
}
- /* emulate events for absolute wheel when it is a touch ring (on pad) */
- if ( (ds->abswheel != priv->oldWheel) && IsPad(priv) &&
- (priv->oldProximity == ds->proximity))
+ delta = current - old;
+
+ if (flags & AXIS_INVERT)
+ delta = -delta;
+
+ if (wrap != 0)
{
+ /* Wraparound detection. If the distance old..current
+ * is larger than the old..current considering the
+ * wraparound, assume wraparound and readjust */
int wrap_delta;
- value = priv->oldWheel - ds->abswheel;
- /* Wraparound detection. If the distance oldvalue..value is
- * larger than the oldvalue..value considering the
- * wraparound, assume wraparound and readjust */
- if (value < 0)
- wrap_delta = ((MAX_PAD_RING + 1) + priv->oldWheel) - ds->abswheel;
+ if (delta < 0)
+ wrap_delta = (wrap + 1) + delta;
else
- wrap_delta = priv->oldWheel - ((MAX_PAD_RING + 1) + ds->abswheel);
+ wrap_delta = -((wrap + 1) - delta);
- DBG(12, priv, "wrap detection for %d (old %d): %d (wrap %d)\n",
- ds->abswheel, priv->oldWheel, value, wrap_delta);
+ if (abs(wrap_delta) < abs(delta))
+ delta = wrap_delta;
+ }
- if (abs(wrap_delta) < abs(value))
- value = wrap_delta;
+ return delta;
+}
- fakeButton = (value > 0) ? priv->wheelup : priv->wheeldn;
- *fakeKey = (value > 0) ? priv->wheel_keys[2+1] : priv->wheel_keys[3+1];
- }
+/**
+ * Get the scroll button/action to send given the delta of
+ * the scrolling axis and the possible events that can be
+ * sent.
+ *
+ * @param delta Amount of change in the scrolling axis
+ * @param button_up Button event to send on scroll up
+ * @param button_dn Button event to send on scroll down
+ * @param action_up Action to send on scroll up
+ * @param action_dn Action to send on scroll down
+ * @param[out] action Action that should be performed
+ * @return Button that should be pressed
+ */
+static int getWheelButton(int delta, int button_up, int button_dn,
+ unsigned int *action_up, unsigned int *action_dn,
+ unsigned int **action)
+{
+ int button = 0;
+ *action = NULL;
- /* emulate events for left strip */
- if ( ds->stripx != priv->oldStripX )
+ if (delta)
{
- value = ds->stripx - priv->oldStripX;
-
- fakeButton = (value < 0) ? priv->striplup : priv->stripldn;
- *fakeKey = (value < 0) ? priv->strip_keys[0+1] : priv->strip_keys[1+1];
+ button = delta > 0 ? button_up : button_dn;
+ *action = delta > 0 ? action_up : action_dn;
}
- /* emulate events for right strip */
- if ( ds->stripy != priv->oldStripY )
- {
- value = ds->stripy - priv->oldStripY;
+ return button;
+}
- fakeButton = (value < 0) ? priv->striprup : priv->striprdn;
- *fakeKey = (value < 0) ? priv->strip_keys[2+1] : priv->strip_keys[3+1];
- }
+/**
+ * Send button or actions for a scrolling axis.
+ *
+ * @param button X button number to send if no action is defined
+ * @param action Action to send
+ * @param pInfo
+ * @param first_val
+ * @param num_vals
+ * @param valuators
+ */
+static void sendWheelStripEvent(int button, unsigned int *action, InputInfoPtr pInfo,
+ int first_val, int num_vals, int *valuators)
+{
+ WacomDevicePtr priv = (WacomDevicePtr) pInfo->private;
- DBG(10, priv, "send fakeButton %x with value = %d \n",
- fakeButton, value);
+ unsigned int button_action[1] = {button | AC_BUTTON | AC_KEYBTNPRESS};
+ if (!action || !(*action)) {
+ DBG(10, priv, "No wheel/strip action set; sending button %d (action %d).\n", button, button_action[0]);
+ action = &button_action[0];
+ }
- return fakeButton;
+ sendAction(pInfo, 1, action, ARRAY_SIZE(action), first_val, num_vals, valuators);
+ sendAction(pInfo, 0, action, ARRAY_SIZE(action), first_val, num_vals, valuators);
}
+
/*****************************************************************************
* sendWheelStripEvents --
* Send events defined for relative/absolute wheels or strips
@@ -393,31 +426,49 @@ static void sendWheelStripEvents(InputInfoPtr pInfo, const WacomDeviceState* ds,
int first_val, int num_vals, int *valuators)
{
WacomDevicePtr priv = (WacomDevicePtr) pInfo->private;
- int fakeButton = 0;
+ int fakeButton = 0, delta = 0;
unsigned int *fakeKey = NULL;
DBG(10, priv, "\n");
- fakeButton = getWheelButton(pInfo, ds, &fakeKey);
-
- if (!fakeButton && (!fakeKey || !(*fakeKey)))
- return;
+ /* emulate events for left strip */
+ delta = getScrollDelta(ds->stripx, priv->oldStripX, 0, AXIS_INVERT | AXIS_BITWISE);
+ if (delta && IsPad(priv) && priv->oldProximity == ds->proximity)
+ {
+ DBG(10, priv, "Left touch strip scroll delta = %d\n", delta);
+ fakeButton = getWheelButton(delta, priv->striplup, priv->stripldn,
+ priv->strip_keys[0+1], priv->strip_keys[1+1], &fakeKey);
+ sendWheelStripEvent(fakeButton, fakeKey, pInfo, first_val, num_vals, valuators);
+ }
- if (!fakeKey || !(*fakeKey))
+ /* emulate events for right strip */
+ delta = getScrollDelta(ds->stripy, priv->oldStripY, 0, AXIS_INVERT | AXIS_BITWISE);
+ if (delta && IsPad(priv) && priv->oldProximity == ds->proximity)
{
- /* send both button on/off in the same event for pad */
- xf86PostButtonEventP(pInfo->dev, is_absolute(pInfo), fakeButton & AC_CODE,
- 1, first_val, num_vals, VCOPY(valuators, num_vals));
+ DBG(10, priv, "Right touch strip scroll delta = %d\n", delta);
+ fakeButton = getWheelButton(delta, priv->striprup, priv->striprdn,
+ priv->strip_keys[2+1], priv->strip_keys[3+1], &fakeKey);
+ sendWheelStripEvent(fakeButton, fakeKey, pInfo, first_val, num_vals, valuators);
+ }
- xf86PostButtonEventP(pInfo->dev, is_absolute(pInfo), fakeButton & AC_CODE,
- 0, first_val, num_vals, VCOPY(valuators, num_vals));
+ /* emulate events for relative wheel */
+ delta = getScrollDelta(ds->relwheel, 0, 0, 0);
+ if (delta && IsCursor(priv) && priv->oldProximity == ds->proximity)
+ {
+ DBG(10, priv, "Relative wheel scroll delta = %d\n", delta);
+ fakeButton = getWheelButton(delta, priv->relup, priv->reldn,
+ priv->wheel_keys[0+1], priv->wheel_keys[1+1], &fakeKey);
+ sendWheelStripEvent(fakeButton, fakeKey, pInfo, first_val, num_vals, valuators);
}
- else
+
+ /* emulate events for left touch ring */
+ delta = getScrollDelta(ds->abswheel, priv->oldWheel, MAX_PAD_RING, AXIS_INVERT);
+ if (delta && IsPad(priv) && priv->oldProximity == ds->proximity)
{
- sendAction(pInfo, 1, fakeKey, ARRAY_SIZE(priv->wheel_keys[0]),
- first_val, num_vals, valuators);
- sendAction(pInfo, 0, fakeKey, ARRAY_SIZE(priv->wheel_keys[0]),
- first_val, num_vals, valuators);
+ DBG(10, priv, "Left touch wheel scroll delta = %d\n", delta);
+ fakeButton = getWheelButton(delta, priv->wheelup, priv->wheeldn,
+ priv->wheel_keys[2+1], priv->wheel_keys[3+1], &fakeKey);
+ sendWheelStripEvent(fakeButton, fakeKey, pInfo, first_val, num_vals, valuators);
}
}
diff --git a/src/xf86WacomDefs.h b/src/xf86WacomDefs.h
index 1cdfa1a..32b18ee 100644
--- a/src/xf86WacomDefs.h
+++ b/src/xf86WacomDefs.h
@@ -189,6 +189,8 @@ struct _WacomModel
* For backward compability support,
* tablet buttons besides the strips are
* treated as buttons */
+#define AXIS_INVERT 0x01 /* Flag describing an axis which increases "downward" */
+#define AXIS_BITWISE 0x02 /* Flag describing an axis which changes bitwise */
/* get/set/property */
typedef struct _PROPINFO PROPINFO;
diff --git a/test/wacom-tests.c b/test/wacom-tests.c
index d91d9c3..a22c970 100644
--- a/test/wacom-tests.c
+++ b/test/wacom-tests.c
@@ -29,6 +29,88 @@
* change the behaviour.
*/
+static void
+test_get_scroll_delta(void)
+{
+ int test_table[][5] = {
+ { 100, 25, 0, 0, 75}, { 25, 100, 0, 0, -75},
+ {-100, -25, 0, 0, -75}, {-25, -100, 0, 0, 75},
+ { 100, -25, 0, 0, 125}, {-25, 100, 0, 0,-125},
+ { 100, 100, 0, 0, 0}, {-25, -25, 0, 0, 0},
+
+ {23, 0, 50, 0, 23}, {0, 23, 50, 0, -23},
+ {24, 0, 50, 0, 24}, {0, 24, 50, 0, -24},
+ {25, 0, 50, 0, 25}, {0, 25, 50, 0, -25},
+ {26, 0, 50, 0, -25}, {0, 26, 50, 0, 25},
+ {27, 0, 50, 0, -24}, {0, 27, 50, 0, 24},
+ {28, 0, 50, 0, -23}, {0, 28, 50, 0, 23},
+
+ {1024, 0, 0, AXIS_BITWISE, 11}, {0, 1024, 0, AXIS_BITWISE, -11},
+
+ { 0, 4, 256, AXIS_BITWISE, -3}, {4, 0, 256, AXIS_BITWISE, 3},
+ { 1, 4, 256, AXIS_BITWISE, -2}, {4, 1, 256, AXIS_BITWISE, 2},
+ { 2, 4, 256, AXIS_BITWISE, -1}, {4, 2, 256, AXIS_BITWISE, 1},
+ { 4, 4, 256, AXIS_BITWISE, 0}, {4, 4, 256, AXIS_BITWISE, 0},
+ { 8, 4, 256, AXIS_BITWISE, 1}, {4, 8, 256, AXIS_BITWISE, -1},
+ { 16, 4, 256, AXIS_BITWISE, 2}, {4, 16, 256, AXIS_BITWISE, -2},
+ { 32, 4, 256, AXIS_BITWISE, 3}, {4, 32, 256, AXIS_BITWISE, -3},
+ { 64, 4, 256, AXIS_BITWISE, 4}, {4, 64, 256, AXIS_BITWISE, -4},
+ {128, 4, 256, AXIS_BITWISE, 5}, {4, 128, 256, AXIS_BITWISE, -5},
+ {256, 4, 256, AXIS_BITWISE, -4}, {4, 256, 256, AXIS_BITWISE, 4}
+ };
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(test_table); i++)
+ {
+ int delta;
+ int current, old, wrap, flags;
+ current = test_table[i][0];
+ old = test_table[i][1];
+ wrap = test_table[i][2];
+ flags = test_table[i][3];
+
+ delta = getScrollDelta(current, old, wrap, flags);
+ assert(delta == test_table[i][4]);
+
+ flags |= AXIS_INVERT;
+ delta = getScrollDelta(current, old, wrap, flags);
+ assert(delta == -1 * test_table[i][4]);
+ }
+}
+
+static void
+test_get_wheel_button(void)
+{
+ int delta;
+ int button_up, button_dn, action_up, action_dn;
+
+ button_up = 100;
+ button_dn = 200;
+ action_up = 300;
+ action_dn = 400;
+
+ for (delta = -32; delta <= 32; delta++)
+ {
+ int *action;
+ int result = getWheelButton(delta, button_up, button_dn, &action_up, &action_dn, &action);
+ if (delta < 0)
+ {
+ assert(result == button_dn);
+ assert(action == &action_dn);
+ }
+ else if (delta == 0)
+ {
+ assert(result == 0);
+ assert(action == NULL);
+ }
+ else
+ {
+ assert(result == button_up);
+ assert(action == &action_up);
+ }
+ }
+}
+
/**
* Test refcounting of the common struct.
*/
@@ -552,6 +634,8 @@ int main(int argc, char** argv)
test_mod_buttons();
test_set_type();
test_flag_set();
+ test_get_scroll_delta();
+ test_get_wheel_button();
return 0;
}