4.4BSD/usr/src/contrib/X11R5-hp300/mit/server/ddx/hpbsd/input/x_hil.c

Compare this file to the similar file:
Show the results in this format:

/* $Header: /host/debretts/disk2/X11R5/R5-hp300/mit/server/ddx/hpbsd/input/RCS/x_hil.c,v 1.2 1993/04/21 21:41:28 root Exp $ */

/*******************************************************************
**
**    *********************************************************
**    *
**    *  File:          ddx/hp/hp/x_hil.c
**    *
**    *  Contents:      Input event procedures for the 
**    *                 X/Starbase Merged Server
**    *
**    *  Created:       4/28/88
**    *
**    *  Last Change:   12/05/88
**    *
**    *  Last Release:  IC2
**    *
**    *  Revision:      A.01.00
**    *
**    *  Author:        --gms
**    *
**    *  Copyright:     (c) 1988 Hewlett-Packard Company
**    *
**    *********************************************************
** 
********************************************************************/

/********************************************************

Copyright (c) 1988 by Hewlett-Packard Company
Copyright (c) 1988 by the Massachusetts Institute of Technology

Permission to use, copy, modify, and distribute this software 
and its documentation for any purpose and without fee is hereby 
granted, provided that the above copyright notice appear in all 
copies and that both that copyright notice and this permission 
notice appear in supporting documentation, and that the names of 
Hewlett-Packard or  M.I.T.  not be used in advertising or publicity 
pertaining to distribution of the software without specific, written 
prior permission.

********************************************************/

#include "stdio.h"

#ifndef hp9000
#ifndef __apollo
#include "termio.h"
#else
#include "/sys5/usr/include/sys/termio.h"
#endif	/* __apollo */
#endif

#define	 NEED_EVENTS
#include "X.h"
#include "Xproto.h"
#include "hildef.h"
#include "hppriv.h"
#include "windowstr.h"
#include "XHPproto.h"
#include "x_hil.h"
#include "x_serialdrv.h"
#include "hpkeys.h"
#include "inputstr.h"
#include "../../../os/osdep.h"
#include <sys/times.h>
#ifdef __apollo
#include "../apollo/xshscreenpriv.h"
#endif /* __apollo */
#ifdef __hp_osf
#include <hp/hilioctl.h>
extern	HILQ *hil_qp;
#endif /* __hp_osf */
#ifdef __hpux
#include <sys/hilioctl.h>
#endif /* __hpux */
#ifdef hp9000
#include <sys/ioctl.h>
#include <hilioctl.h>
#endif
#include <errno.h>

#define	FIRST_EXTENSION_EVENT	64

#define	MIN_KEYCODE		8	
#define REPEAT_ARROW		0x2

#ifdef XTESTEXT1
/*
 * defined in xtestext1di.c
 */
extern int	on_steal_input;
extern int	exclusive_steal;
#endif /* XTESTEXT1 */

/******************************************************************
 *
 * Externs and variables referenced from other files.
 *
 */

extern int num_serial_devices;
extern SerialProcs serialprocs[];

xEvent	*format_ev();

xHPEvent  xE;

#ifdef	XINPUT
extern	int		DeviceMotionNotify;
extern	int		DeviceKeyPress;
extern	int		DeviceKeyRelease;
extern	int		DeviceButtonPress;
extern	int		DeviceButtonRelease;
extern	int		DeviceValuator;
extern	int		ProximityIn;
extern	int		ProximityOut;
#endif	/* XINPUT */
int			*dheadmotionBuf[MAX_LOGICAL_DEVS];
int			*dpmotionBuf[MAX_LOGICAL_DEVS];
extern	int 		axes_changed;
extern	int 		keyboard_click;
extern	int 		screenIsSaved;
extern	int		lastEventTime;
extern	int		x_axis, y_axis;
extern	struct		inputs_selected valid_inputs;
extern	HPInputDevice	l_devs[MAX_LOGICAL_DEVS];
extern	HPInputDevice	*hpKeyboard;
extern	HPInputDevice	*hpPointer;
extern	HPInputDevice	*hptablet_extension;
extern	WindowPtr 	*WindowTable;
extern	InputInfo inputInfo;
extern	DeviceIntPtr	screen_change_dev;
extern	DeviceIntPtr	tablet_extension_device;

extern	unsigned	tablet_xorg;
extern	unsigned	tablet_yorg;
extern	unsigned	tablet_xlimit;
extern	unsigned	tablet_ylimit;
extern	u_int		tablet_width;

static	Bool		in_tablet_extension = FALSE;

u_char		pointer_amt_bits[3];
u_char		ptr_mods, mv_mods, rs_mods, bw_mods;
u_char		buf[BUF_SIZ];
u_char		*pkt_ptr = buf;
Bool		screen_was_changed = FALSE;
Bool		reset_enabled = TRUE;
int 		hpActiveScreen = 0; 		/* active screen ndx (Zaphod) */
int		queue_events_free = MAX_EVENTS;
int		data_cnt = 0;
int		data_fd = -1;
int		pending_index;
int		pending_bytes;
int		acceleration;
int		threshold;
struct		x11EventQueue *events_queue;	/* pointer to events queue.  */
xHPEvent	*allocate_event();
struct		dev_info hil_info;		/* holds hil_data */
Bool		display_borrowed = FALSE;
#ifdef XINPUT
DeviceIntPtr	LookupDeviceIntRec ();
#endif /* XINPUT */
#if defined(__hp9000s800) && !defined(__hp9000s700)
unsigned long 	timediff;
Bool		time_set = FALSE;
#endif /* __hp9000s800 */

/******************************************************************
 *
 * Variables global to this file.
 *
 */

static	DeviceIntPtr find_deviceintrec();
static	int  process_inputs();
static	void process_hil_data();
static	void process_serial_data();
static	check_subset_and_scale();
static	move_sprite();
static	send_motion();
static	send_button();
static	move_mouse();
static	u_char	last_direction;
static	u_char	last_key;
static	u_char	last_arrow = REPEAT_ARROW;/*keycode of arrow key pressed last */
static	int	k_down_flag[4];
static	int	k_down_incx[4];
static	int	k_down_incy[4];

/****************************************************************************
 *
 * Process all available data from the input devices and put it on the server's
 * internal events queue.  When this routine is invoked, that queue is empty 
 * since the server empties it each time through its main dispatch loop.
 * 
 * The server's internal queue can hold 256 events.  If the server is busy for
 * a long time, it is possible for the queue to fill up.  In that case we 
 * can return with unread data, or data that is left in a global buffer.
 * This routine must be prepared to handle such leftover data.
 *
 * After handling leftovers, this routine finds a file descriptor with data
 * ready to be read and calls process_inputs to handle it.
 *
 */

