Skip to content

Commit

Permalink
Implement smooth panscrolling
Browse files Browse the repository at this point in the history
  • Loading branch information
Greenscreener authored and whot committed Nov 23, 2022
1 parent 2a9e595 commit fe923e9
Show file tree
Hide file tree
Showing 8 changed files with 117 additions and 37 deletions.
11 changes: 10 additions & 1 deletion src/WacomInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,10 @@ enum WacomAxisType {
WACOM_AXIS_WHEEL = (1 << 9), /* Artpen rotation or airbrush wheel */
WACOM_AXIS_RING = (1 << 10),
WACOM_AXIS_RING2 = (1 << 11),
WACOM_AXIS_SCROLL_X = (1 << 12),
WACOM_AXIS_SCROLL_Y = (1 << 13),

_WACOM_AXIS_LAST = WACOM_AXIS_RING2,
_WACOM_AXIS_LAST = WACOM_AXIS_SCROLL_Y,
};

typedef struct {
Expand All @@ -77,6 +79,7 @@ typedef struct {
int throttle;
int wheel;
int ring, ring2;
int scroll_x, scroll_y;
} WacomAxisData;


Expand Down Expand Up @@ -163,6 +166,8 @@ static inline void wcmAxisSet(WacomAxisData *data,
case WACOM_AXIS_WHEEL: data->wheel = value; break;
case WACOM_AXIS_RING: data->ring = value; break;
case WACOM_AXIS_RING2: data->ring2 = value; break;
case WACOM_AXIS_SCROLL_X: data->scroll_x = value; break;
case WACOM_AXIS_SCROLL_Y: data->scroll_y = value; break;
default:
abort();
}
Expand All @@ -187,6 +192,8 @@ static inline bool wcmAxisGet(const WacomAxisData *data,
case WACOM_AXIS_WHEEL: *value_out = data->wheel; break;
case WACOM_AXIS_RING: *value_out = data->ring; break;
case WACOM_AXIS_RING2: *value_out = data->ring2; break;
case WACOM_AXIS_SCROLL_X: *value_out = data->scroll_x; break;
case WACOM_AXIS_SCROLL_Y: *value_out = data->scroll_y; break;
default:
abort();
}
Expand Down Expand Up @@ -224,6 +231,8 @@ static inline const char* wcmAxisName(enum WacomAxisType which)
case WACOM_AXIS_WHEEL: return "wheel";
case WACOM_AXIS_RING: return "ring";
case WACOM_AXIS_RING2: return "ring2";
case WACOM_AXIS_SCROLL_X: return "scroll-x";
case WACOM_AXIS_SCROLL_Y: return "scroll-y";
default:
abort();
}
Expand Down
5 changes: 4 additions & 1 deletion src/gwacom/wacom-device.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,10 @@ typedef enum {
WAXIS_WHEEL = (1 << 9),
WAXIS_RING = (1 << 10),
WAXIS_RING2 = (1 << 11),
WAXIS_SCROLL_X = (1 << 12),
WAXIS_SCROLL_Y = (1 << 13),

_WAXIS_LAST = WAXIS_RING2,
_WAXIS_LAST = WAXIS_SCROLL_Y,
} WacomEventAxis;

/* The pointer argument to all the event signals. If the mask is set for
Expand All @@ -124,6 +126,7 @@ typedef struct {
int throttle;
int wheel;
int ring, ring2;
int scroll_x, scroll_y;
} WacomEventData;

#define WACOM_TYPE_EVENT_DATA (wacom_event_data_get_type())
Expand Down
35 changes: 6 additions & 29 deletions src/wcmCommon.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,38 +95,17 @@ Bool wcmDevSwitchModeCall(WacomDevicePtr priv, Bool absolute)
return TRUE;
}


static int wcmButtonPerNotch(WacomDevicePtr priv, int value, int threshold, int btn_positive, int btn_negative)
{
int mode = is_absolute(priv);
int notches = value / threshold;
int button = (notches > 0) ? btn_positive : btn_negative;
int i;
WacomAxisData axes = {0};

for (i = 0; i < abs(notches); i++) {
wcmEmitButton(priv, mode, button, 1, &axes);
wcmEmitButton(priv, mode, button, 0, &axes);
}

return value % threshold;
}

static void wcmPanscroll(WacomDevicePtr priv, const WacomDeviceState *ds, int x, int y)
{
WacomCommonPtr common = priv->common;
int threshold = common->wcmPanscrollThreshold;
int *accumulated_x, *accumulated_y;
int delta_x, delta_y;

if (!(priv->flags & SCROLLMODE_FLAG) || !(ds->buttons & 1))
return;

/* Tip has gone down down; store state for dragging */
/* Tip has gone down down; don't send pan event yet */
if (!(priv->oldState.buttons & 1)) {
priv->wcmPanscrollState = *ds;
priv->wcmPanscrollState.x = 0;
priv->wcmPanscrollState.y = 0;
return;
}

