µGFX  2.9
version 2.9
ginput_keyboard.c
Go to the documentation of this file.
1 /*
2  * This file is subject to the terms of the GFX License. If a copy of
3  * the license was not distributed with this file, you can obtain one at:
4  *
5  * http://ugfx.io/license.html
6  */
7 
8 /**
9  * @file src/ginput/ginput_keyboard.c
10  * @brief GINPUT keyboard code.
11  */
12 
13 // We need to include stdio.h below for MICROCODE_DEBUG. Turn off GFILE_NEED_STDIO just for this file to prevent conflicts
14 #define GFILE_NEED_STDIO_MUST_BE_OFF
15 
16 #include "../../gfx.h"
17 
18 #if GFX_USE_GINPUT && GINPUT_NEED_KEYBOARD
19 
20 #define MICROCODE_DEBUG GFXOFF
21 
22 #if MICROCODE_DEBUG
23  #include <stdio.h>
24 #endif
25 
26 // Get the keyboard driver interface
27 #include "ginput_driver_keyboard.h"
29 
30 // The keyboard poll timer
31 static GTIMER_DECL(KeyboardTimer);
32 
33 static void SendKeyboardEventToListener(GSourceListener *psl, GKeyboard *k) {
34  GEventKeyboard *pe;
35  int i;
36 
37  // If there is no event buffer just mark a missed event
38  if (!(pe = (GEventKeyboard *)geventGetEventBuffer(psl))) {
39  // This listener is missing - save the meta events that have happened
40  psl->srcflags |= GKEYSTATE_MISSED_EVENT;
41  return;
42  }
43 
44  if ((psl->listenflags & GLISTEN_KEYRAW)) {
45  pe->type = GEVENT_KEYBOARD;
46  pe->bytecount = k->cntsc;
47  for(i = 0; i < k->cntsc; i++) pe->c[i] = k->sc[i];
48  for(; i < 8; i++) pe->c[i] = 0;
49  pe->keystate = k->keystate | psl->srcflags | GKEYSTATE_RAW;
50  psl->srcflags = 0;
51  return;
52  }
53 
54  if ((psl->listenflags & GLISTEN_KEYREPEATSOFF) && (k->keystate & GKEYSTATE_REPEAT))
55  return;
56 
57  if ((psl->listenflags & GLISTEN_KEYNOSPECIALS) && (k->keystate & GKEYSTATE_SPECIAL))
58  return;
59 
60  if (!(psl->listenflags & GLISTEN_KEYUP) && (k->keystate & GKEYSTATE_KEYUP))
61  k->cntc = 0;
62 
63  if (!(psl->listenflags & GLISTEN_KEYTRANSITIONS) && !k->cntc)
64  return;
65 
66  pe->type = GEVENT_KEYBOARD;
67  pe->bytecount = k->cntc;
68  for(i = 0; i < k->cntc; i++) pe->c[i] = k->c[i];
69  for(; i < 8; i++) pe->c[i] = 0;
70  pe->keystate = k->keystate | psl->srcflags;
71  psl->srcflags = 0;
72  geventSendEvent(psl);
73 }
74 
75 static void SendKeyboardEvent(GKeyboard *k) {
76  GSourceListener *psl;
77 
78  // Send to the "All Keyboards" source listeners
79  psl = 0;
80  while ((psl = geventGetSourceListener((GSourceHandle)&KeyboardTimer, psl)))
81  SendKeyboardEventToListener(psl, k);
82 
83  // Send to the keyboard specific source listeners
84  psl = 0;
85  while ((psl = geventGetSourceListener((GSourceHandle)k, psl)))
86  SendKeyboardEventToListener(psl, k);
87 }
88 
89 #define FLAG_ERROR 0x01
90 #define FLAG_INIT 0x02
91 
92 #if GKEYBOARD_LAYOUT_OFF
93  static void microengine(GKeyboard *k, gU8 code, gU8 flags) {
94  if (flags)
95  return;
96 
97  // Just send an event using the char
98  k->c[0] = k->sc[0] = code;
99  k->cntc = k->cntsc = 1;
100  SendKeyboardEvent(k);
101  k->cntc = k->cntsc = 0;
102  }
103 #else
104  static void microengine(GKeyboard *k, gU8 code, gU8 flags) {
105  const gU8 *pc;
106  const gU8 *nrec;
107  gU8 ver, diff, p1, p2;
108  #if MICROCODE_DEBUG
109  unsigned cnt;
110  #endif
111 
112  pc = k->pLayout;
113  if (!pc) {
114  if (flags)
115  return;
116 
117  // Default is to just send an event using the char
118  k->c[0] = k->sc[0] = code;
119  k->cntc = k->cntsc = 1;
120  SendKeyboardEvent(k);
121  k->cntc = k->cntsc = 0;
122  return;
123  }
124 
125  // Check the layout header
126  if (*pc++ != KMC_HEADERSTART || *pc++ != KMC_HEADER_ID1 || *pc++ != KMC_HEADER_ID2)
127  return;
128 
129  // We only understand version 1 currently
130  ver = *pc++;
131  if (ver < KMC_HEADER_VER_MIN || ver > KMC_HEADER_VER_MAX)
132  return;
133 
134  // Setup
135  diff = code;
136  if (k->cntsc >= sizeof(k->sc))
137  flags |= FLAG_ERROR;
138  else
139  k->sc[k->cntsc++] = code;
140 
141  #if MICROCODE_DEBUG
142  cnt = 0;
143  #endif
144 
145  while(*pc++ == KMC_RECORDSTART) {
146  // Get the record length
147  p1 = *pc++;
148  if (!p1) break;
149  nrec = pc + p1;
150 
151  #if MICROCODE_DEBUG
152  cnt++;
153  #endif
154 
155  while(pc < nrec) {
156  switch(*pc++) {
157  case KMC_TEST_INIT:
158  if (!(flags & FLAG_INIT)) goto nextrecord;
159  break;
160  case KMC_TEST_ERROR:
161  if (!(flags & FLAG_ERROR)) goto nextrecord;
162  break;
163  case KMC_TEST_CODE:
164  if (flags != 0) goto nextrecord;
165  p1 = *pc++;
166  if (p1 != code) goto nextrecord;
167  diff = 0;
168  break;
169  case KMC_TEST_CODERANGE:
170  if (flags != 0) goto nextrecord;
171  p1 = *pc++;
172  p2 = *pc++;
173  if (code < p1 || code > p2) goto nextrecord;
174  diff = code - p1;
175  break;
176  case KMC_TEST_CODETABLE:
177  if (flags != 0) goto nextrecord;
178  p1 = *pc++;
179  for(p2 = 0; ; p2++, p1--, pc++) {
180  if (!p1) goto nextrecord;
181  if (*pc == code) break;
182  }
183  pc += p1;
184  diff = p2;
185  break;
186  case KMC_TEST_STATEBIT:
187  p1 = *pc++;
188  if ((p1 & KMC_BIT_CLEAR)) {
189  if ((k->keystate & (1 << (p1 & 31)))) goto nextrecord;
190  } else {
191  if (!(k->keystate & (1 << (p1 & 31)))) goto nextrecord;
192  }
193  break;
194  case KMC_TEST_STATEOR:
195  p1 = *pc++;
196  if ((p1 & KMC_BIT_CLEAR)) {
197  if (!(k->keystate & (1 << (p1 & 31)))) break;
198  } else {
199  if ((k->keystate & (1 << (p1 & 31)))) break;
200  }
201  p2 = *pc++;
202  if ((p2 & KMC_BIT_CLEAR)) {
203  if (!(k->keystate & (1 << (p2 & 31)))) break;
204  } else {
205  if ((k->keystate & (1 << (p2 & 31)))) break;
206  }
207  goto nextrecord;
208  case KMC_TEST_STATEAND:
209  p1 = *pc++;
210  if ((p1 & KMC_BIT_CLEAR)) {
211  if ((k->keystate & (1 << (p1 & 31)))) goto nextrecord;
212  } else {
213  if (!(k->keystate & (1 << (p1 & 31)))) goto nextrecord;
214  }
215  p2 = *pc++;
216  if ((p2 & KMC_BIT_CLEAR)) {
217  if ((k->keystate & (1 << (p2 & 31)))) goto nextrecord;
218  } else {
219  if (!(k->keystate & (1 << (p2 & 31)))) goto nextrecord;
220  }
221  break;
222  case KMC_TEST_LAYOUTBIT:
223  p1 = *pc++;
224  if ((p1 & KMC_BIT_CLEAR)) {
225  if ((k->laystate & (1 << (p1 & 15)))) goto nextrecord;
226  } else {
227  if (!(k->laystate & (1 << (p1 & 15)))) goto nextrecord;
228  }
229  break;
230  case KMC_TEST_LAYOUTOR:
231  p1 = *pc++;
232  if ((p1 & KMC_BIT_CLEAR)) {
233  if (!(k->laystate & (1 << (p1 & 15)))) break;
234  } else {
235  if ((k->laystate & (1 << (p1 & 15)))) break;
236  }
237  p2 = *pc++;
238  if ((p2 & KMC_BIT_CLEAR)) {
239  if (!(k->laystate & (1 << (p2 & 15)))) break;
240  } else {
241  if ((k->laystate & (1 << (p2 & 15)))) break;
242  }
243  goto nextrecord;
244  case KMC_TEST_LAYOUTAND:
245  p1 = *pc++;
246  if ((p1 & KMC_BIT_CLEAR)) {
247  if ((k->laystate & (1 << (p1 & 15)))) goto nextrecord;
248  } else {
249  if (!(k->laystate & (1 << (p1 & 15)))) goto nextrecord;
250  }
251  p2 = *pc++;
252  if ((p2 & KMC_BIT_CLEAR)) {
253  if ((k->laystate & (1 << (p2 & 15)))) goto nextrecord;
254  } else {
255  if (!(k->laystate & (1 << (p2 & 15)))) goto nextrecord;
256  }
257  break;
258  case KMC_TEST_CODEBIT:
259  if (flags != 0) goto nextrecord;
260  p1 = *pc++;
261  if ((p1 & KMC_BIT_CLEAR)) {
262  if ((code & (1 << (p1 & 7)))) goto nextrecord;
263  } else {
264  if (!(code & (1 << (p1 & 7)))) goto nextrecord;
265  }
266  break;
267  case KMC_TEST_CODEOR:
268  if (flags != 0) goto nextrecord;
269  p1 = *pc++;
270  if ((p1 & KMC_BIT_CLEAR)) {
271  if (!(code & (1 << (p1 & 7)))) break;
272  } else {
273  if ((code & (1 << (p1 & 7)))) break;
274  }
275  p2 = *pc++;
276  if ((p2 & KMC_BIT_CLEAR)) {
277  if (!(code & (1 << (p2 & 7)))) break;
278  } else {
279  if ((code & (1 << (p2 & 7)))) break;
280  }
281  goto nextrecord;
282  case KMC_TEST_CODEAND:
283  if (flags != 0) goto nextrecord;
284  p1 = *pc++;
285  if ((p1 & KMC_BIT_CLEAR)) {
286  if ((code & (1 << (p1 & 7)))) goto nextrecord;
287  } else {
288  if (!(code & (1 << (p1 & 7)))) goto nextrecord;
289  }
290  p2 = *pc++;
291  if ((p2 & KMC_BIT_CLEAR)) {
292  if ((code & (1 << (p2 & 7)))) goto nextrecord;
293  } else {
294  if (!(code & (1 << (p2 & 7)))) goto nextrecord;
295  }
296  break;
297  case KMC_TEST_LASTCODE:
298  p1 = *pc++;
299  if (k->cntsc < 2) goto nextrecord;
300  if (p1 != k->sc[k->cntsc-2]) goto nextrecord;
301  break;
302  case KMC_TEST_SHIFT:
303  if ((k->keystate & (GKEYSTATE_SHIFT_L|GKEYSTATE_SHIFT_R))) break;
304  goto nextrecord;
305  case KMC_TEST_NOSHIFT:
306  if (!(k->keystate & (GKEYSTATE_SHIFT_L|GKEYSTATE_SHIFT_R))) break;
307  goto nextrecord;
308  case KMC_TEST_CTRL:
309  if ((k->keystate & (GKEYSTATE_CTRL_L|GKEYSTATE_CTRL_R))) break;
310  goto nextrecord;
311  case KMC_TEST_NOCTRL:
312  if (!(k->keystate & (GKEYSTATE_CTRL_L|GKEYSTATE_CTRL_R))) break;
313  goto nextrecord;
314  case KMC_TEST_ALT:
315  if ((k->keystate & (GKEYSTATE_ALT_L|GKEYSTATE_ALT_R))) break;
316  goto nextrecord;
317  case KMC_TEST_NOALT:
318  if (!(k->keystate & (GKEYSTATE_ALT_L|GKEYSTATE_ALT_R))) break;
319  goto nextrecord;
320  case KMC_TEST_CAPS:
321  if ((k->keystate & GKEYSTATE_CAPSLOCK)) {
322  if (!(k->keystate & (GKEYSTATE_SHIFT_L|GKEYSTATE_SHIFT_R))) break;
323  } else {
324  if ((k->keystate & (GKEYSTATE_SHIFT_L|GKEYSTATE_SHIFT_R))) break;
325  }
326  goto nextrecord;
327  case KMC_TEST_NOCAPS:
328  if ((k->keystate & GKEYSTATE_CAPSLOCK)) {
329  if ((k->keystate & (GKEYSTATE_SHIFT_L|GKEYSTATE_SHIFT_R))) break;
330  } else {
331  if (!(k->keystate & (GKEYSTATE_SHIFT_L|GKEYSTATE_SHIFT_R))) break;
332  }
333  goto nextrecord;
334  case KMC_TEST_NUMLOCK:
335  if ((k->keystate & GKEYSTATE_NUMLOCK)) break;
336  goto nextrecord;
337  case KMC_TEST_NONUMLOCK:
338  if (!(k->keystate & GKEYSTATE_NUMLOCK)) break;
339  goto nextrecord;
340 
341  case KMC_ACT_STOP:
342  #if MICROCODE_DEBUG
343  fprintf(stderr, "Executed STOP: Records=%2u Flags=0x%02X Code=0x%02X\n", cnt, flags, code); fflush(stderr);
344  #endif
345  return;
346  case KMC_ACT_DONE:
347  SendKeyboardEvent(k);
348  k->cntc = k->cntsc = 0;
349  k->keystate &= ~(GKEYSTATE_KEYUP|GKEYSTATE_SPECIAL);
350  #if MICROCODE_DEBUG
351  fprintf(stderr, "Executed DONE: Records=%2u Flags=0x%02X Code=0x%02X\n", cnt, flags, code); fflush(stderr);
352  #endif
353  return;
354  case KMC_ACT_RESET:
355  k->cntc = k->cntsc = 0;
356  k->keystate &= ~(GKEYSTATE_KEYUP|GKEYSTATE_SPECIAL);
357  break;
358  case KMC_ACT_STATEBIT:
359  p1 = *pc++;
360  if ((p1 & KMC_BIT_INVERT))
361  k->keystate ^= (1 << (p1 & 31));
362  else if ((p1 & KMC_BIT_CLEAR))
363  k->keystate &= ~(1 << (p1 & 31));
364  else
365  k->keystate |= (1 << (p1 & 31));
366  break;
367  case KMC_ACT_LAYOUTBIT:
368  p1 = *pc++;
369  if ((p1 & KMC_BIT_INVERT))
370  k->laystate ^= (1 << (p1 & 15));
371  else if ((p1 & KMC_BIT_CLEAR))
372  k->laystate &= ~(1 << (p1 & 15));
373  else
374  k->laystate |= (1 << (p1 & 15));
375  break;
376  case KMC_ACT_CODEBIT:
377  p1 = *pc++;
378  if ((p1 & KMC_BIT_INVERT))
379  code ^= (1 << (p1 & 7));
380  else if ((p1 & KMC_BIT_CLEAR))
381  code &= ~(1 << (p1 & 7));
382  else
383  code |= (1 << (p1 & 7));
384  break;
385  case KMC_ACT_CHAR:
386  if (k->cntc >= sizeof(k->c)) goto codeerror;
387  k->c[k->cntc++] = *pc++;
388  break;
389  case KMC_ACT_CHARCODE:
390  if (k->cntc >= sizeof(k->c)) goto codeerror;
391  k->c[k->cntc++] = code;
392  break;
393  case KMC_ACT_CHARRANGE:
394  if (k->cntc >= sizeof(k->c)) goto codeerror;
395  k->c[k->cntc++] = diff + *pc++;
396  break;
397  case KMC_ACT_CHARTABLE:
398  p1 = *pc++;
399  if (diff < p1) {
400  if (k->cntc >= sizeof(k->c)) goto codeerror;
401  k->c[k->cntc++] = pc[diff];
402  }
403  pc += p1;
404  break;
405  case KMC_ACT_CLEAR:
406  k->cntc = 0;
407  break;
408  case KMC_ACT_CHARADD:
409  p1 = *pc++;
410  if (!k->cntc)
411  k->c[k->cntc++] = 0;
412  k->c[k->cntc-1] = k->c[k->cntc-1] * p1 + diff;
413  break;
414  case KMC_ACT_DATA:
415  p1 = *pc++;
416  if (gkvmt(k)->putdata)
417  gkvmt(k)->putdata(k, p1);
418  break;
419 
420  default:
421  codeerror:
422  #if MICROCODE_DEBUG
423  fprintf(stderr, "Executed ERROR: Records=%2u Flags=0x%02X Code=0x%02X\n", cnt, flags, code); cnt = 0; fflush(stderr);
424  #endif
425 
426  // Prevent recursion
427  if (flags & FLAG_ERROR)
428  return;
429 
430  // Process as an error
431  flags |= FLAG_ERROR;
432  nrec = k->pLayout + 4; // Jump back to the end of the header to process the error
433  goto nextrecord; // Nothing left to do here.
434  }
435  }
436 
437  nextrecord:
438  pc = nrec;
439  }
440 
441  #if MICROCODE_DEBUG
442  fprintf(stderr, "Executed END: Records=%2u Flags=0x%02X Code=0x%02X\n", cnt, flags, code); fflush(stderr);
443  #endif
444  }
445 #endif
446 
447 static void KeyboardPoll(void *param) {
448  GKeyboard * k;
449  gU8 scancodes[8];
450  int sz, i;
451  (void) param;
452 
453  for(k = (GKeyboard *)gdriverGetNext(GDRIVER_TYPE_KEYBOARD, 0); k; k = (GKeyboard *)gdriverGetNext(GDRIVER_TYPE_KEYBOARD, (GDriver *)k)) {
454  if (!(gkvmt(k)->d.flags & GKEYBOARD_VFLG_NOPOLL) || (k->flags & GKEYBOARD_FLG_NEEDREAD)) {
455  k->flags &= ~GKEYBOARD_FLG_NEEDREAD;
456  sz = gkvmt(k)->getdata(k, scancodes, sizeof(scancodes));
457  for(i = 0; i < sz; i++)
458  microengine(k, scancodes[i], 0);
459  }
460  }
461 }
462 
463 void _gkeyboardInit(void) {
464  // GINPUT_KEYBOARD_DRIVER_LIST is defined - create each driver instance
465  #if defined(GINPUT_KEYBOARD_DRIVER_LIST)
466  {
467  int i;
468  typedef const GKeyboardVMT const GKEYBOARDVMTLIST[1];
469 
470  extern GKEYBOARDVMTLIST GINPUT_KEYBOARD_DRIVER_LIST;
471  static const GKeyboardVMT * const dclist[] = {GINPUT_KEYBOARD_DRIVER_LIST};
472 
473  for(i = 0; i < sizeof(dclist)/sizeof(dclist[0]); i++) {
474  if (!(dclist[i]->d.flags & GKEYBOARD_VFLG_DYNAMICONLY))
475  gdriverRegister(&dclist[i]->d, 0);
476  }
477  }
478 
479  // One and only one mouse
480  #else
481  {
482  extern const GKeyboardVMT const GKEYBOARDVMT_OnlyOne[1];
483 
484  if (!(GKEYBOARDVMT_OnlyOne->d.flags & GKEYBOARD_VFLG_DYNAMICONLY))
485  gdriverRegister(&GKEYBOARDVMT_OnlyOne->d, 0);
486  }
487  #endif
488 
489 }
490 
491 void _gkeyboardDeinit(void) {
492  gtimerDeinit(&KeyboardTimer);
493 }
494 
495 gBool _gkeyboardInitDriver(GDriver *g, void *param, unsigned driverinstance, unsigned systeminstance) {
496  #define k ((GKeyboard *)g)
497  (void) param;
498  (void) systeminstance;
499 
500  // The initial keyboard layout comes from the VMT
501  k->pLayout = gkvmt(k)->defLayout;
502 
503  // Init the mouse
504  if (!gkvmt(k)->init((GKeyboard *)g, driverinstance))
505  return gFalse;
506 
507  // Ensure the Poll timer is started
508  if (!gtimerIsActive(&KeyboardTimer))
509  gtimerStart(&KeyboardTimer, KeyboardPoll, 0, gTrue, GINPUT_KEYBOARD_POLL_PERIOD);
510 
511  return gTrue;
512 
513  #undef k
514 }
515 
516 void _gkeyboardPostInitDriver(GDriver *g) {
517  #define k ((GKeyboard *)g)
518 
519  // Run the init sequence from the layout microcode.
520  microengine(k, 0, FLAG_INIT);
521 
522  #undef k
523 }
524 
525 void _gkeyboardDeInitDriver(GDriver *g) {
526  (void) g;
527 }
528 
529 GSourceHandle ginputGetKeyboard(unsigned instance) {
530  if (instance == GKEYBOARD_ALL_INSTANCES)
531  return (GSourceHandle)&KeyboardTimer;
532  return (GSourceHandle)gdriverGetInstance(GDRIVER_TYPE_KEYBOARD, instance);
533 }
534 
535 gBool ginputGetKeyboardStatus(unsigned instance, GEventKeyboard *pe) {
536  GKeyboard *k;
537 
538  // Win32 threads don't seem to recognise priority and/or pre-emption
539  // so we add a sleep here to prevent 100% polled applications from locking up.
541 
542  if (!(k = (GKeyboard *)gdriverGetInstance(GDRIVER_TYPE_KEYBOARD, instance)))
543  return gFalse;
544 
545  pe->type = GEVENT_KEYBOARD;
546  // TODO
547  return gTrue;
548 }
549 
550 #if !GKEYBOARD_LAYOUT_OFF
551  gBool ginputSetKeyboardLayout(unsigned instance, const void *pLayout) {
552  GKeyboard *k;
553 
554  if (!(k = (GKeyboard *)gdriverGetInstance(GDRIVER_TYPE_KEYBOARD, instance)))
555  return gFalse;
556 
557  if (pLayout)
558  k->pLayout = pLayout;
559  else
560  k->pLayout = gkvmt(k)->defLayout;
561 
562  return gTrue;
563  }
564 #endif
565 
566 /* Wake up the keyboard driver from an interrupt service routine (there may be new readings available) */
567 void _gkeyboardWakeup(GKeyboard *k) {
568  if (k)
569  k->flags |= GKEYBOARD_FLG_NEEDREAD;
570  gtimerJab(&KeyboardTimer);
571 }
572 
573 /* Wake up the keyboard driver from an interrupt service routine (there may be new readings available) */
574 void _gkeyboardWakeupI(GKeyboard *k) {
575  if (k)
576  k->flags |= GKEYBOARD_FLG_NEEDREAD;
577  gtimerJabI(&KeyboardTimer);
578 }
579 
580 #endif /* GFX_USE_GINPUT && GINPUT_NEED_KEYBOARD */
GINPUT LLD header file for keyboard drivers.
GINPUT keyboard layout microcode definition.
GDriver * gdriverRegister(const GDriverVMT *vmt, void *param)
Register a new driver instance.
Definition: gdriver.c:31
GDriver * gdriverGetInstance(gU16 type, unsigned instance)
Get the driver for a particular instance of a type of device.
Definition: gdriver.c:98
GDriver * gdriverGetNext(gU16 type, GDriver *driver)
Get the next driver for a type of device.
Definition: gdriver.c:127
GEvent * geventGetEventBuffer(GSourceListener *psl)
Get the event buffer from the GSourceListener.
Definition: gevent.c:187
void geventSendEvent(GSourceListener *psl)
Called by a source to indicate the listener's event buffer has been filled.
Definition: gevent.c:200
GSourceListener * geventGetSourceListener(GSourceHandle gsh, GSourceListener *lastlr)
Called by a source with a possible event to get a listener record.
Definition: gevent.c:163
#define GINPUT_KEYBOARD_POLL_PERIOD
Milliseconds between keyboard polls.
void gfxSleepMilliseconds(gDelay ms)
Put the current thread to sleep for the specified period in milliseconds.
void gtimerJabI(GTimer *pt)
Jab a timer causing the current period to immediate expire.
Definition: gtimer.c:223
void gtimerStart(GTimer *pt, GTimerFunction fn, void *param, gBool periodic, gDelay millisec)
Set a timer going or alter its properties if it is already going.
Definition: gtimer.c:139
void gtimerDeinit(GTimer *pt)
Deinitialise a timer.
Definition: gtimer.c:134
gBool gtimerIsActive(GTimer *pt)
Test if a timer is currently active.
Definition: gtimer.c:208
void gtimerJab(GTimer *pt)
Jab a timer causing the current period to immediate expire.
Definition: gtimer.c:212
gBool ginputSetKeyboardLayout(unsigned instance, const void *pLayout)
Set the keyboard layout.
GSourceHandle ginputGetKeyboard(unsigned instance)
Create a keyboard input instance.
gBool ginputGetKeyboardStatus(unsigned instance, GEventKeyboard *pkeyboard)
Get the current keyboard status.
All runtime driver structures start with this structure.
Definition: gdriver.h:58