Пример #1
0
static void wcmSendScrollEvent(WacomDevicePtr priv, int dist,
			 int buttonUp, int buttonDn)
{
	int button = (dist > 0) ? buttonUp : buttonDn;
	WacomCommonPtr common = priv->common;
	int count = (int)((1.0 * abs(dist)/
		common->wcmGestureParameters.wcmScrollDistance) + 0.5);
	WacomChannelPtr firstChannel = common->wcmChannel;
	WacomChannelPtr secondChannel = common->wcmChannel + 1;
	WacomDeviceState ds[2] = { firstChannel->valid.states[0],
				secondChannel->valid.states[0] };

	/* user might have changed from up to down or vice versa */
	if (count < common->wcmGestureParameters.wcmGestureUsed)
	{
		common->wcmGestureState[0] = ds[0];
		common->wcmGestureState[1] = ds[1];
		common->wcmGestureParameters.wcmGestureUsed  = 0;
		return;
	}

	count -= common->wcmGestureParameters.wcmGestureUsed;
	common->wcmGestureParameters.wcmGestureUsed += count;
	while (count--)
	{
		wcmSendButtonClick(priv, button, 1);
		wcmSendButtonClick(priv, button, 0);
		DBG(10, priv, "loop count = %d \n", count);
	}
}
Пример #2
0
static void wcmFingerTapToClick(WacomDevicePtr priv)
{
	WacomCommonPtr common = priv->common;
	WacomDeviceState ds[2] = {}, dsLast[2] = {};

	if (!common->wcmGesture)
		return;

	getStateHistory(common, ds, ARRAY_SIZE(ds), 0);
	getStateHistory(common, dsLast, ARRAY_SIZE(dsLast), 1);

	DBG(10, priv, "\n");

	/* process second finger tap if matched */
	if ((ds[0].sample < ds[1].sample) &&
	    ((GetTimeInMillis() -
	    dsLast[1].sample) <= common->wcmGestureParameters.wcmTapTime) &&
	    !ds[1].proximity && dsLast[1].proximity)
	{
		/* send left up before sending right down */
		wcmSendButtonClick(priv, 1, 0);
		common->wcmGestureMode = GESTURE_TAP_MODE;

		/* right button down */
		wcmSendButtonClick(priv, 3, 1);

		/* right button up */
		wcmSendButtonClick(priv, 3, 0);
	}
}
Пример #3
0
static void wcmFingerTapToClick(WacomDevicePtr priv)
{
	WacomCommonPtr common = priv->common;
	WacomChannelPtr firstChannel = common->wcmChannel;
	WacomChannelPtr secondChannel = common->wcmChannel + 1;
	WacomDeviceState ds[2] = { firstChannel->valid.states[0],
				   secondChannel->valid.states[0] };
	WacomDeviceState dsLast[2] = { firstChannel->valid.states[1],
					secondChannel->valid.states[1] };

	DBG(10, priv, "\n");

	/* process second finger tap if matched */
	if ((ds[0].sample < ds[1].sample) &&
	    ((GetTimeInMillis() -
	    dsLast[1].sample) <= common->wcmGestureParameters.wcmTapTime) &&
	    !ds[1].proximity && dsLast[1].proximity)
	{
		/* send left up before sending right down */
		wcmSendButtonClick(priv, 1, 0);
		common->wcmGestureMode = GESTURE_TAP_MODE;

		/* right button down */
		wcmSendButtonClick(priv, 3, 1);

		/* right button up */
		wcmSendButtonClick(priv, 3, 0);
	}
}
Пример #4
0
/**
 * Send multitouch events. If entering multitouch mode (indicated by
 * GESTURE_LAG_MODE), then touch events are sent for all in-prox
 * contacts. Otherwise, only the specified contact has a touch event
 * generated.
 *
 * @param[in] priv
 * @param[in] contact_id  ID of the contact to send event for (at minimum)
 */