store_inputs(ready_inputs)
    long	ready_inputs[];
    {
    int	    i;
    int     checkfd = valid_inputs.max_fd;	/* max fd valid for input*/
    int     checkword = MASKIDX(checkfd);	/* max valid word of mask*/
    long    mask[mskcnt];
    long    checkmask[mskcnt];
#if defined(__hp9000s800) && !defined(__hp9000s700)  /* building for s800 */
    struct tms 		buffer;
    int newtime;
    struct timeval tv, get_tv();

    /**********************************************************************
     *
     * On s800 machines, the time reported in HIL events has its origin at
     * the time of machine power-up.  The time reported by gettimeofday(),
     * which will be called by UpdateCurrentTime when a grab is done, always
     * has its origin at Jan. 1, 1970.  On s800s, we must compute a difference
     * to be added to the HIL times to keep the two in sync.  We must also
     * check each time via get_tv (PA-RISC fast gettimeofday) to see if the
     * time reported by gettimeofday has been changed via the date() command.
     * If so, our time difference is invalid and must be recalculated.
     */

    tv = get_tv();
    newtime = (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
    if (!time_set || newtime < lastEventTime)
	{
	time_set = 1;
	lastEventTime = GetTimeInMillis();
	timediff = lastEventTime - (times(&buffer)*10);
	}
#endif /* __hp9000s800 */

    for (i=0; i<mskcnt; i++)
	checkmask[i] = 0;

    if (data_cnt > 0)				/* we have leftover data*/
	{
	process_inputs (data_fd);		/* go process it	*/
	}

    MASKANDSETBITS (mask, ready_inputs, valid_inputs.input_mask);

    BITSET(checkmask, checkfd);			/* corresponding mask	*/

    for (i=checkword; i>=0; i--)		/* for all mask words   */
	{
	while (mask[i])				/* while input available*/
	    {
	    if (mask[i] & checkmask[i]) 	/* if current fd valid  */
		{
		mask[i] &= ~checkmask[i];
		process_inputs(checkfd);	/* process its input	*/
		}
	    checkfd--;
	    checkmask[i] = checkmask[i] >> 1;
            }
	if (i>0)
	    {
	    checkfd = (i-1) * 32 + 31;
	    BITSET(checkmask, checkfd);		/* corresponding mask	*/
	    }
        }
    }
		
/****************************************************************************
 *
 * Find the device data structure that matches the file descriptor from which
 * data will be read.  Read up to 2000 bytes (HIL driver buffer is only 512)
 * from that file descriptor.  From the data read, get 1 HIL data packet.
 * That packet may contain up to 8 keycodes and 1 motion event.  In the case
 * of a barcode reader in ASCII mode, each keycode may generate up to 6
 * X input events.  The worst case is therefore 49 X events from 1 HIL data
 * packet.
 *
 */

#define TIME_POLL_BYTES		5	/* bytes indicating time and poll*/

static int process_inputs (file_ds)
    int	file_ds;			/* file_ds to read from      	 */
    {
    int			i;
    u_char		*hil_ptr;
    HPInputDevice 	*indevice = NULL; 
    DeviceIntPtr 	dev;
    xHPEvent		*xHP;
    Bool 		done = FALSE;

    for (i=0; i<MAX_LOGICAL_DEVS; i++)
	{
	if (file_ds == l_devs[i].file_ds) 
	    {
	    indevice = &(l_devs[i]);
	    break;
	    }
	}
	
    dev = find_deviceintrec(indevice);

    if (data_cnt == 0 &&	 		/* no leftover data	    */
      !(indevice->hpflags & IS_SERIAL_DEVICE))
	{
	pkt_ptr = buf;
	data_cnt = read (file_ds, buf, READ_SIZ);
	/* We get here with nothing actually to read after a SIGHUP 
	   so ignore it */
	if (data_cnt == -1 && errno == EWOULDBLOCK)
	    {
	    data_cnt = 0;
	    return;
	    }
	}
    while (data_cnt > 0 || 			/* data yet to be processed */
      (indevice->hpflags & IS_SERIAL_DEVICE && !done))
	{
	if (queue_events_free <= MAXHILEVENTS)	/* no room on server queue  */
	    {
	    if (data_fd == -1)
		data_fd = file_ds;		/* save the file descriptor */
	    return;
	    }
	hil_ptr = (unsigned char *) &hil_info;/* place to copy packet to*/
	if (indevice->hpflags & IS_SERIAL_DEVICE)
	    {
	    done = get_serial_event (hil_ptr);
	    process_serial_data (dev, indevice, &(hil_info));
	    }
	else
	    {
	    get_hil_event (file_ds, hil_ptr);
#if defined(__hp9000s800) && !defined(__hp9000s700)  /* building for s800 */
	    hil_info.timestamp += timediff;
#endif /* __hp9000s800 */
	    process_hil_data (dev, indevice, &(hil_info));
	    }
	lastEventTime = hil_info.timestamp;	/* Used by ScreenSaver  */
	}
    data_fd = -1;
    if (xE.b.u.u.type != 0)			/* at least 1 motion event */
	{
        xHP = allocate_event();			/* get current queue pointer*/
        *xHP = xE;				/* copy from global struct  */
        xE.b.u.u.type = 0;			/* mark it as processed	    */
	}
    }

/***************************************************************************
 *
 * Given the HP device structure, find the DIX device structure that
 * logically corresponds to it.  There is a one-to-one correspondence,
 * expect when the keyboard is also the X pointer, a tablet is subsetted,
 * or an input device is merged with the X pointer or X keyboard.
 *
 * Callers: process_inputs(), read_shmhil().
 *
 */

static
DeviceIntPtr find_deviceintrec (indevice)
    HPInputDevice *indevice;
    {
    PtrFeedbackPtr	p;
    DeviceIntPtr dev = NULL;

    if (indevice != NULL)
	{
	hil_info.hil_dev = indevice;		/* input device struct ptr  */
	if (hptablet_extension &&
	    indevice->file_ds==hptablet_extension->file_ds && 
	    in_tablet_extension)
	    {
	    hil_info.hil_dev = hptablet_extension;
	    dev = tablet_extension_device;
	    }
	else if (indevice==hpKeyboard || (indevice->x_type==KEYBOARD && 
		(indevice->hpflags & MERGED_DEVICE)))
	    dev = inputInfo.keyboard;
	else if (indevice==hpPointer || (indevice->x_type==MOUSE && 
		(indevice->hpflags & MERGED_DEVICE)))
	    dev = inputInfo.pointer;
#ifdef XINPUT
	else
	    dev = LookupDeviceIntRec (indevice->dev_id);

    	p = dev->ptrfeed;
	if (p != NULL)
	    {
	    threshold = p->ctrl.threshold;
	    acceleration = p->ctrl.num / p->ctrl.den;
	    }
#endif /* XINPUT */
	if (acceleration == 0)
	    acceleration = 1;
	}
    else
	FatalError ("X server couldn't find current input device - Aborting.\n");
    return (dev);
    }

/****************************************************************************
 *
 * Get one HIL data packet from the data that was previously read.
 * If the buffer only contains a partial packet, read the rest.
 *
 * This function may also be called from x_threebut.c.
 *
 */

get_hil_event (fd, dest)
    int		fd;
    char	*dest;
    {
    int	packet_size;
    int	i;
    struct dev_info *info = (struct dev_info *) dest;

    packet_size = *pkt_ptr++;		/* 1st byte is size	    */
    if(data_cnt < packet_size)		/* We got a partial packet  */
	{
	data_cnt += read(fd,		/* get rest of packet */ 
			pkt_ptr + data_cnt, 
			packet_size - data_cnt);

	if(data_cnt != packet_size)
	    FatalError ("Unable to read all of an HIL data packet.  Server exiting! \n");
	}
    for (i=1; i<packet_size; i++)	/* copy the current packet  */
        *dest++ = *pkt_ptr++;

    info->timestamp = (info->timestamp - 1) * 10;
    info->poll_hdr &= HIL_POLL_HDR_BITS;/* zero nonsignifcant bits  */
    data_cnt -= packet_size;		/* fix unprocessed data cnt */
    pending_index = 0;
    pending_bytes = packet_size - 1  - TIME_POLL_BYTES;
    }

/****************************************************************************
 *
 * process the HIL data packet and generate X input events as needed.
 *
 */

#define UP_LEFT_ARROW		0xf8	/* HIL key codes for arrow keys. */
#define DOWN_LEFT_ARROW		0xf9
#define UP_DOWN_ARROW		0xfa
#define DOWN_DOWN_ARROW		0xfb
#define UP_UP_ARROW		0xfc
#define DOWN_UP_ARROW		0xfd
#define UP_RIGHT_ARROW		0xfe
#define DOWN_RIGHT_ARROW	0xff
#define HIL_PROXIMITY		0x4f

static u_char	code[2];

static void process_hil_data (dev, phys, info)
    DeviceIntPtr 	dev;
    HPInputDevice	*phys;
    struct		dev_info	*info;
    {
    xEvent		*ev;
    int			count;
    u_char		type, keyset, kcode, bcode, *hil_code;
    struct hil_desc_record *h = &phys->hil_header;

    while (pending_index < pending_bytes ) 
	{  
	if (info->poll_hdr & MOTION_MASK)
	    {
	    handle_motion_event (dev, phys, info);
	    info->poll_hdr &= ~MOTION_MASK;
	    }
    
	if (info->poll_hdr & KEY_DATA_MASK)
	    {  
	    keyset   = info->poll_hdr & HILPRH_KEYSET;
	    hil_code = code;
	    if (phys->hpflags & DATA_IS_8_BITS)
		*hil_code = (info->dev_data)[pending_index++];
	    else if (phys->hpflags & DATA_IS_16_BITS)
		{
		*hil_code = ((info->dev_data)[pending_index] << 8) |
		    (info->dev_data)[pending_index+1];
		pending_index += 2;
		}
	    /* Check if cursor keys are repeating. */
    
	    switch (*hil_code)
		{
		case DOWN_DOWN_ARROW	:
		case UP_DOWN_ARROW		:
		case UP_LEFT_ARROW		:
		case DOWN_LEFT_ARROW	:
		case UP_RIGHT_ARROW		:
		case DOWN_RIGHT_ARROW	:
		case UP_UP_ARROW		:
		case DOWN_UP_ARROW		:
		    last_arrow = *hil_code;
		    break;
		case	REPEAT_ARROW		:
		    if ((keyset==HILPRH_KEYSET1) && last_arrow!=REPEAT_ARROW)
		        *hil_code = last_arrow;
		    break;
		default:
		    break;
		}


	    if (phys->dev_type == BARCODE)
		hil_code = ascii_to_code[*hil_code];

	    for (count=0; (count==0 || *hil_code != 0); count++)
		{
#ifdef XINPUT
		/* proximity HIL codes cause a different event type.
		   However, proximity is not reported for devices being
		   used as the X pointer, unless they have no buttons
		   (like a touchscreen), in which case the proximity is
		   treated as button 1.
		   */

		kcode = ((u_char) *hil_code) >> 1;	/* same code up & down*/
		kcode += MIN_KEYCODE;		        /* avoid mouse codes. */

		/* Check to see if this is a "down" keycode for a key that is
		   already down.  If so, and autorepeat has been disabled for
		   this key, ignore the key and return.
		   */

		if (!(*hil_code % 2) && KeyIsDown(dev,kcode) &&
		    !KeyIsRepeating(dev,kcode))
		    return;

		bcode = *(hil_code++);
		if ((h->iob & HILIOB_PIO) && kcode == HIL_PROXIMITY)
		    if (dev!=inputInfo.pointer)
			{
			type = (bcode & UP_MASK) ? ProximityOut : ProximityIn;
			ev= format_ev (type, 0, info->timestamp, phys, NULL);
			return;
			}
		    else if (h->p_button_count == 0)
			bcode -= 0x0e;			/* make it button 1 */
		    else
			return;	/* proximity not reported for X pointer */
#endif /* XINPUT */
		if (bcode >= BUTTON_BASE && bcode < PROXIMITY_IN)
		    {
		    if (phys == hptablet_extension && phys->open_cnt == 0)
			return;
		    if (dev==inputInfo.pointer)
			if (bcode & UP_MASK) 
			    type = ButtonRelease;
			else
			    type = ButtonPress;
		    else
			if (bcode & UP_MASK) 
			    type = DeviceButtonRelease;
			else
			    type = DeviceButtonPress;
		    ev= format_ev (type, kcode, info->timestamp, phys, NULL);
		    process_button (ev, dev, info, bcode, h->p_button_count);
		    }
		else
		    {
		    if (dev==inputInfo.keyboard)
			if (bcode & UP_MASK) 
			    type = KeyRelease;
			else
			    type = KeyPress;
		    else
			if (bcode & UP_MASK) 
			    type = DeviceKeyRelease;
			else
			    type = DeviceKeyPress;
		    ev= format_ev (type, kcode, info->timestamp, phys, NULL);

		    parse_keycode (dev, phys, ev);
		    }
	        }
	    }
	}
   }

/****************************************************************************
 *
 * process the serial data packet and generate X input events as needed.
 *
 */

static u_int	s_code[2];

static void process_serial_data (dev, phys, info)
    DeviceIntPtr 	dev;
    HPInputDevice	*phys;
    struct		dev_info	*info;
    {
    xEvent		*ev;
    int			count;
    u_int		*hil_code;
    u_char		type, kcode;
    int button_count = phys->hil_header.p_button_count;

    while (pending_index < pending_bytes ) 
	{  
	if (info->poll_hdr & MOTION_DATA)
	    {
	    handle_motion_event (dev, phys, info);
	    }
    
	hil_code = s_code;

	if (phys->hpflags & DATA_IS_8_BITS)
	    *hil_code = (info->dev_data)[pending_index++];
	else if (phys->hpflags & DATA_IS_16_BITS)
	    {
	    *hil_code = ((info->dev_data)[pending_index+1] << 8) |
		(info->dev_data)[pending_index];
	    pending_index += 2;
	    }
	else if (phys->hpflags & DATA_IS_32_BITS)
	    {
	    *hil_code = ((info->dev_data)[pending_index+3] << 24) |
		(info->dev_data)[pending_index+2] << 16 |
		(info->dev_data)[pending_index+1] << 8 |
		(info->dev_data)[pending_index];
	    pending_index += 4;
	    }

	if (info->poll_hdr & KEY_DATA)
	    {
	    /* Check to see if this is a "down" keycode for a key that is
	       already down.  If so, and autorepeat has been disabled for
	       this key, ignore the key and return.
	       */

	    kcode = (u_char) (*hil_code >> 1); /* same code up & down */

	    if (*hil_code & UP_MASK) 
		if (dev==inputInfo.keyboard)
		    type = KeyRelease;
		else
		    type = DeviceKeyRelease;
	    else
		{
		if (KeyIsDown(dev,kcode) && !KeyIsRepeating(dev,kcode))
		    return;
		if (dev==inputInfo.keyboard)
		    type = KeyPress;
		else
		    type = DeviceKeyPress;
		}

	    ev= format_ev (type, kcode, info->timestamp, phys, NULL);
	    parse_keycode (dev, phys, ev);
	    }
	else if (info->poll_hdr & BUTTON_DATA)
	    {
	    if (*hil_code & UP_MASK) 
		if (dev==inputInfo.pointer)
		    type = ButtonRelease;
		else
		    type = DeviceButtonRelease;
	    else
		if (dev==inputInfo.pointer)
		    type = ButtonPress;
		else
		    type = DeviceButtonPress;

	    kcode = *hil_code + BUTTON_BASE;
	    if (dev==inputInfo.pointer && kcode > PROXIMITY_OUT)
		return;
	    if (phys == hptablet_extension && phys->open_cnt == 0)
	        return;
	    ev= format_ev (type,kcode,info->timestamp,phys,NULL);
	    process_button (ev, dev, info, kcode, button_count);
	    }
#ifdef XINPUT
	else if (info->poll_hdr & PROXIMITY_DATA)
	    {
	    /* proximity HIL codes cause a different event type.
	       However, proximity is not reported for devices being
	       used as the X pointer, unless they have no buttons
	       (like a touchscreen), in which case the proximity is
	       treated as button 1.
	       */
	    if (dev!=inputInfo.pointer)
		{
		type = (*hil_code & UP_MASK) ? ProximityOut : ProximityIn;
		ev= format_ev (type, 0, info->timestamp, phys, NULL);
		return;
		}
	    else if (button_count == 0)
		{
		kcode = 1;			/* make it button 1 */
	        ev= format_ev (type, kcode, info->timestamp, phys, NULL);
		if (phys == hptablet_extension && phys->open_cnt == 0)
		    return;
		process_button (ev, dev, info, kcode, button_count);
		}
	    else
		return;	/* proximity not reported for X pointer */
	    }
#endif /* XINPUT */
	}
   }

/*******************************************************************
 *
 * handle_motion_event()
 *
 */

handle_motion_event (dev, phys, info)
    DeviceIntPtr dev;
    HPInputDevice *phys;
    struct dev_info *info;
    {
    int			i, type, bytes_coord;
    int			tmp, coords[MAX_AXES];
    char  		*sdata;
    u_char  		*udata;
    HPInputDevice	*log;

    if (dev==inputInfo.pointer)
	{
	type = MotionNotify;
	log = hpPointer;
	}
    else
	{
	type = DeviceMotionNotify;
	log = phys;
	}
    if (phys->hpflags & DATA_IS_32_BITS)
	bytes_coord = 4;
    else if (phys->hpflags & DATA_IS_16_BITS)
	bytes_coord = 2;
    else
	bytes_coord = 1;

    pending_index += phys->hil_header.ax_num * bytes_coord;

    if (phys->hil_header.flags & HIL_ABSOLUTE)		/* absolute device */
	{
	udata = info->dev_data; 
	for (i=0; i < (u_char) phys->hil_header.ax_num; i++, udata+=bytes_coord)
	    if (bytes_coord == 1)
		coords[i] = *udata;
	    else if (bytes_coord == 2)
		coords[i] = *udata | *(udata+1) << 8;
	    else if (bytes_coord == 4)
		coords[i] = *udata | (*(udata+1) << 8) | (*(udata+2) << 16) | 
			    (*(udata+3) << 24);

	if (!check_subset_and_scale (&dev, phys, &log, coords))
	    return;
	}
    else
	{
	sdata = (char *) info->dev_data; 
	for (i=0; i < (u_char) phys->hil_header.ax_num; i++, sdata+=bytes_coord)
	    if (bytes_coord == 1)
		coords[i] = *sdata;
	    else if (bytes_coord == 2)
		coords[i] = *(sdata+1) << 8 | (*sdata & 0x0ff);
	    else if (bytes_coord == 2)
		coords[i] = (*(sdata+3) << 24) | ((*(sdata+2) << 16) & 0x0ff)|
			    ((*(sdata+1) << 8) & 0xff) | (*sdata & 0x0ff);
	}

    if (phys==hpPointer && axes_changed)
	{
	tmp = coords[0];
	coords[0] = coords[x_axis];
	if (y_axis==0)
	    coords[1] = tmp;
	else
	    coords[1] = coords[y_axis];
	}
    if (!(phys->hil_header.flags & HIL_ABSOLUTE) &&
	phys->dev_type != NINE_KNOB)
	coords[1] = -coords[1];

    process_motion (dev, phys, log, coords);
    (void) format_ev (type, 0, info->timestamp, log, &xE);
    }

/*******************************************************************
 *
 * check_subset_and_scale()
 * all we care about is the x and y coordinates.
 *
 */

static
check_subset_and_scale (dev, phys, log, c)
    DeviceIntPtr	*dev;
    HPInputDevice	*phys;
    HPInputDevice	**log;
    int			c[];
    {	
    extern u_char screen_change_amt;

    if (tablet_width)
	if (c[0]< tablet_xorg || c[0] > tablet_xlimit ||
	    c[1]> tablet_yorg || c[1] < tablet_ylimit)
	    {
	    in_tablet_extension = TRUE;
	    *dev = tablet_extension_device;
	    *log = hptablet_extension;
	    }
	else
	    {
	    in_tablet_extension = FALSE;
	    }
		
    if (*log == hpPointer)
	{
	if (*dev == screen_change_dev)
	    c[0] = (float) (c[0]-tablet_xorg) * phys->scaleX-screen_change_amt;
	else
	    c[0] = (float) (c[0]-tablet_xorg) * phys->scaleX;
        c[1] = (*log)->pScreen->height -
		((float) (c[1]-tablet_ylimit) * phys->scaleY);
	}
    else
	{
	if (*dev == screen_change_dev)
	    c[0] -= screen_change_amt;
        c[1] = phys->hil_header.size_y - c[1]; /* Y-coord  reversed.*/
	}
    if (c[0]==(*log)->coords[0] && c[1]==(*log)->coords[1])
	return (FALSE);
    c[0] -= (*log)->coords[0];
    c[1] -= (*log)->coords[1];
    return (TRUE);
    }

unsigned char lockcode = CAPSCODE;

/****************************************************************************
 *
 * parse_keycode (dev, phys, ev, x_type)
 *   Parse keycode information.
 *   Buttons from a three-button mouse also end up here.
 *
 */

#if defined(__hpux) || defined(__hp_osf) || defined(hp9000)
struct	 _LedCmd {
    int 	on;
    int		off;
    } LedCmd[] = {{HILP1,HILA1},{HILP2,HILA2},{HILP3,HILA3},{HILP3,HILA3}};
#endif

int parse_keycode (dev, phys, ev)
    DeviceIntPtr 	dev;
    HPInputDevice	*phys;
    xEvent		*ev;
    {
#ifdef	XTESTEXT1
    extern u_char	xtest_command_key;	 /* defined in xtestext1dd.c */
#endif	/* XTESTEXT1 */
    u_char	down_mods;
    char 	ioctl_data[12];

    if (hpPointer->x_type == KEYBOARD)
	if (hpKeyboard->hpflags & SECOND_LOGICAL_DEVICE &&
	    ((ev->u.keyButtonPointer.pad1==hpKeyboard->dev_id ||
	      ev->u.keyButtonPointer.pad1==hpPointer->dev_id ) &&
	     move_sprite (dev, hpPointer, ev)))
		return;
	else
	    if (ev->u.keyButtonPointer.pad1==hpPointer->dev_id &&
		(move_sprite (dev, hpPointer, ev)))
		return;
    
    /* allow borrow-mode switching on Domain/OS machines */
#ifdef __apollo

    if (ev->u.u.detail==borrow_mode)
	if ((hpKeyboard->hpflags & SECOND_LOGICAL_DEVICE &&
	    (ev->u.keyButtonPointer.pad1==hpKeyboard->dev_id ||
	     ev->u.keyButtonPointer.pad1==hpPointer->dev_id)) ||
	    ev->u.keyButtonPointer.pad1==hpKeyboard->dev_id)
	{
	get_down_modifiers (inputInfo.keyboard->key->down, &down_mods);
	if ((bw_mods & down_mods) == bw_mods)
	    {
	    extern unsigned char last_code;	/* in smd_input.c */
	    unsigned long timestamp;

	    timestamp = ev->u.keyButtonPointer.time;
	    deallocate_event (ev);	/* eat the borrow mode key */
	    ev = format_ev (KeyRelease, borrow_mode_mods[0]+MIN_KEYCODE,
		timestamp, phys, NULL);
	    ev = format_ev (KeyRelease, borrow_mode_mods[1]+MIN_KEYCODE,
		timestamp, phys, NULL);
	    last_code = 0;
	    leave_X();
	    }
	}
#endif /* __apollo */


    /* allow reset only from the X system keyboard,
	   and only if reset is enabled.		*/

    if (ev->u.u.detail==reset && reset_enabled)
	if ((hpKeyboard->hpflags & SECOND_LOGICAL_DEVICE &&
	    (ev->u.keyButtonPointer.pad1==hpKeyboard->dev_id ||
	     ev->u.keyButtonPointer.pad1==hpPointer->dev_id)) ||
	    ev->u.keyButtonPointer.pad1==hpKeyboard->dev_id)
	{
	get_down_modifiers (inputInfo.keyboard->key->down, &down_mods);
#ifdef NOT_DONE /* We don't have hp extensions, thus no ResetManager */
	if (((rs_mods & down_mods) == rs_mods) && !SendEventToResetManager())
	    GiveUp();
	}
#else
	if ((rs_mods & down_mods) == rs_mods)
	    GiveUp();
	}
#endif

#if defined(__hpux) || defined(__hp_osf) || defined(hp9000)

    /* Special case handling for the Caps Lock modifier and LED.
       If a key is pressed that is bound to the Lock modifier,
       turn on the Caps Lock LED and treat the key as latched.
       However, do this only if a client has not overridden the
       default use of the Caps Lock LED via the HPConfigureInput
       protocol request.  */

    if (IsLockKey(dev, ev->u.u.detail))		/* lock modifier pressed */
	{
	if (ev->u.u.detail != lockcode)		/* was changed by xmodmap*/
	    {
	    UnlatchKey(phys, lockcode);
	    LatchKey(phys, ev->u.u.detail);
	    lockcode = ev->u.u.detail;
	    }
	}
    else if (ev->u.u.detail == lockcode) 	/* is former lock modifier */
	{
	UnlatchKey(phys, lockcode);
	lockcode = 0xff;
	}

    if (KeyIsLatched(phys, ev->u.u.detail))
	if (KeyIsIgnored(phys,ev->u.u.detail))
	    {
	    if (KeyDownEvent(ev))
	        UnignoreKey(phys,ev->u.u.detail);
	    deallocate_event (ev);
	    return;
	    }
	else if (KeyDownEvent(ev))
	    IgnoreKey(phys,ev->u.u.detail);

    if (DeviceHasLeds(phys) && KeyHasLed(dev,phys,ev->u.u.detail))
	if (KeyUpEvent(ev))
	    LedOff(dev, phys, ev->u.u.detail, ioctl_data);
	else
	    LedOn(dev, phys, ev->u.u.detail, ioctl_data);

#endif /* __hpux */

#ifdef	XTESTEXT1
    if (on_steal_input)
	{ 
	XTestStealKeyData(ev->u.u.detail, ev->u.u.type, phys->x_type, 
	    ev->u.keyButtonPointer.rootX, ev->u.keyButtonPointer.rootY);
	if (exclusive_steal)
	    { 
	    if (ev->u.u.detail != xtest_command_key)
		deallocate_event (ev);
	    }
	else if (ev->u.u.detail == xtest_command_key)
	    deallocate_event (ev);
	}
#endif /* XTESTEXT1 */
    }

