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