Expand All @@ -139,15 +118,13 @@ static void wcmPanscroll(WacomDevicePtr priv, const WacomDeviceState *ds, int x,
delta_y = (y - priv->oldState.y);
}

accumulated_x = &priv->wcmPanscrollState.x;
accumulated_y = &priv->wcmPanscrollState.y;
*accumulated_x += delta_x;
*accumulated_y += delta_y;

DBG(6, priv, "pan x = %d, pan y = %d\n", *accumulated_x, *accumulated_y);
DBG(6, priv, "pan x = %d, pan y = %d\n", delta_x, delta_y);

*accumulated_x = wcmButtonPerNotch(priv, *accumulated_x, threshold, 6, 7);
*accumulated_y = wcmButtonPerNotch(priv, *accumulated_y, threshold, 4, 5);
WacomAxisData axes = {0};
wcmAxisSet(&axes, WACOM_AXIS_SCROLL_X, -delta_x * PANSCROLL_INCREMENT/threshold);
wcmAxisSet(&axes, WACOM_AXIS_SCROLL_Y, -delta_y * PANSCROLL_INCREMENT/threshold);
wcmEmitMotion(priv, FALSE, &axes);
}

void wcmResetButtonAction(WacomDevicePtr priv, int button)
Expand Down
15 changes: 13 additions & 2 deletions src/wcmConfig.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ WacomDevicePtr wcmAllocate(void *frontend, const char *name)
priv->touch_timer = wcmTimerNew();

/* reusable valuator mask */
priv->valuator_mask = valuator_mask_new(7);
priv->valuator_mask = valuator_mask_new(8);

return priv;

Expand Down Expand Up @@ -1220,6 +1220,14 @@ static int wcmInitAxes(WacomDevicePtr priv)
wcmInitAxis(priv, WACOM_AXIS_RING2, min, max, res);
}

if (IsPen(priv)) {
/* seventh valuator: scroll_x */
wcmInitAxis(priv, WACOM_AXIS_SCROLL_X, -1, -1, 0);

/* eighth valuator: scroll_y */
wcmInitAxis(priv, WACOM_AXIS_SCROLL_Y, -1, -1, 0);
}

return TRUE;
}

Expand All @@ -1232,14 +1240,17 @@ Bool wcmDevInit(WacomDevicePtr priv)
if (priv->common->wcmModel->DetectConfig)
priv->common->wcmModel->DetectConfig (priv);

nbaxes = priv->naxes; /* X, Y, Pressure, Tilt-X, Tilt-Y, Wheel */
nbaxes = priv->naxes; /* X, Y, Pressure, Tilt-X, Tilt-Y, Wheel, Scroll-X, Scroll-Y */
if (!nbaxes || nbaxes > 6)
nbaxes = priv->naxes = 6;
nbbuttons = priv->nbuttons; /* Use actual number of buttons, if possible */

if (IsPad(priv) && TabletHasFeature(priv->common, WCM_DUALRING))
nbaxes = priv->naxes = nbaxes + 1; /* ABS wheel 2 */

if (IsPen(priv))
nbaxes = priv->naxes = nbaxes + 2; /* Scroll X and Y */

/* if more than 3 buttons, offset by the four scroll buttons,
* otherwise, alloc 7 buttons for scroll wheel. */
nbbuttons = min(max(nbbuttons + 4, 7), WCM_MAX_BUTTONS);
Expand Down
25 changes: 21 additions & 4 deletions src/x11/xf86Wacom.c
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,8 @@ valuatorNumber(enum WacomAxisType which)
case WACOM_AXIS_WHEEL: pos = 5; break;
case WACOM_AXIS_RING: pos = 5; break;
case WACOM_AXIS_RING2: pos = 6; break;
case WACOM_AXIS_SCROLL_X: pos = 6; break;
case WACOM_AXIS_SCROLL_Y: pos = 7; break;
break;
default:
abort();
Expand Down Expand Up @@ -518,15 +520,28 @@ void wcmInitAxis(WacomDevicePtr priv, enum WacomAxisType type,
break;
case WACOM_AXIS_RING2:
break;
case WACOM_AXIS_SCROLL_X:
label = XIGetKnownProperty(AXIS_LABEL_PROP_REL_HSCROLL);
break;
case WACOM_AXIS_SCROLL_Y:
label = XIGetKnownProperty(AXIS_LABEL_PROP_REL_VSCROLL);
break;

default:
abort();
}

index = valuatorNumber(type);
InitValuatorAxisStruct(pInfo->dev, index,
label,
min, max, res, min_res, max_res,
Absolute);
label,
min, max, res, min_res, max_res,
Absolute);

