| From: HYDRA::LNARAYAN "R Lakshminarayan, Software Partner Engg" 30-JAN-1997 12:47:18.04
To: US3RMC::"[email protected]"
CC: LNARAYAN
Subj: RE: Information on writing an XInput device driver
Bill Phillips
While Xinput is not documented outside of what's in /var/X11/Xserver.conf,
there is some general X and graphics driver documentation.
Currently we do not support addition of kernel input device
drivers, but we are planning to do so in the next major release.
It sounds like X input handles your situation.
The following is calcomp driver code and the associated text from the
engineer who gave this. You may use this as an example. Hope this helps.
Thank You
Nari
I'm forwarding you a copy of the CalComp driver code. The tablet code didn't
use streams because tty driver was not stream base and would required more
effort and time than allowed. The tablet can become the system pointer device.
Due to the device driver,the system mouse will also be a system pointer device
at the same time. This is only a problem when the puck is moved on the tablet
at the same time that the system mouse. The PUT_EVENT_ON_QUEUE ioctl is used
to put the formated input on the event queue. This is handled as by the dix
layer as another event that is recieved.
/*
* @DEC_COPYRIGHT@
*/
#pragma ident "@(#)$RCSfile: db3.c,v $ $Revision: 1.1.2.5 $ (DEC) $Date: 1996/04/17 20:07:57 $"
/*
There are multiple hacks in here when the tablet is set to the
corepointer. Currently there is no method to separate the system mouse
movement from the cursor movement because it's a hardware cursor
controlled by the os kernel. When there's an ioctl to disconnect the
cursor glyph from the system mouse, then this needs to be looked at
again. At the same time the Xi hack needs to be removed too.
*/
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/file.h>
#include <sys/time.h>
#include <sys/tty.h>
#include <sys/devio.h>
#include <sys/workstation.h>
#include <sys/inputdevice.h>
#include <sys/wsdevice.h>
#include "misc.h"
#include "X.h"
#define NEED_EVENTS
#include "Xproto.h"
#include "scrnintstr.h"
#include "pixmap.h"
#include "input.h"
#include "inputstr.h"
#include "ws.h"
#include "dix.h"
#include "os.h"
#include <sys/termios.h>
#include "XI.h"
#include "XIproto.h"
/************************************************************************/
/* */
/* The PUT_EVENT_ON_QUEUE macro should be defined in */
/* <sys/inputdevice.h> and is used in an ioctl call to add a ws_event */
/* to the workstation event queue. */
/* */
/************************************************************************/
#ifndef PUT_EVENT_ON_QUEUE
#define PUT_EVENT_ON_QUEUE _IOW('w', 35, ws_event)
#endif
#define DBUTTON 0x7c /* These bits determine a button press */
#define CBUTTON 0x3c /* Button decode */
#define BUTTON(inbuf) (((inbuf[0]) & DBUTTON) >>2)
#define XAXIS(inbuf) ((((inbuf[0]) & 0x03) << 14) | (((inbuf[1]) & 0x7f) << 7) | ((inbuf[2]) & 0x7f) | (((inbuf[3]) & 0x18) << 13 ))
#define YAXIS(inbuf) (((inbuf[3]) & 0x07) << 14 | ((inbuf[4]) & 0x7f) << 7 \
| ((inbuf[5]) & 0x7f))
/* XTILT and YTILT sign extend bit 6, the range according to the manual is
-64 to 63 */
#define XTILT(inbuf, a) \
if((inbuf[6]) & 0x40) a = (signed char)(((inbuf[6]) & 0x7f) | 0x80);\
else a = (signed char)(((inbuf[6]) & 0x7f));
#define YTILT(inbuf, a) \
if((inbuf[7]) & 0x40) a = (signed char)(((inbuf[7]) & 0x7f) | 0x80);\
else a = (signed char)(((inbuf[7]) & 0x7f));
#define PRESS(inbuf) ((inbuf[8]) & 0x7f)
#define HEIGHT(inbuf) ((inbuf[9]) & 0x7f)
#define INPROX(inbuf) (!((inbuf[3]) & 0x20))
#define SETOUTOFPROX(inbuf) ((inbuf[3]) |= 0x20)
typedef struct _Db3DevStruct
{
char *devName; /* Name of the tty for the device */
int Num; /* Which db3 this is (1,2,3...) */
int fd; /* File descriptor for the device */
int id; /* Xi ID of the tablet */
Bool corePointer; /* Use as the core pointer. */
Bool absMode; /* 1 = absolute 0 = relative mode */
int x; /* current x valuator */
int y; /* current y valuator */
int pressure;
int xPrev;
int yPrev;
int xAxis; /* valuators to report as x and y axis */
int yAxis; /* valuators to report as x and y axis */
int mntrX, mntrY; /* screen resolution of current screen */
int tabletX; /* tablet dimensions using a scaling of 1000 lpi */
int tabletY; /* tablet dimensions using a scaling of 1000 lpi */
int resolution; /* lines per inch */
int Xincrement; /* incremental tablet value 1 */
int Yincrement; /* incremental tablet value 1 */
int mouseScale; /* mouse scale factor in relative mode */
int numbtns; /* number of buttons on the mouse */
unsigned char coreBtn; /* 0 = no "mouse" button down; otherwise 1 to 3 */
unsigned char btn; /* number of button down; 0 = no button down */
Bool inProx; /* TRUE when xducer is in proximity */
} db3PrivRec, *db3PrivPtr;
static DeviceIntPtr db3dev;
static int db3corepointer_id;
static BYTE btnCodes[16]; /* button codes for InitButtonClassDeviceStruct */
static char buff[256];
static ws_edge_connection wec[MAXSCREENS];
extern int BadMode;
extern InputInfo inputInfo;
extern ws_descriptor wsinfo;
extern int wsFd;
extern int rememberedScreen;
extern int wsGetMotionEvents();
extern void RegisterOtherDevice(DevicePtr);
extern ExtDevicePtr ExtDeviceArray[];
extern void (*(ExtProcessDevInput[]))();
extern void RegisterPointerDevice (DevicePtr);
extern Bool InitPointerDeviceStruct();
/* Forward declarations */
void XiDb3Init(int, ScreenPtr, int, char **, char *, pointer);
int Db3DevInitProc(DevicePtr, int);
int Db3ChangeDeviceControl(ClientPtr, DevicePtr, xDeviceCtl *control);
int Db3SetDeviceValuators(ClientPtr, DeviceIntPtr, int *, int, int);
int Db3SetDeviceMode(ClientPtr, DevicePtr, int);
void Db3RawInputProc(int);
Bool Db3ProcessInputEvents(xEvent *, ws_event *);
static void CursorOffScreen(db3PrivPtr, unsigned char *, short *, short *);
extern int DeviceButtonPress, DeviceButtonRelease, DeviceButtonRelease,
DeviceMotionNotify, ProximityIn, ProximityOut, DeviceValuator;
/*
*
* ParseTableArgs
* device:mode:tabletWidth:tabletHeight:corePointer:mouseScale:resolution:Xincrement:Yincrement
!
parse tablet arguments and add appropriate init strings
*
* parse tablet arguments and add appropriate init strings
*
* Break the arguments into the following in the following
* order: port, mouse type, baud rate, emulate 3, chord middle,
* sample rate, clear dtr, clear rts, and whether the mouse should
* be the core pointer device or not.
*
*/
static
int ParseTabletArgs(char *arguments, db3PrivPtr pPriv, char *init)
{
char *myCopy;
char *myToken;
int x;
int tabletWidth = 12;
int tabletHeight = 12;
/* Make a local copy of the arguments string. */
myCopy = (char *)xalloc(strlen(arguments)+1);
strcpy(myCopy, arguments);
/* tablet dev */
if (myToken = strtok(myCopy,":")){
pPriv->devName = (char *)xalloc(strlen(myToken)+1);
strcpy((char *)pPriv->devName, myToken);
myToken = myToken + strlen(myToken) + 1;
}
else{
pPriv->devName = (char *)xalloc(strlen("/dev/tty00")+1);
strcpy((char *)pPriv->devName, "/dev/tty00");
return;
}
/* mode */
if( myToken && (*myToken != ':') && (myToken = strtok(NULL,":"))){
x = atoi(myToken);
pPriv->absMode = (x == 0) ? 0: 1;
myToken = myToken + strlen(myToken) + 1;
}
else
if(myToken) myToken++;
/* tabletWidth */
if(myToken && (*myToken != ':') && (myToken = strtok(NULL,":"))){
x = atoi(myToken);
tabletWidth = x ? x : 12;
myToken = myToken + strlen(myToken) + 1;
}
else
if(myToken) myToken++;
/* tabletHeight */
if(myToken && (*myToken != ':') && (myToken = strtok(NULL,":"))){
x = atoi(myToken);
tabletHeight = x ? x : 12;
myToken = myToken + strlen(myToken) + 1;
}
else
if(myToken) myToken++;
/* numbtns, default is 16, max is 16, min. is 3 */
if(myToken && (*myToken != ':') && (myToken = strtok(NULL,":"))){
x = atoi(myToken);
pPriv->numbtns = ( x > 16 || x < 3) ? 16 : x;
myToken = myToken + strlen(myToken) + 1;
}
else
if(myToken) myToken++;
/* corePointer */
if(myToken && (*myToken != ':') && (myToken = strtok(NULL,":"))){
x = atoi(myToken);
pPriv->corePointer = (x == 0) ? 0 : 1;
myToken = myToken + strlen(myToken) + 1;
}
else
if(myToken) myToken++;
/* mouseScale */
if(myToken && (*myToken != ':') && (myToken = strtok(NULL,":"))){
x = atoi(myToken);
pPriv->mouseScale = (x) ? x : 8;
myToken = myToken + strlen(myToken) + 1;
}
else
if(myToken) myToken++;
/* resolution */
if(myToken && (*myToken != ':') && (myToken = strtok(NULL,":"))){
x = atoi(myToken);
pPriv->resolution = (x == 0) ? 1000 : x;
if(pPriv->resolution != 1000){
x = strlen(init);
init = (char *)Xrealloc(init, x+1);
sprintf(init+x,"\033%%JR%04d,0\r", pPriv->resolution);
}
myToken = myToken + strlen(myToken) + 1;
}
else
if(myToken) myToken++;
pPriv->tabletX = pPriv->resolution * tabletWidth;
pPriv->tabletY = pPriv->resolution * tabletHeight;
if(myToken && (*myToken != ':') && (myToken = strtok(NULL,":"))){
x = atoi(myToken);
pPriv->Xincrement = ( x == 1 || x < 65536) ? x : 1;
if(pPriv->Xincrement != 1){
x = strlen(init);
init = (char *)Xrealloc(init, x+1);
sprintf(init+x,"\033%%X%05d\r", pPriv->Xincrement);
}
myToken = myToken + strlen(myToken) + 1;
}
else
if(myToken) myToken++;
if(myToken && (*myToken != ':') && (myToken = strtok(NULL,":"))){
x = atoi(myToken);
pPriv->Yincrement = ( x == 1 || x < 65536) ? x : 1;
if(pPriv->Yincrement != 1){
x = strlen(init);
init = (char *)Xrealloc(init, x+1);
sprintf(init+x,"\033%%Y%05d\r", pPriv->Yincrement);
}
}
return;
}
/* I/O for drawingboard III */
int
Db3Output(db3PrivPtr pPriv, char *outbuff, int size)
{
int numWritten;
numWritten = write(pPriv->fd, outbuff, size);
if(numWritten < size){
sprintf(buff,"Db3Ouput: only wrote %d of %d chars", numWritten, size);
ErrorF(buff);
}
return(numWritten);
}
int
Db3Input(int fd, CARD8 *inbuff, int size)
{
int x, bytesRead;
int inx;
bytesRead = 0;
inx = size;
while (!bytesRead){
x = read(fd, &inbuff[bytesRead], 1);
if( x == -1)
return(-1);
/* make sure there is sync */
if(!(inbuff[0] & 0x80))
continue;
if(x > 0){
inx -= x;
bytesRead += x;
}
}
/* first byte has been found, now read rest */
while(inx){
x = read(fd, &inbuff[bytesRead], inx);
if(x > 0){
inx -= x;
bytesRead += x;
}
}
if(inx != 0 || bytesRead != size){
sprintf(buff,"Db3input: only read %d of %d chars\n", inx, size);
ErrorF(buff);
}
return(bytesRead);
}
/************************************************************************/
/* */
/* XiDb3Init - Routine responsible for opening the device, setting */
/* line attributes, initialization of the device, and */
/* providing the server with proc routines that are */
/* specific to this device. */
/************************************************************************/
void
XiDb3Init(int unused1, ScreenPtr unused2, int argc, char **argv,
char *tabArgs, pointer unused3)
{
ScreenPtr pScreen = wsScreens[0];
DevicePtr pdev;
db3PrivPtr pPriv;
int db3Fd;
struct termios termios;
char *init;
int id;
int i;
#ifdef DEBUG
ErrorF("XiDb3Init.\n");
#endif
init = (char *)Xalloc(30); /* length of current init */
sprintf(init,"\033%%V9\r\033%%VR6\r\033%%W125\r\033%%VV7\r\033%%Z3\r");
/* get screen edge connections */
for(i = 0; i < MAXSCREENS; i++){
wec[i].screen = i;
ioctl(wsFd, GET_EDGE_CONNECTION, &wec[i]);
}
pPriv = (db3PrivPtr)xalloc(sizeof(db3PrivRec));
pPriv->mntrX = pScreen->width;
pPriv->mntrY = pScreen->height;
pPriv->pressure = 0;
pPriv->xAxis = 0;
pPriv->yAxis = 1;
pPriv->btn = 0;
pPriv->coreBtn = 0;
pPriv->numbtns = 16; /* default */
pPriv->absMode = 1; /* default */
pPriv->mouseScale = 8; /* default */
pPriv->corePointer = 1; /* default */
pPriv->Xincrement = 1; /* default */
pPriv->Yincrement = 1; /* default */
pPriv->resolution = 1000; /* default */
/*
* Use as the core pointer.
* Tell the DB3 to initialize itself.
*/
ParseTabletArgs(tabArgs, pPriv, (char *)init);
pPriv->x = pPriv->xPrev = pPriv->tabletX / 2;
pPriv->y = pPriv->yPrev = pPriv->tabletY / 2;
/* Open the file descriptor for the DB3 device. */
if ((db3Fd = open(pPriv->devName, O_RDWR, 0)) < 0)
{
sprintf(buff,"XiDb3Init: couldn't open device %s", pPriv->devName);
ErrorF(buff);
return;
}
if (fcntl (db3Fd, F_SETFL, (FNDELAY|FASYNC)) < 0) {
ErrorF ("XiDb3Init - fcntl failed - fd = %d\n", db3Fd);
return;
}
/* Set NDELAY mode - makes reads and writes be non-blocking.
* This is important because we do not want to hang the server
* with a blocked read or write.
*/
/* Define the attributes of the port:
*
* iflag = oflag = Raw input.
* cflag = 8 bits, enabled input, close on hup, local mode.
* lflag = No special processing.
* VMIN = 1 character makes a read work (default is 128).
* ispeed = ospeed = 9600 baud.
*/
tcgetattr(db3Fd, &termios);
termios.c_iflag = 0;
termios.c_oflag = OPOST | CR3;
termios.c_cflag = CS8 | CREAD | HUPCL | CLOCAL;
termios.c_lflag = 0;
termios.c_cc[VMIN] = 1;
termios.c_cc[VTIME] = 0;
termios.c_ispeed = termios.c_ospeed = B9600;
if (tcsetattr( db3Fd, TCSANOW, &termios) < 0){
close(db3Fd);
sprintf(buff,"XiDb3Init: couldn't condition %s", pPriv->devName);
ErrorF(buff);
return;
}
tcflush(db3Fd, TCIOFLUSH);
pPriv->fd = db3Fd;
i = strlen(init);
init = (char *)Xrealloc(init, (i + 12));
sprintf(init+i,"\033%%IR\r\033%%Z0\r\n\0");
Db3Output(pPriv, init, strlen(init)+1);
Xfree(init);
pdev = AddInputDevice((DeviceProc)Db3DevInitProc, TRUE);
pdev->devicePrivate = (pointer)pPriv;
RegisterOtherDevice(pdev);
db3dev = (DeviceIntPtr)pdev;
pPriv->id = id = ((DeviceIntPtr)(pdev))->id;
ExtDeviceArray[id] = (ExtDevicePtr)xalloc(sizeof(ExtDeviceRec));
ExtDeviceArray[id]->SetDeviceMode = Db3SetDeviceMode;
ExtDeviceArray[id]->SetDeviceValuators = Db3SetDeviceValuators;
ExtDeviceArray[id]->ChangeDeviceControl = Db3ChangeDeviceControl;
ExtDeviceArray[id]->ProcessInputEvents = Db3ProcessInputEvents;
/* Let the server know it should look for input from the tablet and
* what routine it should call to process the raw input.
*/
ExtProcessDevInput[db3Fd] = Db3RawInputProc;
AddEnabledDevice(db3Fd);
AddEnabledExtDevice(db3Fd);
}
/************************************************************************/
/* Db3DevInitProv - handle DEVICE_INIT, DEVICE_ON, DEVICE_OFF, and */
/* DEVICE_CLOSE */
/************************************************************************/
int
Db3DevInitProc(DevicePtr device, int what)
{
db3PrivPtr pPriv;
Atom typeatom;
char name[30];
int i;
char nmstr[] = "\033%__p\r"; /* send back CalComp model number */
char inbuf[15];
pPriv = (db3PrivPtr)device->devicePrivate;
switch (what) {
case DEVICE_INIT:
/*
* Make an atom and let server know about it.
*/
typeatom = MakeAtom (XI_TABLET, strlen(XI_TABLET), FALSE);
sprintf(name,"%s %d", XI_TABLET, pPriv->Num);
AssignTypeAndName ((DeviceIntPtr)device, typeatom, name);
db3corepointer_id = inputInfo.pointer->id;
/*
* Register procedures with server.
* The initial values here could be determined by a table,
* because this is specific for a CalComp tablet we will not
* take the time. Just hardcode it.
*/
InitValuatorClassDeviceStruct ((DeviceIntPtr)device, 3,
wsGetMotionEvents, MOTION_BUFFER_SIZE, Absolute);
/* The last parameter is resolution expressed as
counts/meter. 1000 lines per inch = 393.70
lines per centimeter. 128 pressure counts. */
InitValuatorAxisStruct ((DeviceIntPtr)device, 0, 0,
pPriv->tabletX, 1000, 1, 2540);
InitValuatorAxisStruct ((DeviceIntPtr)device, 1, 0,
pPriv->tabletY, 1000, 1, 2540);
InitValuatorAxisStruct ((DeviceIntPtr)device, 2, 0,
128, 1, 1, 1); /* pressure */
InitProximityClassDeviceStruct ((DeviceIntPtr)device);
/* Button map is indexed from 1. Refer to
XGetDeviceButtonMapping description - X Input
Extension Library Specification. */
/* nominal mapping; a button value of 0 isn't used */
for (i = 0; i < 17; i++)
btnCodes[i] = i;
/* number of buttons are configurable; max 17 (3 - 16) */
InitButtonClassDeviceStruct ((DeviceIntPtr)device,
pPriv->numbtns, btnCodes);
InitFocusClassDeviceStruct ((DeviceIntPtr)device);
break;
case DEVICE_ON:
#ifdef DEBUG
ErrorF("ON\n");
#endif
/* forces some i/o incase the tablet is initially out
of proximaty */
Db3Output((db3PrivPtr)device->devicePrivate, nmstr, strlen(nmstr));
read(pPriv->fd, inbuf, 12);
/* Tablet can become core pointer. */
if(pPriv->corePointer)
RegisterPointerDevice ((DevicePtr)device);
device->on = TRUE;
break;
break;
case DEVICE_OFF:
#ifdef DEBUG
ErrorF("OFF\n");
#endif
pPriv = (db3PrivPtr)device->devicePrivate;
RemoveEnabledDevice (pPriv->fd);
device->on = FALSE;
break;
case DEVICE_CLOSE:
#ifdef DEBUG
ErrorF("CLOSE\n");
#endif
if(device->on){
RemoveEnabledDevice (pPriv->fd);
device->on = FALSE;
}
xfree(ExtDeviceArray[pPriv->id]);
ExtDeviceArray[pPriv->id] = NULL;
close(pPriv->fd);
xfree(pPriv->devName);
pPriv->id = 0;
xfree (device->devicePrivate);
break;
}
return Success;
}
/*
* Db3SetDeviceMode - Absolute or relative mode
*/
int
Db3SetDeviceMode(ClientPtr client, DevicePtr device, int mode)
{
db3PrivPtr pPriv;;
pPriv = (db3PrivPtr)device->devicePrivate;
if(!pPriv)
return BadMatch;
switch(mode) {
case Absolute:
pPriv->absMode = 1;
break;
case Relative:
pPriv->absMode = 0;
break;
default:
return(BadMode);
}
return Success;
}
/************************************************************************/
/* Db3SetDeviceValuators - set the value of the valuators. */
/* Dummy routine place holder */
/************************************************************************/
int
Db3SetDeviceValuators(ClientPtr client, DeviceIntPtr device, int *valuators,
int first_valuator, int num_valuators)
{
DevicePtr pdev;
db3PrivPtr pPriv;
int val;
int i;
pPriv = (db3PrivPtr)((DevicePtr)device)->devicePrivate;
if(!pPriv)
return BadMatch;
val = first_valuator;
for (i = 0; i < num_valuators; i++, val++)
{
if ((valuators[i] > device->valuator->axes[val].max_value) ||
(valuators[i] < device->valuator->axes[val].min_value))
return BadValue;
else{
device->valuator->axisVal[val] = valuators[i];
if(i == 0){
pPriv->x = valuators[i];
pPriv->xPrev = valuators[i];
}
else if(i == 1){
pPriv->y = valuators[i];
pPriv->yPrev = valuators[i];
}
}
val++;
}
return Success;
}
/************************************************************************/
/* PcmProcessInputEvents - get an event from the workstation event */
/* queue and turn it into an X Input Extension */
/* event. */
/************************************************************************/
Bool
Db3ProcessInputEvents(xEvent *x, ws_event *e)
{
DevicePtr pdev;
db3PrivPtr pPriv;
deviceKeyButtonPointer xev[4];
deviceValuator *vev;
int eventcount;
int xPos, yPos;
if(((DeviceIntPtr)pdev)->id == db3dev->id){
pdev = (DevicePtr)db3dev;
pPriv = (db3PrivPtr)pdev->devicePrivate;
}
else {
pdev = (DevicePtr)inputInfo.devices;
while(pdev){
if(e->device == ((DeviceIntPtr)pdev)->id){
pPriv = (db3PrivPtr)pdev->devicePrivate;
break;
}
pdev = (DevicePtr)((DeviceIntPtr)pdev)->next;
}
}
if(!pPriv){
ErrorF("Db3ProcessInputEvents: pPriv not found evnt id: %d devid: %d\n",
e->device, ((DeviceIntPtr)pdev)->id);
return;
}
/* Just a sanity check */
if(e->device_type != STABLET_DEVICE)
return FALSE;
GetSpritePosition(&xPos,&yPos);
xev[0].root_x = xPos;
xev[0].root_y = yPos;
xev[0].detail = e->e.key.key;
xev[0].time = e->time;
xev[0].deviceid = e->device;
/*
* 1st event is DeviceButtonPress, DeviceButtonRelease,
* DeviceMotionNotify, ProximityIn, or ProximityOut.
* 2nd event is DeviceValuator.
*/
if(pPriv->corePointer){
if(e->type == DeviceButtonPress){
xev[0].type = ButtonPress;
xev[0].deviceid |= MORE_EVENTS;
}
else if(e->type == DeviceButtonRelease){
xev[0].type = ButtonRelease;
xev[0].deviceid |= MORE_EVENTS;
}
else if(e->type == DeviceMotionNotify){
xev[0].type = MotionNotify;
}
else{
return(TRUE);
}
}
else {
if(e->type == DeviceButtonPress){
xev[0].type = DeviceButtonPress;
xev[0].deviceid |= MORE_EVENTS;
}
else if(e->type == DeviceButtonRelease){
xev[0].type = DeviceButtonRelease;
xev[0].deviceid |= MORE_EVENTS;
}
else if(e->type == DeviceMotionNotify){
xev[0].type = DeviceMotionNotify;
}
else if(e->type == ProximityIn){
xev[0].type = ProximityIn;
xev[0].detail = 0;
}
else if(e->type == ProximityOut){
xev[0].type = ProximityOut;
xev[0].detail = 0;
}
else {
return(TRUE);
}
}
if(e->type == PROXIMITY_IN || e->type == PROXIMITY_OUT ||
e->type == ProximityIn || e->type == ProximityOut ){
eventcount = 1;
}
else {
vev = (deviceValuator *) &xev[1];
vev->type = DeviceValuator;
vev->deviceid = e->device;
vev->device_state = 0;
vev->num_valuators = 3;
vev->first_valuator = 0;
vev->valuator0 = e->e.key.x;
vev->valuator1 = e->e.key.y;
vev->valuator2 = e->e.key.pad;
eventcount = 2;
}
#ifdef DEBUG
ErrorF ("Db3ProcessInputEvents: type0: 0x%x type1: 0x%x v0: %d v1: %d v2: %d\n",
xev[0].type, vev->type, vev->valuator0, vev->valuator1, vev->valuator2);
#endif
(*pdev->processInputProc) ((xEventPtr)xev, (DeviceIntPtr)pdev, eventcount);
return TRUE;
}
/*
change resolution of the specified valuator, -1 == no change
only a lines per inch resolution is support
*/
int
Db3ChangeDeviceControl(ClientPtr client, DevicePtr device,
xDeviceCtl *control)
{
xDeviceResolutionCtl *drsctl;
CARD32 *resolution;
char out[12];
drsctl = (xDeviceResolutionCtl *)control;
resolution = (CARD32 *) (drsctl + 1);
if(drsctl->control != DEVICE_RESOLUTION)
return (BadMatch);
if(drsctl->first_valuator || drsctl->num_valuators != 1)
return (BadValue);
if(*(resolution) != -1){
sprintf(out,"\033%%JR%d,0\r\0",*(resolution));
Db3Output((db3PrivPtr)device->devicePrivate, out, strlen(out));
}
return (Success);
}
/* NOTE: ws_event is barely large enough to pass data the min. number
of valuators for the tablet. Ws_event needs to increase or a method
to become a variable size.
A tablet motion event abuses ws_event structure:
key.key == pressure
key.x == absolute x
key.y == absolute y
*/
void
Db3RawInputProc(int db3Fd)
{
ws_event e;
DeviceIntPtr pdev;
db3PrivPtr pPriv;
ws_pointer_position pos;
ScreenPtr pScreen;
int xPos, yPos;
int size, in;
int xaxis, yaxis, button, prox;
int xtilt, ytilt, press, height;
static int mylastscreen = 0;
unsigned char inbuf[20];
int x;
pdev = inputInfo.devices;
while(pdev){
if(pdev->public.devicePrivate
&& ((db3PrivPtr)(pdev->public.devicePrivate))->fd == db3Fd){
pPriv = (db3PrivPtr)pdev->public.devicePrivate;
break;
}
pdev = pdev->next;
}
if(!pPriv){
ErrorF("Db3RawInputProc: pPriv not found\n");
return;
}
if(pPriv->fd != db3Fd){
ErrorF("Db3RawInputProc: pPriv not found\n");
return;
}
/* pointer hack, so system mouse and tablet can both be
pointer device, hack alart - xxx */
if(pdev == inputInfo.pointer){
inputInfo.pointer = inputInfo.devices;
pPriv->corePointer = 1;
}
in = Db3Input(db3Fd, inbuf, 10);
if(in != 10){
ErrorF("Db3RawInputProc: Pkt Read failed\n");
return;
}
if(inbuf[0] & 0x80){
pPriv->x = XAXIS(inbuf);
pPriv->y = YAXIS(inbuf);
pPriv->pressure = PRESS(inbuf);
prox = INPROX(inbuf);
XTILT(inbuf, xtilt);
YTILT(inbuf, ytilt);
height = HEIGHT(inbuf);
button = BUTTON(inbuf);
if (button > 0 && button < 16) {
if (button == 1)
button = 16;
else
if (button == 2)
button = 17;
else
if (button == 4)
button = 18;
else
if (button == 8)
button = 19;
else
button = pPriv->btn + 15; /* if chord, discard */
}
if (button > 0)
button -= 15;
}
else
ErrorF("Db3RawInputProc: out of sync");
bzero(&e,sizeof(ws_event));
e.device_type = STABLET_DEVICE;
e.device = pdev->id;
if(pPriv->corePointer){
/*
* Because the device is switching the device id to the
* real system mouse, we do button translations here.
*/
e.type = MOTION_TYPE;
e.device_type = MOUSE_DEVICE;
e.device = db3corepointer_id;
e.screen = rememberedScreen;
if(button != pPriv->btn){
if (button == 0) {
if (pPriv->coreBtn) {
e.type = BUTTON_UP_TYPE;
e.e.key.key = pPriv->coreBtn;
pPriv->coreBtn = 0;
}
}
else {
/* Is a left, middle, or right button down? */
e.type = BUTTON_DOWN_TYPE;
e.e.key.key = pPriv->coreBtn =
pdev->button->map[button & 0x0f];
}
pPriv->btn = pdev->button->map[button];
}
if(pPriv->absMode){
e.e.key.x = (pPriv->mntrX * pPriv->x)/pPriv->tabletX;
e.e.key.y = pPriv->mntrY - ((pPriv->mntrY * pPriv->y)/pPriv->tabletY);
pPriv->inProx = prox;
CursorOffScreen(pPriv, &e.screen, &e.e.key.x, &e.e.key.y);
pScreen = wsScreens[e.screen];
pos.screen = WS_SCREEN(pScreen);
pos.device_number = wsinfo.console_pointer;
pos.x = e.e.key.x;
pos.y = e.e.key.y;
if (pos.screen != rememberedScreen){
wspCursorControl(rememberedScreen, CURSOR_OFF);
wspCursorControl(pos.screen, CURSOR_ON);
rememberedScreen = pos.screen;
}
if (ioctl (wsFd, SET_POINTER_POSITION, &pos) == -1) {
ErrorF ("error warping cursor\n");
return;
}
NewCurrentScreen(pScreen, pos.x, pos.y);
pPriv->xPrev = pPriv->x;
pPriv->yPrev = pPriv->y;
}
else {
if(!prox){
pPriv->inProx = FALSE;
return;
}
if(!pPriv->inProx){
pPriv->xPrev = pPriv->x;
pPriv->yPrev = pPriv->y;
pPriv->inProx = TRUE;
}
GetSpritePosition(&xPos,&yPos);
e.e.key.x = (pPriv->x - pPriv->xPrev) / pPriv->mouseScale;
e.e.key.y = (pPriv->yPrev - pPriv->y) / pPriv->mouseScale;
e.e.key.x += xPos;
e.e.key.y += yPos;
CursorOffScreen(pPriv, &e.screen, &e.e.key.x, &e.e.key.y);
pScreen = wsScreens[e.screen];
pos.screen = WS_SCREEN(pScreen);
pos.device_number = wsinfo.console_pointer;
pos.x = e.e.key.x;
pos.y = e.e.key.y;
if (pos.screen != rememberedScreen){
wspCursorControl(rememberedScreen, CURSOR_OFF);
wspCursorControl(pos.screen, CURSOR_ON);
rememberedScreen = pos.screen;
}
if (ioctl (wsFd, SET_POINTER_POSITION, &pos) == -1) {
ErrorF ("error warping cursor\n");
return;
}
NewCurrentScreen(pScreen, pos.x, pos.y);
pPriv->xPrev = pPriv->x;
pPriv->yPrev = pPriv->y;
}
#ifdef DEBUG
ErrorF ("Db3RawInputP: raw: 0x%x btn: 0x%x type: %d key: %d x: %d y: %d\n",
inbuf[0], button, e.type, e.e.key.key, e.e.key.x, e.e.key.y);
#endif
if (ioctl(wsFd, PUT_EVENT_ON_QUEUE, &e) < 0)
ErrorF("PUT_EVENT_ON_QUEUE: failed to put event on queue.\n");
return;
}
/* we're not a core device */
/* Precedence: Proximity, Button, Motion. No chording
allowed. E.g. If button 1 is down and user presses button 2,
nothing is reported. A button release for 1 is sent when
user releases button 1. A button press for button 2 is not
reported when button 1 is released. Going out of prox -
ButtonRelease (if needed), ProximityOut. (Discard 2nd
out-of-prox packet from tablet.) Coming into prox -
ProximityIn. Don't use info from first in-prox packet. Wait
for next packet. Normal operation -
ButtonPress/MotionNotify followed by DeviceValuator. */
/* If button 1 is down and user presses button 2 no event is generated
because there is no way to tell if it's button 3. Or if button 16 is
pressed there is no indication if any other buttons are pressed. */
e.screen = mylastscreen;
/* xducer in proximity */
if (prox != pPriv->inProx) {
if (!pPriv->inProx) {
pPriv->inProx = TRUE;
e.type = ProximityIn;
}
else {
/* button down */
if (pPriv->btn) {
e.type = DeviceButtonRelease;
e.e.key.key = pPriv->btn;
if (ioctl(wsFd, PUT_EVENT_ON_QUEUE, &e) < 0)
ErrorF("PUT_EVENT_ON_QUEUE: failed to put event on queue.\n");
e.type = DeviceMotionNotify;
e.e.key.x = pPriv->x;
e.e.key.y = pPriv->y;
e.e.key.pad = pPriv->pressure = 0;
if (ioctl(wsFd, PUT_EVENT_ON_QUEUE, &e) < 0)
ErrorF("PUT_EVENT_ON_QUEUE: failed to put event on queue.\n");
pPriv->pressure = 0;
pPriv->btn = 0;
}
pPriv->inProx = FALSE;
e.type = ProximityOut;
}
e.e.key.key = 0;
if (ioctl(wsFd, PUT_EVENT_ON_QUEUE, &e) < 0)
ErrorF("PUT_EVENT_ON_QUEUE: failed to put event on queue.\n");
}
if(!pPriv->inProx)
return;
/* already in proximity */
e.e.key.key = 0; /* normal, not hint */
if (button != pPriv->btn) {
if (button == 0) {
e.type = DeviceButtonRelease;
e.e.key.key = pPriv->btn;
pPriv->btn = 0;
}
else {
if(!pPriv->btn){
e.type = DeviceButtonPress;
e.e.key.key = button;
}
}
pPriv->btn = button; /* store new button number */
}
else {
e.type = DeviceMotionNotify;
e.e.key.key = 0; /* normal, not hint */
}
e.e.key.x = pPriv->x;
e.e.key.y = pPriv->y;
e.e.key.pad = pPriv->pressure;
if (ioctl(wsFd, PUT_EVENT_ON_QUEUE, &e) < 0)
ErrorF("PUT_EVENT_ON_QUEUE: failed to put event on queue.\n");
}
/************************************************************************/
/* */
/* CursorOffScreen - Checks to see if the cursor went off to another */
/* screen. This is wacky if the user goes */
/* off a corner in a diagonal direction. I was too */
/* lazy to check for this particular set of cases. */
/* */
/************************************************************************/
void
CursorOffScreen(db3PrivPtr pPriv, unsigned char *screen, short *x, short *y)
{
int i;
short next_screen = -1;
short current_screen = *screen;
ScreenPtr pScreen = wsScreens[*screen];
static int myprevscrn = 0;
static int xlastprox = 1; /* starts always in prox. */
static int ylastprox = 1;
/* absolute mode, not in prox., could be switching screen */
/* process only one out of prox */
if(pPriv->absMode && !pPriv->inProx){
/* x off the left, high bits set 0x3xxxx */
if(pPriv->x & 0x30000){
if(xlastprox){
next_screen = wec[current_screen].adj_screens.left;
if (next_screen != -1)
*x = wsScreens[next_screen]->width - 1;
else
*x = 0;
}
else {
if(myprevscrn != current_screen)
*x = pScreen->width - 1;
else
*x = 0;
}
}
/* x off the right and was in proximty the last time */
else if(pPriv->x >= pPriv->tabletX){
if(xlastprox){
next_screen = wec[current_screen].adj_screens.right;
if (next_screen != -1)
*x = 0;
else
*x = pScreen->width - 1;
}
else {
if(myprevscrn != current_screen)
*x = 0;
else
*x = pScreen->width - 1;
}
}
/* y off the bottom, high bit is set 0x1xxxx */
if (pPriv->y & 0x10000){
if(ylastprox){
next_screen = wec[current_screen].adj_screens.bottom;
if (next_screen != -1)
*y = 0;
else
*y = pScreen->height - 1;
}
else {
if(myprevscrn != current_screen)
*y = 0;
else
*y = pScreen->height - 1;
}
}
/* y off the top */
else if(pPriv->y >= pPriv->tabletY){
if(ylastprox){
next_screen = wec[current_screen].adj_screens.top;
if (next_screen != -1)
*y = *y + wsScreens[next_screen]->height;
else
*y = 0;
}
else{
if(myprevscrn != current_screen)
*y = pScreen->height - 1;
else
*y = 0;
}
}
}
xlastprox = ylastprox = pPriv->inProx;
if(!pPriv->absMode){
/* Going off the top? */
if (*y < 0) {
next_screen = wec[current_screen].adj_screens.top;
if (next_screen != -1)
*y = *y + wsScreens[next_screen]->height;
}
/* Going off the bottom? */
else if (*y > wsScreens[*screen]->height) {
next_screen = wec[current_screen].adj_screens.bottom;
if (next_screen != -1)
*y = *y - wsScreens[next_screen]->height;
}
/* Going off the left? */
if (*x < 0) {
next_screen = wec[current_screen].adj_screens.left;
if (next_screen != -1)
*x = *x + wsScreens[next_screen]->width;
}
/* Going off the right? */
else if (*x > wsScreens[*screen]->width) {
next_screen = wec[current_screen].adj_screens.right;
if (next_screen != -1)
*x = *x - wsScreens[next_screen]->width;
}
}
if(next_screen != -1 && current_screen != next_screen){
pPriv->mntrX = wsScreens[next_screen]->width;
pPriv->mntrY = wsScreens[next_screen]->height;
}
myprevscrn = current_screen;
if(next_screen != -1) pScreen = wsScreens[next_screen];
/* Just for sanity */
if(next_screen != -1) *screen = (unsigned char)next_screen;
if (*x < 0) *x = 0;
if (*x >= pScreen->width) *x = pScreen->width - 1;
if (*y < 0) *y = 0;
if (*y >= pScreen->height) *y = pScreen->height - 1;
} /* CursorOffScreen */
|