1 /*
2 * Copyright 1995-2002 by Frederic Lepied, France. <Lepied@XFree86.org>
3 * Copyright 2002-2010 by Ping Cheng, Wacom. <pingc@wacom.com>
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #include "xf86Wacom.h"
25 #include "Xwacom.h"
26 #include "wcmFilter.h"
27 #include "wcmTouchFilter.h"
28 #include <xkbsrv.h>
29 #include <xf86_OSproc.h>
30
31
32 struct _WacomDriverRec WACOM_DRIVER = {
33 .active = NULL,
34 };
35
36 /* X servers pre 1.9 didn't copy data passed into xf86Post*Event.
37 * Data passed in would be modified, requiring the driver to copy the
38 * data beforehand.
39 */
40 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 11
41 static int v[MAX_VALUATORS];
VCOPY(const int * valuators,int nvals)42 static int *VCOPY(const int *valuators, int nvals)
43 {
44 memcpy(v, valuators, nvals * sizeof(int));
45 return v;
46 }
47 #else /* ABI >= 11 */
48 #define VCOPY(vals, nval) (vals)
49 #endif
50
51
52
53 /*****************************************************************************
54 * Static functions
55 ****************************************************************************/
56
57 static int applyPressureCurve(WacomDevicePtr pDev, const WacomDeviceStatePtr pState);
58 static void commonDispatchDevice(InputInfoPtr pInfo,
59 const WacomChannelPtr pChannel);
60 static void sendAButton(InputInfoPtr pInfo, const WacomDeviceState* ds, int button,
61 int mask, int first_val, int num_vals, int *valuators);
62
63 /*****************************************************************************
64 * Utility functions
65 ****************************************************************************/
66
67 /**
68 * @return TRUE if the device is set to abolute mode, or FALSE otherwise
69 */
is_absolute(InputInfoPtr pInfo)70 Bool is_absolute(InputInfoPtr pInfo)
71 {
72 WacomDevicePtr priv = (WacomDevicePtr)pInfo->private;
73 return !!(priv->flags & ABSOLUTE_FLAG);
74 }
75
76 /**
77 * Set the device to absolute or relative mode
78 *
79 * @param absolute TRUE to set the device to absolute mode.
80 */
set_absolute(InputInfoPtr pInfo,Bool absolute)81 void set_absolute(InputInfoPtr pInfo, Bool absolute)
82 {
83 WacomDevicePtr priv = (WacomDevicePtr)pInfo->private;
84
85 if (absolute)
86 priv->flags |= ABSOLUTE_FLAG;
87 else
88 priv->flags &= ~ABSOLUTE_FLAG;
89 }
90
wcmButtonPerNotch(WacomDevicePtr priv,int value,int threshold,int btn_positive,int btn_negative)91 static int wcmButtonPerNotch(WacomDevicePtr priv, int value, int threshold, int btn_positive, int btn_negative)
92 {
93 int mode = is_absolute(priv->pInfo);
94 int notches = value / threshold;
95 int button = (notches > 0) ? btn_positive : btn_negative;
96 int i;
97
98 for (i = 0; i < abs(notches); i++) {
99 xf86PostButtonEventP(priv->pInfo->dev, mode, button, 1, 0, 0, 0);
100 xf86PostButtonEventP(priv->pInfo->dev, mode, button, 0, 0, 0, 0);
101 }
102
103 return value % threshold;
104 }
105
wcmPanscroll(InputInfoPtr pInfo,const WacomDeviceState * ds,int x,int y)106 static void wcmPanscroll(InputInfoPtr pInfo, const WacomDeviceState *ds, int x, int y)
107 {
108 WacomDevicePtr priv = (WacomDevicePtr)pInfo->private;
109 WacomCommonPtr common = priv->common;
110 int threshold = common->wcmPanscrollThreshold;
111 int *accumulated_x, *accumulated_y;
112 int delta_x, delta_y;
113
114 if (!(priv->flags & SCROLLMODE_FLAG) || !(ds->buttons & 1))
115 return;
116
117 /* Tip has gone down down; store state for dragging */
118 if (!(priv->oldState.buttons & 1)) {
119 priv->wcmPanscrollState = *ds;
120 priv->wcmPanscrollState.x = 0;
121 priv->wcmPanscrollState.y = 0;
122 return;
123 }
124
125 if (!is_absolute(pInfo)) {
126 delta_x = x;
127 delta_y = y;
128 }
129 else {
130 delta_x = (x - priv->oldState.x);
131 delta_y = (y - priv->oldState.y);
132 }
133
134 accumulated_x = &priv->wcmPanscrollState.x;
135 accumulated_y = &priv->wcmPanscrollState.y;
136 *accumulated_x += delta_x;
137 *accumulated_y += delta_y;
138
139 DBG(6, priv, "pan x = %d, pan y = %d\n", *accumulated_x, *accumulated_y);
140
141 *accumulated_x = wcmButtonPerNotch(priv, *accumulated_x, threshold, 6, 7);
142 *accumulated_y = wcmButtonPerNotch(priv, *accumulated_y, threshold, 4, 5);
143 }
144
145 /*****************************************************************************
146 * wcmSendButtons --
147 * Send button events by comparing the current button mask with the
148 * previous one.
149 ****************************************************************************/
150
wcmSendButtons(InputInfoPtr pInfo,const WacomDeviceState * ds,int buttons,int first_val,int num_vals,int * valuators)151 static void wcmSendButtons(InputInfoPtr pInfo, const WacomDeviceState* ds, int buttons,
152 int first_val, int num_vals, int *valuators)
153 {
154 unsigned int button, mask, first_button;
155 WacomDevicePtr priv = (WacomDevicePtr) pInfo->private;
156 WacomCommonPtr common = priv->common;
157 DBG(6, priv, "buttons=%d\n", buttons);
158
159 /* button behaviour (TPC button on):
160 if only tip is pressed/released, send button 1 events
161 if button N is pressed and tip is pressed/released, send
162 button N events.
163 if tip is already down and button N is pressed/released,
164 send button 1 release, then button N events.
165 */
166
167 first_button = 0; /* zero-indexed because of mask */
168
169 /* Tablet PC buttons only apply to penabled devices */
170 if (common->wcmTPCButton && IsStylus(priv))
171 {
172 first_button = (buttons <= 1) ? 0 : 1;
173
174 /* tip released? release all buttons */
175 if ((buttons & 1) == 0)
176 buttons = 0;
177 /* tip pressed? send all other button presses */
178 else if ((buttons & 1) != (priv->oldState.buttons & 1))
179 priv->oldState.buttons = 0;
180 /* other button changed while tip is still down? release tip */
181 else if ((buttons & 1) && (buttons != priv->oldState.buttons))
182 {
183 buttons &= ~1;
184 first_button = 0;
185 }
186 }
187
188 for (button = first_button; button < WCM_MAX_BUTTONS; button++)
189 {
190 mask = 1u << button;
191 if ((mask & priv->oldState.buttons) != (mask & buttons))
192 sendAButton(pInfo, ds, button, (mask & buttons),
193 first_val, num_vals, valuators);
194 }
195
196 }
197
wcmEmitKeycode(DeviceIntPtr keydev,int keycode,int state)198 void wcmEmitKeycode (DeviceIntPtr keydev, int keycode, int state)
199 {
200 xf86PostKeyboardEvent (keydev, keycode, state);
201 }
202
203 /*****************************************************************************
204 * countPresses
205 * Count the number of key/button presses not released for the given key
206 * array.
207 ****************************************************************************/
countPresses(int keybtn,unsigned int * keys,int size)208 static int countPresses(int keybtn, unsigned int* keys, int size)
209 {
210 int i, act, count = 0;
211
212 for (i = 0; i < size; i++)
213 {
214 act = keys[i];
215 if ((act & AC_CODE) == keybtn)
216 count += (act & AC_KEYBTNPRESS) ? 1 : -1;
217 }
218
219 return count;
220 }
221
sendAction(InputInfoPtr pInfo,const WacomDeviceState * ds,int press,unsigned int * keys,int nkeys,int first_val,int num_val,int * valuators)222 static void sendAction(InputInfoPtr pInfo, const WacomDeviceState* ds,
223 int press, unsigned int *keys, int nkeys,
224 int first_val, int num_val, int *valuators)
225 {
226 WacomDevicePtr priv = (WacomDevicePtr) pInfo->private;
227 int i;
228
229 /* Actions only trigger on press, not release */
230 for (i = 0; press && i < nkeys; i++)
231 {
232 unsigned int action = keys[i];
233
234 if (!action)
235 break;
236
237 switch ((action & AC_TYPE))
238 {
239 case AC_BUTTON:
240 {
241 int btn_no = (action & AC_CODE);
242 int is_press = (action & AC_KEYBTNPRESS);
243 if (btn_no == 1 && (priv->flags & SCROLLMODE_FLAG)) {
244 /* Don't send clicks in scroll mode */
245 }
246 else {
247 xf86PostButtonEventP(pInfo->dev,
248 is_absolute(pInfo), btn_no,
249 is_press, first_val, num_val,
250 VCOPY(valuators, num_val));
251 }
252 }
253 break;
254 case AC_KEY:
255 {
256 int key_code = (action & AC_CODE);
257 int is_press = (action & AC_KEYBTNPRESS);
258 wcmEmitKeycode(pInfo->dev, key_code, is_press);
259 }
260 break;
261 case AC_MODETOGGLE:
262 if (press)
263 wcmDevSwitchModeCall(pInfo,
264 (is_absolute(pInfo)) ? Relative : Absolute); /* not a typo! */
265 break;
266 case AC_PANSCROLL:
267 priv->flags |= SCROLLMODE_FLAG;
268 priv->wcmPanscrollState = *ds;
269 priv->wcmPanscrollState.x = 0;
270 priv->wcmPanscrollState.y = 0;
271 break;
272 }
273 }
274
275 /* Release all non-released keys for this button. */
276 for (i = 0; !press && i < nkeys; i++)
277 {
278 unsigned int action = keys[i];
279
280 switch ((action & AC_TYPE))
281 {
282 case AC_BUTTON:
283 {
284 int btn_no = (action & AC_CODE);
285
286 /* don't care about releases here */
287 if (!(action & AC_KEYBTNPRESS))
288 break;
289
290 if (countPresses(btn_no, &keys[i], nkeys - i))
291 xf86PostButtonEventP(pInfo->dev,
292 is_absolute(pInfo), btn_no,
293 0, first_val, num_val,
294 VCOPY(valuators, num_val));
295 }
296 break;
297 case AC_KEY:
298 {
299 int key_code = (action & AC_CODE);
300
301 /* don't care about releases here */
302 if (!(action & AC_KEYBTNPRESS))
303 break;
304
305 if (countPresses(key_code, &keys[i], nkeys - i))
306 wcmEmitKeycode(pInfo->dev, key_code, 0);
307 }
308 break;
309 case AC_PANSCROLL:
310 priv->flags &= ~SCROLLMODE_FLAG;
311 break;
312 }
313 }
314 }
315
316 /*****************************************************************************
317 * sendAButton --
318 * Send one button event, called by wcmSendButtons
319 ****************************************************************************/
sendAButton(InputInfoPtr pInfo,const WacomDeviceState * ds,int button,int mask,int first_val,int num_val,int * valuators)320 static void sendAButton(InputInfoPtr pInfo, const WacomDeviceState* ds, int button,
321 int mask, int first_val, int num_val, int *valuators)
322 {
323 WacomDevicePtr priv = (WacomDevicePtr) pInfo->private;
324 #ifdef DEBUG
325 WacomCommonPtr common = priv->common;
326 #endif
327
328 DBG(4, priv, "TPCButton(%s) button=%d state=%d\n",
329 common->wcmTPCButton ? "on" : "off", button, mask);
330
331 if (!priv->keys[button][0])
332 return;
333
334 sendAction(pInfo, ds, (mask != 0), priv->keys[button],
335 ARRAY_SIZE(priv->keys[button]),
336 first_val, num_val, valuators);
337 }
338
339 /**
340 * Get the distance an axis was scrolled. This function is aware
341 * of the different ways different scrolling axes work and strives
342 * to produce a common representation of relative change.
343 *
344 * @param current Current value of the axis
345 * @param old Previous value of the axis
346 * @param wrap Maximum value before wraparound occurs (0 if axis does not wrap)
347 * @param flags Flags defining axis attributes: AXIS_INVERT and AXIS_BITWISE
348 * @return Relative change in axis value
349 */
getScrollDelta(int current,int old,int wrap,int flags)350 TEST_NON_STATIC int getScrollDelta(int current, int old, int wrap, int flags)
351 {
352 int delta;
353
354 if (flags & AXIS_BITWISE)
355 {
356 current = log2((current << 1) | 0x01);
357 old = log2((old << 1) | 0x01);
358 wrap = log2((wrap << 1) | 0x01);
359 }
360
361 delta = current - old;
362
363 if (flags & AXIS_INVERT)
364 delta = -delta;
365
366 if (wrap != 0)
367 {
368 /* Wraparound detection. If the distance old..current
369 * is larger than the old..current considering the
370 * wraparound, assume wraparound and readjust */
371 int wrap_delta;
372
373 if (delta < 0)
374 wrap_delta = (wrap + 1) + delta;
375 else
376 wrap_delta = -((wrap + 1) - delta);
377
378 if (abs(wrap_delta) < abs(delta))
379 delta = wrap_delta;
380 }
381
382 return delta;
383 }
384
385 /**
386 * Get the scroll button/action to send given the delta of
387 * the scrolling axis and the possible events that can be
388 * sent.
389 *
390 * @param delta Amount of change in the scrolling axis
391 * @param action_up Array index of action to send on scroll up
392 * @param action_dn Array index of action to send on scroll down
393 * @return Array index of action that should be performed, or -1 if none.
394 */
getWheelButton(int delta,int action_up,int action_dn)395 TEST_NON_STATIC int getWheelButton(int delta, int action_up, int action_dn)
396 {
397 if (delta > 0)
398 return action_up;
399 else if (delta < 0)
400 return action_dn;
401 else
402 return -1;
403 }
404
405 /**
406 * Send button or actions for a scrolling axis.
407 *
408 * @param button X button number to send if no action is defined
409 * @param action Action to send
410 * @param nactions Length of action array
411 * @param pInfo
412 * @param first_val
413 * @param num_vals
414 * @param valuators
415 */
sendWheelStripEvent(unsigned int * action,const WacomDeviceState * ds,int nactions,InputInfoPtr pInfo,int first_val,int num_vals,int * valuators)416 static void sendWheelStripEvent(unsigned int *action, const WacomDeviceState* ds, int nactions,
417 InputInfoPtr pInfo, int first_val, int num_vals, int *valuators)
418 {
419 sendAction(pInfo, ds, 1, action, nactions, first_val, num_vals, valuators);
420 sendAction(pInfo, ds, 0, action, nactions, first_val, num_vals, valuators);
421 }
422
423 /*****************************************************************************
424 * sendWheelStripEvents --
425 * Send events defined for relative/absolute wheels or strips
426 ****************************************************************************/
427
sendWheelStripEvents(InputInfoPtr pInfo,const WacomDeviceState * ds,int first_val,int num_vals,int * valuators)428 static void sendWheelStripEvents(InputInfoPtr pInfo, const WacomDeviceState* ds,
429 int first_val, int num_vals, int *valuators)
430 {
431 WacomDevicePtr priv = (WacomDevicePtr) pInfo->private;
432 WacomCommonPtr common = priv->common;
433 int delta = 0, idx = 0;
434
435 DBG(10, priv, "\n");
436
437 /* emulate events for left strip */
438 delta = getScrollDelta(ds->stripx, priv->oldState.stripx, 0, AXIS_INVERT | AXIS_BITWISE);
439 idx = getWheelButton(delta, STRIP_LEFT_UP, STRIP_LEFT_DN);
440 if (idx >= 0 && IsPad(priv) && priv->oldState.proximity == ds->proximity)
441 {
442 DBG(10, priv, "Left touch strip scroll delta = %d\n", delta);
443 sendWheelStripEvent(priv->strip_keys[idx], ds, ARRAY_SIZE(priv->strip_keys[idx]),
444 pInfo, first_val, num_vals, valuators);
445 }
446
447 /* emulate events for right strip */
448 delta = getScrollDelta(ds->stripy, priv->oldState.stripy, 0, AXIS_INVERT | AXIS_BITWISE);
449 idx = getWheelButton(delta, STRIP_RIGHT_UP, STRIP_RIGHT_DN);
450 if (idx >= 0 && IsPad(priv) && priv->oldState.proximity == ds->proximity)
451 {
452 DBG(10, priv, "Right touch strip scroll delta = %d\n", delta);
453 sendWheelStripEvent(priv->strip_keys[idx], ds, ARRAY_SIZE(priv->strip_keys[idx]),
454 pInfo, first_val, num_vals, valuators);
455 }
456
457 /* emulate events for relative wheel */
458 delta = getScrollDelta(ds->relwheel, 0, 0, 0);
459 idx = getWheelButton(delta, WHEEL_REL_UP, WHEEL_REL_DN);
460 if (idx >= 0 && (IsCursor(priv) || IsPad(priv)) && priv->oldState.proximity == ds->proximity)
461 {
462 DBG(10, priv, "Relative wheel scroll delta = %d\n", delta);
463 sendWheelStripEvent(priv->wheel_keys[idx], ds, ARRAY_SIZE(priv->wheel_keys[idx]),
464 pInfo, first_val, num_vals, valuators);
465 }
466
467 /* emulate events for left touch ring */
468 delta = getScrollDelta(ds->abswheel, priv->oldState.abswheel, common->wcmMaxRing, AXIS_INVERT);
469 idx = getWheelButton(delta, WHEEL_ABS_UP, WHEEL_ABS_DN);
470 if (idx >= 0 && IsPad(priv) && priv->oldState.proximity == ds->proximity)
471 {
472 DBG(10, priv, "Left touch wheel scroll delta = %d\n", delta);
473 sendWheelStripEvent(priv->wheel_keys[idx], ds, ARRAY_SIZE(priv->wheel_keys[idx]),
474 pInfo, first_val, num_vals, valuators);
475 }
476
477 /* emulate events for right touch ring */
478 delta = getScrollDelta(ds->abswheel2, priv->oldState.abswheel2, common->wcmMaxRing, AXIS_INVERT);
479 idx = getWheelButton(delta, WHEEL2_ABS_UP, WHEEL2_ABS_DN);
480 if (idx >= 0 && IsPad(priv) && priv->oldState.proximity == ds->proximity)
481 {
482 DBG(10, priv, "Right touch wheel scroll delta = %d\n", delta);
483 sendWheelStripEvent(priv->wheel_keys[idx], ds, ARRAY_SIZE(priv->wheel_keys[idx]),
484 pInfo, first_val, num_vals, valuators);
485 }
486 }
487
488 /*****************************************************************************
489 * sendCommonEvents --
490 * Send events common between pad and stylus/cursor/eraser.
491 ****************************************************************************/
492
sendCommonEvents(InputInfoPtr pInfo,const WacomDeviceState * ds,int first_val,int num_vals,int * valuators)493 static void sendCommonEvents(InputInfoPtr pInfo, const WacomDeviceState* ds,
494 int first_val, int num_vals, int *valuators)
495 {
496 WacomDevicePtr priv = (WacomDevicePtr) pInfo->private;
497 int buttons = ds->buttons;
498
499 /* send scrolling events if necessary */
500 wcmPanscroll(pInfo, ds, valuators[0], valuators[1]);
501
502 /* send button events when state changed or first time in prox and button unpresses */
503 if (priv->oldState.buttons != buttons || (!priv->oldState.proximity && !buttons))
504 wcmSendButtons(pInfo, ds, buttons, first_val, num_vals, valuators);
505
506 /* emulate wheel/strip events when defined */
507 if ( ds->relwheel || (ds->abswheel != priv->oldState.abswheel) || (ds->abswheel2 != priv->oldState.abswheel2) ||
508 ( (ds->stripx - priv->oldState.stripx) && ds->stripx && priv->oldState.stripx) ||
509 ((ds->stripy - priv->oldState.stripy) && ds->stripy && priv->oldState.stripy) )
510 sendWheelStripEvents(pInfo, ds, first_val, num_vals, valuators);
511 }
512
513 /* rotate x and y before post X inout events */
wcmRotateAndScaleCoordinates(InputInfoPtr pInfo,int * x,int * y)514 void wcmRotateAndScaleCoordinates(InputInfoPtr pInfo, int* x, int* y)
515 {
516 WacomDevicePtr priv = (WacomDevicePtr) pInfo->private;
517 WacomCommonPtr common = priv->common;
518 DeviceIntPtr dev = pInfo->dev;
519 AxisInfoPtr axis_x, axis_y;
520 int tmp_coord;
521
522 /* scale into on topX/topY area */
523 axis_x = &dev->valuator->axes[0];
524 axis_y = &dev->valuator->axes[1];
525
526 /* Don't try to scale relative axes */
527 if (axis_x->max_value > axis_x->min_value)
528 *x = xf86ScaleAxis(*x, axis_x->max_value, axis_x->min_value,
529 priv->bottomX, priv->topX);
530
531 if (axis_y->max_value > axis_y->min_value)
532 *y = xf86ScaleAxis(*y, axis_y->max_value, axis_y->min_value,
533 priv->bottomY, priv->topY);
534
535 /* coordinates are now in the axis rage we advertise for the device */
536
537 if (common->wcmRotate == ROTATE_CW || common->wcmRotate == ROTATE_CCW)
538 {
539 tmp_coord = *x;
540
541 *x = xf86ScaleAxis(*y,
542 axis_x->max_value, axis_x->min_value,
543 axis_y->max_value, axis_y->min_value);
544 *y = xf86ScaleAxis(tmp_coord,
545 axis_y->max_value, axis_y->min_value,
546 axis_x->max_value, axis_x->min_value);
547 }
548
549 if (common->wcmRotate == ROTATE_CW)
550 *y = axis_y->max_value - (*y - axis_y->min_value);
551 else if (common->wcmRotate == ROTATE_CCW)
552 *x = axis_x->max_value - (*x - axis_x->min_value);
553 else if (common->wcmRotate == ROTATE_HALF)
554 {
555 *x = axis_x->max_value - (*x - axis_x->min_value);
556 *y = axis_y->max_value - (*y - axis_y->min_value);
557 }
558
559
560 DBG(10, priv, "rotate/scaled to %d/%d\n", *x, *y);
561 }
562
wcmUpdateOldState(const InputInfoPtr pInfo,const WacomDeviceState * ds,int currentX,int currentY)563 static void wcmUpdateOldState(const InputInfoPtr pInfo,
564 const WacomDeviceState *ds, int currentX, int currentY)
565 {
566 const WacomDevicePtr priv = (WacomDevicePtr) pInfo->private;
567
568 priv->oldState = *ds;
569 priv->oldState.x = currentX;
570 priv->oldState.y = currentY;
571 }
572
573 static void
wcmSendPadEvents(InputInfoPtr pInfo,const WacomDeviceState * ds,int first_val,int num_vals,int * valuators)574 wcmSendPadEvents(InputInfoPtr pInfo, const WacomDeviceState* ds,
575 int first_val, int num_vals, int *valuators)
576 {
577 int i;
578 WacomDevicePtr priv = (WacomDevicePtr) pInfo->private;
579
580 if (!priv->oldState.proximity && ds->proximity)
581 xf86PostProximityEventP(pInfo->dev, 1, first_val, num_vals, VCOPY(valuators, num_vals));
582
583 for (i = 0; i < num_vals; i++)
584 if (valuators[i])
585 break;
586 if (i < num_vals || ds->buttons || ds->relwheel ||
587 (ds->abswheel != priv->oldState.abswheel) || (ds->abswheel2 != priv->oldState.abswheel2))
588 {
589 sendCommonEvents(pInfo, ds, first_val, num_vals, valuators);
590
591 /* xf86PostMotionEvent is only needed to post the valuators
592 * It should NOT move the cursor.
593 */
594 xf86PostMotionEventP(pInfo->dev, TRUE, first_val, num_vals,
595 VCOPY(valuators, num_vals));
596 }
597 else
598 {
599 if (priv->oldState.buttons)
600 wcmSendButtons(pInfo, ds, ds->buttons, first_val, num_vals, valuators);
601 }
602
603 if (priv->oldState.proximity && !ds->proximity)
604 xf86PostProximityEventP(pInfo->dev, 0, first_val, num_vals,
605 VCOPY(valuators, num_vals));
606 }
607
608 /* Send events for all tools but pads */
609 static void
wcmSendNonPadEvents(InputInfoPtr pInfo,const WacomDeviceState * ds,int first_val,int num_vals,int * valuators)610 wcmSendNonPadEvents(InputInfoPtr pInfo, const WacomDeviceState *ds,
611 int first_val, int num_vals, int *valuators)
612 {
613 WacomDevicePtr priv = (WacomDevicePtr) pInfo->private;
614
615 if (!is_absolute(pInfo))
616 {
617 valuators[0] -= priv->oldState.x;
618 valuators[1] -= priv->oldState.y;
619 valuators[2] -= priv->oldState.pressure;
620 if (IsCursor(priv))
621 {
622 valuators[3] -= priv->oldState.rotation;
623 valuators[4] -= priv->oldState.throttle;
624 } else
625 {
626 valuators[3] -= priv->oldState.tiltx;
627 valuators[4] -= priv->oldState.tilty;
628 }
629 valuators[5] -= priv->oldState.abswheel;
630 valuators[6] -= priv->oldState.abswheel2;
631 }
632
633 /* coordinates are ready we can send events */
634 if (ds->proximity)
635 {
636 /* don't emit proximity events if device does not support proximity */
637 if ((pInfo->dev->proximity && !priv->oldState.proximity))
638 xf86PostProximityEventP(pInfo->dev, 1, first_val, num_vals,
639 VCOPY(valuators, num_vals));
640
641 /* Move the cursor to where it should be before sending button events */
642 if(!(priv->flags & BUTTONS_ONLY_FLAG) &&
643 !(priv->flags & SCROLLMODE_FLAG && priv->oldState.buttons & 1))
644 {
645 xf86PostMotionEventP(pInfo->dev, is_absolute(pInfo),
646 first_val, num_vals,
647 VCOPY(valuators, num_vals));
648 /* For relative events, do not repost
649 * the valuators. Otherwise, a button
650 * event in sendCommonEvents will move the
651 * axes again.
652 */
653 if (!is_absolute(pInfo))
654 {
655 first_val = 0;
656 num_vals = 0;
657 }
658 }
659
660 sendCommonEvents(pInfo, ds, first_val, num_vals, valuators);
661 }
662 else /* not in proximity */
663 {
664 int buttons = 0;
665
666 /* reports button up when the device has been
667 * down and becomes out of proximity */
668 if (priv->oldState.buttons)
669 wcmSendButtons(pInfo, ds, buttons, first_val, num_vals, valuators);
670
671 if (priv->oldState.proximity)
672 xf86PostProximityEventP(pInfo->dev, 0, first_val, num_vals,
673 VCOPY(valuators, num_vals));
674 } /* not in proximity */
675 }
676
677 #define IsArtPen(ds) (ds->device_id == 0x885 || ds->device_id == 0x804 || ds->device_id == 0x100804)
678
679 /*****************************************************************************
680 * wcmSendEvents --
681 * Send events according to the device state.
682 ****************************************************************************/
683
wcmSendEvents(InputInfoPtr pInfo,const WacomDeviceState * ds)684 void wcmSendEvents(InputInfoPtr pInfo, const WacomDeviceState* ds)
685 {
686 #ifdef DEBUG
687 int is_button = !!(ds->buttons);
688 #endif
689 int type = ds->device_type;
690 int id = ds->device_id;
691 unsigned int serial = ds->serial_num;
692 int x = ds->x;
693 int y = ds->y;
694 int z = ds->pressure;
695 int tx = ds->tiltx;
696 int ty = ds->tilty;
697 WacomDevicePtr priv = (WacomDevicePtr) pInfo->private;
698 int v3, v4, v5, v6;
699 int valuators[priv->naxes];
700
701 if (priv->serial && serial != priv->serial)
702 {
703 DBG(10, priv, "serial number"
704 " is %u but your system configured %u",
705 serial, (int)priv->serial);
706 return;
707 }
708
709 wcmUpdateSerial(pInfo, serial, id);
710
711 /* don't move the cursor when going out-prox */
712 if (!ds->proximity)
713 {
714 x = priv->oldState.x;
715 y = priv->oldState.y;
716 }
717
718 /* use tx and ty to report stripx and stripy */
719 if (type == PAD_ID)
720 {
721 tx = ds->stripx;
722 ty = ds->stripy;
723 }
724
725 /* cancel panscroll */
726 if (!ds->proximity)
727 priv->flags &= ~SCROLLMODE_FLAG;
728
729 DBG(7, priv, "[%s] o_prox=%s x=%d y=%d z=%d "
730 "b=%s b=%d tx=%d ty=%d wl=%d wl2=%d rot=%d th=%d\n",
731 pInfo->type_name,
732 priv->oldState.proximity ? "true" : "false",
733 x, y, z, is_button ? "true" : "false", ds->buttons,
734 tx, ty, ds->abswheel, ds->abswheel2, ds->rotation, ds->throttle);
735
736 if (ds->proximity)
737 wcmRotateAndScaleCoordinates(pInfo, &x, &y);
738
739 if (IsCursor(priv))
740 {
741 v3 = ds->rotation;
742 v4 = ds->throttle;
743 }
744 else /* Intuos styli have tilt */
745 {
746 v3 = tx;
747 v4 = ty;
748 }
749
750 v5 = ds->abswheel;
751 v6 = ds->abswheel2;
752 if (IsStylus(priv) && !IsArtPen(ds))
753 {
754 /* Normalize abswheel airbrush data to Art Pen rotation range.
755 * We do not normalize Art Pen. They are already at the range.
756 */
757 v5 = ds->abswheel * MAX_ROTATION_RANGE/
758 (double)MAX_ABS_WHEEL + MIN_ROTATION;
759 }
760
761 DBG(6, priv, "%s prox=%d\tx=%d"
762 "\ty=%d\tz=%d\tv3=%d\tv4=%d\tv5=%d\tv6=%d\tid=%d"
763 "\tserial=%u\tbutton=%s\tbuttons=%d\n",
764 is_absolute(pInfo) ? "abs" : "rel",
765 ds->proximity,
766 x, y, z, v3, v4, v5, v6, id, serial,
767 is_button ? "true" : "false", ds->buttons);
768
769 /* when entering prox, replace the zeroed-out oldState with a copy of
770 * the current state to prevent jumps. reset the prox and button state
771 * to zero to properly detect changes.
772 */
773 if(!priv->oldState.proximity)
774 {
775 wcmUpdateOldState(pInfo, ds, x, y);
776 priv->oldState.proximity = 0;
777 priv->oldState.buttons = 0;
778 }
779
780 valuators[0] = x;
781 valuators[1] = y;
782 valuators[2] = z;
783 valuators[3] = v3;
784 valuators[4] = v4;
785 valuators[5] = v5;
786 if (priv->naxes > 6)
787 valuators[6] = v6;
788
789 if (type == PAD_ID)
790 wcmSendPadEvents(pInfo, ds, 3, priv->naxes - 3, &valuators[3]); /* pad doesn't post x/y/z */
791 else {
792 /* don't move the cursor if in gesture mode (except drag mode) */
793 if ((type != TOUCH_ID) || wcmTouchNeedSendEvents(priv->common))
794 wcmSendNonPadEvents(pInfo, ds, 0, priv->naxes, valuators);
795 }
796
797 if (ds->proximity)
798 wcmUpdateOldState(pInfo, ds, x, y);
799 else
800 {
801 priv->oldState = OUTPROX_STATE;
802 priv->oldState.serial_num = serial;
803 priv->oldState.device_id = id;
804 wcmUpdateSerial(pInfo, 0, 0);
805 }
806 }
807
808 /**
809 * Determine whether device state has changed enough to warrant further
810 * processing. The driver's "suppress" setting decides how much
811 * movement/state change must occur before we process events to avoid
812 * overloading the server with minimal changes (and getting fuzzy events).
813 * wcmCheckSuppress ensures that events meet this standard.
814 *
815 * @param dsOrig Previous device state
816 * @param dsNew Current device state
817 *
818 * @retval SUPPRESS_ALL Ignore this event completely.
819 * @retval SUPPRESS_NONE Process event normally.
820 * @retval SUPPRESS_NON_MOTION Suppress all data but motion data.
821 */
822 TEST_NON_STATIC enum WacomSuppressMode
wcmCheckSuppress(WacomCommonPtr common,const WacomDeviceState * dsOrig,WacomDeviceState * dsNew)823 wcmCheckSuppress(WacomCommonPtr common,
824 const WacomDeviceState* dsOrig,
825 WacomDeviceState* dsNew)
826 {
827 int suppress = common->wcmSuppress;
828 enum WacomSuppressMode returnV = SUPPRESS_NONE;
829
830 /* Ignore all other changes that occur after initial out-of-prox. */
831 if (!dsNew->proximity && !dsOrig->proximity)
832 return SUPPRESS_ALL;
833
834 /* Never ignore proximity changes. */
835 if (dsOrig->proximity != dsNew->proximity) goto out;
836
837 if (dsOrig->buttons != dsNew->buttons) goto out;
838 if (dsOrig->stripx != dsNew->stripx) goto out;
839 if (dsOrig->stripy != dsNew->stripy) goto out;
840
841 /* FIXME: we should have different suppress values for different
842 * axes with vastly different ranges.
843 */
844 if (abs(dsOrig->tiltx - dsNew->tiltx) > suppress) goto out;
845 if (abs(dsOrig->tilty - dsNew->tilty) > suppress) goto out;
846 if (abs(dsOrig->pressure - dsNew->pressure) > suppress) goto out;
847 if (abs(dsOrig->throttle - dsNew->throttle) > suppress) goto out;
848 if (abs(dsOrig->rotation - dsNew->rotation) > suppress &&
849 (1800 - abs(dsOrig->rotation - dsNew->rotation)) > suppress) goto out;
850
851 /* look for change in absolute wheel position
852 * or any relative wheel movement
853 */
854 if (abs(dsOrig->abswheel - dsNew->abswheel) > suppress) goto out;
855 if (abs(dsOrig->abswheel2 - dsNew->abswheel2) > suppress) goto out;
856 if (dsNew->relwheel != 0) goto out;
857
858 returnV = SUPPRESS_ALL;
859
860 out:
861 /* Special handling for cursor: if nothing else changed but the
862 * pointer x/y, suppress all but cursor movement. This return value
863 * is used in commonDispatchDevice to short-cut event processing.
864 */
865 if ((abs(dsOrig->x - dsNew->x) > suppress) ||
866 (abs(dsOrig->y - dsNew->y) > suppress))
867 {
868 if (returnV == SUPPRESS_ALL)
869 returnV = SUPPRESS_NON_MOTION;
870 }
871 else /* don't move cursor */
872 {
873 dsNew->x = dsOrig->x;
874 dsNew->y = dsOrig->y;
875 }
876
877 DBG(10, common, "level = %d"
878 " return value = %d\n", suppress, returnV);
879 return returnV;
880 }
881
882 /**
883 * Find the device the current events are meant for. If multiple tools are
884 * configured on this tablet, the one that matches the serial number for the
885 * current device state is returned. If none match, the tool that has a
886 * serial of 0 is returned.
887 *
888 * @param ds The current device state as read from the fd
889 * @return The tool that should be used to emit the current events.
890 */
findTool(const WacomCommonPtr common,const WacomDeviceState * ds)891 static WacomToolPtr findTool(const WacomCommonPtr common,
892 const WacomDeviceState *ds)
893 {
894 WacomToolPtr tooldefault = NULL;
895 WacomToolPtr tool = NULL;
896
897 /* 1: Find the tool (the one with correct serial or in second
898 * hand, the one with serial set to 0 if no match with the
899 * specified serial exists) that is used for this event */
900 for (tool = common->wcmTool; tool; tool = tool->next)
901 {
902 if (tool->typeid == ds->device_type)
903 {
904 if (tool->serial == ds->serial_num)
905 break;
906 else if (!tool->serial)
907 tooldefault = tool;
908 }
909 }
910
911 /* Use default tool (serial == 0) if no specific was found */
912 if (!tool)
913 tool = tooldefault;
914
915 return tool;
916 }
917
918 /**
919 * Check if the given device should grab control of the pointer in
920 * preference to whatever tool currently has access.
921 *
922 * @param pInfo The device to check for access
923 * @param ds The current state of the device
924 * @returns 'TRUE' if control of the pointer should be granted, FALSE otherwise
925 */
check_arbitrated_control(InputInfoPtr pInfo,WacomDeviceStatePtr ds)926 static Bool check_arbitrated_control(InputInfoPtr pInfo, WacomDeviceStatePtr ds)
927 {
928 WacomDevicePtr active = WACOM_DRIVER.active;
929 WacomDevicePtr priv = pInfo->private;
930
931 if (IsPad(priv)) {
932 /* Pad may never be the "active" pointer controller */
933 DBG(6, priv, "Event from pad; not yielding pointer control\n.");
934 return FALSE;
935 }
936
937 if (active == NULL || active->oldState.device_id == ds->device_id) {
938 DBG(11, priv, "Event from active device; maintaining pointer control.\n");
939 return TRUE;
940 }
941 else if (IsCursor(active)) {
942 /* Cursor devices are often left idle in range, so allow other devices
943 * to grab control if the tool has not been used for some time.
944 */
945 Bool yield = (ds->time - active->oldState.time > 100) && (active->oldState.buttons == 0);
946 DBG(6, priv, "Currently-active cursor %s idle; %s pointer control.\n",
947 yield ? "is" : "is not", yield ? "yielding" : "not yielding");
948 return yield;
949 }
950 else if (IsCursor(priv)) {
951 /* An otherwise idle cursor may still occasionally jitter and send
952 * events while the user is actively using other tools or touching
953 * the device. Do not allow the cursor to grab control in this
954 * particular case.
955 */
956 DBG(6, priv, "Event from non-active cursor; not yielding pointer control.\n");
957 return FALSE;
958 }
959 else {
960 /* Non-touch input has priority over touch in general */
961 Bool yield = !IsTouch(priv);
962 DBG(6, priv, "Event from non-active %s device; %s pointer control.\n",
963 yield ? "non-touch" : "touch", yield ? "yielding" : "not yielding");
964 return yield;
965 }
966 }
967
968 /*****************************************************************************
969 * wcmEvent -
970 * Handles suppression, transformation, filtering, and event dispatch.
971 ****************************************************************************/
972
wcmEvent(WacomCommonPtr common,unsigned int channel,const WacomDeviceState * pState)973 void wcmEvent(WacomCommonPtr common, unsigned int channel,
974 const WacomDeviceState* pState)
975 {
976 WacomDeviceState ds;
977 WacomChannelPtr pChannel;
978 InputInfoPtr pInfo;
979 WacomToolPtr tool;
980 WacomDevicePtr priv;
981 pChannel = common->wcmChannel + channel;
982
983 DBG(10, common, "channel = %d\n", channel);
984
985 /* sanity check the channel */
986 if (channel >= MAX_CHANNELS)
987 return;
988
989 /* we must copy the state because certain types of filtering
990 * will need to change the values (ie. for error correction) */
991 ds = *pState;
992
993 DBG(10, common,
994 "c=%d i=%d t=%d s=%u x=%d y=%d b=%d "
995 "p=%d rz=%d tx=%d ty=%d aw=%d aw2=%d rw=%d "
996 "t=%d px=%d st=%d cs=%d \n",
997 channel,
998 ds.device_id,
999 ds.device_type,
1000 ds.serial_num,
1001 ds.x, ds.y, ds.buttons,
1002 ds.pressure, ds.rotation, ds.tiltx,
1003 ds.tilty, ds.abswheel, ds.abswheel2, ds.relwheel, ds.throttle,
1004 ds.proximity, ds.sample,
1005 pChannel->nSamples);
1006
1007 /* Find the device the current events are meant for */
1008 tool = findTool(common, &ds);
1009 if (!tool || !tool->device)
1010 {
1011 DBG(11, common, "no device matches with id=%d, serial=%u\n",
1012 ds.device_type, ds.serial_num);
1013 return;
1014 }
1015
1016 /* Tool on the tablet when driver starts. This sometime causes
1017 * access errors to the device */
1018 if (!tool->enabled) {
1019 LogMessageVerbSigSafe(X_ERROR, 0, "tool not initialized yet. Skipping event. \n");
1020 return;
1021 }
1022
1023 pInfo = tool->device;
1024 priv = pInfo->private;
1025 DBG(11, common, "tool id=%d for %s\n", ds.device_type, pInfo->name);
1026
1027 if (TabletHasFeature(common, WCM_ROTATION) &&
1028 TabletHasFeature(common, WCM_RING) &&
1029 ds.device_type == CURSOR_ID) /* I4 mouse */
1030 {
1031 /* convert Intuos4 mouse tilt to rotation */
1032 ds.rotation = wcmTilt2R(ds.tiltx, ds.tilty,
1033 INTUOS4_CURSOR_ROTATION_OFFSET);
1034 ds.tiltx = 0;
1035 ds.tilty = 0;
1036 }
1037
1038 /* JEJ - Do not move this code without discussing it with me.
1039 * The device state is invariant of any filtering performed below.
1040 * Changing the device state after this point can and will cause
1041 * a feedback loop resulting in oscillations, error amplification,
1042 * unnecessary quantization, and other annoying effects. */
1043
1044 /* save channel device state and device to which last event went */
1045 memmove(pChannel->valid.states + 1,
1046 pChannel->valid.states,
1047 sizeof(WacomDeviceState) * (common->wcmRawSample - 1));
1048 pChannel->valid.state = ds; /*save last raw sample */
1049 if (pChannel->nSamples < common->wcmRawSample) ++pChannel->nSamples;
1050
1051 /* arbitrate pointer control */
1052 if (check_arbitrated_control(pInfo, &ds)) {
1053 if (WACOM_DRIVER.active != NULL && priv != WACOM_DRIVER.active) {
1054 wcmSoftOutEvent(WACOM_DRIVER.active->pInfo);
1055 wcmCancelGesture(WACOM_DRIVER.active->pInfo);
1056 }
1057 if (ds.proximity)
1058 WACOM_DRIVER.active = priv;
1059 else
1060 WACOM_DRIVER.active = NULL;
1061 }
1062 else if (!IsPad(priv)) {
1063 return;
1064 }
1065
1066 if ((ds.device_type == TOUCH_ID) && common->wcmTouch)
1067 {
1068 wcmGestureFilter(priv, ds.serial_num - 1);
1069 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 16
1070 /*
1071 * When using XI 2.2 multitouch events don't do common dispatching
1072 * for direct touch devices
1073 */
1074 if (!common->wcmGesture && TabletHasFeature(common, WCM_LCD))
1075 return;
1076 #endif
1077 }
1078
1079 /* For touch, only first finger moves the cursor */
1080 if ((common->wcmTouch && ds.device_type == TOUCH_ID && ds.serial_num == 1) ||
1081 (ds.device_type != TOUCH_ID))
1082 commonDispatchDevice(pInfo, pChannel);
1083 }
1084
1085
1086 /**
1087 * Return the minimum pressure based on the current minimum pressure and the
1088 * hardware state. This is mainly to deal with the case where heavily used
1089 * stylus may have a "pre-loaded" initial pressure. In that case, the tool
1090 * comes into proximity with a pressure > 0 to begin with and thus offsets
1091 * the pressure values. This preloaded pressure must be known for pressure
1092 * normalisation to work.
1093 *
1094 * @param priv The wacom device
1095 * @param ds Current device state
1096 *
1097 * @return The minimum pressure value for this tool.
1098 *
1099 * @see normalizePressure
1100 */
1101 TEST_NON_STATIC int
rebasePressure(const WacomDevicePtr priv,const WacomDeviceState * ds)1102 rebasePressure(const WacomDevicePtr priv, const WacomDeviceState *ds)
1103 {
1104 int min_pressure;
1105
1106 /* set the minimum pressure when in prox */
1107 if (!priv->oldState.proximity)
1108 min_pressure = ds->pressure;
1109 else
1110 min_pressure = min(priv->minPressure, ds->pressure);
1111
1112 return min_pressure;
1113 }
1114
1115 /**
1116 * Instead of reporting the raw pressure, we normalize
1117 * the pressure from 0 to maxCurve. This is
1118 * mainly to deal with the case where heavily used
1119 * stylus may have a "pre-loaded" initial pressure. To
1120 * do so, we keep the in-prox pressure and subtract it
1121 * from the raw pressure to prevent a potential
1122 * left-click before the pen touches the tablet.
1123 *
1124 * @param priv The wacom device
1125 * @param ds Current device state
1126 *
1127 * @return normalized pressure
1128 * @see rebasePressure
1129 */
1130 TEST_NON_STATIC int
normalizePressure(const WacomDevicePtr priv,const int raw_pressure)1131 normalizePressure(const WacomDevicePtr priv, const int raw_pressure)
1132 {
1133 WacomCommonPtr common = priv->common;
1134 double pressure;
1135 int p = raw_pressure;
1136 int range_left = common->wcmMaxZ;
1137
1138 if (common->wcmPressureRecalibration) {
1139 p -= priv->minPressure;
1140 range_left -= priv->minPressure;
1141 }
1142 /* normalize pressure to 0..maxCurve */
1143 if (range_left >= 1)
1144 pressure = xf86ScaleAxis(p,
1145 priv->maxCurve, 0,
1146 range_left,
1147 0);
1148 else
1149 pressure = priv->maxCurve;
1150
1151 return (int)pressure;
1152 }
1153
1154 /*
1155 * Based on the current pressure, return the button state with Button1
1156 * either set or unset, depending on whether the pressure threshold
1157 * conditions have been met.
1158 *
1159 * Returns the state of all buttons, but buttons other than button 1 are
1160 * unmodified.
1161 */
1162 #define PRESSURE_BUTTON 1
1163 static int
setPressureButton(const WacomDevicePtr priv,int buttons,const int pressure)1164 setPressureButton(const WacomDevicePtr priv, int buttons, const int pressure)
1165 {
1166 WacomCommonPtr common = priv->common;
1167 int button = PRESSURE_BUTTON;
1168
1169 /* button 1 Threshold test */
1170 /* set button1 (left click) on/off */
1171 if (pressure < common->wcmThreshold)
1172 {
1173 buttons &= ~button;
1174 if (priv->oldState.buttons & button) /* left click was on */
1175 {
1176 /* don't set it off if it is within the tolerance
1177 and threshold is larger than the tolerance */
1178 if ((common->wcmThreshold > (priv->maxCurve * THRESHOLD_TOLERANCE)) &&
1179 (pressure > common->wcmThreshold - (priv->maxCurve * THRESHOLD_TOLERANCE)))
1180 buttons |= button;
1181 }
1182 }
1183 else
1184 buttons |= button;
1185
1186 return buttons;
1187 }
1188
1189 /*
1190 * Broken pen with a broken tip might give high pressure values
1191 * all the time. We want to warn about this. To avoid getting
1192 * spurious warnings when the tablet is hit quickly will wait
1193 * until the device goes out of proximity and check if the minimum
1194 * pressure is still above a threshold of 20 percent of the maximum
1195 * pressure. Also we make sure the device has seen a sufficient number
1196 * of events while in proximity that it had a chance to see decreasing
1197 * pressure values.
1198 */
1199 #define LIMIT_LOW_PRESSURE 20 /* percentage of max value */
1200 #define MIN_EVENT_COUNT 15
1201
detectPressureIssue(WacomDevicePtr priv,WacomCommonPtr common,WacomDeviceStatePtr ds)1202 static void detectPressureIssue(WacomDevicePtr priv,
1203 WacomCommonPtr common,
1204 WacomDeviceStatePtr ds)
1205 {
1206 /* pen is just going out of proximity */
1207 if (priv->oldState.proximity && !ds->proximity) {
1208
1209 int pressureThreshold = common->wcmMaxZ * LIMIT_LOW_PRESSURE / 100;
1210 /* check if minPressure has persisted all the time
1211 and is too close to the maximum pressure */
1212 if (priv->oldMinPressure > pressureThreshold &&
1213 priv->eventCnt > MIN_EVENT_COUNT)
1214 LogMessageVerbSigSafe(
1215 X_WARNING, 0,
1216 "On %s(%d) a base pressure of %d persists while the pen is in proximity.\n"
1217 "\tThis is > %d percent of the maximum value (%d).\n"
1218 "\tThis indicates a worn out pen, it is time to change your tool. Also see:\n"
1219 "\thttps://github.com/linuxwacom/xf86-input-wacom/wiki/Pen-Wear.\n",
1220 priv->pInfo->name, priv->serial, priv->minPressure, LIMIT_LOW_PRESSURE, common->wcmMaxZ);
1221 } else if (!priv->oldState.proximity)
1222 priv->eventCnt = 0;
1223
1224 priv->oldMinPressure = priv->minPressure;
1225 priv->eventCnt++;
1226 }
1227
commonDispatchDevice(InputInfoPtr pInfo,const WacomChannelPtr pChannel)1228 static void commonDispatchDevice(InputInfoPtr pInfo,
1229 const WacomChannelPtr pChannel)
1230 {
1231 WacomDeviceState* ds = &pChannel->valid.states[0];
1232 WacomDevicePtr priv = pInfo->private;
1233 WacomCommonPtr common = priv->common;
1234 WacomDeviceState filtered;
1235 enum WacomSuppressMode suppress;
1236 int raw_pressure = 0;
1237
1238 /* device_type should have been retrieved and set in the respective
1239 * models, wcmISDV4.c or wcmUSB.c. Once it comes here, something
1240 * must have been wrong. Ignore the events.
1241 */
1242 if (!ds->device_type)
1243 {
1244 DBG(11, common, "no device type matches with"
1245 " serial=%u\n", ds->serial_num);
1246 return;
1247 }
1248
1249 DBG(10, common, "device type = %d\n", ds->device_type);
1250
1251 filtered = pChannel->valid.state;
1252
1253 /* Device transformations come first */
1254 if (priv->serial && filtered.serial_num != priv->serial)
1255 {
1256 DBG(10, priv, "serial number"
1257 " is %u but your system configured %u\n",
1258 filtered.serial_num, priv->serial);
1259 return;
1260 }
1261
1262 if ((IsPen(priv) || IsTouch(priv)) && common->wcmMaxZ)
1263 {
1264 int prev_min_pressure = priv->oldState.proximity ? priv->minPressure : 0;
1265
1266 detectPressureIssue(priv, common, &filtered);
1267
1268 raw_pressure = filtered.pressure;
1269 if (!priv->oldState.proximity)
1270 priv->maxRawPressure = raw_pressure;
1271
1272 priv->minPressure = rebasePressure(priv, &filtered);
1273
1274 filtered.pressure = normalizePressure(priv, filtered.pressure);
1275 if (IsPen(priv)) {
1276 filtered.buttons = setPressureButton(priv,
1277 filtered.buttons,
1278 filtered.pressure);
1279
1280 /* Here we run some heuristics to avoid losing button events if the
1281 * pen gets pushed onto the tablet so quickly that the first pressure
1282 * event read is non-zero and is thus interpreted as a pressure bias */
1283 if (filtered.buttons & PRESSURE_BUTTON) {
1284 /* If we triggered 'normally' reset max pressure to
1285 * avoid to trigger again while this device is in proximity */
1286 priv->maxRawPressure = 0;
1287 } else if (priv->maxRawPressure) {
1288 int norm_max_pressure;
1289
1290 /* If we haven't triggered normally we record the maximal pressure
1291 * and see if this would have triggered with a lowered bias. */
1292 if (priv->maxRawPressure < raw_pressure)
1293 priv->maxRawPressure = raw_pressure;
1294 norm_max_pressure = normalizePressure(priv, priv->maxRawPressure);
1295 filtered.buttons = setPressureButton(priv, filtered.buttons,
1296 norm_max_pressure);
1297
1298 /* If minPressure is not decrementing any more or a button
1299 * press has been generated or minPressure has just become zero
1300 * reset maxRawPressure to avoid that worn devices
1301 * won't report a button release until going out of proximity */
1302 if ((filtered.buttons & PRESSURE_BUTTON &&
1303 priv->minPressure == prev_min_pressure) ||
1304 !priv->minPressure)
1305 priv->maxRawPressure = 0;
1306
1307 }
1308 }
1309 filtered.pressure = applyPressureCurve(priv,&filtered);
1310 }
1311
1312 /* Optionally filter values only while in proximity */
1313 if (filtered.proximity && filtered.device_type != PAD_ID)
1314 {
1315 /* Start filter fresh when entering proximity */
1316 if (!priv->oldState.proximity)
1317 wcmResetSampleCounter(pChannel);
1318
1319 /* Reset filter whenever the tip is touched to the
1320 * screen to ensure clicks are sent from the pen's
1321 * actual position. Don't reset on other buttons or
1322 * tip-up, or else there may be a noticible jump/
1323 * hook produced in the middle/end of the stroke.
1324 */
1325 if ((filtered.buttons & PRESSURE_BUTTON) && !(priv->oldState.buttons & PRESSURE_BUTTON))
1326 wcmResetSampleCounter(pChannel);
1327
1328 wcmFilterCoord(common,pChannel,&filtered);
1329 }
1330
1331 /* skip event if we don't have enough movement */
1332 suppress = wcmCheckSuppress(common, &priv->oldState, &filtered);
1333 if (suppress == SUPPRESS_ALL)
1334 return;
1335
1336 /* Store cursor hardware prox for next use */
1337 if (IsCursor(priv))
1338 priv->oldCursorHwProx = ds->proximity;
1339
1340 /* User-requested filtering comes next */
1341
1342 /* User-requested transformations come last */
1343
1344 if (!is_absolute(pInfo) && !IsPad(priv))
1345 {
1346 /* To improve the accuracy of relative x/y,
1347 * don't send motion event when there is no movement.
1348 */
1349 double deltx = filtered.x - priv->oldState.x;
1350 double delty = filtered.y - priv->oldState.y;
1351
1352 /* less than one device coordinate movement? */
1353 if (fabs(deltx)<1 && fabs(delty)<1)
1354 {
1355 /* We have no other data in this event, skip */
1356 if (suppress == SUPPRESS_NON_MOTION)
1357 {
1358 DBG(10, common, "Ignore non-movement relative data \n");
1359 return;
1360 }
1361
1362 filtered.x = priv->oldState.x;
1363 filtered.y = priv->oldState.y;
1364 }
1365 }
1366
1367 /* force out-prox when distance from surface exceeds wcmProxoutDist */
1368 if (IsTablet(priv) && !is_absolute(pInfo))
1369 {
1370 /* Assume the the user clicks the puck buttons while
1371 * it is resting on the tablet (and taps styli onto
1372 * the tablet surface). This works for both
1373 * tablets that have a normal distance scale (protocol
1374 * 5) as well as those with an inverted scale (protocol
1375 * 4 for many many kernel versions).
1376 */
1377 if ((IsCursor(priv) && filtered.buttons) ||
1378 (IsStylus(priv) && filtered.buttons & 0x01))
1379 priv->wcmSurfaceDist = filtered.distance;
1380
1381 DBG(10, priv, "Distance over"
1382 " the tablet: %d, ProxoutDist: %d current"
1383 " surface %d hard prox: %d\n",
1384 filtered.distance,
1385 priv->wcmProxoutDist,
1386 priv->wcmSurfaceDist,
1387 ds->proximity);
1388
1389 if (priv->wcmSurfaceDist >= 0) {
1390 if (priv->oldState.proximity)
1391 {
1392 if (abs(filtered.distance - priv->wcmSurfaceDist)
1393 > priv->wcmProxoutDist)
1394 filtered.proximity = 0;
1395 }
1396 /* once it is out. Don't let it in until a hard in */
1397 /* or it gets inside wcmProxoutDist */
1398 else
1399 {
1400 if (abs(filtered.distance - priv->wcmSurfaceDist) >
1401 priv->wcmProxoutDist && ds->proximity)
1402 return;
1403 if (!ds->proximity)
1404 return;
1405 }
1406 }
1407 }
1408 wcmSendEvents(pInfo, &filtered);
1409 }
1410
1411 /*****************************************************************************
1412 * wcmInitTablet -- common initialization for all tablets
1413 ****************************************************************************/
1414
wcmInitTablet(InputInfoPtr pInfo,const char * id,float version)1415 int wcmInitTablet(InputInfoPtr pInfo, const char* id, float version)
1416 {
1417 WacomDevicePtr priv = (WacomDevicePtr)pInfo->private;
1418 WacomCommonPtr common = priv->common;
1419 WacomModelPtr model = common->wcmModel;
1420
1421 /* Initialize the tablet */
1422 model->Initialize(common,id,version);
1423
1424 /* Get tablet resolution */
1425 if (model->GetResolution)
1426 model->GetResolution(pInfo);
1427
1428 /* Get tablet range */
1429 if (model->GetRanges && (model->GetRanges(pInfo) != Success))
1430 return !Success;
1431
1432 /* Default threshold value if not set */
1433 if (common->wcmThreshold <= 0 && IsPen(priv))
1434 {
1435 /* Threshold for counting pressure as a button */
1436 common->wcmThreshold = priv->maxCurve * DEFAULT_THRESHOLD;
1437
1438 xf86Msg(X_PROBED, "%s: using pressure threshold of %d for button 1\n",
1439 pInfo->name, common->wcmThreshold);
1440 }
1441
1442 /* Calculate default panscroll threshold if not set */
1443 xf86Msg(X_CONFIG, "%s: panscroll is %d\n", pInfo->name, common->wcmPanscrollThreshold);
1444 if (common->wcmPanscrollThreshold < 1) {
1445 common->wcmPanscrollThreshold = common->wcmResolY * 13 / 1000; /* 13mm */
1446 }
1447 if (common->wcmPanscrollThreshold < 1) {
1448 common->wcmPanscrollThreshold = 1000;
1449 }
1450 xf86Msg(X_CONFIG, "%s: panscroll modified to %d\n", pInfo->name, common->wcmPanscrollThreshold);
1451
1452 /* output tablet state as probed */
1453 if (IsPen(priv))
1454 xf86Msg(X_PROBED, "%s: maxX=%d maxY=%d maxZ=%d "
1455 "resX=%d resY=%d tilt=%s\n",
1456 pInfo->name,
1457 common->wcmMaxX, common->wcmMaxY, common->wcmMaxZ,
1458 common->wcmResolX, common->wcmResolY,
1459 HANDLE_TILT(common) ? "enabled" : "disabled");
1460 else if (IsTouch(priv))
1461 xf86Msg(X_PROBED, "%s: maxX=%d maxY=%d maxZ=%d "
1462 "resX=%d resY=%d \n",
1463 pInfo->name,
1464 common->wcmMaxTouchX, common->wcmMaxTouchY,
1465 common->wcmMaxZ,
1466 common->wcmTouchResolX, common->wcmTouchResolY);
1467
1468 return Success;
1469 }
1470
1471 /* Send a soft prox-out event for the device */
wcmSoftOutEvent(InputInfoPtr pInfo)1472 void wcmSoftOutEvent(InputInfoPtr pInfo)
1473 {
1474 WacomDeviceState out = OUTPROX_STATE;
1475 WacomDevicePtr priv = (WacomDevicePtr) pInfo->private;
1476
1477 out.device_type = DEVICE_ID(priv->flags);
1478 out.device_id = wcmGetPhyDeviceID(priv);
1479 DBG(2, priv->common, "send a soft prox-out\n");
1480 wcmSendEvents(pInfo, &out);
1481 }
1482
1483 /*****************************************************************************
1484 ** Transformations
1485 *****************************************************************************/
1486
1487 /**
1488 * Apply the current pressure curve to the current pressure.
1489 *
1490 * @return The modified pressure value.
1491 */
applyPressureCurve(WacomDevicePtr pDev,const WacomDeviceStatePtr pState)1492 static int applyPressureCurve(WacomDevicePtr pDev, const WacomDeviceStatePtr pState)
1493 {
1494 /* clip the pressure */
1495 int p = max(0, pState->pressure);
1496
1497 p = min(pDev->maxCurve, p);
1498
1499 /* apply pressure curve function */
1500 if (pDev->pPressCurve == NULL)
1501 return p;
1502 else
1503 return pDev->pPressCurve[p];
1504 }
1505
1506 /*****************************************************************************
1507 * wcmRotateTablet
1508 ****************************************************************************/
1509
wcmRotateTablet(InputInfoPtr pInfo,int value)1510 void wcmRotateTablet(InputInfoPtr pInfo, int value)
1511 {
1512 WacomDevicePtr priv = (WacomDevicePtr)pInfo->private;
1513 WacomCommonPtr common = priv->common;
1514 WacomToolPtr tool;
1515
1516 DBG(10, priv, "\n");
1517 common->wcmRotate = value;
1518
1519 /* Only try updating properties once we're enabled, no point
1520 * otherwise. */
1521 tool = priv->tool;
1522 if (tool->enabled)
1523 wcmUpdateRotationProperty(priv);
1524 }
1525
1526 /* Common pointer refcounting utilities.
1527 * Common is shared across all wacom devices off the same port. These
1528 * functions implement basic refcounting to avoid double-frees and memleaks.
1529 *
1530 * Usage:
1531 * wcmNewCommon() to create a new struct.
1532 * wcmRefCommon() to get a new reference to an already exiting one.
1533 * wcmFreeCommon() to unref. After the last ref has been unlinked, the
1534 * struct is freed.
1535 *
1536 */
1537
wcmNewCommon(void)1538 WacomCommonPtr wcmNewCommon(void)
1539 {
1540 WacomCommonPtr common;
1541 common = calloc(1, sizeof(WacomCommonRec));
1542 if (!common)
1543 return NULL;;
1544
1545 common->refcnt = 1;
1546 common->wcmFlags = 0; /* various flags */
1547 common->wcmProtocolLevel = WCM_PROTOCOL_4; /* protocol level */
1548 common->wcmTPCButton = 0; /* set Tablet PC button on/off */
1549 common->wcmGestureParameters.wcmScrollDirection = 0;
1550 common->wcmGestureParameters.wcmTapTime = 250;
1551 common->wcmRotate = ROTATE_NONE; /* default tablet rotation to off */
1552 common->wcmMaxX = 0; /* max digitizer logical X value */
1553 common->wcmMaxY = 0; /* max digitizer logical Y value */
1554 common->wcmMaxTouchX = 1024; /* max touch X value */
1555 common->wcmMaxTouchY = 1024; /* max touch Y value */
1556 common->wcmMaxStripX = 4096; /* Max fingerstrip X */
1557 common->wcmMaxStripY = 4096; /* Max fingerstrip Y */
1558 common->wcmProxoutDistDefault = PROXOUT_INTUOS_DISTANCE;
1559 /* default to Intuos */
1560 common->wcmSuppress = DEFAULT_SUPPRESS;
1561 /* transmit position if increment is superior */
1562 common->wcmRawSample = DEFAULT_SAMPLES;
1563 /* number of raw data to be used to for filtering */
1564 common->wcmPanscrollThreshold = 0;
1565 common->wcmPressureRecalibration = 1;
1566 return common;
1567 }
1568
1569
wcmFreeCommon(WacomCommonPtr * ptr)1570 void wcmFreeCommon(WacomCommonPtr *ptr)
1571 {
1572 WacomCommonPtr common = *ptr;
1573
1574 if (!common)
1575 return;
1576
1577 DBG(10, common, "common refcount dec to %d\n", common->refcnt - 1);
1578 if (--common->refcnt == 0)
1579 {
1580 free(common->private);
1581 while (common->serials)
1582 {
1583 WacomToolPtr next;
1584
1585 DBG(10, common, "Free common serial: %d %s\n",
1586 common->serials->serial,
1587 common->serials->name);
1588
1589 free(common->serials->name);
1590 next = common->serials->next;
1591 free(common->serials);
1592 common->serials = next;
1593 }
1594 free(common->device_path);
1595 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 16
1596 free(common->touch_mask);
1597 #endif
1598 free(common);
1599 }
1600 *ptr = NULL;
1601 }
1602
wcmRefCommon(WacomCommonPtr common)1603 WacomCommonPtr wcmRefCommon(WacomCommonPtr common)
1604 {
1605 if (!common)
1606 common = wcmNewCommon();
1607 else
1608 common->refcnt++;
1609 DBG(10, common, "common refcount inc to %d\n", common->refcnt);
1610 return common;
1611 }
1612
1613 /* vim: set noexpandtab tabstop=8 shiftwidth=8: */
1614