µGFX  2.9
version 2.9
gwin_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/gwin/gwin_keyboard.c
10  * @brief GWIN sub-system virtual keyboard code
11  */
12 
13 #include "../../gfx.h"
14 
15 #if GFX_USE_GWIN && GWIN_NEED_KEYBOARD
16 
17 #include "gwin_class.h"
18 #include "gwin_keyboard_layout.h"
19 
20 typedef gU8 utf8;
21 typedef gU16 utf16;
22 typedef gU32 utf32;
23 
24 // A character code - note this is not UTF-32 but a representation of the UTF-8 code stream for a single character.
25 typedef gU32 ucode;
26 
27 static GSourceHandle AllKeyboards;
28 
29 // Get the length of a UTF-8 string
30 static int UTF8StrLen(const utf8 *s) {
31  int len;
32 
33  len = 0;
34  if (s) {
35  while (*s) {
36  len++;
37  if (!(s[0] & 0x80))
38  s++;
39  else if ((s[0] & 0xE0) == 0xC0 && (s[1] & 0xC0) == 0x80)
40  s+=2;
41  else if ((s[0] & 0xF0) == 0xE0 && (s[1] & 0xC0) == 0x80 && (s[2] & 0xC0) == 0x80)
42  s+=3;
43  else if ((s[0] & 0xF8) == 0xF0 && (s[1] & 0xC0) == 0x80 && (s[2] & 0xC0) == 0x80 && (s[3] & 0xC0) == 0x80)
44  s+=4;
45  else
46  // Invalid UTF-8 sequence - assume a single byte
47  s++;
48  }
49  }
50  return len;
51 }
52 
53 // Return the nth character of a UTF8 string
54 static ucode UTF8CharAt(const utf8 *s, int n) {
55  ucode u;
56 
57  u = 0;
58  if (!s) return 0;
59 
60  while(*s) {
61  if (!(s[0] & 0x80)) {
62  u = s[0];
63  s++;
64  } else if ((s[0] & 0xE0) == 0xC0 && (s[1] & 0xC0) == 0x80) {
65  u = s[1] | ((ucode)s[0] << 8);
66  s+=2;
67  } else if ((s[0] & 0xF0) == 0xE0 && (s[1] & 0xC0) == 0x80 && (s[2] & 0xC0) == 0x80) {
68  u = s[2] | ((ucode)s[1] << 8) | ((ucode)s[0] << 16);
69  s+=3;
70  } else if ((s[0] & 0xF8) == 0xF0 && (s[1] & 0xC0) == 0x80 && (s[2] & 0xC0) == 0x80 && (s[3] & 0xC0) == 0x80) {
71  u = s[3] | ((ucode)s[2] << 8) | ((ucode)s[1] << 16) | ((ucode)s[0] << 24);
72  s+=4;
73  } else {
74  // Invalid UTF-8 sequence - assume a single byte
75  u = s[0];
76  s++;
77  }
78  if (--n < 0)
79  return u;
80  }
81  return 0;
82 }
83 
84 // Convert a ucode to a UTF8 string (with no NULL on the end). Returns the number of bytes.
85 static unsigned UCode2UTF8(utf8 *dst, ucode u) {
86  if (!(u & 0xFFFFFF00)) {
87  dst[0] = u;
88  return 1;
89  }
90  if (!(u & 0xFFFF0000)) {
91  dst[0] = u >> 8;
92  dst[1] = u;
93  return 2;
94  }
95  if (!(u & 0xFF000000)) {
96  dst[0] = u >> 16;
97  dst[1] = u >> 8;
98  dst[2] = u;
99  return 3;
100  }
101  dst[0] = u >> 24;
102  dst[1] = u >> 16;
103  dst[2] = u >> 8;
104  dst[3] = u;
105  return 4;
106 }
107 
108 static int NumKeyRows(const char **keyset) {
109  int len;
110 
111  len = 0;
112  while(*keyset++)
113  len++;
114  return len;
115 }
116 
117 static void SendVirtualKeyEventToListener(GSourceListener *psl, GKeyboardObject *gk) {
118  GEventKeyboard *pe;
119  const GVSpecialKey *skey;
120  unsigned i;
121 
122  // If there is no event buffer just mark a missed event
123  if (!(pe = (GEventKeyboard *)geventGetEventBuffer(psl))) {
124  // This listener is missing - save the meta events that have happened
125  psl->srcflags |= GKEYSTATE_MISSED_EVENT;
126  return;
127  }
128 
129  // The virtual keyboard can't generate repeats
130  //if ((psl->listenflags & GLISTEN_KEYREPEATSOFF) && (k->keystate & GKEYSTATE_REPEAT))
131  // return;
132 
133  // The virtual keyboard can't generate special keys
134  //if ((psl->listenflags & GLISTEN_KEYNOSPECIALS) && (k->keystate & GKEYSTATE_SPECIAL))
135  // return;
136 
137  // The virtual keyboard treats a key release as a keydown
138  //if (!(psl->listenflags & GLISTEN_KEYUP) && (k->keystate & GKEYSTATE_KEYUP))
139  // k->cntc = 0;
140 
141  // The virtual keyboard has no transitions
142  //if (!(psl->listenflags & GLISTEN_KEYTRANSITIONS) && !k->cntc)
143  // return;
144 
145  pe->type = GEVENT_KEYBOARD;
146  if (gk->key < 0x20) {
147  skey = &gk->keytable->skeys[gk->key-1];
148  for(i=0; skey->sendkey[i]; i++)
149  pe->c[i] = skey->sendkey[i];
150  } else
151  i = UCode2UTF8((utf8 *)pe->c, gk->key);
152  pe->bytecount = i;
153  for(; i < 8; i++)
154  pe->c[i] = 0;
155  pe->keystate = psl->srcflags;
156  psl->srcflags = 0;
157  geventSendEvent(psl);
158 }
159 
160 static void SendVirtualKeyEvent(GKeyboardObject *gk) {
161  GSourceListener *psl;
162 
163  // Send to the "All Keyboards" source listeners
164  psl = 0;
165  while ((psl = geventGetSourceListener(AllKeyboards, psl)))
166  SendVirtualKeyEventToListener(psl, gk);
167 
168  // Send to the keyboard specific source listeners
169  psl = 0;
170  while ((psl = geventGetSourceListener((GSourceHandle)gk, psl)))
171  SendVirtualKeyEventToListener(psl, gk);
172 }
173 
174 
175 #if GINPUT_NEED_MOUSE
176  // Find the key from the keyset and the x, y position
177  static void KeyFindKey(GKeyboardObject *gk, gCoord x, gCoord y) {
178  const utf8 *krow;
179  fixed f;
180  int idx;
181 
182  if (x < 0 || y < 0 || x >= gk->w.g.width || y >= gk->w.g.height) {
183  gk->keyrow = gk->keycol = GKEY_BAD_ROWCOL;
184  return;
185  }
186 
187  // Get the y parameters
188  f = FIXED(gk->w.g.height) / NumKeyRows(gk->keyset);
189  gk->keyrow = FIXED(y) / f;
190  gk->keyy = NONFIXED(f * gk->keyrow + FIXED0_5);
191  gk->keycy = NONFIXED(f * (gk->keyrow+1) + FIXED0_5) - gk->keyy;
192 
193  // Get the current row
194  krow = (const utf8 *)gk->keyset[gk->keyrow];
195 
196  // Get the x parameters
197  f = FIXED(gk->w.g.width) / UTF8StrLen(krow);
198  gk->keycol = FIXED(x) / f;
199 
200  // Get the key
201  gk->key = UTF8CharAt(krow, gk->keycol);
202 
203  // Amalgamate identical keys into one big key
204  idx = gk->keycol;
205  while(gk->keycol > 0 && UTF8CharAt(krow, gk->keycol-1) == gk->key)
206  gk->keycol--;
207  while(UTF8CharAt(krow, ++idx) == gk->key);
208  gk->keyx = NONFIXED(f * gk->keycol + FIXED0_5);
209  gk->keycx = NONFIXED(f * idx + FIXED0_5) - gk->keyx;
210  }
211 
212  // A mouse up has occurred (it may or may not be over the button)
213  static void KeyMouseUp(GWidgetObject *gw, gCoord x, gCoord y) {
214  #define gk ((GKeyboardObject *)gw)
215 
216  KeyFindKey(gk, x, y);
217 
218  // Do we have a valid key?
219  if (gk->keyrow == GKEY_BAD_ROWCOL) {
220  if (gk->lastkeyrow != GKEY_BAD_ROWCOL) {
221  gw->g.flags |= GKEYBOARD_FLG_QUICKUPDATE;
222  _gwinUpdate((GHandle)gw);
223  }
224  return;
225  }
226 
227  // We are turning off the display of the key
228  gk->keyrow = gk->keycol = GKEY_BAD_ROWCOL;
229 
230  // Is this one of the special keys
231  if (gk->key < 0x20) {
232  // This is a special key
233  const GVSpecialKey *skey;
234 
235  skey = &gk->keytable->skeys[gk->key - 1];
236 
237  if ((skey->flags & GVKEY_SINGLESET)) {
238  // Single character switch to a new layout
239  gk->keyset = gk->keytable->ksets[skey->newset];
240  gk->w.g.flags &= ~(GKEYBOARD_FLG_QUICKUPDATE|GKEYBOARD_FLG_REVERTSET);
242 
243  } else if ((skey->flags & GVKEY_LOCKSET)) {
244  // Locked switch to a new layout
245  gk->keyset = gk->keytable->ksets[skey->newset];
246  gk->w.g.flags &= ~(GKEYBOARD_FLG_QUICKUPDATE|GKEYBOARD_FLG_REVERTSET);
247 
248  } else if ((gk->w.g.flags & GKEYBOARD_FLG_REVERTSET)) {
249  // Revert to default layout
250  gk->keyset = gk->keytable->ksets[0];
251  gk->w.g.flags &= ~(GKEYBOARD_FLG_QUICKUPDATE|GKEYBOARD_FLG_REVERTSET);
252 
253  } else {
254  // Just turning off a key
255  gw->g.flags |= GKEYBOARD_FLG_QUICKUPDATE;
256  }
257 
258  // Send the key if required
259  if (skey->sendkey && skey->sendkey[0])
260  SendVirtualKeyEvent(gk);
261 
262  // Update the display
263  _gwinUpdate((GHandle)gw);
264 
265  return;
266  }
267 
268  // Do we need to revert to the standard layout?
269  if ((gk->w.g.flags & GKEYBOARD_FLG_REVERTSET)) {
270  gk->keyset = gk->keytable->ksets[0];
271  gk->w.g.flags &= ~(GKEYBOARD_FLG_QUICKUPDATE|GKEYBOARD_FLG_REVERTSET);
272  } else {
273  gw->g.flags |= GKEYBOARD_FLG_QUICKUPDATE;
274  }
275 
276  // Send the key
277  SendVirtualKeyEvent(gk);
278 
279  // Update the display
280  _gwinUpdate((GHandle)gw);
281  }
282 
283  // A mouse move has occurred (it may or may not be over the button)
284  static void KeyMouseMove(GWidgetObject *gw, gCoord x, gCoord y) {
285  #define gk ((GKeyboardObject *)gw)
286 
287  KeyFindKey(gk, x, y);
288 
289  if (gk->keyrow != gk->lastkeyrow || gk->keycol != gk->lastkeycol) {
290  gk->w.g.flags |= GKEYBOARD_FLG_QUICKUPDATE;
291  _gwinUpdate((GHandle)gw);
292  }
293  #undef gk
294  }
295 #endif
296 
297 extern const GVKeyTable GWIN_KEYBOARD_DEFAULT_LAYOUT;
298 
299 // The button VMT table
300 static const gwidgetVMT keyboardVMT = {
301  {
302  "VKeyboard", // The classname
303  sizeof(GKeyboardObject), // The object size
304  _gwidgetDestroy, // The destroy routine
305  _gwidgetRedraw, // The redraw routine
306  0, // The after-clear routine
307  },
308  gwinKeyboardDraw_Normal, // The default drawing routine
309  #if GINPUT_NEED_MOUSE
310  {
311  KeyMouseMove, // Process mouse down events
312  KeyMouseUp, // Process mouse up events
313  KeyMouseMove, // Process mouse move events
314  },
315  #endif
316  #if GINPUT_NEED_KEYBOARD || GWIN_NEED_KEYBOARD
317  {
318  0 // Process keyboard events
319  },
320  #endif
321  #if GINPUT_NEED_TOGGLE
322  {
323  0, // No toggle roles
324  0, // Assign Toggles
325  0, // Get Toggles
326  0, // Process toggle off events
327  0, // Process toggle on events
328  },
329  #endif
330  #if GINPUT_NEED_DIAL
331  {
332  0, // No dial roles
333  0, // Assign Dials (NOT USED)
334  0, // Get Dials (NOT USED)
335  0, // Process dial move events (NOT USED)
336  },
337  #endif
338 };
339 
340 GHandle gwinGKeyboardCreate(GDisplay *g, GKeyboardObject *gk, const GWidgetInit *pInit) {
341  if (!(gk = (GKeyboardObject *)_gwidgetCreate(g, &gk->w, pInit, &keyboardVMT)))
342  return 0;
343 
344  gk->keytable = &GWIN_KEYBOARD_DEFAULT_LAYOUT;
345  gk->keyset = gk->keytable->ksets[0];
346  gk->lastkeyrow = gk->lastkeycol = gk->keyrow = gk->keycol = GKEY_BAD_ROWCOL;
347 
348  if (!AllKeyboards)
349  AllKeyboards = ginputGetKeyboard(GKEYBOARD_ALL_INSTANCES);
350 
351  gwinSetVisible((GHandle)gk, pInit->g.show);
352  return (GHandle)gk;
353 }
354 
355 GSourceHandle gwinKeyboardGetEventSource(GHandle gh) {
356  if (gh->vmt != (gwinVMT *)&keyboardVMT)
357  return 0;
358  return (GSourceHandle)gh;
359 }
360 
361 void gwinKeyboardSetLayout(GHandle gh, const struct GVKeyTable *layout) {
362  #define gk ((GKeyboardObject *)gh)
363 
364  if (gh->vmt != (gwinVMT *)&keyboardVMT)
365  return;
366 
367  if (!layout)
369  gk->keytable = layout;
370  gk->keyset = gk->keytable->ksets[0];
371  gk->lastkeyrow = gk->lastkeycol = gk->keyrow = gk->keycol = GKEY_BAD_ROWCOL;
372  gk->w.g.flags &= ~(GKEYBOARD_FLG_QUICKUPDATE|GKEYBOARD_FLG_REVERTSET);
373  gwinRedraw(gh);
374  #undef gk
375 }
376 
377 /*----------------------------------------------------------
378  * Custom Draw Routines
379  *----------------------------------------------------------*/
380 
381 /*
382 static const GColorSet *getDrawColors(GWidgetObject *gw) {
383  if (!(gw->g.flags & GWIN_FLG_SYSENABLED)) return &gw->pstyle->disabled;
384  if ((gw->g.flags & GBUTTON_FLG_PRESSED)) return &gw->pstyle->pressed;
385  return &gw->pstyle->enabled;
386 }
387 */
388 
389 void gwinKeyboardDraw_Normal(GWidgetObject *gw, void *param) {
390  #define gk ((GKeyboardObject *)gw)
391 
392  char cap[5];
393  const char *pcap;
394  const utf8 *krow;
395  gCoord x, y, cx, cy;
396  gU8 rows, cols, row, col, kcols;
397  ucode key;
398  fixed fx, fy;
399  const GColorSet *pcol;
400 
401  (void) param;
402 
403  // Make sure that this is a keyboard widget object
404  if (gw->g.vmt != (gwinVMT *)&keyboardVMT)
405  return;
406 
407  // Get the y parameters
408  rows = NumKeyRows(gk->keyset);
409  fy = FIXED(gk->w.g.height) / rows;
410  for (row = 0; row < rows; row++) {
411  y = NONFIXED(fy * row + FIXED0_5);
412  cy = NONFIXED(fy * (row+1) + FIXED0_5) - y;
413 
414  // Get the current row
415  krow = (const utf8 *)gk->keyset[row];
416 
417  // Get the x parameters
418  cols = UTF8StrLen(krow);
419  fx = FIXED(gk->w.g.width) / cols;
420  for (col = 0; col < cols; col=kcols) {
421 
422  // Get the correct color set
423  if (!(gk->w.g.flags & GWIN_FLG_SYSENABLED))
424  pcol = &gk->w.pstyle->disabled;
425  else
426  pcol = &gk->w.pstyle->enabled;
427 
428  // Get the key
429  key = UTF8CharAt(krow, col);
430 
431  // Fuse identical keys into one big key
432  kcols = col+1;
433  while (UTF8CharAt(krow, kcols) == key)
434  kcols++;
435 
436  // If quick update needed and keyboard already drawn (if not use this flag, then bug when screen touched before keyboard was drawn)
437  if ( (gk->w.g.flags & GKEYBOARD_FLG_QUICKUPDATE) && !(gk->w.g.flags & GWIN_FLG_BGREDRAW) ) {
438 
439  // If key pressed
440  if ( (gk->keyrow != GKEY_BAD_ROWCOL) && (gk->keycol != GKEY_BAD_ROWCOL) ) {
441 
442  // And previous key have
443  if ( (gk->lastkeyrow != GKEY_BAD_ROWCOL) && (gk->lastkeycol != GKEY_BAD_ROWCOL) ) {
444 
445  if (gk->lastkeyrow == row && gk->lastkeycol == col) {
446  // If keyboard has no "disabled" color
447  if (pcol != &gk->w.pstyle->disabled)
448  pcol = &gk->w.pstyle->enabled;
449  gk->lastkeyrow = gk->lastkeycol = GKEY_BAD_ROWCOL;
450  } else {
451  continue;
452  }
453  }
454 
455  // If no previous key
456  else {
457 
458  if (gk->keyrow == row && gk->keycol == col) {
459  if (pcol != &gk->w.pstyle->disabled)
460  pcol = &gk->w.pstyle->pressed;
461  gk->lastkeyrow = row;
462  gk->lastkeycol = col;
463  }
464  else if (gk->lastkeyrow == row && gk->lastkeycol == col)
465  {
466  if (pcol != &gk->w.pstyle->disabled) pcol = &gk->w.pstyle->enabled;
467  }
468  else continue;
469  }
470  }
471 
472  // If key up, and need clear the previous key
473  else if ( (gk->lastkeyrow != GKEY_BAD_ROWCOL) && (gk->lastkeycol != GKEY_BAD_ROWCOL) )
474  {
475  if ( (gk->lastkeyrow == row) && (gk->lastkeycol == col) )
476  {
477  if (pcol != &gk->w.pstyle->disabled) pcol = &gk->w.pstyle->enabled;
478  }
479  else continue;
480  }
481  }
482  else
483  {
484  gk->lastkeyrow = gk->lastkeycol = GKEY_BAD_ROWCOL;
485  }
486 
487  x = NONFIXED(fx * col + FIXED0_5);
488  cx = NONFIXED(fx * kcols + FIXED0_5) - x;
489 
490  if (key < 0x20) {
491  pcap = gk->keytable->skeys[key-1].keycap;
492  } else {
493  cap[UCode2UTF8((utf8 *)cap, key)] = 0;
494  pcap = cap;
495  }
496 
497  switch(*pcap) {
498 
499  case '\001': // Shift (up-arrow)
500  gdispGFillArea(gw->g.display, gw->g.x+x, gw->g.y+y, cx, cy, pcol->fill);
501 
502  gdispGDrawLine(gw->g.display, gw->g.x+x +cx/4, gw->g.y+y+cy/2, gw->g.x+x+cx/2, gw->g.y+y +cy/4, pcol->text); /* / \ */
503  gdispGDrawLine(gw->g.display, gw->g.x+x+cx -cx/4, gw->g.y+y+cy/2, gw->g.x+x+cx/2, gw->g.y+y +cy/4, pcol->text);
504  gdispGDrawLine(gw->g.display, gw->g.x+x +cx/4, gw->g.y+y+cy/2, gw->g.x+x+cx/2-cx/6, gw->g.y+y+cy/2, pcol->text); /* _ _ */
505  gdispGDrawLine(gw->g.display, gw->g.x+x+cx -cx/4, gw->g.y+y+cy/2, gw->g.x+x+cx/2+cx/6, gw->g.y+y+cy/2, pcol->text);
506  gdispGDrawLine(gw->g.display, gw->g.x+x+cx/2-cx/6, gw->g.y+y+cy/2, gw->g.x+x+cx/2-cx/6, gw->g.y+y+cy -cy/3, pcol->text); /* || */
507  gdispGDrawLine(gw->g.display, gw->g.x+x+cx/2+cx/6, gw->g.y+y+cy/2, gw->g.x+x+cx/2+cx/6, gw->g.y+y+cy -cy/3, pcol->text);
508  gdispGDrawLine(gw->g.display, gw->g.x+x+cx/2-cx/6, gw->g.y+y+cy -cy/3, gw->g.x+x+cx/2+cx/6, gw->g.y+y+cy -cy/3, pcol->text); /* _ */
509 
510  break;
511 
512  case '\002': // Shift locked (underlined up-arrow)
513  gdispGFillArea(gw->g.display, gw->g.x+x, gw->g.y+y, cx, cy, pcol->fill);
514 
515  gdispGDrawLine(gw->g.display, gw->g.x+x +cx/4, gw->g.y+y+cy/2, gw->g.x+x+cx/2, gw->g.y+y +cy/4, pcol->text); /* / \ */
516  gdispGDrawLine(gw->g.display, gw->g.x+x+cx -cx/4, gw->g.y+y+cy/2, gw->g.x+x+cx/2, gw->g.y+y +cy/4, pcol->text);
517  gdispGDrawLine(gw->g.display, gw->g.x+x +cx/4, gw->g.y+y+cy/2, gw->g.x+x+cx/2-cx/6, gw->g.y+y+cy/2, pcol->text); /* _ _ */
518  gdispGDrawLine(gw->g.display, gw->g.x+x+cx -cx/4, gw->g.y+y+cy/2, gw->g.x+x+cx/2+cx/6, gw->g.y+y+cy/2, pcol->text);
519  gdispGDrawLine(gw->g.display, gw->g.x+x+cx/2-cx/6, gw->g.y+y+cy/2, gw->g.x+x+cx/2-cx/6, gw->g.y+y+cy -cy/3, pcol->text); /* || */
520  gdispGDrawLine(gw->g.display, gw->g.x+x+cx/2+cx/6, gw->g.y+y+cy/2, gw->g.x+x+cx/2+cx/6, gw->g.y+y+cy -cy/3, pcol->text);
521  gdispGDrawLine(gw->g.display, gw->g.x+x+cx/2-cx/6, gw->g.y+y+cy -cy/3, gw->g.x+x+cx/2+cx/6, gw->g.y+y+cy -cy/3, pcol->text); /* _ */
522  gdispGDrawLine(gw->g.display, gw->g.x+x+cx/2-cx/5, gw->g.y+y+cy -cy/4, gw->g.x+x+cx/2+cx/5, gw->g.y+y+cy -cy/4, pcol->text); /* ___ */
523 
524  break;
525 
526  case '\t': // Tabulator
527  gdispGFillArea(gw->g.display, gw->g.x+x, gw->g.y+y, cx, cy, pcol->fill);
528 
529  gdispGDrawLine(gw->g.display, gw->g.x+x+1, gw->g.y+y+1, gw->g.x+x+cx-1, gw->g.y+y+cy/2, pcol->text);
530  gdispGDrawLine(gw->g.display, gw->g.x+x+1, gw->g.y+y+cy-1, gw->g.x+x+cx-1, gw->g.y+y+cy/2, pcol->text);
531  gdispGDrawLine(gw->g.display, gw->g.x+x+cx-1, gw->g.y+y+1, gw->g.x+x+cx-1, gw->g.y+y+cy-1, pcol->text);
532 
533  break;
534 
535  case '\b': // Backspace
536  gdispGFillArea(gw->g.display, gw->g.x+x, gw->g.y+y, cx, cy, pcol->fill);
537 
538  gdispGDrawLine(gw->g.display, gw->g.x+x+ cx/8, gw->g.y+y+cy/2, gw->g.x+x+cx/2, gw->g.y+y +cy/3, pcol->text); /* / */
539  gdispGDrawLine(gw->g.display, gw->g.x+x+ cx/8, gw->g.y+y+cy/2, gw->g.x+x+cx-cx/8, gw->g.y+y+cy/2, pcol->text); /* -- */
540  gdispGDrawLine(gw->g.display, gw->g.x+x+ cx/8, gw->g.y+y+cy/2, gw->g.x+x+cx/2, gw->g.y+y+cy -cy/3, pcol->text); /* \ */
541 
542  break;
543 
544  case '\r': // Enter
545  gdispGFillArea(gw->g.display, gw->g.x+x, gw->g.y+y, cx, cy, pcol->fill);
546 
547  gdispGDrawLine(gw->g.display, gw->g.x+x+(cx/3)*2, gw->g.y+y+cy/2, gw->g.x+x+(cx/3)*2, gw->g.y+y+cy/5, pcol->text); /* | */
548  gdispGDrawLine(gw->g.display, gw->g.x+x+ cx/3, gw->g.y+y+cy/2, gw->g.x+x+cx/3 +cx/8, gw->g.y+y+cy/3, pcol->text); /* / */
549  gdispGDrawLine(gw->g.display, gw->g.x+x+ cx/3, gw->g.y+y+cy/2, gw->g.x+x+(cx/3)*2, gw->g.y+y+cy/2, pcol->text); /* -- */
550  gdispGDrawLine(gw->g.display, gw->g.x+x+ cx/3, gw->g.y+y+cy/2, gw->g.x+x+cx/3 +cx/8, gw->g.y+y+cy -cy/3, pcol->text); /* \ */
551 
552  break;
553 
554  default: // Regular character
555  gdispGFillStringBox(gw->g.display, gw->g.x+x, gw->g.y+y, cx, cy, pcap, gw->g.font, pcol->text, pcol->fill, gJustifyCenter);
556 
557  break;
558  }
559 
560  // Draw the frame (border around the entire widget)
561  gdispGDrawBox(gw->g.display, gw->g.x+x, gw->g.y+y, cx, cy, pcol->edge);
562 
563  // If key up and we already cleared the previous key
564  if ( (gk->keyrow == GKEY_BAD_ROWCOL) && (gk->keycol == GKEY_BAD_ROWCOL) && (gk->lastkeyrow == row) && (gk->lastkeycol == col) ) {
565  gk->lastkeyrow = gk->lastkeycol = GKEY_BAD_ROWCOL;
566  return;
567  }
568 
569  // Just quit the cycle if we did all the work in order not to waste any CPU time
570  if ( (row >= gk->keyrow && col >= gk->keycol) && (row >= gk->lastkeyrow && col >= gk->lastkeycol) ) {
571  return;
572  }
573  }
574  }
575 
576  #undef gk
577 }
578 
579 #if !(GFX_USE_GINPUT && GINPUT_NEED_KEYBOARD)
580  GSourceHandle ginputGetKeyboard(unsigned instance) {
581  if (instance == GKEYBOARD_ALL_INSTANCES)
582  return (GSourceHandle)&AllKeyboards;
583  return 0;
584  }
585 #endif
586 
587 #endif /* GFX_USE_GWIN && GWIN_NEED_KEYBOARD */
void gdispGFillArea(GDisplay *g, gCoord x, gCoord y, gCoord cx, gCoord cy, gColor color)
Fill an area with a color.
void gdispGDrawLine(GDisplay *g, gCoord x0, gCoord y0, gCoord x1, gCoord y1, gColor color)
Draw a line.
void gdispGFillStringBox(GDisplay *g, gCoord x, gCoord y, gCoord cx, gCoord cy, const char *str, gFont font, gColor color, gColor bgColor, gJustify justify)
Draw a text string vertically centered within the specified box. The box background is filled with th...
gI16 gCoord
The type for a coordinate or length on the screen.
Definition: gdisp.h:39
void gdispGDrawBox(GDisplay *g, gCoord x, gCoord y, gCoord cx, gCoord cy, gColor color)
Draw a rectangular box.
@ gJustifyCenter
Definition: gdisp.h:62
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
gI32 fixed
The type for a fixed point type.
Definition: gmisc.h:60
#define FIXED(x)
Macros to convert to and from a fixed point.
Definition: gmisc.h:66
#define GWIN_KEYBOARD_DEFAULT_LAYOUT
The default keyboard layout for the virtual gwin keyboard.
Definition: gwin_options.h:395
GSourceHandle ginputGetKeyboard(unsigned instance)
Create a keyboard input instance.
void gwinKeyboardDraw_Normal(GWidgetObject *gw, void *param)
The default rendering function for the keyboard widget.
#define GKEYBOARD_FLG_REVERTSET
The internal keyboard flags and other defines.
Definition: gwin_keyboard.h:47
GHandle gwinGKeyboardCreate(GDisplay *g, GKeyboardObject *gb, const GWidgetInit *pInit)
Create a keyboard widget.
void gwinKeyboardSetLayout(GHandle gh, const struct GVKeyTable *layout)
Set the layout for the virtual keyboard.
struct GKeyboardObject GKeyboardObject
The keyboard widget structure.
GSourceHandle gwinKeyboardGetEventSource(GHandle gh)
Get the keyboard event source for a GWIN virtual keyboard.
void gwinRedraw(GHandle gh)
Redraw a window.
void gwinSetVisible(GHandle gh, gBool visible)
Sets whether a window is visible or not.
GWIN Virtual Keyboard Layout structures.
The GColorSet structure.
Definition: gwin_widget.h:37
gColor fill
Definition: gwin_widget.h:40
gColor text
Definition: gwin_widget.h:38
gColor edge
Definition: gwin_widget.h:39
The keyboard widget structure.
Definition: gwin_keyboard.h:56
The structure to initialise a widget.
Definition: gwin_widget.h:97
GWindowInit g
Definition: gwin_widget.h:98
The GWIN Widget structure.
Definition: gwin_widget.h:118
GWindowObject g
Definition: gwin_widget.h:119
const GWidgetStyle * pstyle
Definition: gwin_widget.h:123
GColorSet disabled
Definition: gwin_widget.h:56
GColorSet enabled
Definition: gwin_widget.h:55
GColorSet pressed
Definition: gwin_widget.h:57
gBool show
Definition: gwin.h:80
A window object structure.
Definition: gwin.h:40
GDisplay * display
Definition: gwin.h:46
gCoord x
Definition: gwin.h:47
gCoord width
Definition: gwin.h:49
const struct gwinVMT * vmt
Definition: gwin.h:45
gU32 flags
Definition: gwin.h:53
gCoord y
Definition: gwin.h:48
gCoord height
Definition: gwin.h:50
The Virtual Method Table for a widget.
Definition: gwin_class.h:85
The Virtual Method Table for a GWIN window.
Definition: gwin_class.h:55