/************************************************************************
 *
 * This routine checks to see if the key should be interpreted as a 
 * sprite movement or a button.
 *
 */

static move_sprite (dev, phys, ev)
    DeviceIntPtr	dev;
    HPInputDevice	*phys;
    xEvent		*ev;
    {
    u_char      down_mods;
    u_char      key = ev->u.u.detail;
    u_char      type = ev->u.u.type;
    int		inc;
    Bool	motion_mods;

    get_down_modifiers (dev->key->down, &down_mods);
    if (down_mods & (~ptr_mods & ~mv_mods))
	motion_mods = FALSE;
    else if ((down_mods & ptr_mods) == ptr_mods)
	motion_mods = TRUE;
    else
	motion_mods = FALSE;

    if (!(down_mods & mv_mods))
        inc = pointer_move;
    else if ((down_mods & mv_mods) == pointer_amt_bits[0])
        inc = pointer_mod1_amt;
    else if ((down_mods & mv_mods) == pointer_amt_bits[1])
        inc = pointer_mod2_amt;
    else if ((down_mods & mv_mods) == pointer_amt_bits[2])
        inc = pointer_mod3_amt;
    else
	motion_mods = FALSE;

    k_down_incy[DOWN] = inc;
    k_down_incx[RIGHT] = inc;
    k_down_incy[UP] = inc * -1;
    k_down_incx[LEFT] = inc * -1;

    if (key==cursor_down && type==KeyPress && motion_mods)
        return (send_motion (phys, ev, 0, inc, DOWN));
    else if (key==cursor_down && type==KeyRelease)
        {
        k_down_flag[DOWN] = 0;
        return (1);
        }
    else if (key==cursor_left && type==KeyPress && motion_mods)
        return (send_motion (phys, ev, inc * -1, 0, LEFT));
    else if (key==cursor_left && type==KeyRelease)
        {
        k_down_flag[LEFT] = 0;
        return (1);
        }
    else if (key==cursor_right && type==KeyPress && motion_mods)
        return (send_motion (phys, ev, inc, 0, RIGHT));
    else if (key==cursor_right && type==KeyRelease)
        {
        k_down_flag[RIGHT] = 0;
        return (1);
        }
    else if (key==cursor_up && type==KeyPress && motion_mods)
        return (send_motion (phys, ev, 0, inc * -1, UP));
    else if (key==cursor_up && type==KeyRelease)
        {
        k_down_flag[UP] = 0;
        return (1);
        }
    else 
	{
	if (type==KeyPress)
	    type = ButtonPress;
	if (type==KeyRelease)
	    type = ButtonRelease;

	if (key == button_1)
	    return (send_button (ev, type, 1));
	else if (key == button_2)
	    return (send_button (ev, type, 2));
	else if (key == button_3)
	    return (send_button (ev, type, 3));
	else if (key == button_4)
	    return (send_button (ev, type, 4));
	else if (key == button_5)
	    return (send_button (ev, type, 5));
	else if (key == button_6)
	    return (send_button (ev, type, 6));
	else if (key == button_7)
	    return (send_button (ev, type, 7));
	else if (key == button_8)
	    return (send_button (ev, type, 8));
	}
    return (0);
    }

