diff options
-rw-r--r-- | include/Xwacom.h | 1 | ||||
-rw-r--r-- | include/wacom-properties.h | 3 | ||||
-rw-r--r-- | man/wacom.man | 7 | ||||
-rw-r--r-- | man/xsetwacom.man | 14 | ||||
-rw-r--r-- | src/wcmCommon.c | 90 | ||||
-rw-r--r-- | src/wcmValidateDevice.c | 3 | ||||
-rw-r--r-- | src/wcmXCommand.c | 21 | ||||
-rw-r--r-- | src/xf86WacomDefs.h | 3 | ||||
-rw-r--r-- | tools/xsetwacom.c | 26 |
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); } |