summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Gerecke <killertofu@gmail.com>2017-10-24 08:44:34 -0700
committerJason Gerecke <killertofu@gmail.com>2018-01-04 15:21:22 -0800
commit21f498ef8b4ac826c6873ce9d54edcee313a0844 (patch)
treeebfb00a69c5f8ddd0088bb1715db551d42edb10b
parent36ec4c098a89170f5f76d8e0ad250f9d6405a69f (diff)
downloadxf86-input-wacom-21f498ef8b4ac826c6873ce9d54edcee313a0844.tar.gz
Implement "pan" scrolling functionality
When enabled through `xsetwacom set <id> button <n> pan`, this causes the driver to appear to "drag" scrollable window contents by emitting appropriate scroll events as the pen is dragged around. Signed-off-by: Jason Gerecke <jason.gerecke@wacom.com> Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
-rw-r--r--include/Xwacom.h1
-rw-r--r--include/wacom-properties.h3
-rw-r--r--man/wacom.man7
-rw-r--r--man/xsetwacom.man14
-rw-r--r--src/wcmCommon.c90
-rw-r--r--src/wcmValidateDevice.c3
-rw-r--r--src/wcmXCommand.c21
-rw-r--r--src/xf86WacomDefs.h3
-rw-r--r--tools/xsetwacom.c26
9 files changed, 161 insertions, 7 deletions
diff --git a/include/Xwacom.h b/include/Xwacom.h
index 49489ff..c2af381 100644
--- a/include/Xwacom.h
+++ b/include/Xwacom.h
@@ -60,6 +60,7 @@
#define AC_MODETOGGLE 0x00020000 /* Toggle absolute/relative mode */
#define AC_DBLCLICK 0x00030000 /* DEPRECATED: use two button events instead */
#define AC_DISPLAYTOGGLE 0x00040000 /* DEPRECATED: has no effect (used to toggle among screens) */
+#define AC_PANSCROLL 0x00050000 /* Enter/exit panscroll mode */
#define AC_BUTTON 0x00080000 /* Emit button events */
#define AC_TYPE 0x000f0000 /* The mask to isolate event type bits */
#define AC_KEYBTNPRESS 0x00100000 /* bit set for key/button presses */
diff --git a/include/wacom-properties.h b/include/wacom-properties.h
index b845083..0796ab0 100644
--- a/include/wacom-properties.h
+++ b/include/wacom-properties.h
@@ -111,6 +111,9 @@
*/
#define WACOM_PROP_PRESSURE_RECAL "Wacom Pressure Recalibration"
+/* 32 bit, 1 values */
+#define WACOM_PROP_PANSCROLL_THRESHOLD "Wacom Panscroll Threshold"
+
/* The following are tool types used by the driver in WACOM_PROP_TOOL_TYPE
* or in the 'type' field for XI1 clients. Clients may check for one of
* these types to identify tool types.
diff --git a/man/wacom.man b/man/wacom.man
index 3693c94..3e9c7bd 100644
--- a/man/wacom.man
+++ b/man/wacom.man
@@ -277,6 +277,13 @@ initial pressure reading may be unequal to zero even for a perfectly
good pen. If the consecutive pressure readings are not higher than
the initial pressure by a threshold no button event will be generated.
This option allows to disable the recalibration.
+.TP 4
+.B Option \fI"PanScrollThreshold"\fP \fI"number"\fP
+Specifies the distance the pen must move (in tablet units) before a
+scroll event is generated when using the "pan" action. Smaller values
+will require less distance and be more sensitive. Larger values will
+require more distance and be less sensitive. Default: 1300 or 2600
+depending on tablet resolution (corresponds to 13 mm of distance).
.RE
.SH "TOUCH GESTURES"
.SS Single finger (1FG)
diff --git a/man/xsetwacom.man b/man/xsetwacom.man
index 234e9ba..6e82301 100644
--- a/man/xsetwacom.man
+++ b/man/xsetwacom.man
@@ -134,6 +134,13 @@ numbers.
The "modetoggle" keyword is also recognized; it takes no arguments,
and toggles the device mode between relative and absolute pointer tracking.
+The "pan" keyword causes the driver to send scroll events while the pen
+is dragged. This makes it easy to scroll through lists and documents,
+pan around 2D canvases, and zoom in/out of 3D scenes (exact behavior
+depends on application interpretation of scrollwheel events). Dragging
+the pen up/down will send scrollwheel down/up events; dragging it left/right
+will send scrollwheel right/left events.
+
The events in the action mapping are sent when the physical button is pressed.
If the action mapping leaves any buttons or keys pressed (such as a modifier
key), they will be released when the physical button is released.
@@ -273,6 +280,13 @@ initial pressure reading may be unequal to zero even for a perfectly
good pen. If the consecutive pressure readings are not higher than
the initial pressure by a threshold no button event will be generated.
This option allows to disable the recalibration. Default: on
+.TP
+\fBPanScrollThreshold\fR distance
+This specifies the distance the pen must move (in tablet units) before
+a scroll event is generated when using the "pan" action. Smaller values
+will require less distance and be more sensitive. Larger values will
+require more distance and be less sensitive. Default: 1300 or 2600
+depending on tablet resolution (corresponds to 13 mm of distance).
.SH "AUTHORS"
diff --git a/src/wcmCommon.c b/src/wcmCommon.c
index 595c933..e56045a 100644
--- a/src/wcmCommon.c
+++ b/src/wcmCommon.c
@@ -88,6 +88,50 @@ void set_absolute(InputInfoPtr pInfo, Bool absolute)
priv->flags &= ~ABSOLUTE_FLAG;
}
+static int wcmButtonPerNotch(WacomDevicePtr priv, int value, int threshold, int btn_positive, int btn_negative)
+{
+ int mode = is_absolute(priv->pInfo);
+ int notches = value / threshold;
+ int button = (notches > 0) ? btn_positive : btn_negative;
+ int i;
+
+ for (i = 0; i < abs(notches); i++) {
+ xf86PostButtonEventP(priv->pInfo->dev, mode, button, 1, 0, 0, 0);
+ xf86PostButtonEventP(priv->pInfo->dev, mode, button, 0, 0, 0, 0);
+ }
+
+ return value % threshold;
+}
+
+static void wcmPanscroll(WacomDevicePtr priv, const WacomDeviceState *ds)
+{
+ WacomCommonPtr common = priv->common;
+ int threshold = common->wcmPanscrollThreshold;
+ int *accumulated_x, *accumulated_y;
+
+ if (!(priv->flags & SCROLLMODE_FLAG) || !(ds->buttons & 1))
+ return;
+
+ /* Tip has gone down down; store state for dragging */
+ if (!(priv->oldState.buttons & 1)) {
+ priv->wcmPanscrollState = *ds;
+ priv->wcmPanscrollState.x = 0;
+ priv->wcmPanscrollState.y = 0;
+ return;
+ }
+
+ accumulated_x = &priv->wcmPanscrollState.x;
+ accumulated_y = &priv->wcmPanscrollState.y;
+
+ *accumulated_x += (ds->x - priv->oldState.x);
+ *accumulated_y += (ds->y - priv->oldState.y);
+
+ DBG(6, priv, "pan x = %d, pan y = %d\n", *accumulated_x, *accumulated_y);
+
+ *accumulated_x = wcmButtonPerNotch(priv, *accumulated_x, threshold, 6, 7);
+ *accumulated_y = wcmButtonPerNotch(priv, *accumulated_y, threshold, 4, 5);
+}
+
/*****************************************************************************
* wcmSendButtons --
* Send button events by comparing the current button mask with the
@@ -169,6 +213,7 @@ static void sendAction(InputInfoPtr pInfo, const WacomDeviceState* ds,
int press, unsigned int *keys, int nkeys,
int first_val, int num_val, int *valuators)
{
+ WacomDevicePtr priv = (WacomDevicePtr) pInfo->private;
int i;
/* Actions only trigger on press, not release */
@@ -185,10 +230,15 @@ static void sendAction(InputInfoPtr pInfo, const WacomDeviceState* ds,
{
int btn_no = (action & AC_CODE);
int is_press = (action & AC_KEYBTNPRESS);
- xf86PostButtonEventP(pInfo->dev,
- is_absolute(pInfo), btn_no,
- is_press, first_val, num_val,
- VCOPY(valuators, num_val));
+ if (btn_no == 1 && (priv->flags & SCROLLMODE_FLAG)) {
+ /* Don't send clicks in scroll mode */
+ }
+ else {
+ xf86PostButtonEventP(pInfo->dev,
+ is_absolute(pInfo), btn_no,
+ is_press, first_val, num_val,
+ VCOPY(valuators, num_val));
+ }
}
break;
case AC_KEY:
@@ -203,6 +253,12 @@ static void sendAction(InputInfoPtr pInfo, const WacomDeviceState* ds,
wcmDevSwitchModeCall(pInfo,
(is_absolute(pInfo)) ? Relative : Absolute); /* not a typo! */
break;
+ case AC_PANSCROLL:
+ priv->flags |= SCROLLMODE_FLAG;
+ priv->wcmPanscrollState = *ds;
+ priv->wcmPanscrollState.x = 0;
+ priv->wcmPanscrollState.y = 0;
+ break;
}
}
@@ -239,8 +295,11 @@ static void sendAction(InputInfoPtr pInfo, const WacomDeviceState* ds,
if (countPresses(key_code, &keys[i], nkeys - i))
wcmEmitKeycode(pInfo->dev, key_code, 0);
}
+ break;
+ case AC_PANSCROLL:
+ priv->flags &= ~SCROLLMODE_FLAG;
+ break;
}
-
}
}
@@ -427,6 +486,9 @@ static void sendCommonEvents(InputInfoPtr pInfo, const WacomDeviceState* ds,
WacomDevicePtr priv = (WacomDevicePtr) pInfo->private;
int buttons = ds->buttons;
+ /* send scrolling events if necessary */
+ wcmPanscroll(priv, ds);
+
/* send button events when state changed or first time in prox and button unpresses */
if (priv->oldState.buttons != buttons || (!priv->oldState.proximity && !buttons))
wcmSendButtons(pInfo, ds, buttons, first_val, num_vals, valuators);
@@ -567,7 +629,8 @@ wcmSendNonPadEvents(InputInfoPtr pInfo, const WacomDeviceState *ds,
VCOPY(valuators, num_vals));
/* Move the cursor to where it should be before sending button events */
- if(!(priv->flags & BUTTONS_ONLY_FLAG))
+ if(!(priv->flags & BUTTONS_ONLY_FLAG) &&
+ !(priv->flags & SCROLLMODE_FLAG && priv->oldState.buttons & 1))
{
xf86PostMotionEventP(pInfo->dev, is_absolute(pInfo),
first_val, num_vals,
@@ -649,6 +712,10 @@ void wcmSendEvents(InputInfoPtr pInfo, const WacomDeviceState* ds)
ty = ds->stripy;
}
+ /* cancel panscroll */
+ if (!ds->proximity)
+ priv->flags &= ~SCROLLMODE_FLAG;
+
DBG(7, priv, "[%s] o_prox=%s x=%d y=%d z=%d "
"b=%s b=%d tx=%d ty=%d wl=%d wl2=%d rot=%d th=%d\n",
pInfo->type_name,
@@ -1361,6 +1428,16 @@ int wcmInitTablet(InputInfoPtr pInfo, const char* id, float version)
pInfo->name, common->wcmThreshold);
}
+ /* Calculate default panscroll threshold if not set */
+ xf86Msg(X_CONFIG, "%s: panscroll is %d\n", pInfo->name, common->wcmPanscrollThreshold);
+ if (common->wcmPanscrollThreshold < 1) {
+ common->wcmPanscrollThreshold = common->wcmResolY * 13 / 1000; /* 13mm */
+ }
+ if (common->wcmPanscrollThreshold < 1) {
+ common->wcmPanscrollThreshold = 1000;
+ }
+ xf86Msg(X_CONFIG, "%s: panscroll modified to %d\n", pInfo->name, common->wcmPanscrollThreshold);
+
/* output tablet state as probed */
if (IsPen(priv))
xf86Msg(X_PROBED, "%s: maxX=%d maxY=%d maxZ=%d "
@@ -1473,6 +1550,7 @@ WacomCommonPtr wcmNewCommon(void)
/* transmit position if increment is superior */
common->wcmRawSample = DEFAULT_SAMPLES;
/* number of raw data to be used to for filtering */
+ common->wcmPanscrollThreshold = 0;
common->wcmPressureRecalibration = 1;
return common;
}
diff --git a/src/wcmValidateDevice.c b/src/wcmValidateDevice.c
index 21ccd5f..486235b 100644
--- a/src/wcmValidateDevice.c
+++ b/src/wcmValidateDevice.c
@@ -912,6 +912,9 @@ Bool wcmPreInitParseOptions(InputInfoPtr pInfo, Bool is_primary,
tool = priv->tool;
tool->serial = priv->serial;
+ common->wcmPanscrollThreshold = xf86SetIntOption(pInfo->options, "PanScrollThreshold",
+ common->wcmPanscrollThreshold);
+
/* The first device doesn't need to add any tools/areas as it
* will be the first anyway. So if different, add tool
* and/or area to the existing lists
diff --git a/src/wcmXCommand.c b/src/wcmXCommand.c
index e18fb8f..63d1b3d 100644
--- a/src/wcmXCommand.c
+++ b/src/wcmXCommand.c
@@ -99,6 +99,7 @@ static Atom prop_tooltype;
static Atom prop_btnactions;
static Atom prop_product_id;
static Atom prop_pressure_recal;
+static Atom prop_panscroll_threshold;
#ifdef DEBUG
static Atom prop_debuglevels;
#endif
@@ -336,6 +337,9 @@ void InitWcmDeviceProperties(InputInfoPtr pInfo)
XA_INTEGER, 8, 1, values);
}
+ values[0] = common->wcmPanscrollThreshold;
+ prop_panscroll_threshold = InitWcmAtom(pInfo->dev, WACOM_PROP_PANSCROLL_THRESHOLD, XA_INTEGER, 32, 1, values);
+
values[0] = common->vendor_id;
values[1] = common->tablet_id;
prop_product_id = InitWcmAtom(pInfo->dev, XI_PROP_PRODUCT_ID, XA_INTEGER, 32, 2, values);
@@ -455,6 +459,8 @@ static int wcmCheckActionProperty(WacomDevicePtr priv, Atom property, XIProperty
break;
case AC_MODETOGGLE:
break;
+ case AC_PANSCROLL:
+ break;
default:
DBG(3, priv, "ERROR: Unknown command\n");
return BadValue;
@@ -972,6 +978,21 @@ int wcmSetProperty(DeviceIntPtr dev, Atom property, XIPropertyValuePtr prop,
if (!checkonly)
common->wcmPressureRecalibration = values[0];
+ } else if (property == prop_panscroll_threshold)
+ {
+ CARD32 *values = (CARD32*)prop->data;
+
+ if (prop->size != 1 || prop->format != 32)
+ return BadValue;
+
+ if (values[0] <= 0)
+ return BadValue;
+
+ if (IsTouch(priv))
+ return BadMatch;
+
+ if (!checkonly)
+ common->wcmPanscrollThreshold = values[0];
} else
{
Atom *handler = NULL;
diff --git a/src/xf86WacomDefs.h b/src/xf86WacomDefs.h
index a772597..a2053a8 100644
--- a/src/xf86WacomDefs.h
+++ b/src/xf86WacomDefs.h
@@ -175,6 +175,7 @@ struct _WacomModel
#define ABSOLUTE_FLAG 0x00000100
#define BAUD_19200_FLAG 0x00000400
#define BUTTONS_ONLY_FLAG 0x00000800
+#define SCROLLMODE_FLAG 0x00001000
#define IsCursor(priv) (DEVICE_ID((priv)->flags) == CURSOR_ID)
#define IsStylus(priv) (DEVICE_ID((priv)->flags) == STYLUS_ID)
@@ -288,6 +289,7 @@ struct _WacomDeviceRec
WacomCommonPtr common; /* common info pointer */
/* state fields in device coordinates */
+ struct _WacomDeviceState wcmPanscrollState; /* panscroll state tracking */
struct _WacomDeviceState oldState; /* previous state information */
int oldCursorHwProx; /* previous cursor hardware proximity */
@@ -467,6 +469,7 @@ struct _WacomCommonRec
int wcmRawSample; /* Number of raw data used to filter an event */
int wcmPressureRecalibration; /* Determine if pressure recalibration of
worn pens should be performed */
+ int wcmPanscrollThreshold; /* distance pen must move to send a panscroll event */
int bufpos; /* position with buffer */
unsigned char buffer[BUFFER_SIZE]; /* data read from device */
diff --git a/tools/xsetwacom.c b/tools/xsetwacom.c
index c098b5f..e2810a0 100644
--- a/tools/xsetwacom.c
+++ b/tools/xsetwacom.c
@@ -472,6 +472,15 @@ static param_t parameters[] =
.prop_flags = PROP_FLAG_BOOLEAN
},
{
+ .name = "PanScrollThreshold",
+ .x11name = "PanScrollThreshold",
+ .desc = "Adjusts distance required for pan actions to generate a scroll event",
+ .prop_name = WACOM_PROP_PANSCROLL_THRESHOLD,
+ .prop_format = 32,
+ .prop_offset = 0,
+ .arg_count = 1,
+ },
+ {
.name = "MapToOutput",
.desc = "Map the device to the given output. ",
.set_func = set_output,
@@ -1011,6 +1020,7 @@ static int special_map_button(Display *dpy, int argc, char **argv, unsigned long
static int special_map_core(Display *dpy, int argc, char **argv, unsigned long *ndata, unsigned long *data, const size_t size);
static int special_map_modetoggle(Display *dpy, int argc, char **argv, unsigned long *ndata, unsigned long *data, const size_t size);
static int special_map_displaytoggle(Display *dpy, int argc, char **argv, unsigned long *ndata, unsigned long *data, const size_t size);
+static int special_map_panscroll(Display *dpy, int argc, char **argv, unsigned long *ndata, unsigned long *data, const size_t size);
/* Valid keywords for the --set ButtonX options */
static struct keywords {
@@ -1022,6 +1032,7 @@ static struct keywords {
{"core", special_map_core},
{"modetoggle", special_map_modetoggle},
{"displaytoggle", special_map_displaytoggle},
+ {"pan", special_map_panscroll},
{ NULL, NULL }
};
@@ -1066,6 +1077,19 @@ static int special_map_displaytoggle(Display *dpy, int argc, char **argv, unsign
return 0;
}
+static int special_map_panscroll(Display *dpy, int argc, char **argv, unsigned long *ndata, unsigned long *data, const size_t size)
+{
+ if (*ndata + 1 > size) {
+ fprintf(stderr, "Insufficient space to store all commands.\n");
+ return 0;
+ }
+ data[*ndata] = AC_PANSCROLL;
+
+ *ndata += 1;
+
+ return 0;
+}
+
static inline int is_valid_keyword(const char *keyword)
{
struct keywords *kw = keywords;
@@ -2978,7 +3002,7 @@ static void test_parameter_number(void)
* deprecated them.
* Numbers include trailing NULL entry.
*/
- assert(ARRAY_SIZE(parameters) == 39);
+ assert(ARRAY_SIZE(parameters) == 40);
assert(ARRAY_SIZE(deprecated_parameters) == 17);
}