/****************************************************************************
 *
 * Send motion information from the keyboard, when it is the pointer device.
 *
 */

static send_motion (phys, ev, x, y, which)
    HPInputDevice	*phys;
    xEvent		*ev;
    int 		x, y, which;
    {
    int 		coords[MAX_AXES];
    int	i;

    for (i=0; i<4; i++)
        if (i != which && k_down_flag[i] != 0)
            {
            x += k_down_incx[i];
            y += k_down_incy[i];
            }
    coords[0] = x;
    coords[1] = y;
    k_down_flag[which] = 1;
    deallocate_event(ev);
    process_motion (inputInfo.pointer, phys, hpPointer, coords);
    ev = format_ev (MotionNotify, 0, ev->u.keyButtonPointer.time,hpPointer,&xE);
    return (1);
    }

/****************************************************************************
 *
 * Send button information from the keyboard, when it is the pointer device.
 *
 */

static send_button (ev, direction, bcode)
    xEvent *ev;
    u_char direction, bcode;
    {

    if (bcode == last_key && direction == last_direction)
	deallocate_event(ev);
    else
	{
	ev->u.u.type = direction;
	ev->u.u.detail = bcode;
	last_key = bcode;
	last_direction = direction;
#ifdef XTESTEXT1
	if (on_steal_input)
	    XTestStealKeyData(ev->u.u.detail, ev->u.u.type, MOUSE, 
		ev->u.keyButtonPointer.rootX, ev->u.keyButtonPointer.rootY);
#endif /* XTESTEXT1 */
	}

    return (1);
    }

