XEMUL(4)

NAME
xemul - X Input Emulator, for queuing keyboard and mouse events.

SYNOPSIS
xemul

DESCRIPTION
The X emulator is used for queuing input events from the keyboard and mouse into a shared queue area between kernel and the user level X server. This emulator follows the restrictions and conventions determined by X but can be used by other user processes as well.

Starting the X Emulator
Since the X Emulator is a non standard input emulator the user should open the non standard console device associated with the display being used e.g. (/dev/aed, /dev/apa8, etc.). After the open the user should perform the EISETD ioctl command to set the E_XINPUT emulator. The following piece of code would do this initialization;

    #include <machinecons/screen_conf.h>
    #include <machinecons/xio.h>
    main()
    {
    	int fd, input_emul;

    	fd = open ("/dev/apa16", O_RDWR);
    	input_emul = E_XINPUT;
    	ioctl (fd, EISETD, &input_emul);
    }

Once you have set the input emulator to E_XINPUT all input from the keyboard will be queued in shared memory. The normal read system call will return an error. As described in the emulator document when you open the nonstandard device the output emulator will default to the buffer emulator. This assumes that the user process will be taking over the display and any write system calls will be buffered until the user process gives up the display, see budemul(4). Also see stdemul(4) or ibmemul(4) if you wish to change the output emulator back to the standard type emulator.

To have mouse events forwarded to the X input emulator you must set the mouse to a special line discipline which forwards to an input emulator. Please see tty_tb(4) for more information. Because the nonstandard emulator was open, if the process dies or closes the device the default emulators will be restored.

The user process is responsible to find out where the shared memory queue is, read input events off the head of the queue, and update the head queue pointer.

The following structure is kept in shared memory and filled in when the X emulator is opened.

    struct XBuffArea {
            XIoAddr xioa;			/* Queue and control information */
            XEvent  ibuff[XMAXEVQ];		/* Circular event queue */
    };
    typedef struct _XIoAddr {
            short    status;		/* Status of emulator (not used) */
            XEvent  *ibuff;			/* Pointer to event queue */
            int      iqsize;                /* Circular queue size (power of 2) */
            int      ihead;                 /* Queue head */
            int      itail;                 /* Queue tail */
            XCursor mouse;                  /* Current Mouse position */
            XCursor hotspot;                /* Current Mouse hot spot */
            XBox     mbox;                  /* Current Mouse movement box */
            int     make_break;             /* =0 then make =1 then break */
            short   mthreshold;             /* Mouse motion parameter */
            short   mscale;                 /* Mouse scale factor (if negative
                                               then do square).     */
            MSBox    hmbox;                 /* Hide mouse box */
    } XIoAddr;
    typedef XIoAddr *XIoAddrAddr;

Once the user process sets the X input emulator the following code shows the ioctl call and assignment which should be performed to get the address of the above information.

    	XIoAddrAddr XAddr;
    	XEventQueue *queue;
    	ioctl (fd, QIOCADDR, &XAddr);
    	queue = (XEventQueue *) (&XAddr->ibuff);

The last assignment above creates a pointer to the section of the shared memory where the queue pointers and information are kept. The XEventQueue typedef, XEvent structure and defines shown below are defined in <machinecons/qevent.h>.

    /* The event queue */
    typedef struct _X_eventqueue {
    	XEvent *events;         /* input event buffer */
            int size;               /* size of event buffer */
            int head;               /* index into events */
            int tail;               /* index into events */
    } XEventQueue;
    typedef struct  _X_event {
            u_short xe_x;		/* x position */
            u_short xe_y;		/* y position */
            u_short xe_time;	/* 10 millisecond units (button only) */
            u_char xe_type;		/* button or motion? */
            u_char xe_key;		/* the key (button only) */
            u_char xe_direction;	/* which direction (button only) */
            u_char xe_device;	/* which device (button only) */
    } XEvent;
    /* xe_type field */
    #define XE_BUTTON      0               /* button moved */
    #define XE_MMOTION     1               /* mouse moved */
    #define XE_TMOTION     2               /* tablet moved */
    /* xe_direction field */
    #define XE_KBTUP        0               /* up */
    #define XE_KBTDOWN      1               /* down */
    #define XE_KBTRAW       2               /* undetermined */

    /* xe_device field */
    #define XE_MOUSE       1               /* mouse */
    #define XE_DKB         2               /* main keyboard */
    #define XE_TABLET      3               /* graphics tablet */
    #define XE_AUX         4               /* auxiliary */
    #define XE_CONSOLE     5               /* console */

At the start the head and tail indexes in the XEventQueue will both be zero. When an event occurs the information will be stored at the tail and then the index will be bumped up by one. If the tail index has reached the end of the queue it will wrap around to zero (circular queue). All input events will be ignored if the tail index catches up to the head index.

The user should poll or issue a select to find out when on event occurs (head != tail). The user should then process the information from the event pointed to by the head index and then adjust the head index in the same manor as described for the tail. The following code is an example of this process:

    	XEvent *ev;
    	while (queue->head != queue->tail) {
    		ev = &queue->events[queue->head];
    		switch (ev->xe_type) {
    			case XE_BUTTON:    /* A key/button moved */
    				key_button_motion (ev);
    				break;
    			case XE_MMOTION:   /* The mouse moved */
    				mouse_motion (ev);
    				break;
    		}
    		if (queue->head < queue->size)
    			queue->head++;
    		else
    			queue->head = 0;
    	}

