]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - board/MAI/bios_emulator/scitech/src/pm/linux/event.svga
* Patch by Thomas Frieden, 13 Nov 2002:
[karo-tx-uboot.git] / board / MAI / bios_emulator / scitech / src / pm / linux / event.svga
1 /****************************************************************************
2 *
3 *           The SuperVGA Kit - UniVBE Software Development Kit
4 *
5 *  ========================================================================
6 *
7 *    The contents of this file are subject to the SciTech MGL Public
8 *    License Version 1.0 (the "License"); you may not use this file
9 *    except in compliance with the License. You may obtain a copy of
10 *    the License at http://www.scitechsoft.com/mgl-license.txt
11 *
12 *    Software distributed under the License is distributed on an
13 *    "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
14 *    implied. See the License for the specific language governing
15 *    rights and limitations under the License.
16 *
17 *    The Original Code is Copyright (C) 1991-1998 SciTech Software, Inc.
18 *
19 *    The Initial Developer of the Original Code is SciTech Software, Inc.
20 *    All Rights Reserved.
21 *
22 *  ========================================================================
23 *
24 * Language:     ANSI C
25 * Environment:  IBM PC (MS DOS)
26 *
27 * Description:  Routines to provide a Linux event queue, which automatically
28 *               handles keyboard and mouse events for the Linux compatability
29 *               libraries. Based on the event handling code in the MGL.
30 *
31 ****************************************************************************/
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <time.h>
37 #include <ctype.h>
38 #include <termios.h>
39 #include <signal.h>
40 #include <fcntl.h>
41 #include <unistd.h>
42 #include <errno.h>
43 #include <sys/time.h>
44 #include <sys/stat.h>
45 #include <sys/types.h>
46 #include <linux/keyboard.h>
47 #include <linux/kd.h>
48 #include <linux/vt.h>
49 #include <gpm.h>
50 #include "pm.h"
51 #include "vesavbe.h"
52 #include "wdirect.h"
53
54 /*--------------------------- Global variables ----------------------------*/
55
56 #define EVENTQSIZE  100             /* Number of events in event queue  */
57
58 static int      head = -1;          /* Head of event queue              */
59 static int      tail = -1;          /* Tail of event queue              */
60 static int      freeHead = -1;      /* Head of free list                */
61 static int      count = 0;          /* No. of items currently in queue  */
62 static WD_event evtq[EVENTQSIZE];   /* The queue structure itself      */
63 static int      oldMove = -1;       /* Previous movement event          */
64 static int      oldKey = -1;        /* Previous key repeat event        */
65 static int      mx,my;              /* Current mouse position           */
66 static int      xRes,yRes;          /* Screen resolution coordinates    */
67 static void     *stateBuf;          /* Pointer to console state buffer  */
68 static int      conn;               /* GPM file descriptor for mouse handling */
69 static int      tty_fd;             /* File descriptor for /dev/console */
70 extern int      tty_vc;             /* Virtual console ID, from the PM/Pro library */
71 static ibool    key_down[128];      /* State of all keyboard keys       */
72 static struct termios old_conf;     /* Saved terminal configuration     */
73 static int      oldkbmode;          /* and previous keyboard mode       */
74 struct vt_mode  oldvtmode;          /* Old virtual terminal mode        */
75 static int      old_flags;          /* Old flags for fcntl              */
76 static ulong    key_modifiers;      /* Keyboard modifiers               */
77 static int      forbid_vt_release=0;/* Flag to forbid release of VT     */
78 static int      forbid_vt_acquire=0;/* Flag to forbid cature of VT      */
79 static int      oldmode;            /* Old SVGA mode saved for VT switch*/
80 static int      initmode;           /* Initial text mode                */
81 static ibool    installed = false;  /* True if we are installed         */
82 static void     (_ASMAPI *moveCursor)(int x,int y) = NULL;
83 static int      (_ASMAPI *suspendAppCallback)(int flags) = NULL;
84
85 #if 0
86 /* Keyboard Translation table from scancodes to ASCII */
87
88 static uchar keyTable[128] =
89 "\0\0331234567890-=\010"
90 "\011qwertyuiop[]\015"
91 "\0asdfghjkl;'`\0\\"
92 "zxcvbnm,./\0*\0 \0"
93 "\0\0\0\0\0\0\0\0\0\0\0\0"      /* Function keys */
94 "789-456+1230.\0\0\0\0\0"       /* Keypad keys */
95 "\0\0\0\0\0\0\0\015\0/";
96
97 static uchar keyTableShifted[128] =
98 "\0\033!@#$%^&*()_+\010"
99 "\011QWERTYUIOP{}\015"
100 "\0ASDFGHJKL:\"~\0|"
101 "ZXCVBNM<>?\0*\0 \0"
102 "\0\0\0\0\0\0\0\0\0\0\0\0"      /* Function keys */
103 "789-456+1230.\0\0\0\0\0"       /* Keypad keys */
104 "\0\0\0\0\0\0\0\015\0/";
105 #endif
106
107 /* Macros to keep track of the CAPS and NUM lock states */
108
109 #define EVT_CAPSSTATE   0x0100
110 #define EVT_NUMSTATE    0x0200
111
112 /* Helper macros for dealing with timers */
113
114 #define TICKS_TO_USEC(t) ((t)*65536.0/1.193180)
115 #define USEC_TO_TICKS(u) ((u)*1.193180/65536.0)
116
117 /* Number of keycodes to read at a time from the console */
118
119 #define KBDREADBUFFERSIZE 32
120
121 /*---------------------------- Implementation -----------------------------*/
122
123 /****************************************************************************
124 REMARKS:
125 Returns the current time stamp in units of 18.2 ticks per second.
126 ****************************************************************************/
127 static ulong getTimeStamp(void)
128 {
129     return (ulong)(clock() / (CLOCKS_PER_SEC / 18.2));
130 }
131
132 /****************************************************************************
133 PARAMETERS:
134 evt - Event to place onto event queue
135
136 REMARKS:
137 Adds an event to the event queue by tacking it onto the tail of the event
138 queue. This routine assumes that at least one spot is available on the
139 freeList for the event to be inserted.
140 ****************************************************************************/
141 static void addEvent(
142     WD_event *evt)
143 {
144     int         evtID;
145
146     /* Get spot to place the event from the free list */
147     evtID = freeHead;
148     freeHead = evtq[freeHead].next;
149
150     /* Add to the tail of the event queue   */
151     evt->next = -1;
152     evt->prev = tail;
153     if (tail != -1)
154         evtq[tail].next = evtID;
155     else
156         head = evtID;
157     tail = evtID;
158     evtq[evtID] = *evt;
159     count++;
160 }
161
162 /****************************************************************************
163 PARAMETERS:
164 what        - Event code
165 message     - Event message
166 modifiers   - keyboard modifiers
167 x           - Mouse X position at time of event
168 y           - Mouse Y position at time of event
169 but_stat    - Mouse button status at time of event
170
171 REMARKS:
172 Adds a new mouse event to the event queue. This routine is called from
173 within the mouse interrupt subroutine, so it must be efficient.
174 ****************************************************************************/
175 static void addMouseEvent(
176     uint what,
177     uint message,
178     int x,
179     int y,
180     uint but_stat)
181 {
182     WD_event    evt;
183
184     if (count < EVENTQSIZE) {
185         evt.what = what;
186         evt.when = getTimeStamp();
187         evt.message = message;
188         evt.modifiers = but_stat | key_modifiers;
189         evt.where_x = x;
190         evt.where_y = y;
191         fprintf(stderr, "(%d,%d), buttons %ld\n", x,y, evt.modifiers);
192         addEvent(&evt);                 /* Add to tail of event queue   */
193         }
194 }
195
196 /****************************************************************************
197 PARAMETERS:
198 scancode    - Raw keyboard scan code
199 modifiers   - Keyboard modifiers flags
200
201 REMARKS:
202 Converts the raw scan code into the appropriate ASCII code using the scan
203 code and the keyboard modifier flags.
204 ****************************************************************************/
205 static ulong getKeyMessage(
206     uint scancode,
207     ulong modifiers)
208 {
209     ushort  code = scancode << 8;
210     ushort  ascii;
211     struct kbentry ke;
212
213     ke.kb_index = scancode;
214
215     /* Find the basic ASCII code for the scan code */
216     if (modifiers & EVT_CAPSSTATE) {
217         if (modifiers & EVT_SHIFTKEY)
218           ke.kb_table = K_NORMTAB;
219         //          ascii = tolower(keyTableShifted[scancode]);
220         else
221           ke.kb_table = K_SHIFTTAB;
222         //          ascii = toupper(keyTable[scancode]);
223         }
224     else {
225         if (modifiers & EVT_SHIFTKEY)
226           ke.kb_table = K_SHIFTTAB;
227           // ascii = keyTableShifted[scancode];
228         else
229           ke.kb_table = K_NORMTAB;
230           // ascii = keyTable[scancode];
231         }
232     if(modifiers & EVT_ALTSTATE)
233       ke.kb_table |= K_ALTTAB;
234
235     if (ioctl(tty_fd, KDGKBENT, (unsigned long)&ke)) {
236         fprintf(stderr, "KDGKBENT at index %d in table %d: ",
237             scancode, ke.kb_table);
238         return 0;
239     }
240     ascii = ke.kb_value;
241
242     /* Add ASCII code if key is not alt'ed or ctrl'ed */
243     if (!(modifiers & (EVT_ALTSTATE | EVT_CTRLSTATE)))
244         code |= ascii;
245
246     return code;
247 }
248
249 /****************************************************************************
250 PARAMETERS:
251 what        - Event code
252 scancode    - Raw scancode of keyboard event to add
253
254 REMARKS:
255 Adds a new keyboard event to the event queue. We only take KEYUP and
256 KEYDOWN event codes, however if a key is already down we convert the KEYDOWN
257 to a KEYREPEAT.
258 ****************************************************************************/
259 static void addKeyEvent(
260     uint what,
261     uint scancode)
262 {
263     WD_event    evt;
264
265     if (count < EVENTQSIZE) {
266         evt.what = what;
267         evt.when = getTimeStamp();
268         evt.message = getKeyMessage(scancode,key_modifiers) | 0x10000UL;
269         evt.where_x = evt.where_y = 0;
270         evt.modifiers = key_modifiers;
271         if (evt.what == EVT_KEYUP)
272             key_down[scancode] = false;
273         else if (evt.what == EVT_KEYDOWN) {
274             if (key_down[scancode]) {
275                 if (oldKey != -1) {
276                     evtq[oldKey].message += 0x10000UL;
277                     }
278                 else {
279                     evt.what = EVT_KEYREPEAT;
280                     oldKey = freeHead;
281                     addEvent(&evt);
282                     oldMove = -1;
283                     }
284                 return;
285                 }
286             key_down[scancode] = true;
287             }
288
289         addEvent(&evt);
290         oldMove = -1;
291         }
292 }
293
294 /****************************************************************************
295 PARAMETERS:
296 sig - Signal being sent to this signal handler
297
298 REMARKS:
299 Signal handler for the timer. This routine takes care of periodically
300 posting timer events to the event queue.
301 ****************************************************************************/
302 void timerHandler(
303     int sig)
304 {
305     WD_event    evt;
306
307     if (sig == SIGALRM) {
308         if (count < EVENTQSIZE) {
309             evt.when = getTimeStamp();
310             evt.what = EVT_TIMERTICK;
311             evt.message = 0;
312             evt.where_x = evt.where_y = 0;
313             evt.modifiers = 0;
314             addEvent(&evt);
315             oldMove = -1;
316             oldKey = -1;
317             }
318         signal(SIGALRM, timerHandler);
319         }
320 }
321
322 /****************************************************************************
323 REMARKS:
324 Restore the terminal to normal operation on exit
325 ****************************************************************************/
326 static void restore_term(void)
327 {
328     RMREGS  regs;
329
330     if (installed) {
331         /* Restore text mode and the state of the console */
332         regs.x.ax = 0x3;
333         PM_int86(0x10,&regs,&regs);
334         PM_restoreConsoleState(stateBuf,tty_fd);
335
336         /* Restore console to normal operation */
337         ioctl(tty_fd, VT_SETMODE, &oldvtmode);
338         ioctl(tty_fd, KDSKBMODE, oldkbmode);
339         tcsetattr(tty_fd, TCSAFLUSH, &old_conf);
340         fcntl(tty_fd,F_SETFL,old_flags &= ~O_NONBLOCK);
341         PM_closeConsole(tty_fd);
342
343         /* Close the mouse driver */
344         close(conn);
345
346         /* Flag that we are not no longer installed */
347         installed = false;
348         }
349 }
350
351 /****************************************************************************
352 REMARKS:
353 Signal handler to capture forced program termination conditions so that
354 we can clean up properly.
355 ****************************************************************************/
356 static void exitHandler(int sig)
357 {
358     exit(-1);
359 }
360
361 /****************************************************************************
362 REMARKS:
363 Sleep until the virtual terminal is active
364 ****************************************************************************/
365 void wait_vt_active(void)
366 {
367     while (ioctl(tty_fd, VT_WAITACTIVE, tty_vc) < 0) {
368         if ((errno != EAGAIN) && (errno != EINTR)) {
369             perror("ioctl(VT_WAITACTIVE)");
370             exit(1);
371             }
372         usleep(150000);
373         }
374 }
375
376 /****************************************************************************
377 REMARKS:
378 Signal handler called when our virtual terminal has been released and we are
379 losing the active focus.
380 ****************************************************************************/
381 static void release_vt_signal(int n)
382 {
383     forbid_vt_acquire = 1;
384     if (forbid_vt_release) {
385         forbid_vt_acquire = 0;
386         ioctl(tty_fd, VT_RELDISP, 0);
387         return;
388         }
389
390     // TODO: Call the user supplied suspendAppCallback and restore text
391     //       mode (saving the existing mode so we can restore it).
392     //
393     //       Also if the suspendAppCallback is NULL then we have to
394     //       ignore the switch request!
395     if(suspendAppCallback){
396       oldmode = VBE_getVideoMode();
397       suspendAppCallback(true);
398       VBE_setVideoMode(initmode);
399     }
400
401     ioctl(tty_fd, VT_RELDISP, 1);
402     forbid_vt_acquire = 0;
403     wait_vt_active();
404 }
405
406 /****************************************************************************
407 REMARKS:
408 Signal handler called when our virtual terminal has been re-aquired and we
409 are now regaiing the active focus.
410 ****************************************************************************/
411 static void acquire_vt_signal(int n)
412 {
413     forbid_vt_release = 1;
414     if (forbid_vt_acquire) {
415         forbid_vt_release = 0;
416         return;
417         }
418
419     // TODO: Restore the old display mode, call the user suspendAppCallback
420     //       and and we will be back in graphics mode.
421
422     if(suspendAppCallback){
423       VBE_setVideoMode(oldmode);
424       suspendAppCallback(false);
425     }
426
427     ioctl(tty_fd, VT_RELDISP, VT_ACKACQ);
428     forbid_vt_release = 0;
429 }
430
431 /****************************************************************************
432 REMARKS:
433 Function to set the action for a specific signal to call our signal handler.
434 ****************************************************************************/
435 static void set_sigaction(int sig,void (*handler)(int))
436 {
437     struct sigaction    siga;
438
439     siga.sa_handler = handler;
440     siga.sa_flags = SA_RESTART;
441     memset(&(siga.sa_mask), 0, sizeof(sigset_t));
442     sigaction(sig, &siga, NULL);
443 }
444
445 /****************************************************************************
446 REMARKS:
447 Function to take over control of VT switching so that we can capture
448 virtual terminal release and aquire signals, allowing us to properly
449 support VT switching while in graphics modes.
450 ****************************************************************************/
451 static void take_vt_control(void)
452 {
453     struct vt_mode      vtmode;
454
455     ioctl(tty_fd, VT_GETMODE, &vtmode);
456     oldvtmode = vtmode;
457     vtmode.mode = VT_PROCESS;
458     vtmode.relsig = SIGUSR1;
459     vtmode.acqsig = SIGUSR2;
460     set_sigaction(SIGUSR1, release_vt_signal);
461     set_sigaction(SIGUSR2, acquire_vt_signal);
462     ioctl(tty_fd, VT_SETMODE, &oldvtmode);
463 }
464
465 /****************************************************************************
466 REMARKS:
467 Set the shift keyboard LED's based on the current keyboard modifiers flags.
468 ****************************************************************************/
469 static void updateLEDStatus(void)
470 {
471     int state = 0;
472     if (key_modifiers & EVT_CAPSSTATE)
473         state |= LED_CAP;
474     if (key_modifiers & EVT_NUMSTATE)
475         state |= LED_NUM;
476     ioctl(tty_fd,KDSETLED,state);
477 }
478
479 /****************************************************************************
480 PARAMETERS:
481 scancode    - Raw scan code to handle
482
483 REMARKS:
484 Handles the shift key modifiers and keeps track of the shift key states
485 so that we can return the correct ASCII codes for the keyboard.
486 ****************************************************************************/
487 static void toggleModifiers(
488     int scancode)
489 {
490     static int caps_down = 0,num_down = 0;
491
492     if (scancode & 0x80) {
493         /* Handle key-release function */
494         scancode &= 0x7F;
495         if (scancode == 0x2A || scancode == 0x36)
496             key_modifiers &= ~EVT_SHIFTKEY;
497         else if (scancode == 0x1D || scancode == 0x61)
498             key_modifiers &= ~EVT_CTRLSTATE;
499         else if (scancode == 0x38 || scancode == 0x64)
500             key_modifiers &= ~EVT_ALTSTATE;
501         else if (scancode == 0x3A)
502             caps_down = false;
503         else if (scancode == 0x45)
504             num_down = false;
505         }
506     else {
507         /* Handle key-down function */
508         scancode &= 0x7F;
509         if (scancode == 0x2A || scancode == 0x36)
510             key_modifiers |= EVT_SHIFTKEY;
511         else if (scancode == 0x1D || scancode == 0x61)
512             key_modifiers |= EVT_CTRLSTATE;
513         else if (scancode == 0x38 || scancode == 0x64)
514             key_modifiers |= EVT_ALTSTATE;
515         else if (scancode == 0x3A) {
516             if (!caps_down) {
517                 key_modifiers ^= EVT_CAPSSTATE;
518                 updateLEDStatus();
519                 }
520             caps_down = true;
521             }
522         else if (scancode == 0x45) {
523             if (!num_down) {
524                 key_modifiers ^= EVT_NUMSTATE;
525                 updateLEDStatus();
526                 }
527             num_down = true;
528             }
529         }
530 }
531
532 /***************************************************************************
533 REMARKS:
534 Returns the number of bits that have changed from 0 to 1
535 (a negative value means the number of bits that have changed from 1 to 0) 
536  **************************************************************************/
537 static int compareBits(short a, short b)
538 {
539     int ret = 0;
540     if( (a&1) != (b&1) ) ret += (b&1) ? 1 : -1;
541     if( (a&2) != (b&2) ) ret += (b&2) ? 1 : -1;
542     if( (a&4) != (b&4) ) ret += (b&4) ? 1 : -1;
543     return ret;
544 }
545
546 /***************************************************************************
547 REMARKS:
548 Turns off all keyboard state because we can't rely on them anymore as soon
549 as we switch VT's
550 ***************************************************************************/
551 static void keyboard_clearstate(void)
552 {
553   key_modifiers = 0;
554   memset(key_down, 0, sizeof(key_down));
555 }
556
557 /****************************************************************************
558 REMARKS:
559 Pumps all events from the console event queue into the WinDirect event queue.
560 ****************************************************************************/
561 static void pumpEvents(void)
562 {
563     static uchar    buf[KBDREADBUFFERSIZE];
564     static char     data[5];
565     static int      old_buts, old_mx, old_my;
566     static struct timeval t;
567     fd_set fds;
568     int             numkeys,i;
569     int             dx, dy, buts;
570
571     /* Read all pending keypresses from keyboard buffer and process */
572     while ((numkeys = read(tty_fd, buf, KBDREADBUFFERSIZE)) > 0) {
573         for (i = 0; i < numkeys; i++) {
574             toggleModifiers(buf[i]);
575             if (key_modifiers & EVT_ALTSTATE){
576               int fkey = 0;
577
578               // Do VT switching here for Alt+Fx keypresses
579               switch(buf[i] & 0x7F){
580               case 59 ... 68: /* F1 to F10 */
581                 fkey = (buf[i] & 0x7F) - 58;
582                 break;
583               case 87: /* F11 */
584               case 88: /* F12 */
585                 fkey = (buf[i] & 0x7F) - 76;
586                 break;
587               }
588               if(fkey){
589                 struct vt_stat vts;
590                 ioctl(tty_fd, VT_GETSTATE, &vts);
591                 
592                 if(fkey != vts.v_active){
593                   keyboard_clearstate();
594                   ioctl(tty_fd, VT_ACTIVATE, fkey);
595                 }
596               }
597             }
598
599             if (buf[i] & 0x80)
600                 addKeyEvent(EVT_KEYUP,buf[i] & 0x7F);
601             else
602                 addKeyEvent(EVT_KEYDOWN,buf[i] & 0x7F);
603             }
604
605         // TODO: If we want to handle VC switching we will need to do it
606         //       in here so that we can switch away from the VC and then
607         //       switch back to it later. Right now VC switching is disabled
608         //       and in order to enable it we need to save/restore the state
609         //       of the graphics screen (using the suspendAppCallback and
610         //       saving/restoring the state of the current display mode).
611
612         }
613
614     /* Read all pending mouse events and process them */
615     if(conn > 0){
616         FD_ZERO(&fds);
617         FD_SET(conn, &fds);
618         t.tv_sec = t.tv_usec = 0L;
619         while (select(conn+1, &fds, NULL, NULL, &t) > 0) {
620             if(read(conn, data, 5) == 5){
621                 buts = (~data[0]) & 0x07;
622                 dx = (char)(data[1]) + (char)(data[3]);
623                 dy = -((char)(data[2]) + (char)(data[4]));
624                 
625                 mx += dx; my += dy;
626                 
627                 if (dx || dy)
628                     addMouseEvent(EVT_MOUSEMOVE, 0, mx, my, buts);
629                 
630                 if (buts != old_buts){
631                     int c = compareBits(buts,old_buts);
632                     if(c>0)
633                         addMouseEvent(EVT_MOUSEDOWN, 0, mx, my, buts);
634                     else if(c<0)
635                         addMouseEvent(EVT_MOUSEUP, 0, mx, my, buts);
636                 }
637                 old_mx = mx; old_my = my;
638                 old_buts = buts;
639                 FD_SET(conn, &fds);
640                 t.tv_sec = t.tv_usec = 0L;
641             }
642         }
643     }
644 }
645
646 /*------------------------ Public interface routines ----------------------*/
647
648 /****************************************************************************
649 PARAMETERS:
650 which       - Which code for event to post
651 what        - Event code for event to post
652 message     - Event message
653 modifiers   - Shift key/mouse button modifiers
654
655 RETURNS:
656 True if the event was posted, false if queue is full.
657
658 REMARKS:
659 Posts an event to the event queue. This routine can be used to post any type
660 of event into the queue.
661 ****************************************************************************/
662 ibool _WDAPI WD_postEvent(
663     ulong which,
664     uint what,
665     ulong message,
666     ulong modifiers)
667 {
668     WD_event    evt;
669
670     if (count < EVENTQSIZE) {
671         /* Save information in event record */
672         evt.which = which;
673         evt.what = what;
674         evt.when = getTimeStamp();
675         evt.message = message;
676         evt.modifiers = modifiers;
677         addEvent(&evt);             /* Add to tail of event queue   */
678         return true;
679         }
680     else
681         return false;
682 }
683
684 /****************************************************************************
685 PARAMETERS:
686 mask    - Event mask to use
687
688 REMARKS:
689 Flushes all the event specified in 'mask' from the event queue.
690 ****************************************************************************/
691 void _WDAPI WD_flushEvent(
692     uint mask)
693 {
694     WD_event    evt;
695
696     do {                            /* Flush all events */
697         WD_getEvent(&evt,mask);
698         } while (evt.what != EVT_NULLEVT);
699 }
700
701 /****************************************************************************
702 PARAMETERS:
703 evt     - Place to store event
704 mask    - Event mask to use
705
706 REMARKS:
707 Halts program execution until a specified event occurs. The event is
708 returned. All pending events not in the specified mask will be ignored and
709 removed from the queue.
710 ****************************************************************************/
711 void _WDAPI WD_haltEvent(
712     WD_event *evt,
713     uint mask)
714 {
715     do {                            /* Wait for an event    */
716         WD_getEvent(evt,EVT_EVERYEVT);
717         } while (!(evt->what & mask));
718 }
719
720 /****************************************************************************
721 PARAMETERS:
722 evt     - Place to store event
723 mask    - Event mask to use
724
725 RETURNS:
726 True if an event was pending.
727
728 REMARKS:
729 Retrieves the next pending event defined in 'mask' from the event queue.
730 The event queue is adjusted to reflect the new state after the event has
731 been removed.
732 ****************************************************************************/
733 ibool _WDAPI WD_getEvent(
734     WD_event *evt,
735     uint mask)
736 {
737     int     evtID,next,prev;
738
739     pumpEvents();
740     if (moveCursor)
741         moveCursor(mx,my);                  /* Move the mouse cursor    */
742     evt->what = EVT_NULLEVT;                /* Default to null event    */
743
744     if (count) {
745         for (evtID = head; evtID != -1; evtID = evtq[evtID].next) {
746             if (evtq[evtID].what & mask)
747                 break;                      /* Found an event           */
748             }
749         if (evtID == -1)
750             return false;                   /* Event was not found      */
751         next = evtq[evtID].next;
752         prev = evtq[evtID].prev;
753         if (prev != -1)
754             evtq[prev].next = next;
755         else
756             head = next;
757         if (next != -1)
758             evtq[next].prev = prev;
759         else
760             tail = prev;
761         *evt = evtq[evtID];                 /* Return the event         */
762         evtq[evtID].next = freeHead;        /* and return to free list  */
763         freeHead = evtID;
764         count--;
765         if (evt->what == EVT_MOUSEMOVE)
766             oldMove = -1;
767         if (evt->what == EVT_KEYREPEAT)
768             oldKey = -1;
769         }
770     return evt->what != EVT_NULLEVT;
771 }
772
773 /****************************************************************************
774 PARAMETERS:
775 evt     - Place to store event
776 mask    - Event mask to use
777
778 RETURNS:
779 True if an event is pending.
780
781 REMARKS:
782 Peeks at the next pending event defined in 'mask' in the event queue. The
783 event is not removed from the event queue.
784 ****************************************************************************/
785 ibool _WDAPI WD_peekEvent(
786     WD_event *evt,
787     uint mask)
788 {
789     int     evtID;
790
791     pumpEvents();
792     if (moveCursor)
793         moveCursor(mx,my);                  /* Move the mouse cursor    */
794     evt->what = EVT_NULLEVT;                /* Default to null event    */
795
796     if (count) {
797         for (evtID = head; evtID != -1; evtID = evtq[evtID].next) {
798             if (evtq[evtID].what & mask)
799                 break;                      /* Found an event           */
800             }
801         if (evtID == -1)
802             return false;                   /* Event was not found      */
803
804         *evt = evtq[evtID];                 /* Return the event         */
805         }
806     return evt->what != EVT_NULLEVT;
807 }
808
809 /****************************************************************************
810 PARAMETERS:
811 hwndMain    - Handle to main window
812 _xRes       - X resolution of graphics mode to be used
813 _yRes       - Y resolulion of graphics mode to be used
814
815 RETURNS:
816 Handle to the fullscreen event window if (we return hwndMain on Linux)
817
818 REMARKS:
819 Initiliase the event handling module. Here we install our mouse handling
820 ISR to be called whenever any button's are pressed or released. We also
821 build the free list of events in the event queue.
822 ****************************************************************************/
823 WD_HWND _WDAPI WD_startFullScreen(
824     WD_HWND hwndMain,
825     int _xRes,
826     int _yRes)
827 {
828     int             i;
829     struct termios  conf;
830     if (!installed) {
831         Gpm_Connect gpm;
832
833         /* Build free list, and initialise global data structures */
834         for (i = 0; i < EVENTQSIZE; i++)
835             evtq[i].next = i+1;
836         evtq[EVENTQSIZE-1].next = -1;       /* Terminate list           */
837         count = freeHead = 0;
838         head = tail = -1;
839         oldMove = -1;
840         oldKey = -1;
841         xRes = _xRes;
842         yRes = _yRes;
843
844         /* Open the console device and initialise it for raw mode */
845         tty_fd = PM_openConsole();
846
847         /* Wait until virtual terminal is active and take over control */
848         wait_vt_active();
849         take_vt_control();
850
851         /* Initialise keyboard handling to raw mode */
852         if (ioctl(tty_fd, KDGKBMODE, &oldkbmode)) {
853             printf("WD_startFullScreen: cannot get keyboard mode.\n");
854             exit(-1);
855             }
856         old_flags = fcntl(tty_fd,F_GETFL);
857         fcntl(tty_fd,F_SETFL,old_flags |= O_NONBLOCK);
858         tcgetattr(tty_fd, &conf);
859         old_conf = conf;
860         conf.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK | ECHONL | NOFLSH | ISIG);
861         conf.c_iflag &= ~(ISTRIP | IGNCR | ICRNL | INLCR | BRKINT | PARMRK | INPCK | IUCLC | IXON | IXOFF);
862         conf.c_iflag  |= (IGNBRK | IGNPAR);
863         conf.c_cc[VMIN] = 1;
864         conf.c_cc[VTIME] = 0;
865         conf.c_cc[VSUSP] = 0;
866         tcsetattr(tty_fd, TCSAFLUSH, &conf);
867         ioctl(tty_fd, KDSKBMODE, K_MEDIUMRAW);
868
869         /* Clear the keyboard state information */
870         memset(key_down, 0, sizeof(key_down));
871         ioctl(tty_fd,KDSETLED,key_modifiers = 0);
872
873         /* Initialize the mouse connection 
874            The user *MUST* run gpm with the  option -R for this to work (or have a MouseSystems mouse)
875         */
876         if(Gpm_Open(&gpm,0) > 0){ /* GPM available */
877             if ((conn = open(GPM_NODE_FIFO,O_RDONLY|O_SYNC)) < 0)
878                 fprintf(stderr,"WD_startFullScreen: Can't open mouse connection.\n");
879         }else{
880             fprintf(stderr,"Warning: when not using gpm -R, only MouseSystems mice are currently supported.\n");
881             if ((conn = open("/dev/mouse",O_RDONLY|O_SYNC)) < 0)
882                 fprintf(stderr,"WD_startFullScreen: Can't open /dev/mouse.\n");
883         }
884         Gpm_Close();
885
886         /* TODO: Scale the mouse coordinates to the specific resolution */
887
888         /* Save the state of the console */
889         if ((stateBuf = malloc(PM_getConsoleStateSize())) == NULL) {
890             printf("Out of memory!\n");
891             exit(-1);
892             }
893         PM_saveConsoleState(stateBuf,tty_fd);
894         initmode = VBE_getVideoMode();
895
896         /* Initialize the signal handler for timer events */
897         signal(SIGALRM, timerHandler);
898
899         /* Capture termination signals so we can clean up properly */
900         signal(SIGTERM, exitHandler);
901         signal(SIGINT, exitHandler);
902         signal(SIGQUIT, exitHandler);
903         atexit(restore_term);
904
905         /* Signal that we are installed */
906         installed = true;
907         }
908     return hwndMain;
909 }
910
911 /****************************************************************************
912 REMARKS:
913 Lets the library know when fullscreen graphics mode has been initialized so
914 that we can properly scale the mouse driver coordinates.
915 ****************************************************************************/
916 void _WDAPI WD_inFullScreen(void)
917 {
918     /* Nothing to do in here */
919 }
920
921 /****************************************************************************
922 REMARKS:
923 Suspends all of our event handling operations. This is also used to
924 de-install the event handling code.
925 ****************************************************************************/
926 void _WDAPI WD_restoreGDI(void)
927 {
928     restore_term();
929 }
930
931 /****************************************************************************
932 PARAMETERS:
933 ticks   - Number of ticks between timer tick messages
934
935 RETURNS:
936 Previous value for the timer tick event spacing.
937
938 REMARKS:
939 The event module will automatically generate periodic timer tick events for
940 you, with 'ticks' between each event posting. If you set the value of
941 'ticks' to 0, the timer tick events are turned off.
942 ****************************************************************************/
943 int _WDAPI WD_setTimerTick(
944     int ticks)
945 {
946     int                 old;
947     struct itimerval    tim;
948     long                ms = TICKS_TO_USEC(ticks);
949
950     getitimer(ITIMER_REAL, &tim);
951     old = USEC_TO_TICKS(tim.it_value.tv_sec*1000000.0 + tim.it_value.tv_usec);
952     tim.it_interval.tv_sec  = ms / 1000000;
953     tim.it_interval.tv_usec = ms % 1000000;
954     setitimer(ITIMER_REAL, &tim, NULL);
955     return old;
956 }
957
958 /****************************************************************************
959 PARAMETERS:
960 saveState   - Address of suspend app callback to register
961
962 REMARKS:
963 Registers a user application supplied suspend application callback so that
964 we can properly handle virtual terminal switching.
965 ****************************************************************************/
966 void _WDAPI WD_setSuspendAppCallback(
967     int (_ASMAPI *saveState)(int flags))
968 {
969   suspendAppCallback = saveState;
970 }
971
972 /****************************************************************************
973 PARAMETERS:
974 x   - New X coordinate to move the mouse cursor to
975 y   - New Y coordinate to move the mouse cursor to
976
977 REMARKS:
978 Moves to mouse cursor to the specified coordinate.
979 ****************************************************************************/
980 void _WDAPI WD_setMousePos(
981     int x,
982     int y)
983 {
984     mx = x;
985     my = y;
986 }
987
988 /****************************************************************************
989 PARAMETERS:
990 x   - Place to store X coordinate of mouse cursor
991 y   - Place to store Y coordinate of mouse cursor
992
993 REMARKS:
994 Reads the current mouse cursor location int *screen* coordinates.
995 ****************************************************************************/
996 void _WDAPI WD_getMousePos(
997     int *x,
998     int *y)
999 {
1000     *x = mx;
1001     *y = my;
1002 }
1003
1004 /****************************************************************************
1005 PARAMETERS:
1006 mcb - Address of mouse callback function
1007
1008 REMARKS:
1009 Registers an application supplied mouse callback function that is called
1010 whenever the mouse cursor moves.
1011 ****************************************************************************/
1012 void _WDAPI WD_setMouseCallback(
1013     void (_ASMAPI *mcb)(int x,int y))
1014 {
1015     moveCursor = mcb;
1016 }
1017
1018 /****************************************************************************
1019 PARAMETERS:
1020 xRes    - New X resolution of graphics mode
1021 yRes    - New Y resolution of graphics mode
1022
1023 REMARKS:
1024 This is called to inform the event handling code that the screen resolution
1025 has changed so that the mouse coordinates can be scaled appropriately.
1026 ****************************************************************************/
1027 void _WDAPI WD_changeResolution(
1028     int xRes,
1029     int yRes)
1030 {
1031     //  Gpm_FitValues(xRes, yRes);  // ??
1032 }
1033
1034 /****************************************************************************
1035 PARAMETERS:
1036 scancode    - Scan code to check if a key is down
1037
1038 REMARKS:
1039 Determines if a particular key is down based on the scan code for the key.
1040 ****************************************************************************/
1041 ibool _WDAPI WD_isKeyDown(
1042     uchar scancode)
1043 {   
1044     return key_down[scancode];
1045 }
1046
1047 /****************************************************************************
1048 REMARKS:
1049 Determines if the application needs to run in safe mode. Not necessary for
1050 anything but broken Windows 95 display drivers so we return false for
1051 Linux.
1052 ****************************************************************************/
1053 int _WDAPI WD_isSafeMode(void)
1054 {
1055     return false;
1056 }
1057
1058