--- Begin Message ---
- To: submit@bugs.debian.org
- Subject: Touchscreen (Viewsonic Viewpad, etc.) absolute positioning patch.
- From: Rob Browning <rlb@defaultvalue.org>
- Date: Wed, 07 Aug 2002 11:21:34 -0500
- Message-id: <87k7n28ws1.fsf@raven.i.defaultvalue.org>
Package: xserver-xfree86
Version: 4.2
Severity: wishlist
This is a patch I created by backporting from the current X CVS tree.
This patch adds support for the Viewsonic Viewpad touchscreen (among
others). Without this patch, the mouse only operates in relative
positioning mode. i.e. if you touch the screen on a button, you don't
click on that button, you click wherever the pointer was when you
touched the screen. I've also forwarded this patch on to the upstream
author who's doing the CVS tree work.
Thanks
--- xc/programs/Xserver/hw/xfree86/input/mouse/mousePriv.h 2002/02/24 15:13:22 1.6
+++ xc/programs/Xserver/hw/xfree86/input/mouse/mousePriv.h 2002/03/18 20:50:34
@@ -19,7 +19,13 @@
typedef struct {
int state;
-} ps2PrivRec, *ps2PrivPtr;
+ int min_x;
+ int max_x;
+ int min_y;
+ int max_y;
+ int rotate;
+ int reporting_mode;
+} mousePrivRec, *mousePrivPtr;
/* mouse proto flags */
#define MPF_NONE 0x00
--- xc/programs/Xserver/hw/xfree86/input/mouse/mouse.c 2002/02/24 15:13:22 1.50
+++ xc/programs/Xserver/hw/xfree86/input/mouse/mouse.c 2002/03/18 20:50:34
@@ -73,6 +73,7 @@
static Bool MouseConvert(LocalDevicePtr local, int first, int num, int v0,
int v1, int v2, int v3, int v4, int v5, int *x,
int *y);
+static int MouseControl(InputInfoPtr pInfo, xDeviceCtl * control);
static void MouseCtrl(DeviceIntPtr device, PtrCtrl *ctrl);
static void MousePostEvent(InputInfoPtr pInfo, int buttons,
@@ -119,6 +120,11 @@
OPTION_FLOW_CONTROL,
OPTION_VTIME,
OPTION_VMIN,
+ OPTION_MINX,
+ OPTION_MAXX,
+ OPTION_MINY,
+ OPTION_MAXY,
+ OPTION_ROTATE,
OPTION_EMULATE_WHEEL,
OPTION_EMU_WHEEL_BUTTON,
OPTION_EMU_WHEEL_INERTIA,
@@ -153,6 +159,13 @@
{ OPTION_FLOW_CONTROL, "FlowControl", OPTV_STRING, {0}, FALSE },
{ OPTION_VTIME, "VTime", OPTV_INTEGER, {0}, FALSE },
{ OPTION_VMIN, "VMin", OPTV_INTEGER, {0}, FALSE },
+ /* touchscreen options */
+ { OPTION_MINX, "MinX", OPTV_INTEGER, {0}, FALSE },
+ { OPTION_MAXX, "MaxX", OPTV_INTEGER, {0}, FALSE },
+ { OPTION_MINY, "MinY", OPTV_INTEGER, {0}, FALSE },
+ { OPTION_MAXY, "MaxY", OPTV_INTEGER, {0}, FALSE },
+ { OPTION_ROTATE, "Rotate", OPTV_STRING, {0}, FALSE },
+ /* end touchscreen options */
{ OPTION_EMULATE_WHEEL, "EmulateWheel", OPTV_BOOLEAN, {0}, FALSE },
{ OPTION_EMU_WHEEL_BUTTON, "EmulateWheelButton", OPTV_INTEGER, {0}, FALSE },
{ OPTION_EMU_WHEEL_INERTIA, "EmulateWheelInertia", OPTV_INTEGER, {0}, FALSE },
@@ -256,7 +269,9 @@
{ "GlidePointPS/2", MSE_XPS2, NULL, PROT_GLIDEPS2 },
{ "NetMousePS/2", MSE_XPS2, NULL, PROT_NETPS2 },
{ "NetScrollPS/2", MSE_XPS2, NULL, PROT_NETSCPS2 },
-
+ { "ScreenCoderPS/2", MSE_XPS2, NULL, PROT_SCPS2 },
+ { "ScreenCoderIMPS/2", MSE_XPS2, NULL, PROT_SCIMPS2 },
+ { "ScreenCoderEXPPS/2", MSE_XPS2, NULL, PROT_SCEXPPS2 },
/* Bus Mouse */
{ "BusMouse", MSE_BUS, NULL, PROT_BM },
@@ -594,8 +609,10 @@
static InputInfoPtr
MousePreInit(InputDriverPtr drv, IDevPtr dev, int flags)
{
+ char *s;
InputInfoPtr pInfo;
MouseDevPtr pMse;
+ mousePrivPtr mPriv;
MessageType from = X_DEFAULT;
const char *protocol;
MouseProtocolID protocolID;
@@ -615,7 +632,7 @@
pInfo->read_input = MouseReadInput;
pInfo->motion_history_proc = xf86GetMotionEvents;
pInfo->history_size = 0;
- pInfo->control_proc = NULL;
+ pInfo->control_proc = MouseControl;
pInfo->close_proc = NULL;
pInfo->switch_mode = NULL;
pInfo->conversion_proc = MouseConvert;
@@ -710,6 +727,9 @@
#endif
pInfo->fd = -1;
+ if (!(mPriv = (pointer) xcalloc(sizeof(mousePrivRec), 1)))
+ return pInfo;
+ pMse->mousePriv = mPriv;
pMse->CommonOptions(pInfo);
pMse->sampleRate = xf86SetIntOption(pInfo->options, "SampleRate", 0);
@@ -743,6 +763,21 @@
xf86ErrorF("\n");
}
+ s = xf86SetStrOption(pInfo->options, "Rotate", NULL);
+ if (s) {
+ if (!xf86NameCmp(s, "CW")) {
+ mPriv->rotate = 1;
+ }else if (!xf86NameCmp(s, "CCW")) {
+ mPriv->rotate = -1;
+ }else{
+ mPriv->rotate = 0;
+ }
+ }
+ mPriv->min_x = xf86SetIntOption(pInfo->options, "MinX", 0);
+ mPriv->max_x = xf86SetIntOption(pInfo->options, "MaxX", 1023);
+ mPriv->min_y = xf86SetIntOption(pInfo->options, "MinY", 0);
+ mPriv->max_y = xf86SetIntOption(pInfo->options, "MaxY", 1023);
+
pInfo->flags |= XI86_CONFIGURED;
return pInfo;
}
@@ -778,6 +813,9 @@
{ 0xf8, 0x80, 0x00, 0x00, 5, 0x00, 0xff, MPF_NONE }, /* BusMouse */
{ 0xf8, 0x80, 0x00, 0x00, 5, 0x00, 0xff, MPF_NONE }, /* Auto (dummy) */
{ 0xf8, 0x80, 0x00, 0x00, 8, 0x00, 0xff, MPF_NONE }, /* SysMouse */
+ { 0x00, 0x00, 0x00, 0x00, 3, 0x00, 0xff, MPF_NONE }, /* ScreenCoder */
+ { 0x00, 0x00, 0x00, 0x00, 4, 0x00, 0xff, MPF_NONE }, /* ScreenCoder Im */
+ { 0x00, 0x00, 0x00, 0x00, 4, 0x00, 0xff, MPF_NONE }, /* ScreenCoder Exp */
};
/*
@@ -1082,9 +1120,9 @@
case PROT_GLIDEPS2:
case PROT_NETPS2: /* NetMouse, NetMouse Pro, Mie Mouse */
case PROT_NETSCPS2: /* NetScroll */
+ case PROT_SCPS2:
+ case PROT_SCIMPS2:
+ case PROT_SCEXPPS2:
- if ((pMse->mousePriv =
- (pointer) xcalloc(sizeof(ps2PrivRec), 1)) == 0)
- return FALSE;
initPs2(pInfo,TRUE);
break;
case PROT_SYSMOUSE:
@@ -1113,6 +1148,7 @@
int pBufP;
int c;
unsigned char *pBuf, u;
+ MouseProtocolID tmpProto;
pMse = pInfo->private;
pBufP = pMse->protoBufTail;
@@ -1332,7 +1368,63 @@
*/
dz = dw = 0;
- switch (pMse->protocolID) {
+ /* The ScreenCoder operates in two modes. In the first
+ mode, it injects relative motion packets along with
+ packets from an external pointer device. The format of
+ packets from both sources is identical. In the second
+ mode, the injected packets represent absolute position.
+ In that case, the external pointer device packets are
+ guaranteed (by reformatting) to have bit 3 of byte 0 set.
+ This block looks for, and processes absolute position
+ packets, while passing relative motion packets along
+ for processing as PS/2, IMPS/2 or EXPPS/2 packets, i.e.,
+ this block of code picks off the absolute position
+ packets from the data stream. [RAB-2002/04/25] */
+ tmpProto = pMse->protocolID;
+ switch (tmpProto) {
+ case PROT_SCPS2:
+ if (pBuf[0] & 0x08){
+ /* it belongs to the external pointer */
+ tmpProto = PROT_PS2;
+ break;
+ }
+ case PROT_SCIMPS2:
+ if (pBuf[0] & 0x08){
+ /* it belongs to the external pointer */
+ tmpProto = PROT_IMPS2;
+ break;
+ }
+ case PROT_SCEXPPS2:
+ if (pBuf[0] & 0x08){
+ /* it belongs to the external pointer */
+ tmpProto = PROT_EXPPS2;
+ break;
+ }
+ /* fall through to common code which deals with
+ * absolute positioning information: common to
+ * PROT_SCPS2, PROT_SCIMPS2, and PROT_SCEXPPS2 */
+ if ((pBuf[0] & 0x03) == 0x03){
+ buttons = 0;
+ }else if ((pBuf[0] & 0x03) == 0x00){
+ buttons = 0x04;
+ }else{
+ buttons = 0;
+ ErrorF("fell out of sync !!!");
+ }
+ dx = ((pBuf[0] & 0x30)<<4) + pBuf[1];
+ dy = ((pBuf[0] & 0xC0)<<2) + pBuf[2];
+ /* dz is ignored in absolute mode */
+ /* this flags dx and dy as absolute position */
+ buttons |= MSE_ABSOLUTE_POSN;
+ tmpProto = PROT_SKIP;
+ break;
+ default:
+ break;
+ }
+
+ switch (tmpProto) {
+ case PROT_SKIP:
+ break;
case PROT_LOGIMAN: /* MouseMan / TrackMan [CHRIS-211092] */
case PROT_MS: /* Microsoft */
if (pMse->chordMiddle)
@@ -1559,6 +1651,24 @@
pMse->threshold = ctrl->threshold;
}
+static int
+MouseControl(InputInfoPtr pInfo, xDeviceCtl * control)
+{
+ MouseDevPtr pMse;
+ mousePrivPtr mPriv;
+ xDeviceTSCalibrationCtl *c;
+
+ pMse = pInfo->private;
+ mPriv = (mousePrivPtr)pMse->mousePriv;
+ c = (xDeviceTSCalibrationCtl *) control;
+
+ mPriv->min_x = c->min_x;
+ mPriv->max_x = c->max_x;
+ mPriv->min_y = c->min_y;
+ mPriv->max_y = c->max_y;
+ return (Success);
+} /* [RAB - 2002/04/25] */
+
/*
***************************************************************************
*
@@ -1989,8 +2099,13 @@
buttons &= ~pMse->wheelButtonMask;
}
- if (dx || dy)
- xf86PostMotionEvent(pInfo->dev, 0, 0, 2, dx, dy);
+ if (buttons & MSE_ABSOLUTE_POSN){ /* [RAB - 2002/04/25] */
+ xf86PostMotionEvent(pInfo->dev, 1, 0, 2, dx, dy);
+ buttons &= ~MSE_ABSOLUTE_POSN;
+ }else{
+ if (dx || dy)
+ xf86PostMotionEvent(pInfo->dev, 0, 0, 2, dx, dy);
+ }
if (truebuttons != pMse->lastButtons) {
@@ -2040,10 +2155,12 @@
MousePostEvent(InputInfoPtr pInfo, int buttons, int dx, int dy, int dz, int dw)
{
MouseDevPtr pMse;
+ mousePrivPtr mPriv;
int zbutton = 0;
pMse = pInfo->private;
+ mPriv = (mousePrivPtr)pMse->mousePriv;
/* Map the Z axis movement. */
/* XXX Could this go in the conversion_proc? */
@@ -2077,12 +2194,43 @@
dz = 0;
break;
}
- dx = pMse->invX * dx;
- dy = pMse->invY * dy;
- if (pMse->flipXY) {
- int tmp = dx;
- dx = dy;
- dy = tmp;
+ if (buttons & MSE_ABSOLUTE_POSN){ /* [RAB - 2002/04/25] */
+ int scaled_x,scaled_y;
+ /*******************************************
+ The use of mPriv->rotate allows absolute positioning
+ to be rotated here, but defers rotation of relative
+ positioning to the screen driver (since that seems to
+ be where it's done in at least the SiS driver).
+
+ Note: The xf86ScaleAxis function could have been used here,
+ but we can fold inversion and the flip operation into our
+ logic better without using this function.
+ *******************************************/
+ #define SCALE 10000
+ scaled_x = (SCALE * (dx - mPriv->min_x)) / mPriv->max_x;
+ scaled_y = (SCALE * (dy - mPriv->min_y)) / mPriv->max_y;
+ if (pMse->invX < 0 || mPriv->rotate == 1){
+ scaled_x = SCALE - scaled_x;
+ }
+ if (pMse->invY < 0 || mPriv->rotate == -1){
+ scaled_y = SCALE - scaled_y;
+ }
+ if (pMse->flipXY || mPriv->rotate ) {
+ dx = scaled_y * screenInfo.screens[0]->width / SCALE;
+ dy = scaled_x * screenInfo.screens[0]->height / SCALE;
+ }else{
+ dx = scaled_x * screenInfo.screens[0]->width / SCALE;
+ dy = scaled_y * screenInfo.screens[0]->height / SCALE;
+ }
+ }else{
+ dx = pMse->invX * dx;
+ dy = pMse->invY * dy;
+
+ if (pMse->flipXY) {
+ int tmp = dx;
+ dx = dy;
+ dy = tmp;
+ }
}
MouseDoPostEvent(pInfo, buttons, dx, dy);
@@ -2151,6 +2299,40 @@
}
break;
+ case PROT_SCIMPS2: /* ScreenCoder Intellimouse PS/2 */
+ {
+ /* "255" says "don't write, just read and discard" !!! */
+ static unsigned char seq[] = { 243, 200, 243, 100, 243, 80, 242,
+ 243, 80, 243, 60, 243, 100,
+ 242, 255, 243, 100 };
+
+ param = seq;
+ paramlen = sizeof(seq);
+ }
+ break;
+ case PROT_SCEXPPS2: /* ScreenCoder Explorer PS/2 */
+ {
+ /* "255" says "don't write, just read and discard" !!! */
+ static unsigned char seq[] = { 243, 200, 243, 100, 243, 80,
+ 243, 200, 243, 200, 243, 80, 242,
+ 243, 80, 243, 60, 243, 100,
+ 242, 255, 243, 100 };
+
+ param = seq;
+ paramlen = sizeof(seq);
+ }
+ break;
+ case PROT_SCPS2: /* ScreenCoder PS/2 */
+ {
+ /* "255" says "don't write, just read and discard" !!! */
+ static unsigned char seq[] = { 243, 80, 243, 60, 243, 100,
+ 242, 255, 243, 100 };
+
+ param = seq;
+ paramlen = sizeof(seq);
+ }
+ break;
+
case PROT_THINKPS2: /* ThinkingMouse */
{
static unsigned char seq[] = { 243, 10, 232, 0, 243, 20, 243, 60,
@@ -2162,14 +2344,23 @@
}
if (paramlen > 0) {
-#ifdef EXTMOUSEDEBUG
+/* The introduction of the "255" escape value, neccessary to initialize
+ * the ScreenCoder, makes it mandatory to use this block. [RAB - 2002/04/25]
+ */
+#if 1
+ int i;
for (i = 0; i < paramlen; ++i) {
- if (xf86WriteSerial(pInfo->fd, ¶m[i], 1) != 1)
+ /* "255" says "don't write, just read and discard" !!!*/
+ if (param[i] != 255){
+ if (xf86WriteSerial(pInfo->fd, ¶m[i], 1) != 1)
ErrorF("SetupMouse: Write to mouse failed (%s)\n",
strerror(errno));
+ }
usleep(30000);
xf86ReadSerial(pInfo->fd, &c, 1);
+#ifdef EXTMOUSEDEBUG
ErrorF("SetupMouse: got %02x\n", c);
+#endif
}
#else
if (xf86WriteSerial(pInfo->fd, param, paramlen) != paramlen)
@@ -2179,7 +2370,7 @@
xf86FlushInput(pInfo->fd);
}
- ((ps2PrivPtr)(pMse->mousePriv))->state = 0;
+ ((mousePrivPtr)(pMse->mousePriv))->state = 0;
if (osInfo->SetPS2Res) {
osInfo->SetPS2Res(pInfo, pMse->protocol, pMse->sampleRate,
pMse->resolution);
@@ -2231,19 +2422,19 @@
ps2mouseReset(InputInfoPtr pInfo, unsigned char val)
{
MouseDevPtr pMse = pInfo->private;
- ps2PrivPtr ps2priv = (ps2PrivPtr)pMse->mousePriv;
+ mousePrivPtr mPriv = (mousePrivPtr)pMse->mousePriv;
#ifdef EXTMOUSEDEBUG
- ErrorF("Ps/2 Mouse State: %i, 0x%x\n",ps2priv->state,val);
+ ErrorF("Ps/2 Mouse State: %i, 0x%x\n",mPriv->state,val);
#endif
- switch (ps2priv->state) {
+ switch (mPriv->state) {
case 0:
if (val == 0xaa)
- ps2priv->state = 1;
+ mPriv->state = 1;
else
- ps2priv->state = 0;
+ mPriv->state = 0;
return FALSE;
case 1:
- ps2priv->state = 0;
+ mPriv->state = 0;
if (val == 0x00) {
xf86MsgVerb(X_INFO,3,
"Got reinsert event: reinitializing PS/2 mouse\n");
--- xc/programs/Xserver/hw/xfree86/input/mouse/mouse.h 2002/02/24 15:14:55 1.10
+++ xc/programs/Xserver/hw/xfree86/input/mouse/mouse.h 2002/03/18 17:23:36
@@ -32,6 +32,10 @@
PROT_BM,
PROT_AUTO,
PROT_SYSMOUSE,
+ PROT_SCPS2,
+ PROT_SCIMPS2,
+ PROT_SCEXPPS2,
+ PROT_SKIP,
PROT_NUMPROTOS /* This must always be last. */
} MouseProtocolID;
--- xc/programs/Xserver/hw/xfree86/os-support/xf86OSmouse.h 2002/02/24 17:22:17 1.16
+++ xc/programs/Xserver/hw/xfree86/os-support/xf86OSmouse.h 2002/02/24 17:23:56
@@ -165,5 +165,6 @@
#define MSE_MAXBUTTONS 12
#define MSE_DFLTBUTTONS 3
+#define MSE_ABSOLUTE_POSN (1<<MSE_MAXBUTTONS)
#endif /* _XF86OSMOUSE_H_ */
--- xc/programs/Xserver/hw/xfree86/doc/sgml/mouse.sgml 2002/03/18 19:46:55 1.11
+++ xc/programs/Xserver/hw/xfree86/doc/sgml/mouse.sgml 2002/03/18 19:33:26
@@ -913,6 +913,51 @@
Option "Protocol" "Auto"
</verb>
+<sect1>Semtech ScreenCoder(PS/2) <p>
+The Semtech Screencoder provides a single packet stream from a resistive
+touchscreen and an "external" pointing device (which could be built into
+a laptop or tablet). By default, it appears as a PS/2 mouse to the system,
+but it will send Intellimouse PS/2 or Explorer PS/2 packets after the
+appropriate "knocking" sequences have been sent by the system.
+
+Since the Screencoder acts as a controller to the pointing device, it
+independently determines the highest level supported by the pointing
+device. It will then reformat the pointing device packets as needed.
+
+By default the touchscreen acts as a relative motion pointer, i.e.,
+it looks like mouse motion with button 1 pressed, so it doesn't
+matter where you initially touch the screen, only the direction
+your touch while in contact with the screen matters.
+
+To use the ScreenCoder in this mode, enter:
+<verb>
+ Option "Protocol" "PS/2"
+</verb>
+<verb>
+ Option "Protocol" "IMPS/2"
+</verb>
+or
+<verb>
+ Option "Protocol" "ExplorerPS/2"
+</verb>
+
+The ScreenCoder can also encode touchscreen positioning in absolute
+form. This is useful for pressing on-screen buttons, etc. In this
+mode, two packet formats appear in the data stream, with a status bit
+to distinguish one from the other.
+
+To use the ScreenCoder in this mode, enter:
+<verb>
+ Option "Protocol" "ScreenCoderPS/2"
+</verb>
+<verb>
+ Option "Protocol" "ScreenCoderIMPS/2"
+</verb>
+or
+<verb>
+ Option "Protocol" "ScreenCoderEXPPS/2"
+</verb>
+
<sect>Configuration Examples <p>
This section shows some example <tt>InputDevice</tt> section for
--
Rob Browning
rlb @defaultvalue.org, @linuxdevel.com, and @debian.org
Previously @cs.utexas.edu
GPG=1C58 8B2C FB5E 3F64 EA5C 64AE 78FE E5FE F0CB A0AD
--- End Message ---