/****************************************************************************
 *
 * process_motion (hil_info)
 *
 * This function may also be called from x_threebut.c and x_tablet.c.
 * It requires the motion passed to be a relative amount.
 * dev_hp and dev are the logical devices, phys is the actual device.
 *
 */

#define DEF_ACCELERATION	1
#define EDGE_L			1 << 0
#define EDGE_R			1 << 1
#define EDGE_T			1 << 2
#define EDGE_B			1 << 3

#define OffRightEdge(log)  (log->coords[0] > (log->change_xmax + \
			    (int) log->change_amt) ? EDGE_R : 0)
#define OffLeftEdge(log)   (log->coords[0] < (log->change_xmin - \
			    (int) log->change_amt) ? EDGE_L : 0) 
#define OffTopEdge(log)    (log->coords[1] < (log->change_ymin - \
			    (int) log->change_amt) ? EDGE_T : 0) 
#define OffBottomEdge(log) (log->coords[1] > (log->change_ymax + \
			    (int) log->change_amt) ? EDGE_B : 0) 

process_motion (dev, phys, log, c)
    DeviceIntPtr dev;
    HPInputDevice *phys, *log;
    int	c[];
    {
    int		i;
    unsigned int state = 0;
#ifdef XTESTEXT1
    extern int playback_on;
#endif
   
    /* Compute x,y taking care of desired threshold and acceleration
     * No acceleration if we're playing back a recorded test script.
     * No acceleration for absolute pointing devices.
     * No acceleration if we're using the default (1) acceleration.
     */

#ifdef XTESTEXT1
    if (!playback_on)
#endif
	{
	if (!(phys->hil_header.flags & HIL_ABSOLUTE) && 
	    (acceleration > DEF_ACCELERATION))
	    {
	    for (i=0; i < (u_char) log->hil_header.ax_num; i++)
	        if ( (c[i] - threshold) > 0)
		    c[i] = threshold + (c[i] - threshold) * acceleration;
	        else if ( (c[i] + threshold) < 0)
		    c[i] = (c[i] + threshold) * acceleration - threshold;
	    }
	}

    /*
     * If this is the pointer or a device whose input is merged
     * with the pointer, accumulate the motion and maintain a current position.
     * If this is an relative device, save the current movement.
     */

    if (log == hpPointer || (phys->hil_header.flags & HIL_ABSOLUTE))
	for (i=0; i< (int) log->hil_header.ax_num; i++)
	    log->coords[i] = log->coords[i] + c[i];
    else
	for (i=0; i< (u_char) log->hil_header.ax_num; i++)
	    log->coords[i] = c[i];

    /*
     * Active Zaphod implementation:
     *    Change the screen if we have more than one screen,
     *	  and the screen change device has gone off one of the edges,
     *    and the device is not grabbed and confined.
     */


#if defined(__hpux) || defined(__hp_osf) || defined(hp9000)
    if ( screenInfo.numScreens > 1 && 
	 log->dev_id == screen_change_dev->id &&
        (!dev->grab || !dev->grab->confineTo))
	{
	if (state = (OffRightEdge(log) | OffLeftEdge(log) | 
	    OffTopEdge(log) | OffBottomEdge(log)))
	    {
	    if (!screen_was_changed)
		change_the_screen (dev, phys, log, state);
	    }
	else 
	    /*
	     * Needed for the case where a tablet is the X pointer device.
	     * Once we change screens, we want to avoid immediately changing
	     * back.  We change when we enter the screen change area and 
	     * do not change again until after we have left it.
	     */
	    screen_was_changed = FALSE;
	}
#endif /* __hpux */
    if (phys == hptablet_extension && log->open_cnt == 0)
	return;
    /*
     * Clip the cursor to stay within the bound of screen.
     */
    if (log == hpPointer &&
        (!hpConstrainXY (&log->coords[0], &log->coords[1])))
	   return;
    move_mouse (log, lastEventTime);
    }

