diff options
author | Jason Gerecke <killertofu@gmail.com> | 2011-12-21 09:26:46 -0800 |
---|---|---|
committer | Jason Gerecke <killertofu@gmail.com> | 2011-12-29 11:23:31 -0800 |
commit | 477a261ef79172d6378613fc4cab0026ed49d02f (patch) | |
tree | 2dac1d22fecdd796b390c264950ee9ac7482d4b4 | |
parent | a60e59a4730d6a11f999085aa8754fd0de5dfbaf (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.c | 177 | ||||
-rw-r--r-- | src/xf86WacomDefs.h | 2 | ||||
-rw-r--r-- | test/wacom-tests.c | 84 |
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; } |