Event Data
The user need only to analyze the data in the event passed to determine what has occurred. The xe_x and xe_y will always contain the current mouse (x, y) position for any event. This same information is also always available in the mouse entry in the XIoAddr structure. The xe_time entry is a timestamp (in 10 millisecond units) marking that event. xe_type describes what type of event occurred, XE_BUTTON meaning a keyboard key or mouse button event, XE_MMOTION meaning a mouse motion event, and XE_TMOTION meaning a tablet motion event. Only if the event was a XE_BUTTON will the xe_key, xe_direction, and xe_device fields be filled in accordingly. The xe_device tells you it the event was from the keyboard, mouse, tablet, etc.. The xe_key will contain the keyboard key code or which mouse button. The xe_direction will tell you if the key/button was depressed or let go (DOWN or UP).. Button events are always presented as new events. See hardware documentation for the keyboard codes and see tty_tb(4) for the mouse button report.

Motion Events
Motion events are joined if the previous event was a motion and the user had not read it yet. As stated before the current mouse position is always kept in the shared memory structure XIoAddr.mouse. Motion events are not always reported as an event to the user. The user may set the mouse motion box, XIoAddr.mbox, to a rectangle in which motion events should not be reported. This is a key feature to the X emulator which optimizes events to only those the user cares about. This is possible since the X emulator tracks the mouse with the cursor/locator on the screen being used. Since the user is not responsible for tracking the mouse on the screen it doesn't need to know every motion event.

    	/* mouse motion rectangle */
    	typedef struct _X_box {
    		short bottom;
    		short right;
    		short left;
    		short top;
    	} XBox;

Cursor/Locator Control
The user can perform the following ioctls for controlling the mouse cursor tracking.

QIOCADDR
    The user passes an XIoAddr address which is filled with the address in shared memory where the structure will be found.

QIOCSMSTATE
    Set the mouse state. The user passes the XCursor structure to specify the new mouse position.

QIOCLDCUR
    The user passes a QIOLocator structure indicating what the cursor/locator bitmap should be on the display.

QIOCHIDECUR
    This ioctl will inhibit the cursor/locator from being displayed on the screen. The cursor will still be tracked and reported to the user.

QIOCSHOWCUR
    The user issues this ioctl to show the cursor/locator after it was been hidden. The locator will appear at it's current location (not where it was hidden). The locator defaults to show.

The structures mentioned above are shown below:

    	/* mouse cursor position */
    	typedef struct _X_cursor {
    		short x;
    		short y;
    	} XCursor;

    	/* Mouse locator bitmap */
    	typedef struct
    	{
    		short   data[16];
    		short   mask[16];
    		struct {
    			short v, h;
    		} hotSpot;
    	} QIOLocator;

Besides the above ioctls the user can control the mouse cursor/locator by writing into the XIoAddr shared memory structure. The following is a synopsis of each remaining part of this structure:

mouse
    The current mouse position. XCursor structure.

hotspot
    Current Mouse hot spot offset from the mouse position. XCursor structure.

mbox
    Current Mouse movement box. XBox structure.

mthreshold
    Mouse motion parameter (not used currently).

mscale
    Mouse scale factor, if negative then do square (not used currently).

hmbox
    Hide mouse box, which the user specifies to tell the X emulator a rectangle in which it should hide the mouse. The emulator passes this box to the hardware locator routines mainly so software driven cursors will not be displayed within this box. This is only used by displays with no hardware cursor support which need to know when to get the software cursor out of the way.

    	typedef struct {
    		short   bottom;
    		short   top;
    		short   left;
    		short   right;
    		int     flags;	/* 0 - not active, 1 - active */
    	} MSBox;

Keyboard Ioctl Control

QIOCBELL
    Ring keyboard bell with integer volume passed from 0 (off) to 7 (loud).

QIOCCLICK
    Set autokeyclick to integer volume passed between -1 (default), 0 (off) and 8 (loud).

QIOCAUTOREP
    Turn keyboard keys autorepeat (1) on or (0) off, integer argument.

QIOCSETCAPSL
    Turn on Caps Lock light on keyboard.

QIOCCLRCAPSL
    Turn off Caps Lock light on keyboard.

QIOCSETNUML
    Turn on Num Lock light on keyboard.

QIOCCLRNUML
    Turn off Num Lock light on keyboard.

QIOCSETSCROLLL
    Turn on Scroll Lock light on keyboard.

QIOCCLRSCROLLL
    Turn off Scroll Lock light on keyboard.

FILES
/dev/aed	ACIS Expiremental display nonstandard device.
/dev/apa8	APA8 display nonstandard device.
/dev/apa8c	APA8 Color display nonstandard device.
/dev/apa16	APA16 display nonstandard device.

SEE ALSO
Emulators in Workstation Unix, bufemul(4), stdemul(4), kbdemul(4), tty_tb(4)

BUGS
Should implement the mouse threshold and scale features.

AUTHOR
David O. Bundy