/****************************************************************************
 *
 * change_the_screen()
 * We have more than one screen, and the screen_change_device has been moved 
 * off one of the edges.  Change to another screen.
 *
 */

#if defined(__hpux) || defined(__hp_osf) || defined(hp9000)

#define INCREMENT_SCREEN_BY_ONE(p,l) (screenInfo.screens[(p->myNum+1) % \
    screenInfo.numScreens])

#define DECREMENT_SCREEN_BY_ONE(p,l) (p->myNum != 0 ? \
    screenInfo.screens[p->myNum-1] : \
    screenInfo.screens[screenInfo.numScreens - 1])

#define INCREMENT_SCREEN_BY_TWO(p,l) (screenInfo.screens[(p->myNum+2) % \
    screenInfo.numScreens])

#define DECREMENT_SCREEN_BY_TWO(p,l) (p->myNum > 1 ? \
    screenInfo.screens[p->myNum-2] : \
    screenInfo.screens[p->myNum + screenInfo.numScreens - 2])

change_the_screen (dev, phys, log, state)
    DeviceIntPtr dev;
    HPInputDevice *phys, *log;				/* logical device */
    unsigned int state;
    {
    ScreenPtr  	pScreen;
    WindowPtr	pRootWin;
    int		tx, ty;

    if (screen_col_wrap == DEFAULT)
	{
	if (screen_orientation == VERTICAL)
	    screen_col_wrap = WRAP;
	else
	    screen_col_wrap = NOWRAP;
	}

    if (screen_row_wrap == DEFAULT)
	{
	if (screen_orientation == HORIZONTAL)
	    screen_row_wrap = WRAP;
	else
	    screen_row_wrap = NOWRAP;
	}

    pScreen = log->pScreen;

    switch (state)
	{
	case EDGE_L:
	    if (screen_row_wrap == NOWRAP &&
		(screen_orientation == VERTICAL ||
	        (pScreen->myNum == 0  ||
	        (pScreen->myNum == 2 && screen_orientation == MATRIX ))))
		return;

	    if (screen_orientation == VERTICAL)
		{
		if (screen_row_wrap == CHANGE_BY_TWO)
		    {
		    log->pScreen = DECREMENT_SCREEN_BY_TWO(pScreen,log);
		    }
		}
	    else if (screen_orientation == HORIZONTAL)
		{
		log->pScreen = DECREMENT_SCREEN_BY_ONE(pScreen,log);
		}
	    else if (screen_orientation == MATRIX)
		{
		if (pScreen->myNum % 2)
		    {
		    log->pScreen = DECREMENT_SCREEN_BY_ONE(pScreen,log);
		    }
	        else if (screen_row_wrap == WRAP)
		    {
		    if (!(screenInfo.numScreens == 3 && pScreen->myNum == 2))
	    	        {
		        log->pScreen = INCREMENT_SCREEN_BY_ONE(pScreen,log);
		        }
		    }
		else
		    break;
		}
    
	    if (!(log->hil_header.flags & HIL_ABSOLUTE))
		log->coords[0] += (log->pScreen->width - log->change_xmin);
	    break;
	case EDGE_R:
	    if (screen_row_wrap == NOWRAP &&
		(screen_orientation == VERTICAL ||
	        (pScreen->myNum == 3  ||
	        (pScreen->myNum == 1 && screen_orientation == MATRIX ))))
		return;

	    if (screen_orientation == VERTICAL)
		{
		if (screen_row_wrap == CHANGE_BY_TWO)
		    {
		    log->pScreen = INCREMENT_SCREEN_BY_TWO(pScreen,log);
		    }
		}
	    else if (screen_orientation == HORIZONTAL)
		{
		log->pScreen = INCREMENT_SCREEN_BY_ONE(pScreen,log);
		}
	    else if (screen_orientation == MATRIX)
		{
	        if (pScreen->myNum % 2)
		    {
	            if (screen_row_wrap == WRAP)
		        {
		        log->pScreen = DECREMENT_SCREEN_BY_ONE(pScreen,log);
		        }
		    else
			break;
		    }
		else if (!(screenInfo.numScreens == 3 && pScreen->myNum == 2))
		    {
		    log->pScreen = INCREMENT_SCREEN_BY_ONE(pScreen,log);
		    }
		else if (screen_row_wrap != WRAP)
		    break;
		}

	    if (!(log->hil_header.flags & HIL_ABSOLUTE))
		log->coords[0] -= (pScreen->width);
	    break;
	case EDGE_T:
	    if (screen_col_wrap == NOWRAP &&
		(screen_orientation == HORIZONTAL ||
	        (pScreen->myNum == 3  ||
	        (pScreen->myNum == 2 && screen_orientation == MATRIX ))))
		return;

	    if (screen_orientation == HORIZONTAL)
		{
		if (screen_col_wrap == CHANGE_BY_TWO)
		    {
		    log->pScreen = INCREMENT_SCREEN_BY_TWO(pScreen,log);
		    }
		}
	    else if (screen_orientation == VERTICAL)
		{
		log->pScreen = INCREMENT_SCREEN_BY_ONE(pScreen,log);
		}
	    else if (screen_orientation == MATRIX)
	        {
		if (pScreen->myNum >= 2) 
		    {
		    if (screen_col_wrap == WRAP)
		        {
		        log->pScreen = DECREMENT_SCREEN_BY_TWO(pScreen,log);
		        }
		    else
			break;
		    }
		else if (!(screenInfo.numScreens == 3 && pScreen->myNum == 1))
		    {
		    log->pScreen = INCREMENT_SCREEN_BY_TWO(pScreen,log);
		    }
		else if (screen_col_wrap != WRAP)
		    break;
		}
    
	    if (!(log->hil_header.flags & HIL_ABSOLUTE))
		log->coords[1] += (pScreen->height);
	    break;
	case EDGE_B:
	    if (screen_col_wrap == NOWRAP &&
		(screen_orientation == HORIZONTAL ||
	        (pScreen->myNum == 0  ||
	        (pScreen->myNum == 1 && screen_orientation == MATRIX))))
		return;

	    if (screen_orientation == HORIZONTAL)
		{
		if (screen_col_wrap == CHANGE_BY_TWO)
		    {
		    log->pScreen = DECREMENT_SCREEN_BY_TWO(pScreen,log);
		    }
		}
	    else if (screen_orientation == VERTICAL)
		{
		log->pScreen = DECREMENT_SCREEN_BY_ONE(pScreen,log);
		}
	    else if (screen_orientation == MATRIX)
	        {
		if (pScreen->myNum >= 2) 
		    {
		    log->pScreen = DECREMENT_SCREEN_BY_TWO(pScreen,log);
		    }
		else if (screen_col_wrap == WRAP)
		    {
		    if (! (screenInfo.numScreens == 3 && pScreen->myNum == 1))
		        {
		        log->pScreen = INCREMENT_SCREEN_BY_TWO(pScreen,log);
		        }
		    }
		else
		    break;
		}

	    if (!(log->hil_header.flags & HIL_ABSOLUTE))
		log->coords[1] -= (pScreen->height);
	    break;
	}

    getPrivScreenPtr(pScreen)->CursorOff(pScreen);
    pScreen = log->pScreen;
    screen_was_changed = TRUE;
    set_scale_and_screen_change (log);
    getPrivScreenPtr(pScreen)->ChangeScreen(pScreen);
    if (phys == hptablet_extension)
	{
	tx = phys->coords[0] < tablet_xorg ? 0 : pScreen->width;
        ty = (float) phys->coords[1] * phys->scaleY;
	NewCurrentScreen(pScreen, tx, ty);
	}
    else
        NewCurrentScreen(pScreen, log->coords[0], log->coords[1]);

    hpActiveScreen = pScreen->myNum;
    if (dev->grab && dev->grab->cursor)
	pScreen->DisplayCursor(pScreen,dev->grab->cursor);
    else if (!(pRootWin = WindowTable[pScreen->myNum]))
	pScreen->DisplayCursor(pScreen,(CursorPtr) NULL);
    else
	pScreen->DisplayCursor(pScreen,pRootWin->optional->cursor);
    }