if (type == WACOM_AXIS_SCROLL_X)
SetScrollValuator(pInfo->dev, index, SCROLL_TYPE_HORIZONTAL, PANSCROLL_INCREMENT, 0);
else if (type == WACOM_AXIS_SCROLL_Y)
SetScrollValuator(pInfo->dev, index, SCROLL_TYPE_VERTICAL, PANSCROLL_INCREMENT, 0);

}

bool wcmInitButtons(WacomDevicePtr priv, unsigned int nbuttons)
Expand Down Expand Up @@ -1119,7 +1134,7 @@ valuator_mask_get(const ValuatorMask *mask, int valuator)
TEST_CASE(test_convert_axes)
{
WacomAxisData axes = {0};
ValuatorMask *mask = valuator_mask_new(7);
ValuatorMask *mask = valuator_mask_new(8);

convertAxes(&axes, mask);
assert(valuator_mask_num_valuators(mask) == 0);
Expand Down Expand Up @@ -1165,6 +1180,7 @@ TEST_CASE(test_convert_axes)
assert(valuator_mask_isset(mask, 5));
assert(valuator_mask_get(mask, 5) == 2);
assert(!valuator_mask_isset(mask, 6));
assert(!valuator_mask_isset(mask, 7));

memset(&axes, 0, sizeof(axes));
valuator_mask_zero(mask);
Expand Down Expand Up @@ -1195,6 +1211,7 @@ TEST_CASE(test_convert_axes)
assert(valuator_mask_get(mask, 5) == 2);
assert(!valuator_mask_isset(mask, 6));
assert(!valuator_mask_isset(mask, 7));
assert(!valuator_mask_isset(mask, 8));

free(mask);
}
Expand Down
5 changes: 5 additions & 0 deletions src/xf86WacomDefs.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,11 @@
#define BTN_STYLUS3 0x149
#endif

/* This value is arbitrary, but low enough values can cause integer division to round
* non-zero numbers to zero. See https://github.com/linuxwacom/xf86-input-wacom/pull/222#discussion_r927920625.
*/
#define PANSCROLL_INCREMENT 0xffff

/******************************************************************************
* Forward Declarations
*****************************************************************************/
Expand Down
56 changes: 56 additions & 0 deletions test/test_wacom.py
Original file line number Diff line number Diff line change
Expand Up @@ -327,4 +327,60 @@ def test_axis_updates_wheel(mainloop, opts, stylus_type):
assert first_wheel == current_wheel


def test_scroll(mainloop, opts):
"""
Check panscrolling works correctly
"""
dev = Device.from_name("PTH660", "Pen")
opts["PanScrollThreshold"] = "150"

prox_in = [
Sev("ABS_X", 50),
Sev("ABS_Y", 50),
Sev("BTN_TOOL_PEN", 1),
Sev("SYN_REPORT", 0),
]

prox_out = [
Sev("BTN_TOOL_PEN", 0),
Sev("SYN_REPORT", 0),
]

press_button2 = [
Sev("BTN_STYLUS", 1),
Sev("SYN_REPORT", 0),
]

touchdown_pen = [
Sev("BTN_TOUCH", 1),
Sev("ABS_PRESSURE", 20),
Sev("SYN_REPORT", 0),
]

move_pen_x = [Sev("ABS_X", 75), Sev("SYN_REPORT", 0)]

up_pen = [Sev("BTN_TOUCH", 0), Sev("ABS_PRESSURE", 0), Sev("SYN_REPORT", 0)]

depress_button2 = [Sev("BTN_STYLUS", 0), Sev("SYN_REPORT", 0)]

monitor = Monitor.new_from_device(dev, opts)
monitor.wacom_device.set_runtime_option("PanButton", "2")

monitor.write_events(prox_in)
monitor.write_events(press_button2)
monitor.write_events(touchdown_pen) # Pen touchdown
monitor.write_events(move_pen_x) # Move pen 25% towards positive x
monitor.write_events(up_pen) # Pen up
monitor.write_events(depress_button2) # Depress button2
monitor.write_events(prox_out)

mainloop.run()
have_we_scrolled = False
for event in monitor.events:
if event.axes.scroll_x != 0:
assert event.axes.scroll_x == -1223320
have_we_scrolled = True
assert have_we_scrolled


# vim: set expandtab tabstop=4 shiftwidth=4:
2 changes: 2 additions & 0 deletions tools/wacom-record.c
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,8 @@ static void device_added(WacomDriver *driver, WacomDevice *device)
case WAXIS_WHEEL: typestr = "wheel"; break;
case WAXIS_RING: typestr = "ring"; break;
case WAXIS_RING2: typestr = "ring2"; break;
case WAXIS_SCROLL_X: typestr = "scroll_x"; break;
case WAXIS_SCROLL_Y: typestr = "scroll_y"; break;
}

printf(" - {type: %-12s, range: [%5d, %5d], resolution: %5d}\n",
Expand Down

0 comments on commit fe923e9

Please sign in to comment.