Using the event manager API

A sample program

The following sample program opens an event queue with a mouse (relative device) and the keyboard (string device). It prints out information about events as they enter the queue. Note that depending on your system, you may have to configure system event parameters.

This program illustrates basic event manager functionality. It does not use the routines for querying or modifying the devices or event masks for the queue, nor the routines for suspending the event queue.

1 #include <stdio.h> 2 #include <signal.h> 3 #include <sys/machdep.h> 4 #include <sys/types.h> 5 #include <sys/param.h> 6 #include <sys/sysmacros.h> 7 #include <sys/page.h> 8 #include <sys/event.h> 9 #include <mouse.h>

10 #define DEL 0x7f

11 char progname[80]; 12 extern int errno;

13 main(argc,argv) 14 int argc; 15 char *argv[]; 16 { 17 int qfd,finish(),report(); 18 EVENT *evp; 19 int ret; 20 dmask_t dmask = D_STRING | D_REL | D_BUTTON; 21 extern int ev_errlev;

line 3
The <sys/machdep.h> header file includes definitions for the event driver IOCTL's and the mouse discipline.

lines 4-6
These header files are required in virtually every device driver to define data types, structures, and macros used to access devices directly. Because the event manager API is so closely tied to the driver, these header files are also required in any program that uses the event manager.

lines 8-9
These two header files must be #included in this order in any program that uses the event manager.

line 10
This maps the DEL variable to the hardware register that is normally associated with the <Del> key. Line discipline zero functionality such as signals is not available to the keyboard, because it is running under the event line discipline. Consequently, the <Del> character loses its special meaning. To solve this problem, the program tests each character against DEL. This variable will be used in line 66.

line 20
The device mask is used as an argument to the ev_open(S) call in line 32. It is a bitwise OR'ing of any values that describe the category of devices that are to be opened. This device mask specifies relative locator devices (such as mice); absolute locator devices (such as bitpads); and devices that generate character strings. A fourth value, D_OTHER, can be used to specify event devices that are not within the other categories. These values are defined on the event(FP) manual page.

32 ev_errlev = 1; 33 strcpy(progname,argv[0]); 34 signal(SIGINT,finish); 35 signal(SIGSEGV, report); 36 signal(SIGSYS, report);

37 printf("\n"); 38 ret = ev_init(); 39 printf("init == %d\n", ret); 40 if ( ret < 0 ) 41 finish(); 42 qfd = ev_open(&dmask); 43 printf("open == %d\n", qfd); 44 if ( qfd < 0 ) 45 fail("could not open event queue"); 46 if ( dmask != (D_STRING | D_REL | D_BUTTON)) 47 fail("could not attach mouse and keyboard"); 48 while ( !(ev_block()) ) 49 if ( (evp = ev_read()) != (EVENT *) NULL ) { 50 evprint(evp); 51 ev_pop(); 52 } 53 return 0; 54 } 55

56 fail(s) 57 char *s; 58 { 59 extern int errno;

60 printf("s(%d): %s\n",progname,errno,s); 61 finish(); 62 return 0; 63 }

line 22
Turn on the event manager diagnostics. ev_errlev is an error-level variable that can be set to a nonzero value to have the event manager print out more verbose diagnostics that can be used for debugging. By default, ev_errlev is set to 0. Once the code is thoroughly debugged, this line should be removed to improve the performance of the program.

lines 28-31
ev_init(S) reads the system event configuration files and initializes the event queue. It must be the first event manager routine called in the program. If there is a syntax error or inconsistency in the configuration files, it returns a small negative integer; if it successfully initializes the event queue, it returns 1.

lines 32-37
ev_open(S) opens an event queue for the process. All the event devices that are are associated with the terminal and whose class is masked in are opened and added to the queue.

The argument to the ev_open routine points to the device mask that was defined in line 20. The function tries to attach devices of the indicated type(s) to the vent queue. If ev_open cannot find any devices to attach to the queue, it closes the queue and returns a negative number indicating an error. If it is able to attach devices, it sets the mask to indicate what kinds of devices it has found. So line 36 verifies that the mask is still set as it was in line 20; if it is not, the program exits and returns an error message using the fail( ) function defined lin lines 47-54.

If ev_open is successful, it returns a file descriptor that is used with the select(S) system call. It should not be used for reading or writing.

lines 38-45
At this point, events should be enqueued. This section of code illustrates the standard practice of using ev_block(S) to block until there is an event in the queue, then read the event with ev_read(S), and then remove the last read event from the queue with ev_pop(S).

ev_read takes no arguments. It reads the next element in the event queue and returns a pointer to the next element in the vent queue, or to NULL if the queue is empty. Multiple calls to this routine return the same pointer until a call to ev_pop is made. ev_pop pops the next element off the queue. As soon as this routine is called, the pointer returned by the most recent call to ev_read must be considered invalid, because the event driver can overwrite the pointed area with new information.

ev_pop fails if the queue is empty. Otherwise, it returns a number that indicates how many events have been lost to queue overrun since the last ev_pop. The queue is of a fixed size (determined by the EVDEVSPERQ tunable parameter). If the application does not read the queue fast enough, events may be lost; this is called ``queue overrun'' because the event driver would overrun the tail of the queue if it wrote new events. The event driver provides a counter that indicates the number of events it has lost. That counter is cleared when it succeeds in writing an event. An ev_pop call always causes a new slot to be available, which clears the overrun counter. ev_pop returns the old overrun counter so that an application is aware if events are being lost.

lines 46-53
The fails( ) function is called in line 35 to indicate an error condition.

54 evprint(evp) 55 EVENT *evp; 56 { 57 static long time=-1;

58 if (time == -1) 59 time = evp->timestamp; 60 if (EV_TAG(*evp) & T_STRING) { 61 printf("time(%d) tag(%d) bufsize(%d) buf(%x)\n", 62 EV_TIME(*evp)-time, 63 EV_TAG(*evp), 64 EV_BUFCNT(*evp), 65 EV_BUF(*evp)[0]); 66 if (EV_BUF(*evp[0]) == DEL) 67 finish(); 68 } 69 else { 70 printf("time(%ld) tag(%d) butts(%d) x(%ld) y(%ld)\n", 71 EV_TIME(*evp) - time, 72 EV_TAG(*evp), 73 EV_BUTTONS(*evp), 74 EV_DX(*evp), 75 EV_DY(*evp)); 76 if (EV_BUTTONS(*evp) == 7) 77 finish(); 78 } 79 return 0; 80 }

81 finish() 82 { 83 ev_close(); 84 printf("done\n"); 85 exit(0); 86 }

87 report(s) 88 int s; 89 { 90 printf("got signal %d\n", s); 91 finish(); 92 }

lines 54-78
This section of code illustrates how a program can access information about a specific event by using the event extracting constants that are listed on the event(FP) manual page.

lines 81-86
This subroutine closes the event queue and exits the program. It is called in line 24 when a SIGINT signal is received, in line 51 as part of the fail( ) routine, in line 91 as part of the report( ) routine, and at other points in the code where the program needs to exit without returning an error message.

Previous topic: Event manager library calls

© 2003 Caldera International, Inc. All rights reserved.
SCO OpenServer Release 5.0.7 -- 11 February 2003