#endif /* __hpux || __hp_osf */

/****************************************************************************
 *
 * move_mouse ()
 * move the sprite, if the device is the pointer.
 * Also move it if some other device is sending MotionNotify events.
 * In any case, send a motion event to dix.
 *
 * This routine may also be called from xtest1dd.c
 *
 */

static
move_mouse (log, event_time)
    HPInputDevice	*log;			/* logical device  */
    int	event_time;				/* event timestamp */
    {
    int			i;
    int			id 	= log->dev_id;
    int			axes = log->hil_header.ax_num;
   
#if defined(__hpux) || defined(__hp_osf) || defined(hp9000)
     register 		hpPrivScreenPtr phpPriv =
	 			getPrivScreenPtr(log->pScreen);
    if (log == hpPointer)
#ifdef SPECIAL_68K_OSF
	miPointerMoveCursor(log->pScreen, log->coords[0], log->coords[1], 1);
#else
        (*phpPriv->MoveMouse) (log->pScreen, log->coords[0], log->coords[1], 1);
#endif
#endif /* __hpux */

#ifdef __apollo
    if (log == hpPointer)
	{
	xshScreenPrivPtr pScreenPriv;

	pScreenPriv = XSH_SCREEN_PRIV (log->pScreen);
	(*pScreenPriv->MoveCursor) (pScreenPriv,log->coords[0],log->coords[1]);
#ifdef XTESTEXT1
	if (on_steal_input)
	    check_for_motion_steal (log->coords[0], log->coords[1]);
#endif /* XTESTEXT1 */
	}
#endif /* __apollo */

    *dpmotionBuf[id]++ = event_time;
    for (i=0; i<axes; i++)
	*dpmotionBuf[id]++ = log->coords[i];
    
    if((dheadmotionBuf[id] + 100 * (axes+1)) == dpmotionBuf[id])
	dpmotionBuf[id] = dheadmotionBuf[id];
    }

/**************************************************************************
 *
 * Called by: hpMouseProc during device initialization, process_motion
 * 	whenever we change screens.
 *
 * This routine sets the scaling factor to be used for absolute pointing
 * devices like graphics tablets.  Input from these devices is scaled to
 * the screen size.  If we have a multi-screen environment, the scaling
 * factor must be changed whenever the screen changes.
 *
 * This routine also sets the margin at the screen edge that will be used
 * to change screens.  For tablets, this is initially 0, allowing the 
 * entire tablet surface to be used by the application.  If a tablet is 
 * the X pointer and a multi-screen environment is being used, the 
 * screen_change_amt variable should be initialized to some value (like 30)
 * to define a area at the tablet edges that will cause the screen to change.
 *
 * Tablet subsetting adds more complications.  The user can define a subset
 * area that used as the X pointer, while the remainder of the tablet surface
 * is treated as a second logical device.  It is this second logical device
 * that controls screen changes.
 *
 */
set_scale_and_screen_change (d)
    HPInputDevice *d;
    {
    int tmp, resx_mm, resy_mm;

    /* Absolute device: graphics tablet or touchscreen */

    if (d->hil_header.flags & HIL_ABSOLUTE)
	{
	resx_mm = d->hil_header.resx / 1000;
	resy_mm = d->hil_header.resy / 1000;

    	/* Tablet subsetting enabled and this is the pointer region.
    	   This is called only during initialization, since when
    	   we change screens, the device is the second logical device. */

	if (tablet_width && d->dev_id == inputInfo.pointer->id)
	    {
	    tablet_xorg = tablet_xorigin * resx_mm;
	    tablet_xlimit = tablet_xorg + tablet_width * resx_mm;
	    tmp  = d->hil_header.size_y - (tablet_yorigin * resy_mm);
	    tablet_yorg = tmp > 0 ? tmp : 0;
	    tmp = tablet_yorg - (tablet_height * resy_mm);
	    if (tmp > 0)
		tablet_ylimit = tmp;
	    else
		{
		tablet_ylimit = 0;
		tablet_height = tablet_yorg / resy_mm;
		}
	    d->scaleX = ((float) d->pScreen->width) /
	        ((float)tablet_width * resx_mm );
	    d->scaleY = ((float) d->pScreen->height) /
		((float)tablet_height * resy_mm );
	    d->change_xmin = 0;
	    d->change_xmax = d->pScreen->width;
	    d->change_amt = 0;
	    }
	else
	
	/* This code is called if we are initializing the second logical
	   device, or if tablet subsetting is not enabled.  It is also
	   called when we are changing screens with a tablet as the X
	   pointer device.

	 */
	    {
	    /* 
	      Set scale for the case where the tablet is the X pointer.
	      The scale is also returned to clients via XHPListInputDevices.
	     */
	    d->scaleX = ((float) (d->pScreen->width+2*screen_change_amt)) /
		((float)d->hil_header.size_x);
	    d->scaleY = ((float)d->pScreen->height) /
		((float)d->hil_header.size_y);
	    if (tablet_width)
		{
		/* If this is the second logical device, we must also
		   change the scale of the X pointer.  Since input from
		   absolute extension devices is not scaled, the
		   screen change amounts units are tablet counts.
		 */
		hpPointer->scaleX = ((float) d->pScreen->width) /
	            ((float)tablet_width * resx_mm );
		hpPointer->scaleY = ((float) d->pScreen->height) /
		    ((float)tablet_height * resy_mm );
		d->change_xmin =  resx_mm * screen_change_amt;
		d->change_xmax = d->hil_header.size_x - d->change_xmin;
		d->change_ymin =  resy_mm * screen_change_amt;
		d->change_ymax = d->hil_header.size_y - d->change_xmin;
		d->change_amt = 0;
		}
	    else
		/* The tablet is the X pointer.  Screen change units
		   are in pixels, since the input will be scaled.
		 */
		{
		d->change_xmin =  1;
		d->change_xmax = d->pScreen->width - 2;
		d->change_ymin =  1;
		d->change_ymax = d->pScreen->height - 2;
		d->change_amt = 0;
		}
	    }
	}
    else

    /* This code is called when a relative device is initialized,
       and when we are changing screens with a relative device.
       These devices  (mice, trackballs, dialboxes, spaceballs)
       cause us to change screens by generating values that are
       beyond the edge of the screen.
     */

	{
	d->change_xmin = 0;
	d->change_xmax = d->pScreen->width;
	d->change_ymin = 0;
	d->change_ymax = d->pScreen->height;
	d->change_amt = screen_change_amt;
	}
    }

/****************************************************************************
 *
 *  queue_motion_event ()
 *  This is a convenience routine for xosSetCursorPosition.
 *  It is used to artifically generate a motion event when WarpPointer
 *  request is made.
 *
 */

queue_motion_event (dev_p)
    HPInputDevice	*dev_p;
    {
    int			coords[MAX_AXES];
    extern		TimeStamp currentTime;

    coords[0] = 0;
    coords[1] = 0;
    process_motion (inputInfo.pointer, dev_p, dev_p, coords);
    (void) format_ev (MotionNotify, 0, currentTime.milliseconds, dev_p, NULL);
    xE.b.u.u.type = 0;
    }

/****************************************************************************
 *
 * format_ev ( )
 *	format one or more key, button, motion or proximity xEvents.
 *	This routine assumes devices have less than 6 axes, or report only
 *      one axis per event.
 */

#define AXES_PER_EVENT 6