static void
wcmFingerMultitouch(WacomDevicePtr priv, int contact_id) {
	Bool lag_mode = priv->common->wcmGestureMode == GESTURE_LAG_MODE;
	Bool prox = FALSE;
	int i;

	if (lag_mode && TabletHasFeature(priv->common, WCM_LCD)) {
		/* wcmSingleFingerPress triggers a button press as
		 * soon as a single finger appears. ensure we release
		 * that button before getting too far along
		 */
		wcmSendButtonClick(priv, 1, 0);
	}

	for (i = 0; i < MAX_CHANNELS; i++) {
		WacomChannelPtr channel = priv->common->wcmChannel+i;
		WacomDeviceState state  = channel->valid.state;
		if (state.device_type != TOUCH_ID)
			continue;

		if (lag_mode || state.serial_num == contact_id + 1) {
			wcmSendTouchEvent(priv, channel, lag_mode);
		}

		prox |= state.proximity;
	}

	if (!prox)
		priv->common->wcmGestureMode = GESTURE_NONE_MODE;
	else if (lag_mode)
		priv->common->wcmGestureMode = GESTURE_MULTITOUCH_MODE;
}
Пример #5
0
static CARD32 wcmSingleFingerTapTimer(OsTimerPtr timer, CARD32 time, pointer arg)
{
	WacomDevicePtr priv = (WacomDevicePtr)arg;
	WacomCommonPtr common = priv->common;

	if (common->wcmGestureMode == GESTURE_PREDRAG_MODE)
	{
		/* left button down */
		wcmSendButtonClick(priv, 1, 1);

		/* left button up */
		wcmSendButtonClick(priv, 1, 0);
		common->wcmGestureMode = GESTURE_NONE_MODE;
	}

	return 0;
}
Пример #6
0
static void wcmFingerZoom(WacomDevicePtr priv)
{
	WacomCommonPtr common = priv->common;
	WacomChannelPtr firstChannel = common->wcmChannel;
	WacomChannelPtr secondChannel = common->wcmChannel + 1;
	WacomDeviceState ds[2] = { firstChannel->valid.states[0],
		secondChannel->valid.states[0] };
	int count, button;
	int dist = touchDistance(common->wcmGestureState[0],
			common->wcmGestureState[1]);
	int max_spread = common->wcmGestureParameters.wcmMaxScrollFingerSpread;

	DBG(10, priv, "\n");

	if (common->wcmGestureMode != GESTURE_ZOOM_MODE)
	{
		/* two fingers moved apart from each other */
		if (abs(touchDistance(ds[0], ds[1]) -
			touchDistance(common->wcmGestureState[0],
				      common->wcmGestureState[1])) >
			(3 * max_spread))
		{
			/* left button might be down, send it up first */
			wcmSendButtonClick(priv, 1, 0);

			/* fingers moved apart more than 3 times
			 * wcmMaxScrollFingerSpread, zoom mode is entered */
			common->wcmGestureMode = GESTURE_ZOOM_MODE;
		}
	}

	if (common->wcmGestureMode != GESTURE_ZOOM_MODE)
		return;

	dist = touchDistance(ds[0], ds[1]) - dist;
	count = (int)((1.0 * abs(dist)/common->wcmGestureParameters.wcmZoomDistance) + 0.5);

	/* user might have changed from left to right or vice versa */
	if (count < common->wcmGestureParameters.wcmGestureUsed)
	{
		/* reset the initial states for the new getsure */
		common->wcmGestureState[0] = ds[0];
		common->wcmGestureState[1] = ds[1];
		common->wcmGestureParameters.wcmGestureUsed  = 0;
		return;
	}

	/* zooming? Send ctrl + scroll up/down event.
	FIXME: this hardcodes the positions of ctrl and assumes that ctrl is
	actually a modifier. Tough luck. The alternative is to run through
	the XKB table and figure out where the key for the ctrl modifier is
	hiding. Good luck.
	Gesture support is not supposed to be in the driver...
	 */
	button = (dist > 0) ? 4 : 5;

	count -= common->wcmGestureParameters.wcmGestureUsed;
	common->wcmGestureParameters.wcmGestureUsed += count;
	while (count--)
	{
		wcmEmitKeycode (priv->pInfo->dev, 37 /*XK_Control_L*/, 1);
		wcmSendButtonClick (priv, button, 1);
		wcmSendButtonClick (priv, button, 0);
		wcmEmitKeycode (priv->pInfo->dev, 37 /*XK_Control_L*/, 0);
	}
}
Пример #7
0
static void wcmFingerScroll(WacomDevicePtr priv)
{
	WacomCommonPtr common = priv->common;
	WacomChannelPtr firstChannel = common->wcmChannel;
	WacomChannelPtr secondChannel = common->wcmChannel + 1;
	WacomDeviceState ds[2] = { firstChannel->valid.states[0],
		secondChannel->valid.states[0] };

	int midPoint_new = 0;
	int midPoint_old = 0;
	int i = 0, dist = 0;
	WacomFilterState filterd;  /* borrow this struct */
	int max_spread = common->wcmGestureParameters.wcmMaxScrollFingerSpread;

	DBG(10, priv, "\n");

	if (common->wcmGestureMode != GESTURE_SCROLL_MODE)
	{
		if (abs(touchDistance(ds[0], ds[1]) -
			touchDistance(common->wcmGestureState[0],
			common->wcmGestureState[1])) < max_spread)
		{
			/* two fingers stay close to each other all the time and
			 * move in vertical or horizontal direction together
			 */
			if (pointsInLine(common, ds[0], common->wcmGestureState[0])
			    && pointsInLine(common, ds[1], common->wcmGestureState[1])
			    && common->wcmGestureParameters.wcmScrollDirection)
			{
				/* left button might be down. Send it up first */
				wcmSendButtonClick(priv, 1, 0);
				common->wcmGestureMode = GESTURE_SCROLL_MODE;
			}
		}
	}

	/* still not a scroll event yet? */
	if (common->wcmGestureMode != GESTURE_SCROLL_MODE)
		return;

	/* initialize the points so we can rotate them */
	filterd.x[0] = ds[0].x;
	filterd.y[0] = ds[0].y;
	filterd.x[1] = ds[1].x;
	filterd.y[1] = ds[1].y;
	filterd.x[2] = common->wcmGestureState[0].x;
	filterd.y[2] = common->wcmGestureState[0].y;
	filterd.x[3] = common->wcmGestureState[1].x;
	filterd.y[3] = common->wcmGestureState[1].y;

	/* scrolling has directions so rotation has to be considered first */
	for (i=0; i<6; i++)
		wcmRotateAndScaleCoordinates(priv->pInfo, &filterd.x[i], &filterd.y[i]);

	/* check vertical direction */
	if (common->wcmGestureParameters.wcmScrollDirection == WACOM_VERT_ALLOWED)
	{
		midPoint_old = (((double)filterd.y[2] + (double)filterd.y[3]) / 2.);
		midPoint_new = (((double)filterd.y[0] + (double)filterd.y[1]) / 2.);

		/* allow one finger scroll */
		if (!ds[0].proximity)
		{
			midPoint_old = filterd.y[3];
			midPoint_new = filterd.y[1];
		}

		if (!ds[1].proximity)
		{
			midPoint_old = filterd.y[2];
			midPoint_new = filterd.y[0];
		}

		dist = midPoint_old - midPoint_new;
		wcmSendScrollEvent(priv, dist, WCM_SCROLL_UP, WCM_SCROLL_DOWN);
	}

	if (common->wcmGestureParameters.wcmScrollDirection == WACOM_HORIZ_ALLOWED)
	{
		midPoint_old = (((double)filterd.x[2] + (double)filterd.x[3]) / 2.);
		midPoint_new = (((double)filterd.x[0] + (double)filterd.x[1]) / 2.);

		/* allow one finger scroll */
		if (!ds[0].proximity)
		{
			midPoint_old = filterd.x[3];
			midPoint_new = filterd.x[1];
		}

		if (!ds[1].proximity)
		{
			midPoint_old = filterd.x[2];
			midPoint_new = filterd.x[0];
		}

		dist = midPoint_old - midPoint_new;
		wcmSendScrollEvent(priv, dist, WCM_SCROLL_RIGHT, WCM_SCROLL_LEFT);
	}
}
Пример #8
0
/* parsing gesture mode according to 2FGT data */
void wcmGestureFilter(WacomDevicePtr priv, int channel)
{
	WacomCommonPtr common = priv->common;
	WacomChannelPtr firstChannel = common->wcmChannel;
	WacomChannelPtr secondChannel = common->wcmChannel + 1;
	WacomDeviceState ds[2] = { firstChannel->valid.states[0],
				secondChannel->valid.states[0] };
	WacomDeviceState dsLast[2] = { firstChannel->valid.states[1],
				secondChannel->valid.states[1] };

	DBG(10, priv, "\n");

	if (!IsTouch(priv))
	{
		/* this should never happen */
		xf86Msg(X_ERROR, "WACOM: No touch device found for %s \n",
			 common->device_path);
		return;
	}

	if (!common->wcmGesture)
		goto ret;

	/* When 2 fingers are in proximity, it must always be in one of
	 * the valid 2 fingers modes: LAG, SCROLL, or ZOOM.
	 * LAG mode is used while deciding between SCROLL and ZOOM and
	 * prevents cursor movement.  Force to LAG mode if ever in NONE
	 * mode to stop cursor movement.
	 */
	if (ds[0].proximity && ds[1].proximity)
	{
		if (common->wcmGestureMode == GESTURE_NONE_MODE)
			common->wcmGestureMode = GESTURE_LAG_MODE;
	}
	/* When only 1 finger is in proximity, it can be in either LAG mode,
	 * NONE mode or DRAG mode.
	 * 1 finger LAG mode is a very short time period mainly to debounce
	 * initial touch.
	 * NONE and DRAG mode means cursor is allowed to move around.
	 * DRAG mode in addition means that left button pressed.
	 * There is no need to bother about LAG_TIME while in DRAG mode.
	 * TODO: This has to use dsLast[0] because of later logic that
	 * wants mode to be NONE still when 1st entering proximity.
	 * That could use some re-arranging/cleanup.
	 *
	 */
	else if (dsLast[0].proximity && common->wcmGestureMode != GESTURE_DRAG_MODE)
	{
		CARD32 ms = GetTimeInMillis();

		if ((ms - ds[0].sample) < WACOM_GESTURE_LAG_TIME)
		{
			/* Must have recently come into proximity.  Change
			 * into LAG mode.
			 */
			if (common->wcmGestureMode == GESTURE_NONE_MODE)
				common->wcmGestureMode = GESTURE_LAG_MODE;
		}
		else
		{
			/* Been in LAG mode long enough. Force to NONE mode. */
			common->wcmGestureMode = GESTURE_NONE_MODE;
		}
	}

	if  (ds[1].proximity && !dsLast[1].proximity)
	{
		/* keep the initial states for gesture mode */
		common->wcmGestureState[1] = ds[1];

		/* reset the initial count for a new getsure */
		common->wcmGestureParameters.wcmGestureUsed  = 0;
	}

	if (ds[0].proximity && !dsLast[0].proximity)
	{
		/* keep the initial states for gesture mode */
		common->wcmGestureState[0] = ds[0];

		/* reset the initial count for a new getsure */
		common->wcmGestureParameters.wcmGestureUsed  = 0;

		/* initialize the cursor position */
		if (common->wcmGestureMode == GESTURE_NONE_MODE && !channel)
			goto ret;

		/* got second touch in TapTime interval after first one,
		 * switch to DRAG mode */
		if (common->wcmGestureMode == GESTURE_PREDRAG_MODE)
		{
			/* left button down */
			wcmSendButtonClick(priv, 1, 1);
			common->wcmGestureMode = GESTURE_DRAG_MODE;
			goto ret;
		}
	}

	if (!ds[0].proximity && !ds[1].proximity)
	{
		/* first finger was out-prox when GestureMode was still on */
		if (!dsLast[0].proximity &&
		    common->wcmGestureMode != GESTURE_NONE_MODE)
			/* send first finger out prox */
			wcmSoftOutEvent(priv->pInfo);

		/* if were in DRAG mode, send left button up now */
		if (common->wcmGestureMode == GESTURE_DRAG_MODE)
			wcmSendButtonClick(priv, 1, 0);

		/* exit gesture mode when both fingers are out */
		common->wcmGestureMode = GESTURE_NONE_MODE;
		common->wcmGestureParameters.wcmScrollDirection = 0;

		goto ret;
	}

	if (!(common->wcmGestureMode & (GESTURE_SCROLL_MODE | GESTURE_ZOOM_MODE)) && channel)
		wcmFingerTapToClick(priv);

	/* Change mode happens only when both fingers are out */
	if (common->wcmGestureMode & GESTURE_TAP_MODE)
		goto ret;

	/* skip initial finger event for scroll and zoom */
	if (!dsLast[0].proximity || !dsLast[1].proximity)
		goto ret;

	/* was in zoom mode no time check needed */
	if ((common->wcmGestureMode & GESTURE_ZOOM_MODE) &&
	    ds[0].proximity && ds[1].proximity)
		wcmFingerZoom(priv);

	/* was in scroll mode no time check needed */
	else if (common->wcmGestureMode & GESTURE_SCROLL_MODE)
		    wcmFingerScroll(priv);

	/* process complex two finger gestures */
	else {
		CARD32 ms = GetTimeInMillis();
		int taptime = common->wcmGestureParameters.wcmTapTime;

		if (ds[0].proximity && ds[1].proximity &&
		    (taptime < (ms - ds[0].sample)) &&
		    (taptime < (ms - ds[1].sample)))
		{
			/* scroll should be considered first since it requires
			 * a finger distance check */
			wcmFingerScroll(priv);

			if (!(common->wcmGestureMode & GESTURE_SCROLL_MODE))
				wcmFingerZoom(priv);
		}
	}
ret:
	if (common->wcmGestureMode == GESTURE_NONE_MODE && !channel)
	{
		/* Since this is in ret block, can not rely on generic
		 * wcmGesture enable check from above.
		 */
		if (common->wcmGesture)
			wcmSingleFingerTap(priv);
		wcmSingleFingerPress(priv);
	}
}