xEvent *
format_ev (type, detail, event_time, log, event)
    u_char		type;
    u_char		detail;
    unsigned  int 	event_time;
    HPInputDevice	*log;
    xHPEvent		*event;
    {
    int i, j;
    int n_axes = log->hil_header.ax_num;
    INT32 *ip;
    xEvent *ret = NULL;

    for (i=0; i<=n_axes/AXES_PER_EVENT; i++)
	{
	if (event==NULL)
	    {
	    if (xE.b.u.u.type != 0)	/* we have a previous motion event  */
		{
        	event = allocate_event();/* queue it before the new event    */
        	*event = xE;
        	xE.b.u.u.type = 0;
		}
	    event = allocate_event();
	    }
	if (!ret)
	    ret = (xEvent *) event;

	event->b.u.u.type = type;
	event->b.u.u.detail = detail;
	event->b.u.keyButtonPointer.time = event_time;
	event->b.u.keyButtonPointer.rootX = hpPointer->coords[0];
	event->b.u.keyButtonPointer.rootY = hpPointer->coords[1];
	event->b.u.keyButtonPointer.pad1 = log->dev_id;
#ifdef XINPUT
	if (type >= FIRST_EXTENSION_EVENT)
	    {
	    event->b.u.keyButtonPointer.pad1 |= MORE_EVENTS;
	    event->x.type = DeviceValuator;
	    event->x.deviceid = log->dev_id;

	    if (log->hpflags & NON_CONTIGUOUS_DATA)
		for (j=0; j < (u_char) log->hil_header.ax_num; j++)
		    {
		    if (log->coords[j]!=0)
			{
			event->x.num_valuators = 1;
			event->x.first_valuator = j;
			event->x.valuator0 = log->coords[j];
			return (ret);
			}
		    }
	    else
		{
		event->x.num_valuators = log->hil_header.ax_num;
		event->x.first_valuator = 0;
		ip = &event->x.valuator0;
		for (j=0; j<6; j++)
		    if ( i < (u_char) log->hil_header.ax_num)
			*ip++ =  log->coords[j];
		    else
			*ip++ =  0;
		}
	    }
#endif /* XINPUT */
	}

    return (ret);
    }

/********************************************************************
 *
 * ProcessInputEvents()
 * This routine is invoked from the dispatcher to route events.  
 * It invokes the dix routines to do this.
 *
 */

#define CLICK_VOICE 		2

ProcessInputEvents()
    {
    int	click, id, i;
    INT32 *ip;
    int	count;
    xHPEvent	*event;
    DeviceIntPtr	dev;
    Bool checkedscreensave = FALSE;

#if defined(__hp_osf)
    if (hil_qp->hil_evqueue.head != hil_qp->hil_evqueue.tail)
	read_shmhil();
#endif /* __hp_osf */

    while ( events_queue->head != events_queue->tail) 
	{
	if (!checkedscreensave)
	    {
	    if (screenIsSaved==SCREEN_SAVER_ON && !display_borrowed)
		SaveScreens (SCREEN_SAVER_OFF, ScreenSaverReset);
	    checkedscreensave = TRUE;
	    }
        event =  &((events_queue->events)[(events_queue->head)]);

	switch (event->b.u.u.type) 
	    {
	    case KeyPress:
	        if (keyboard_click)
		    beep(CLICK_VOICE,800,keyboard_click,1);
	    case KeyRelease:
		dev = (DeviceIntPtr) LookupKeyboardDevice ();
		(*dev->public.processInputProc) (event, dev, 1);
	        break;
	    case ButtonPress:
	    case ButtonRelease:
	    case MotionNotify:
		dev = (DeviceIntPtr) LookupPointerDevice ();
		(*dev->public.processInputProc) (event, dev, 1);
	        break;
	    default:
#ifdef XINPUT
		id = event->b.u.keyButtonPointer.pad1 & DEVICE_BITS;
		if (!(event->b.u.keyButtonPointer.pad1 & MORE_EVENTS))
		    count=1;
		else
		    count=2;
		dev = LookupDeviceIntRec (id);
		if (dev == NULL)
		    break;
		if (event->b.u.u.type == DeviceKeyPress)
		    {
		    if (dev->kbdfeed)
		        click = (int)((double)(dev->kbdfeed->ctrl.click) * 
				15.0 / 100.0);
		    if (click)
		        beep(CLICK_VOICE,800,click,1);
		    }
		else if (event->b.u.u.type == DeviceMotionNotify)
		    {
		    ip = &event->x.valuator0;
		    for (i=0; i < (u_char) event->x.num_valuators; i++)
			dev->valuator->axisVal[i] = *(ip+i);
		    }
		(*dev->public.processInputProc) (event, dev, count);
#endif /* XINPUT */
	    break;
	    }

	if (events_queue->head == WR_EVENTS)
	    events_queue->head = 0;
	else
	    events_queue->head++;

        }
    queue_events_free	= WR_EVENTS;
    }

#ifdef __hp_osf
/******************************************************************
 * 
 * This routine removes data from the HIL shared memory event queue,
 * and processes it through the server ddx input event processing code.
 *
 */

#define		NONDATA_BYTES	7
#define		MAXNAMLEN	255

read_shmhil()
    {
    int			i, head;
    char		dev_name[MAXNAMLEN];
    u_char		*buf;
    DeviceIntPtr 	dev;
    void		process_hil_data();
    xHPEvent		*xHP;

    while (hil_qp->hil_evqueue.head != hil_qp->hil_evqueue.tail)
        {
	head = hil_qp->hil_evqueue.head;
	sprintf (dev_name, "/dev/hil%d", hil_qp->hil_event[head].dev);
	for (i=0; i<MAX_LOGICAL_DEVS; i++)
	    if (strcmp (l_devs[i].dev_name, dev_name) == 0)
		break;

	if (i==MAX_LOGICAL_DEVS)
	   	    FatalError ("Can't find input device %s\n queue head = %d\n queue tail = %d\n event timestamp = 0x%x\n event pollheader = 0x%x\n event size = %d\n",
			dev_name,
			head,hil_qp->hil_evqueue.tail,
			hil_qp->hil_event[head].tstamp,
			hil_qp->hil_event[head].poll_hdr,
			hil_qp->hil_event[head].size);
	dev = find_deviceintrec (&l_devs[i]);
	buf = (u_char *) &hil_qp->hil_event[head].tstamp;
	hil_info.timestamp = ((*buf & 0x0ff) << 24) |
			     ((*(buf+1) & 0x0ff) << 16) |
			     ((*(buf+2) & 0x0ff) << 8) |
			     ( *(buf+3) & 0x0ff);

	hil_info.timestamp = (hil_info.timestamp - 1) * 10;
	hil_info.poll_hdr = hil_qp->hil_event[head].poll_hdr & HIL_POLL_HDR_BITS;

	pending_bytes = hil_qp->hil_event[head].size - NONDATA_BYTES;
	pending_index = 0;
	for (i=0; i < pending_bytes; i++)
	    hil_info.dev_data[i] = hil_qp->hil_event[head].dev_data[i];

	lastEventTime = hil_info.timestamp;	/* Used by ScreenSaver  */
	process_hil_data (dev, hil_info.hil_dev, &(hil_info));
        hil_qp->hil_evqueue.head = (hil_qp->hil_evqueue.head + 1) % 
		hil_qp->hil_evqueue.size;	/* MUST use real head pointer,
						   process_button may have
						   incremented it.      */
	}

    if (xE.b.u.u.type != 0)			/* at least 1 motion event */
	{
        xHP = allocate_event();			/* get current queue pointer*/
        *xHP = xE;				/* copy from global struct  */
        xE.b.u.u.type = 0;			/* mark it as processed	    */
	}
    }
#endif /* __hp_osf */

Bool
get_serial_event (hil_ptr)
    struct dev_info *hil_ptr;				/* holds hil_data */
    {
    int i, status;

    hil_ptr->timestamp = GetTimeInMillis();
    hil_ptr->poll_hdr = 0;
    pending_index=0;
    pending_bytes=0;
    bzero (hil_ptr->dev_data, 36);
    for (i=0; i<num_serial_devices; i++)
	if (hil_ptr->hil_dev->file_ds==serialprocs[i].fd)
	    {
 	    status = (*(serialprocs[i].read))
		(hil_ptr->hil_dev->file_ds,
	    	hil_ptr->dev_data, 
		&hil_ptr->poll_hdr, 
		&pending_bytes);
	    break;
	    }
    if (status==READ_SUCCESS)
	return(FALSE);
    else
	return(TRUE);
    }