1 /*
2   onscreen_keyboard.c
3 
4   Copyright (c) 2020
5   http://www.tuxpaint.org/
6 
7   This program is free software; you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation; either version 2 of the License, or
10   (at your option) any later version.
11 
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16 
17   You should have received a copy of the GNU General Public License
18   along with this program; if not, write to the Free Software
19   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20   (See COPYING.txt)
21 */
22 
23 #include "onscreen_keyboard.h"
24 
25 //#define DEBUG_OSK_COMPOSEMAP
26 
27 static SDL_Color def_bgcolor = { 255, 255, 255, 255 };
28 static SDL_Color def_fgcolor = { 0, 0, 0, 0 };
29 
30 static void load_hlayout(osk_layout * layout, char *layout_name);
31 static void load_keymap(osk_layout * layout, char *keymap_name);
32 static void load_composemap(osk_layout * layout, char *composemap_name);
33 
34 static int is_blank_or_comment(char *line);
35 
36 /* static int isw_blank_or_comment(wchar_t *line); */
37 
38 
39 static void keybd_prepare(on_screen_keyboard * keyboard);
40 
41 static void draw_key(osk_key key, on_screen_keyboard * keyboard, int hot);
42 
43 static void label_key(osk_key key, on_screen_keyboard * keyboard);
44 static void draw_keyboard(on_screen_keyboard * keyboard);
45 static osk_key *find_key(on_screen_keyboard * keyboard, int x, int y);
46 static void set_key(osk_key * orig, osk_key * dest, int firsttime);
47 static void load_keysymdefs(osk_layout * layout, char *keysymdefs_name);
48 static struct osk_layout *load_layout(on_screen_keyboard * keyboard, char *layout_name);
49 
50 #ifdef DEBUG_OSK_COMPOSEMAP
51 static void print_composemap(osk_composenode * composemap, char *sp);
52 #endif
53 
54 #ifdef WIN32
55 #include <iconv.h>
56 #define wcstok(line, delim, pointer)  wcstok(line, delim)
57 #define strtok_r(line, delim, pointer) strtok(line, delim)
58 
59 static void mtw(wchar_t * wtok, char *tok);
60 
mtw(wchar_t * wtok,char * tok)61 static void mtw(wchar_t * wtok, char *tok)
62 {
63   /* workaround using iconv to get a functionallity somewhat approximate as mbstowcs() */
64   Uint16 *ui16;
65   char *wrptr;
66   size_t n, in, out;
67   iconv_t trans;
68 
69   n = 255;
70   in = 250;
71   out = 250;
72   ui16 = malloc(sizeof(Uint16) * 255);
73   wrptr = (char *)ui16;
74 
75   trans = iconv_open("WCHAR_T", "UTF-8");
76   iconv(trans, (const char **)&tok, &in, &wrptr, &out);
77   *((wchar_t *) wrptr) = L'\0';
78   swprintf(wtok, L"%ls", ui16);
79   free(ui16);
80   iconv_close(trans);
81 }
82 
83 #define mbstowcs(wtok, tok, size) mtw(wtok, tok)
84 #endif
85 
osk_create(char * layout_name,SDL_Surface * canvas,SDL_Surface * LG_button_up,SDL_Surface * LG_button_down,SDL_Surface * LG_button_off,SDL_Surface * LG_button_nav,SDL_Surface * LG_button_hold,SDL_Surface * LG_oskdel,SDL_Surface * LG_osktab,SDL_Surface * LG_oskenter,SDL_Surface * LG_oskcapslock,SDL_Surface * LG_oskshift,SDL_Surface * SM_button_up,SDL_Surface * SM_button_down,SDL_Surface * SM_button_off,SDL_Surface * SM_button_nav,SDL_Surface * SM_button_hold,SDL_Surface * SM_oskdel,SDL_Surface * SM_osktab,SDL_Surface * SM_oskenter,SDL_Surface * SM_oskcapslock,SDL_Surface * SM_oskshift,int disable_change)86 struct osk_keyboard *osk_create(char * layout_name, SDL_Surface * canvas,
87                                 SDL_Surface * LG_button_up, SDL_Surface * LG_button_down,
88                                 SDL_Surface * LG_button_off, SDL_Surface * LG_button_nav,
89                                 SDL_Surface * LG_button_hold,
90                                 SDL_Surface * LG_oskdel, SDL_Surface * LG_osktab, SDL_Surface * LG_oskenter,
91                                 SDL_Surface * LG_oskcapslock, SDL_Surface * LG_oskshift,
92                                 SDL_Surface * SM_button_up, SDL_Surface * SM_button_down,
93                                 SDL_Surface * SM_button_off, SDL_Surface * SM_button_nav,
94                                 SDL_Surface * SM_button_hold,
95                                 SDL_Surface * SM_oskdel, SDL_Surface * SM_osktab, SDL_Surface * SM_oskenter,
96                                 SDL_Surface * SM_oskcapslock, SDL_Surface * SM_oskshift,
97                                 int disable_change)
98 {
99   SDL_Surface * surface;
100   SDL_Surface * button_up, * button_down;
101   SDL_Surface * button_off, * button_nav;
102   SDL_Surface * button_hold;
103   SDL_Surface * oskdel, * osktab, * oskenter;
104   SDL_Surface * oskcapslock, * oskshift;
105   osk_layout * layout;
106   on_screen_keyboard * keyboard;
107 
108   keyboard = malloc(sizeof(on_screen_keyboard));
109 
110   keyboard->osk_fonty = NULL;
111 
112   keyboard->disable_change = disable_change;
113   layout = load_layout(keyboard, layout_name);
114   if (!layout)
115     {
116       fprintf(stderr, "Error trying to load the required layout %s\n", layout_name);
117       layout = load_layout(keyboard, strdup("default.layout"));
118       if (!layout)
119         {
120           fprintf(stderr, "Error trying to load the default layout\n");
121           return NULL;
122         }
123       fprintf(stderr, "Loaded the default layout instead.\n");
124     }
125 
126 #ifdef DEBUG
127   printf("w %i, h %i\n", layout->width, layout->height);
128 #endif
129 
130   if (layout->width * LG_button_up->w >= (canvas->w - 48 * 4) * 0.9 ||
131       layout->height * LG_button_up->h >= canvas->h * 0.5) {
132       /* Full-size buttons too large, use small buttons */
133       button_up = SM_button_up;
134       button_down = SM_button_down;
135       button_off = SM_button_off;
136       button_nav = SM_button_nav;
137       button_hold = SM_button_hold;
138       oskdel = SM_oskdel;
139       osktab = SM_osktab;
140       oskenter = SM_oskenter;
141       oskcapslock = SM_oskcapslock;
142       oskshift = SM_oskshift;
143   } else {
144       button_up = LG_button_up;
145       button_down = LG_button_down;
146       button_off = LG_button_off;
147       button_nav = LG_button_nav;
148       button_hold = LG_button_hold;
149       oskdel = LG_oskdel;
150       osktab = LG_osktab;
151       oskenter = LG_oskenter;
152       oskcapslock = LG_oskcapslock;
153       oskshift = LG_oskshift;
154   }
155 
156   surface = SDL_CreateRGBSurface(canvas->flags,
157                                  layout->width * button_up->w,
158                                  layout->height * button_up->h,
159                                  canvas->format->BitsPerPixel,
160                                  canvas->format->Rmask, canvas->format->Gmask, canvas->format->Bmask, 0);
161   if (!surface)
162     {
163       fprintf(stderr, "Error creating the onscreen keyboard surface\n");
164       return NULL;
165     }
166   //  keyboard->name = layout_name;
167   keyboard->canvas_ptr = canvas;
168   keyboard->layout = layout;
169   keyboard->surface = surface;
170   keyboard->rect.x = 0;
171   keyboard->rect.y = 0;
172   keyboard->rect.w = keyboard->surface->w;
173   keyboard->rect.h = keyboard->surface->h;
174   keyboard->button_up = button_up;
175   keyboard->button_down = button_down;
176   keyboard->button_off = button_off;
177   keyboard->button_nav = button_nav;
178   keyboard->button_hold = button_hold;
179   keyboard->oskdel = oskdel;
180   keyboard->osktab = osktab;
181   keyboard->oskenter = oskenter;
182   keyboard->oskcapslock = oskcapslock;
183   keyboard->oskshift = oskshift;
184   keyboard->composing = layout->composemap;
185   keyboard->composed = NULL;
186   keyboard->last_key_pressed = NULL;
187   keyboard->modifiers = 0;
188 
189   set_key(NULL, &keyboard->keymodifiers.shift, 1);
190   set_key(NULL, &keyboard->keymodifiers.altgr, 1);
191   set_key(NULL, &keyboard->keymodifiers.compose, 1);
192   set_key(NULL, &keyboard->keymodifiers.dead, 1);
193 
194   keyboard->kmdf.shift = NULL;
195   keyboard->kmdf.altgr = NULL;
196   keyboard->kmdf.dead = NULL;
197   keyboard->kmdf.dead2 = NULL;
198   keyboard->kmdf.dead3 = NULL;
199   keyboard->kmdf.dead4 = NULL;
200 
201   keyboard->LG_button_up = LG_button_up;
202   keyboard->LG_button_down = LG_button_down;
203   keyboard->LG_button_off = LG_button_off;
204   keyboard->LG_button_nav = LG_button_nav;
205   keyboard->LG_button_hold = LG_button_hold;
206   keyboard->LG_oskdel = LG_oskdel;
207   keyboard->LG_osktab = LG_osktab;
208   keyboard->LG_oskenter = LG_oskenter;
209   keyboard->LG_oskcapslock = LG_oskcapslock;
210   keyboard->LG_oskshift = LG_oskshift;
211   keyboard->SM_button_up = SM_button_up;
212   keyboard->SM_button_down = SM_button_down;
213   keyboard->SM_button_off = SM_button_off;
214   keyboard->SM_button_nav = SM_button_nav;
215   keyboard->SM_button_hold = SM_button_hold;
216   keyboard->SM_oskdel = SM_oskdel;
217   keyboard->SM_osktab = SM_osktab;
218   keyboard->SM_oskenter = SM_oskenter;
219   keyboard->SM_oskcapslock = SM_oskcapslock;
220   keyboard->SM_oskshift = SM_oskshift;
221 
222   SDL_FillRect(surface, NULL,
223                SDL_MapRGB(surface->format, keyboard->layout->bgcolor.r, keyboard->layout->bgcolor.g,
224                           keyboard->layout->bgcolor.b));
225 
226   keybd_prepare(keyboard);
227 
228   draw_keyboard(keyboard);
229   return keyboard;
230 }
231 
load_layout(on_screen_keyboard * keyboard,char * layout_name)232 static struct osk_layout *load_layout(on_screen_keyboard * keyboard, char *layout_name)
233 {
234   FILE *fi;
235   int hlayout_loaded;
236   char *line;
237   char *filename;
238   char *key, *value;
239   osk_layout *layout;
240   char * __attribute__((unused)) tmp_ptr;
241 
242   layout = malloc(sizeof(osk_layout));
243   layout->name = NULL;
244   hlayout_loaded = 0;
245 #ifdef DEBUG
246   printf("load_layout %s\n", layout_name);
247 #endif
248   filename = malloc(sizeof(char) * 255);
249   if (layout_name != NULL)
250     {
251       keyboard->name = strdup(layout_name);
252       /* Try full path */
253       fi = fopen(layout_name, "r");
254       if (fi == NULL)
255         {
256           /* Try with DATA_PREFIX */
257 
258           snprintf(filename, 255, "%sosk/%s", DATA_PREFIX, layout_name);
259           fi = fopen(filename, "r");
260           if (fi == NULL)
261             {
262               fprintf(stderr, "Can't open either %s nor %s\n", layout_name, filename);
263               /* Fallback to default */
264               snprintf(filename, 255, "%sosk/default.layout", DATA_PREFIX);
265               fi = fopen(filename, "r");
266               keyboard->name = strdup("default.layout");
267             }
268         }
269     }
270   else
271     {
272       snprintf(filename, 255, "%sosk/default.layout", DATA_PREFIX);
273       fi = fopen(filename, "r");
274       keyboard->name = strdup("default.layout");
275     }
276 
277   free(filename);
278   if (fi == NULL)
279     {
280       fprintf(stderr, "Can't load the on screen keyboard layout\n");
281       return NULL;
282     }
283 
284 
285   line = malloc(sizeof(char) * 1024);
286   key = malloc(sizeof(char) * 255);
287   value = malloc(sizeof(char) * 255);
288 
289   while (!feof(fi))
290     {
291       tmp_ptr = fgets(line, 1023, fi);
292 
293       if (is_blank_or_comment(line))
294         continue;
295 
296       sscanf(line, "%s %s", key, value);
297       if (strcmp("layout", key) == 0 && !hlayout_loaded)
298         {
299 #ifdef DEBUG
300           printf("layout found: %s\n", value);
301 #endif
302 
303           load_hlayout(layout, value);
304           hlayout_loaded = 1;
305         }
306       else if (strncmp("keymap", key, 6) == 0)
307         {
308 #ifdef DEBUG
309           printf("keymap found: %s\n", value);
310 #endif
311           load_keymap(layout, value);
312         }
313       else if (strncmp("composemap", key, 10) == 0)
314         {
315 #ifdef DEBUG
316           printf("composemap found: %s\n", value);
317 #endif
318           load_composemap(layout, value);
319         }
320       else if (strncmp("keysymdefs", key, 10) == 0)
321         {
322           load_keysymdefs(layout, value);
323         }
324       else if (strncmp("keyboardlist", key, 12) == 0)
325         {
326           strcpy(value, &line[13]);
327           keyboard->keyboard_list = strdup(value);
328         }
329 
330 #ifdef DEBUG
331       printf("key %s, value %s\n", key, value);
332 #endif
333       key[0] = '\0';
334       value[0] = '\0';
335     }
336 
337 
338 
339   free(key);
340   free(value);
341   free(line);
342   fclose(fi);
343   return layout;
344 }
345 
346 /* A hlayout contains the definitions of the keyboard as seen in the screen.
347    Things like the number of rows of the keyboard, the font used to render the keys,
348    the width of the keys, and a code that matches each key like in real hardware keyboards */
load_hlayout(osk_layout * layout,char * hlayout_name)349 void load_hlayout(osk_layout * layout, char *hlayout_name)
350 {
351   int width, height;
352   int key_number, line_number;
353   int keycode, shiftcaps;
354   int allocated, have_fontpath;
355   int i;
356   int r, g, b;
357   int key_width, key_width_decimal;
358   char *filename;
359   char *line;
360   char *key, *fontpath;
361   char *plain_label, *top_label, *altgr_label, *shift_altgr_label;
362   FILE *fi;
363   char * __attribute__((unused)) tmp_ptr;
364 
365   key_number = line_number = 0;
366   width = height = 0;
367   allocated = 0;
368   have_fontpath = 0;
369 
370   filename = malloc(sizeof(char) * 255);
371 
372   /* Try full path */
373   fi = fopen(hlayout_name, "r");
374   if (fi == NULL)
375     {
376       /* Try with DATA_PREFIX */
377 
378       snprintf(filename, 255, "%sosk/%s", DATA_PREFIX, hlayout_name);
379       fi = fopen(filename, "r");
380       if (fi == NULL)
381         {
382           fprintf(stderr, "Can't open either %s nor %s\n", hlayout_name, filename);
383           layout->keys = NULL;
384           free(filename);
385           return;
386         }
387     }
388 
389   free(filename);
390 
391   line = malloc(sizeof(char) * 1024);
392   key = malloc(sizeof(char) * 255);
393   fontpath = malloc(sizeof(char) * 255);
394   r = g = b = 256;
395 
396   layout->fgcolor.r = def_fgcolor.r;
397   layout->fgcolor.g = def_fgcolor.g;
398   layout->fgcolor.b = def_fgcolor.b;
399 
400   layout->bgcolor.r = def_bgcolor.r;
401   layout->bgcolor.g = def_bgcolor.g;
402   layout->bgcolor.b = def_bgcolor.b;
403 
404 
405   while (!feof(fi))
406     {
407       if (width && height && !allocated)
408         {
409           layout->keys = malloc(height * sizeof(osk_key *));
410           layout->keys[0] = malloc(width * sizeof(osk_key));
411 
412           for (i = 0; i < width; i++)
413             {
414               layout->keys[0][i].width = 0;
415               layout->keys[0][i].plain_label = NULL;
416               layout->keys[line_number][i].top_label = NULL;
417               layout->keys[line_number][i].altgr_label = NULL;
418               layout->keys[line_number][i].shift_altgr_label = NULL;
419             }
420           layout->width = width;
421           layout->height = height;
422 
423 #ifdef DEBUG
424           printf("w %i, h %i\n", layout->width, layout->height);
425 #endif
426           allocated = 1;
427         }
428 
429       tmp_ptr = fgets(line, 1023, fi);
430 
431       if (is_blank_or_comment(line))
432         continue;
433 
434       if (strncmp(line, "WIDTH", 5) == 0)
435         sscanf(line, "%s %i", key, &width);
436 
437       else if (strncmp(line, "HEIGHT", 5) == 0)
438         sscanf(line, "%s %i", key, &height);
439 
440       else if (strncmp(line, "FONTPATH", 8) == 0)
441         {
442 #ifdef DEBUG
443           printf("linefont %s\n", line);
444 #endif
445           sscanf(line, "%s %s", key, fontpath);
446           if (!is_blank_or_comment(fontpath))
447             have_fontpath = 1;
448         }
449       else if (strncmp(line, "FGCOLOR", 5) == 0)
450         {
451 #ifdef DEBUG
452           printf("linefont %s\n", line);
453 #endif
454           sscanf(line, "%s %i %i %i", key, &r, &g, &b);
455           if (r > 0 && r < 256 && g > 0 && g < 256 && b > 0 && b < 256)
456             {
457               layout->fgcolor.r = r;
458               layout->fgcolor.g = g;
459               layout->fgcolor.b = b;
460               r = g = b = 256;
461             }
462         }
463       else if (strncmp(line, "BGCOLOR", 5) == 0)
464         {
465 #ifdef DEBUG
466           printf("linefont %s\n", line);
467 #endif
468           sscanf(line, "%s %i %i %i", key, &r, &g, &b);
469           if (r > 0 && r < 256 && g > 0 && g < 256 && b > 0 && b < 256)
470             {
471               layout->bgcolor.r = r;
472               layout->bgcolor.g = g;
473               layout->bgcolor.b = b;
474               r = g = b = 256;
475             }
476         }
477       else if (strncmp(line, "NEWLINE", 7) == 0)
478         {
479           line_number++;
480           key_number = 0;
481           layout->keys[line_number] = malloc(width * sizeof(osk_key));
482           for (i = 0; i < width; i++)
483             {
484               layout->keys[line_number][i].width = 0;
485               layout->keys[line_number][i].plain_label = NULL;
486               layout->keys[line_number][i].top_label = NULL;
487               layout->keys[line_number][i].altgr_label = NULL;
488               layout->keys[line_number][i].shift_altgr_label = NULL;
489             }
490         }
491       else if (width && height && allocated && strncmp(line, "KEY ", 4) == 0 && key_number < width)
492         {
493           plain_label = malloc(sizeof(char) * 64);
494           top_label = malloc(sizeof(char) * 64);
495           altgr_label = malloc(sizeof(char) * 64);
496           shift_altgr_label = malloc(sizeof(char) * 64);
497 
498           sscanf(line,
499                  "%s %i %i.%i %s %s %s %s %i",
500                  key,
501                  &keycode,
502                  &key_width, &key_width_decimal, plain_label, top_label, altgr_label, shift_altgr_label, &shiftcaps);
503           layout->keys[line_number][key_number].keycode = keycode;
504           layout->keys[line_number][key_number].width = (float)0.1 *key_width_decimal + key_width;
505 
506           layout->keys[line_number][key_number].plain_label = plain_label;
507           layout->keys[line_number][key_number].top_label = top_label;
508           layout->keys[line_number][key_number].altgr_label = altgr_label;
509           layout->keys[line_number][key_number].shift_altgr_label = shift_altgr_label;
510           layout->keys[line_number][key_number].shiftcaps = shiftcaps;
511           layout->keys[line_number][key_number].stick = 0;
512           key_number++;
513         }
514     }
515 
516   if (have_fontpath)
517     layout->fontpath = fontpath;
518   else
519     {
520       free(fontpath);
521       layout->fontpath = NULL;
522     }
523 
524   free(line);
525   free(key);
526   fclose(fi);
527   /* int j; */
528   /* for(i = 0; i<= line_number; i++) */
529   /* { */
530   /*   printf("Line %i\n", i); */
531   /*   for (j =0; j < width; j++) */
532   /*   { */
533   /*     printf("        %i,    \n ", j); */
534   /*                 if(layout.keys[i][j].width) */
535   /*    printf("keycode %d, width %f, plain %ls, caps %ls\n", */
536   /*           layout.keys[i][j].keycode, */
537   /*           layout.keys[i][j].width, */
538   /*           layout.keys[i][j].plain_label, */
539   /*           layout.keys[i][j].caps_label); */
540   /*   } */
541   /* } */
542 }
543 
544 
545 /* A keymap contains the keysyms (X keysym mnemonics) associated to each keycode in the hlayout.*/
load_keymap(osk_layout * layout,char * keymap_name)546 void load_keymap(osk_layout * layout, char *keymap_name)
547 {
548   int i, keycode, readed;
549   char *filename;
550   char *ksname1, *ksname2, *ksname3, *ksname4;
551   char *line;
552   FILE *fi;
553   char * __attribute__((unused)) tmp_ptr;
554 
555   filename = malloc(sizeof(char) * 255);
556 
557   /* Try full path */
558   fi = fopen(keymap_name, "r");
559   if (fi == NULL)
560     {
561       /* Try with DATA_PREFIX */
562 
563       snprintf(filename, 255, "%sosk/%s", DATA_PREFIX, keymap_name);
564       fi = fopen(filename, "r");
565       if (fi == NULL)
566         {
567           fprintf(stderr, "Can't open either %s nor %s\n", keymap_name, filename);
568           layout->keys = NULL;
569           free(filename);
570           return;
571         }
572     }
573 
574   free(filename);
575 
576   line = malloc(sizeof(char) * 1024);
577   layout->keymap = malloc(256 * sizeof(osk_keymap));
578 
579   for (i = 0; i < 256; i++)
580     {
581       layout->keymap[i].plain = NULL;
582       layout->keymap[i].caps = NULL;
583       layout->keymap[i].altgr = NULL;
584       layout->keymap[i].shiftaltgr = NULL;
585     }
586 
587 
588   while (!feof(fi))
589     {
590       tmp_ptr = fgets(line, 1023, fi);
591 
592       if (is_blank_or_comment(line))
593         continue;
594 
595       ksname1 = malloc(sizeof(char) * 64);
596       ksname2 = malloc(sizeof(char) * 64);
597       ksname3 = malloc(sizeof(char) * 64);
598       ksname4 = malloc(sizeof(char) * 64);
599       ksname1[0] = '\0';
600       ksname2[0] = '\0';
601       ksname3[0] = '\0';
602       ksname4[0] = '\0';
603 
604       /* FIXME: Why is the us-intl keymap duplicating the two first entries of every keycode? */
605       /* And why is the arabic keymap using the 5th and 6th entries as plain/shifted keys? */
606       readed = sscanf(line, "keycode %i = %s %s %s %s", &keycode, ksname1, ksname2, ksname3, ksname4);
607 
608       if (readed == 5 && keycode > 8 && keycode < 256)
609         {
610           layout->keymap[keycode].plain = ksname1;
611           layout->keymap[keycode].caps = ksname2;
612           layout->keymap[keycode].altgr = ksname3;
613           layout->keymap[keycode].shiftaltgr = ksname4;
614         }
615       else
616         {
617           free(ksname1);
618           free(ksname2);
619           free(ksname3);
620           free(ksname4);
621           layout->keymap[keycode].plain = NULL;
622           layout->keymap[keycode].caps = NULL;
623           layout->keymap[keycode].altgr = NULL;
624           layout->keymap[keycode].shiftaltgr = NULL;
625         }
626     }
627 
628   free(line);
629   fclose(fi);
630   /* int i; */
631   /* for (i = 0; i < 256; i++) */
632   /* { */
633   /*   if (layout.keymap[i].plain) */
634   /*     printf("%i,  %i, %i, %i, %i\n", i,   */
635   /*         layout.keymap[i].plain, */
636   /*         layout.keymap[i].caps, */
637   /*         layout.keymap[i].altgr, */
638   /*         layout.keymap[i].shiftaltgr); */
639   /* } */
640 
641 
642 
643 }
644 
645 /* Scans a line of keysyms and result and classifies them. */
gettokens(char * line,char * delim,char ** pointer,osk_composenode * composenode,osk_layout * layout)646 static void gettokens(char *line, char *delim, char **pointer, osk_composenode * composenode, osk_layout * layout)
647 {
648   int i;
649   char *tok;
650   wchar_t *result, *wtok;
651   osk_composenode *auxnode;
652 
653   wtok = malloc(sizeof(wchar_t) * 255);
654 
655   tok = strdup(strtok_r(line, delim, pointer));
656 
657   if (!tok)
658     return;
659 
660   if (tok[0] == ':')            /* End of precompose keysyms, next will be the result in UTF-8. */
661     {
662       free(tok);
663       tok = strdup(strtok_r(line, ": \"\t", pointer));
664 
665       mbstowcs(wtok, tok, 255);
666 
667       result = wcsdup(wtok);
668       /* printf("->%ls<-\n", wtok); */
669       free(wtok);
670       free(tok);
671       composenode->result = result;
672       return;
673     }
674   else
675     {
676       if (composenode->size == 0)
677         {
678           composenode->size = 1;
679           auxnode = malloc(sizeof(osk_composenode));
680           composenode->childs = malloc(sizeof(osk_composenode *));
681           composenode->childs[0] = auxnode;
682           mbstowcs(wtok, tok, 254);     /* <<< CRASH */
683           composenode->childs[0]->keysym = wcsdup(wtok);
684           composenode->childs[0]->result = NULL;
685           composenode->childs[0]->size = 0;
686 
687           /* printf("size %d, keysym %ls => ", composenode->size, composenode->childs[0]->keysym); */
688 
689           gettokens(NULL, delim, pointer, composenode->childs[0], layout);
690           free(wtok);
691           free(tok);
692           return;
693         }
694       else
695         {
696           for (i = 0; i < composenode->size; i++)
697             {
698               mbstowcs(wtok, tok, 255);
699               if (wcscmp(composenode->childs[i]->keysym, wtok) == 0)
700                 {
701 
702                   /* printf("Size %d, keysym %ls =>", composenode->size, composenode->childs[i]->keysym); */
703 
704                   gettokens(NULL, delim, pointer, composenode->childs[i], layout);
705                   free(tok);
706                   free(wtok);
707                   return;
708                 }
709             }
710         }
711 
712       composenode->size = composenode->size + 1;
713       composenode->childs = realloc(composenode->childs, composenode->size * sizeof(osk_composenode *));
714 
715       mbstowcs(wtok, tok, 255);
716       auxnode = malloc(sizeof(osk_composenode));
717       composenode->childs[composenode->size - 1] = auxnode;     //malloc(sizeof(osk_composenode));
718       composenode->childs[composenode->size - 1]->keysym = wtok;
719       composenode->childs[composenode->size - 1]->result = NULL;
720       composenode->childs[composenode->size - 1]->size = 0;
721 
722       /* printf("size %d, keysym %ls =>", composenode->size, composenode->childs[composenode->size - 1]->keysym); */
723 
724       gettokens(NULL, delim, pointer, composenode->childs[composenode->size - 1], layout);
725       free(tok);
726       return;
727     }
728 }
729 
730 
731 /* A compose map contains the sequences of keysyms (X keysym mnemonics) needed to generate another keysym.
732    The last in the sequence is the result, the others will be searched in the order they appear.
733    They will be classified in a multiway tree.*/
load_composemap(osk_layout * layout,char * composemap_name)734 static void load_composemap(osk_layout * layout, char *composemap_name)
735 {
736   char *filename;
737   char **pointer;
738   char *line;
739   FILE *fi;
740   char * __attribute__((unused)) tmp_ptr;
741 
742   pointer = malloc(sizeof(wchar_t *));
743   filename = malloc(sizeof(char) * 255);
744 
745   /* Try full path */
746   fi = fopen(composemap_name, "r");
747   if (fi == NULL)
748     {
749       /* Try with DATA_PREFIX */
750 
751       snprintf(filename, 255, "%sosk/%s", DATA_PREFIX, composemap_name);
752       fi = fopen(filename, "r");
753       if (fi == NULL)
754         {
755           fprintf(stderr, "Can't open either %s nor %s\n", composemap_name, filename);
756           layout->keys = NULL;
757           free(filename);
758           return;
759         }
760     }
761 
762   free(filename);
763 
764   layout->composemap = malloc(sizeof(osk_composenode));
765   layout->composemap[0].keysym = NULL;
766   layout->composemap[0].result = NULL;
767 
768   layout->composemap->size = 0;
769   line = malloc(1024 * sizeof(char));
770 
771   while (!feof(fi))
772     {
773       tmp_ptr = fgets(line, 1023, fi);
774 
775       if (is_blank_or_comment(line))
776         continue;
777 
778       gettokens(line, (char *)">< \t", pointer, layout->composemap, layout);
779     }
780 
781   fclose(fi);
782   free(line);
783   free(pointer);
784 #ifdef DEBUG_OSK_COMPOSEMAP
785   print_composemap(layout->composemap, NULL);
786 #endif
787 }
788 
789 #ifdef DEBUG_OSK_COMPOSEMAP
print_composemap(osk_composenode * composemap,char * sp)790 static void print_composemap(osk_composenode * composemap, char *sp)
791 {
792   int i;
793   char *space;
794 
795   space = malloc(sizeof(char) * 255);
796 
797 #ifdef DEBUG
798   printf("%ls, ", composemap->keysym);
799   printf("%d ==> ", composemap->size);
800 #endif
801   if (composemap->size == 0)
802     {
803 #ifdef DEBUG
804       printf("result %ls\n", composemap->result);
805 #endif
806       return;
807     }
808   if (sp)
809     {
810       sprintf(space, "%s\t", sp);
811     }
812   else
813     {
814       sprintf(space, " ");
815     }
816 #ifdef DEBUG
817   printf("%s", space);
818 #endif
819 
820   for (i = 0; i < composemap->size; i++)
821     {
822       print_composemap(composemap->childs[i], space);
823       //      free(space);
824     }
825   /* for (i = 0; i < composemap->size; i++) */
826   /*   { */
827   /*     printf("aaa %ls, ", composemap->keysym); */
828   /*     printf("%d ==> ", composemap->size); */
829   /*     printf("%ls, ", composemap->childs[i]->keysym); */
830   /*     printf("childs %d ==> ", composemap->childs[i]->size); */
831 
832   /*     if (composemap->childs[i]->size == 0) */
833   /*            printf("result %ls\n", composemap->childs[i]->result); */
834   /*     else */
835   /*            print_composemap(composemap->childs[i], space); */
836   /*     //      free(space); */
837   /*   } */
838 }
839 #endif
840 
841 /* This parses the contents of keysymdef.h from the source of xorg.
842    Therefore, if somebody wants to provide custom keysymdefs, he has to follow its syntax. */
load_keysymdefs(osk_layout * layout,char * keysymdefs_name)843 static void load_keysymdefs(osk_layout * layout, char *keysymdefs_name)
844 {
845   int i;
846   char *filename;
847   char *line;
848   FILE *fi;
849   char * __attribute__((unused)) tmp_ptr;
850 
851   filename = malloc(sizeof(char) * 255);
852 
853   /* Try full path */
854   fi = fopen(keysymdefs_name, "r");
855   if (fi == NULL)
856     {
857       /* Try with DATA_PREFIX */
858 
859       snprintf(filename, 255, "%sosk/%s", DATA_PREFIX, keysymdefs_name);
860       fi = fopen(filename, "r");
861       if (fi == NULL)
862         {
863           fprintf(stderr, "Can't open either %s nor %s\n", keysymdefs_name, filename);
864           layout->keysymdefs = NULL;
865           free(filename);
866           return;
867         }
868     }
869 
870   free(filename);
871 
872   layout->keysymdefs = malloc(sizeof(keysymdefs));
873   layout->keysymdefs[0].unicode = 0;
874   i = 0;
875   line = malloc(1024 * sizeof(wchar_t));
876 
877   while (!feof(fi))
878     {
879       tmp_ptr = fgets(line, 1023, fi);
880       if (strncmp("#define XK_", line, 11) != 0)
881         continue;
882 
883       layout->sizeofkeysymdefs = i;
884       layout->keysymdefs = realloc(layout->keysymdefs, sizeof(keysymdefs) * (i + 1));
885 
886       /* Some keysyms doesn't correspond to any unicode value, ej. BackSpace */
887       layout->keysymdefs[i].unicode = 0;
888       layout->keysymdefs[i].mnemo = malloc(sizeof(char) * 128);
889       sscanf(line, "#define XK_%s %x /* U+%x",
890              layout->keysymdefs[i].mnemo, &layout->keysymdefs[i].keysym, &layout->keysymdefs[i].unicode);
891       i++;
892     }
893 
894   fclose(fi);
895   free(line);
896 }
897 
898 /* /\* Return the mnemonic string of a x keysym as defined in the source of xorg in keysymdef.h *\/ */
899 /* static char * keysym2mnemo(int keysym, on_screen_keyboard * keyboard) */
900 /* { */
901 /*   unsigned int i; */
902 /*   for (i = 0; i < keyboard->layout->sizeofkeysymdefs ;i++) */
903 /*     if (keysym == keyboard->layout->keysymdefs[i].keysym) */
904 /*       return(keyboard->layout->keysymdefs[i].mnemo); */
905 
906 /*   /\* For the purpose of onscreen keyboard we don't need the conversion to strings in the form U0000 *\/ */
907 /*   return(NULL); */
908 /* } */
909 
910 /* Returns the x keysym corresponding to a mnemonic string */
mnemo2keysym(char * mnemo,on_screen_keyboard * keyboard)911 static int mnemo2keysym(char *mnemo, on_screen_keyboard * keyboard)
912 {
913   unsigned int i;
914 
915   for (i = 0; i < keyboard->layout->sizeofkeysymdefs; i++)
916     {
917       if (strcmp(mnemo, keyboard->layout->keysymdefs[i].mnemo) == 0)
918         return (keyboard->layout->keysymdefs[i].keysym);
919     }
920   i = 0;
921 
922   /* Perhaps the mnemo is in UXXXX format? */
923   if (sscanf(mnemo, "U%x", &i))
924     return (i | 0x01000000);
925 
926   /* Or maybe mnemo is already a keysym? */
927   if (sscanf(mnemo, "0x%x", &i))
928     return (i);
929 
930   return (0);
931 }
932 
933 /* Returns the unicode value of a x keysym if any, otherwise returns 0 */
keysym2unicode(int keysym,on_screen_keyboard * keyboard)934 static int keysym2unicode(int keysym, on_screen_keyboard * keyboard)
935 {
936   unsigned int i;
937 
938   /* Credits for the conversion from xkeysyms to unicode values, code taken from the source code of xterm, file keysym2ucs.c.
939    *Author: Markus G. Kuhn <mkuhn@acm.org>, University of Cambridge, April 2001
940    *
941    * Special thanks to Richard Verhoeven <river@win.tue.nl> for preparing
942    * an initial draft of the mapping table.
943    *
944    * This software is in the public domain. Share and enjoy!
945    */
946   /* first check for Latin-1 characters (1:1 mapping) */
947   if ((keysym >= 0x0020 && keysym <= 0x007e) || (keysym >= 0x00a0 && keysym <= 0x00ff))
948     return keysym;
949 
950   /* also check for directly encoded 24-bit UCS characters */
951   if ((keysym & 0xff000000) == 0x01000000)
952     return keysym & 0x00ffffff;
953 
954 
955 
956   for (i = 0; i < keyboard->layout->sizeofkeysymdefs; i++)
957     if (keysym == keyboard->layout->keysymdefs[i].keysym)
958       return (keyboard->layout->keysymdefs[i].unicode);
959 
960   return (keysym);
961 }
962 
963 
964 /* Searches in the tree for composing stuff */
get_composed_keysym(on_screen_keyboard * keyboard,osk_composenode * composenode,wchar_t * keysym)965 static void get_composed_keysym(on_screen_keyboard * keyboard, osk_composenode * composenode, wchar_t * keysym)
966 {
967   int i;
968 
969   /* If there is not a compose table return the keysym */
970   if (!composenode)
971     {
972       if (keyboard->composed)
973         free(keyboard->composed);
974       keyboard->composed = wcsdup(keysym);
975       keyboard->composed_type = 0;
976       return;
977     }
978 
979   /* If there is a compose table, lookup for matches */
980   for (i = 0; i < composenode->size; i++)
981     {
982       /* If matches, set either the result or the next node */
983       if (wcscmp(composenode->childs[i]->keysym, keysym) == 0)
984         {
985           if (composenode->childs[i]->result)
986             {
987               if (keyboard->composed)
988                 free(keyboard->composed);
989               keyboard->composed = wcsdup(composenode->childs[i]->result);
990               keyboard->composing = keyboard->layout->composemap;
991               /* The result in the Compose files from xorg is yet in unicode */
992               keyboard->composed_type = 1;
993               return;
994             }
995           else
996             {
997               if (keyboard->composed)
998                 free(keyboard->composed);
999               keyboard->composed = NULL;
1000               keyboard->composing = composenode->childs[i];
1001               return;
1002             }
1003         }
1004     }
1005 
1006   /* No matches found, if we were in the middle of a sequence, reset the compose stuff,
1007      if we were in the beginning node, set the keysym */
1008 
1009   if (keyboard->layout->composemap == composenode)
1010     {
1011       if (keyboard->composed)
1012         free(keyboard->composed);
1013       keyboard->composed = wcsdup(keysym);
1014       keyboard->composed_type = 0;
1015     }
1016   else                          /* reset */
1017     {
1018       keyboard->composing = keyboard->layout->composemap;
1019       if (keyboard->composed)
1020         free(keyboard->composed);
1021       keyboard->composed = NULL;
1022       keyboard->composed_type = 0;
1023     }
1024 }
1025 
1026 
is_blank_or_comment(char * line)1027 static int is_blank_or_comment(char *line)
1028 {
1029   int i;
1030 
1031   i = 0;
1032 
1033   if (strlen(line) == 0)
1034     return 0;
1035   while (line[i] != '\n')
1036     {
1037       if (line[i] == '#')
1038         return 1;
1039       else if (line[i] == ' ' || line[i] == '\t')
1040         i++;
1041       else
1042         return 0;
1043     }
1044   return 1;
1045 }
1046 
1047 
1048 /* static int isw_blank_or_comment(wchar_t *line) */
1049 /* { */
1050 /*   int i; */
1051 
1052 /*   i = 0; */
1053 /*   if (wcslen(line) == 0) */
1054 /*     return 0; */
1055 /*   while (line[i] != L'\n') */
1056 /*   { */
1057 /*     if (line[i] == L'#') */
1058 /*       return 1; */
1059 /*     else if (line[i] == L' ' || line[i] == L'\t') */
1060 /*       i++; */
1061 /*     else */
1062 /*       return 0; */
1063 /*   } */
1064 /*   return 1; */
1065 /* } */
1066 
1067 
1068 /* FIXME: Is it safe to supose that if a font is loaded at one size, it will be loaded at any size? */
1069 /* FIXME: starting a layout with one font causes all other layouts be in that font */
keybd_prepare(on_screen_keyboard * keyboard)1070 static void keybd_prepare(on_screen_keyboard * keyboard)
1071 {
1072   char *fontname;
1073   int font_height;
1074 
1075   /* Pick a height (e.g., 16pt for small (24x24), 32pt for large (48x48) buttons) */
1076   font_height = ((keyboard->button_up->h * 2) / 3);
1077 
1078   fontname = malloc(sizeof(char) * 255);
1079   if (keyboard->osk_fonty == NULL)
1080     {
1081 
1082       if (keyboard->layout->fontpath)
1083         {
1084           /* First try if it is an absolute path */
1085           keyboard->osk_fonty = TTF_OpenFont(keyboard->layout->fontpath, font_height);
1086           if (keyboard->osk_fonty == NULL)
1087             {
1088               /* Now trying if it is relative to DATA_PREFIX/fonts/ */
1089               snprintf(fontname, 255, "%s/fonts/%s", DATA_PREFIX, keyboard->layout->fontpath);
1090 
1091               keyboard->osk_fonty = TTF_OpenFont(fontname, font_height);
1092               if (keyboard->osk_fonty == NULL)
1093                 {
1094                   /* Perhaps it is relative to DATA_PREFIX only? */
1095                   snprintf(fontname, 255, "%s/%s", DATA_PREFIX, keyboard->layout->fontpath);
1096                   keyboard->osk_fonty = TTF_OpenFont(fontname, font_height);
1097                   if (keyboard->osk_fonty == NULL)
1098                     {
1099                       /* Or to DATA_PREFIX/fonts/locale/ ? */
1100                       snprintf(fontname, 255, "%s/fonts/locale/%s", DATA_PREFIX, keyboard->layout->fontpath);
1101                       keyboard->osk_fonty = TTF_OpenFont(fontname, font_height);
1102                     }
1103                 }
1104             }
1105         }
1106 
1107       if (keyboard->osk_fonty == NULL)
1108         {
1109           /* Going with the default */
1110           sprintf(fontname, "%s/fonts/FreeSansBold.ttf", DATA_PREFIX);
1111           keyboard->osk_fonty = TTF_OpenFont(fontname, font_height);
1112         }
1113 
1114       if (keyboard->osk_fonty == NULL)
1115         {
1116           fprintf(stderr, "\nError: Can't open the font!\n"
1117                   "The Simple DirectMedia Layer error that occurred was:\n" "%s\n\n", SDL_GetError());
1118           free(fontname);
1119           exit(1);
1120         }
1121 
1122       free(fontname);
1123     }
1124 }
1125 
1126 
apply_surface(int x,int y,SDL_Surface * source,SDL_Surface * destination,SDL_Rect * clip)1127 static void apply_surface(int x, int y, SDL_Surface * source, SDL_Surface * destination, SDL_Rect * clip)
1128 {
1129   SDL_Rect offset;
1130 
1131   offset.x = x;
1132   offset.y = y;
1133 
1134   SDL_BlitSurface(source, clip, destination, &offset);
1135 }
1136 
1137 
1138 /* /\* NOTE: This is a duplicate of wcstou16 in tuxpaint.c */
1139 
1140 /*    This conversion is required on platforms where Uint16 doesn't match wchar_t. */
1141 /*    On Windows, wchar_t is 16-bit, elsewhere it is 32-bit. */
1142 /*    Mismatch caused by the use of Uint16 for unicode characters by SDL, SDL_ttf. */
1143 /*    I guess wchar_t is really only suitable for internal use ... *\/ */
1144 /* static Uint16 *wcstou16(const wchar_t * str) */
1145 /* { */
1146 /*   unsigned int i, len = wcslen(str); */
1147 /*   Uint16 *res = malloc((len + 1) * sizeof(Uint16)); */
1148 
1149 /*   for (i = 0; i < len + 1; ++i) */
1150 /*   { */
1151 /*     /\* This is a bodge, but it seems unlikely that a case-conversion */
1152 /*        will cause a change from one utf16 character into two.... */
1153 /*        (though at least UTF-8 suffers from this problem) *\/ */
1154 
1155 /*     // FIXME: mangles non-BMP characters rather than using UTF-16 surrogates! */
1156 /*     res[i] = (Uint16) str[i]; */
1157 /*   } */
1158 
1159 /*   return res; */
1160 /* } */
1161 
1162 /* Stretches a button from the middle, keeping the extrems intact */
stretch_surface(SDL_Surface * orig,int width)1163 static SDL_Surface *stretch_surface(SDL_Surface * orig, int width)
1164 {
1165   int i;
1166   SDL_Surface *dest;
1167   SDL_Rect rect;
1168   SDL_Rect orig_rect;
1169 
1170   orig_rect.x = orig->w / 2;
1171   orig_rect.y = 0;
1172   orig_rect.w = 1;
1173   orig_rect.h = orig->h;
1174 
1175   dest = SDL_CreateRGBSurface(orig->flags,
1176                               width,
1177                               orig->h,
1178                               orig->format->BitsPerPixel,
1179                               orig->format->Rmask, orig->format->Gmask, orig->format->Bmask, 0);
1180 
1181   SDL_BlitSurface(orig, NULL, dest, NULL);
1182   rect.y = 0;
1183 
1184   if (width > orig->w)
1185     {
1186       rect.x = width - orig->w;
1187       rect.h = orig->h;
1188       rect.w = orig->w;
1189       SDL_BlitSurface(orig, NULL, dest, &rect);
1190 
1191       rect.w = 1;
1192       for (i = orig->w / 2; i < width - orig->w / 2; i++)
1193         {
1194           rect.x = i;
1195           SDL_BlitSurface(orig, &orig_rect, dest, &rect);
1196         }
1197     }
1198   else if (width < orig->w)
1199     {
1200       rect.y = 0;
1201       rect.w = 1;
1202       rect.h = dest->h;
1203 
1204       orig_rect.y = 0;
1205       orig_rect.w = 1;
1206       orig_rect.h = orig->h;
1207 
1208       for (i = 0; i <= width / 2; i++)
1209         {
1210           rect.x = dest->w - i;
1211           orig_rect.x = orig->w - i;
1212           SDL_BlitSurface(orig, &orig_rect, dest, &rect);
1213         }
1214     }
1215 
1216   return dest;
1217 }
1218 
1219 /* Draws the keyboard surface */
draw_keyboard(on_screen_keyboard * keyboard)1220 static void draw_keyboard(on_screen_keyboard * keyboard)
1221 {
1222   int i, j;
1223   int key_height, accumulated_width, accumulated_height;
1224   float key_width;
1225 
1226   key_width = keyboard->button_up->w;
1227   key_height = keyboard->button_up->h;
1228 
1229   accumulated_height = 0;
1230 
1231   for (j = 0; j < keyboard->layout->height; j++)
1232     {
1233       accumulated_width = 0;
1234       for (i = 0; i < keyboard->layout->width; i++)
1235         {
1236           if (keyboard->layout->keys[j][i].width)
1237             {
1238 
1239               keyboard->layout->keys[j][i].row = j;
1240               keyboard->layout->keys[j][i].x = accumulated_width;
1241               keyboard->layout->keys[j][i].y = accumulated_height;
1242 
1243               draw_key(keyboard->layout->keys[j][i], keyboard, 0);
1244             }
1245           accumulated_width += (keyboard->layout->keys[j][i].width * key_width);
1246         }
1247       accumulated_height += key_height;
1248     }
1249 
1250   /* draw_key(keyboard->keymodifiers.shift, keyboard, 0); */
1251   /* draw_key(keyboard->keymodifiers.altgr, keyboard, 0); */
1252   /* draw_key(keyboard->keymodifiers.compose, keyboard, 0); */
1253   /* draw_key(keyboard->keymodifiers.dead, keyboard, 0); */
1254 }
1255 
draw_key(osk_key key,on_screen_keyboard * keyboard,int hot)1256 static void draw_key(osk_key key, on_screen_keyboard * keyboard, int hot)
1257 {
1258   char *text;
1259   SDL_Surface *skey;
1260 
1261   if (!key.width)
1262     return;
1263 
1264   text = malloc(sizeof(char) * 255);
1265 
1266   snprintf(text, 6, "%s", key.plain_label);
1267 
1268   if (strncmp("NULL", text, 4) != 0 && key.keycode != 0)
1269     {
1270       if (hot)
1271         skey = stretch_surface(keyboard->button_down, key.width * keyboard->button_down->w);
1272 
1273       else if (key.stick)
1274         skey = stretch_surface(keyboard->button_hold, key.width * keyboard->button_hold->w);
1275 
1276       else
1277         {
1278           if (key.keycode == 1 || key.keycode == 2)
1279             {
1280               if (keyboard->disable_change)
1281                 skey = stretch_surface(keyboard->button_off, key.width * keyboard->button_off->w);
1282               else
1283                 skey = stretch_surface(keyboard->button_nav, key.width * keyboard->button_nav->w);
1284             }
1285           else
1286             skey = stretch_surface(keyboard->button_up, key.width * keyboard->button_up->w);
1287         }
1288     }
1289   else
1290     skey = stretch_surface(keyboard->button_off, key.width * keyboard->button_off->w);
1291 
1292   apply_surface(key.x, key.y, skey, keyboard->surface, NULL);
1293 
1294   SDL_FreeSurface(skey);
1295   free(text);
1296   label_key(key, keyboard);
1297 }
1298 
1299 
1300 /* FIXME: TODO draw top and bottom_right (altgr) labels */
label_key(osk_key key,on_screen_keyboard * keyboard)1301 static void label_key(osk_key key, on_screen_keyboard * keyboard)
1302 {
1303   SDL_Surface *messager;
1304   int modstate;
1305   char *text;
1306 
1307   /* To remove a warning... */
1308   text = NULL;
1309 
1310   modstate = keyboard->modifiers;
1311 
1312   /* FIXME There MUST be a simpler way to do this. Pere 2011/8/3 */
1313   /* First the plain ones */
1314   if (modstate == KMOD_NONE || (modstate == (KMOD_NONE | KMOD_LALT)))
1315     text = strdup(key.plain_label);
1316 
1317   else if (modstate == KMOD_SHIFT)
1318     {
1319       text = strdup(key.top_label);
1320     }
1321 
1322   else if (modstate == KMOD_RALT)
1323     {
1324       text = strdup(key.altgr_label);
1325     }
1326 
1327   else if (modstate == KMOD_CAPS)
1328     {
1329       if (key.shiftcaps == 1)
1330         text = strdup(key.top_label);
1331 
1332       else
1333         text = strdup(key.plain_label);
1334     }
1335 
1336   /* Now the combined ones */
1337   else if (modstate & KMOD_RALT && modstate & KMOD_SHIFT)
1338     {
1339       if (modstate & KMOD_CAPS)
1340         {
1341           if (key.shiftcaps)
1342             text = strdup(key.altgr_label);
1343           else
1344             text = strdup(key.shift_altgr_label);
1345         }
1346       else
1347         {
1348           text = strdup(key.shift_altgr_label);
1349         }
1350     }
1351 
1352   else if (modstate & KMOD_RALT && modstate & KMOD_CAPS && !(modstate & KMOD_SHIFT))
1353     {
1354       if (key.shiftcaps)
1355         text = strdup(key.shift_altgr_label);
1356       else
1357         text = strdup(key.altgr_label);
1358     }
1359 
1360   else if (modstate & KMOD_SHIFT && modstate & KMOD_CAPS)
1361     {
1362       if (key.shiftcaps == 1)
1363         text = strdup(key.plain_label);
1364       else
1365         text = strdup(key.top_label);
1366     }
1367 
1368   if (strncmp("DELETE", text, 6) == 0)
1369     {
1370       apply_surface(key.x, key.y, keyboard->oskdel, keyboard->surface, NULL);
1371     }
1372 
1373   else if (strncmp("TAB", text, 3) == 0)
1374     {
1375       apply_surface(key.x, key.y, keyboard->osktab, keyboard->surface, NULL);
1376     }
1377 
1378   else if (strncmp("ENTER", text, 5) == 0)
1379     {
1380       apply_surface(key.x, key.y, keyboard->oskenter, keyboard->surface, NULL);
1381     }
1382 
1383   else if (strncmp("CAPSLOCK", text, 8) == 0)
1384     {
1385       apply_surface(key.x, key.y, keyboard->oskcapslock, keyboard->surface, NULL);
1386     }
1387 
1388   else if (strncmp("SHIFT", text, 5) == 0)
1389     {
1390       apply_surface(key.x, key.y, keyboard->oskshift, keyboard->surface, NULL);
1391     }
1392 
1393   else if (strncmp("SPACE", text, 5) != 0 && strncmp("NULL", text, 4) != 0)
1394     {
1395       messager = TTF_RenderUTF8_Blended(keyboard->osk_fonty, text, keyboard->layout->fgcolor);
1396 
1397       apply_surface(key.x + 5, key.y, messager, keyboard->surface, NULL);
1398       SDL_FreeSurface(messager);
1399     }
1400   free(text);
1401 }
1402 
1403 /* Searches the key corresponding to coordinates */
find_key(on_screen_keyboard * keyboard,int x,int y)1404 static osk_key *find_key(on_screen_keyboard * keyboard, int x, int y)
1405 {
1406   int i, j;
1407   osk_key *key;
1408 
1409   key = NULL;
1410   for (j = 0; j < keyboard->layout->height; j++)
1411     {
1412       if (keyboard->layout->keys[j][0].y < y && keyboard->layout->keys[j][0].y + keyboard->button_up->h > y)
1413         for (i = 0; i < keyboard->layout->width; i++)
1414           if (keyboard->layout->keys[j][i].x < x &&
1415               keyboard->layout->keys[j][i].x + keyboard->layout->keys[j][i].width * keyboard->button_up->w > x)
1416             {
1417               key = &keyboard->layout->keys[j][i];
1418               return key;
1419             }
1420     }
1421 
1422   return NULL;
1423 }
1424 
1425 /* Copies orig to dest or sets dest to defaults if orig is NULL.
1426    if firstime is setted, don't frees the strings as there aren't. */
set_key(osk_key * orig,osk_key * dest,int firsttime)1427 static void set_key(osk_key * orig, osk_key * dest, int firsttime)
1428 {
1429   if (orig == NULL)
1430     {
1431       dest->keycode = 0;
1432       dest->row = 0;
1433       dest->x = 0;
1434       dest->y = 0;
1435       dest->width = 0;
1436       if (!firsttime && dest->plain_label != NULL)
1437         free(dest->plain_label);
1438       dest->plain_label = NULL;
1439       if (!firsttime && dest->top_label != NULL)
1440         free(dest->top_label);
1441       dest->top_label = NULL;
1442       if (!firsttime && dest->altgr_label != NULL)
1443         free(dest->altgr_label);
1444       dest->altgr_label = NULL;
1445       dest->shiftcaps = 0;
1446     }
1447   else
1448     {
1449       dest->keycode = orig->keycode;
1450       dest->row = orig->row;
1451       dest->x = orig->x;
1452       dest->y = orig->y;
1453       dest->width = orig->width;
1454 
1455       if (dest->plain_label != NULL)
1456         free(dest->plain_label);
1457       dest->plain_label = strdup(orig->plain_label);
1458 
1459       if (dest->top_label != NULL)
1460         free(dest->top_label);
1461       dest->top_label = strdup(orig->top_label);
1462 
1463       if (dest->altgr_label != NULL)
1464         free(dest->altgr_label);
1465       dest->altgr_label = strdup(orig->altgr_label);
1466 
1467       dest->shiftcaps = orig->shiftcaps;
1468     }
1469 }
1470 
find_keysym(osk_key key,on_screen_keyboard * keyboard)1471 static char *find_keysym(osk_key key, on_screen_keyboard * keyboard)
1472 {
1473   int keycode;
1474   char *keysym;
1475   osk_keymap keysyms;
1476   SDLMod modstate;
1477 
1478   keycode = key.keycode;
1479   keysyms = keyboard->layout->keymap[keycode];
1480   keysym = NULL;
1481 
1482   modstate = keyboard->modifiers;
1483 
1484   /* FIXME There MUST be a simpler way to do this. Pere 2011/8/3 */
1485   /* First the plain ones */
1486   if (modstate == KMOD_NONE || (modstate == (KMOD_NONE | KMOD_LALT)))
1487     keysym = keysyms.plain;
1488 
1489   else if (modstate == KMOD_SHIFT)
1490     {
1491       keysym = keysyms.caps;
1492     }
1493 
1494   else if (modstate == KMOD_RALT)
1495     {
1496       keysym = keysyms.altgr;
1497     }
1498 
1499   else if (modstate == KMOD_CAPS)
1500     {
1501       if (key.shiftcaps == 1)
1502         keysym = keysyms.caps;
1503       else
1504         keysym = keysyms.plain;
1505     }
1506 
1507   /* Now the combined ones */
1508   else if (modstate & KMOD_RALT && modstate & KMOD_SHIFT)
1509     {
1510       if (modstate & KMOD_CAPS)
1511         {
1512           if (key.shiftcaps)
1513             keysym = keysyms.altgr;
1514           else
1515             keysym = keysyms.shiftaltgr;
1516         }
1517       else
1518         {
1519           keysym = keysyms.shiftaltgr;
1520         }
1521     }
1522 
1523   else if (modstate & KMOD_RALT && modstate & KMOD_CAPS && !(modstate & KMOD_SHIFT))
1524     {
1525       if (key.shiftcaps)
1526         keysym = keysyms.shiftaltgr;
1527       else
1528         keysym = keysyms.altgr;
1529     }
1530 
1531   else if (modstate & KMOD_SHIFT && modstate & KMOD_CAPS)
1532     {
1533       if (key.shiftcaps == 1)
1534         keysym = keysyms.plain;
1535       else
1536         keysym = keysyms.caps;
1537     }
1538 
1539   return (keysym);
1540 }
1541 
1542 /* We lose the SDL ModState by leaving and entering the tuxpaint window, so using a custom state */
handle_keymods(char * keysym,osk_key * key,on_screen_keyboard * keyboard)1543 static int handle_keymods(char *keysym, osk_key * key, on_screen_keyboard * keyboard)
1544 {
1545   SDLMod mod;
1546   SDL_Event ev;
1547 
1548   mod = keyboard->modifiers;
1549 
1550   if (strncmp("Shift", keysym, 5) == 0)
1551     {
1552       if (mod & KMOD_SHIFT)
1553         {
1554           keyboard->modifiers = mod & 0xFFF0;
1555           key->stick = 0;
1556           keyboard->kmdf.shift->stick = 0;
1557         }
1558       else
1559         {
1560           keyboard->modifiers = mod | KMOD_SHIFT;
1561           key->stick = 1;
1562           keyboard->kmdf.shift = key;
1563         }
1564       return 1;
1565     }
1566   else if (strncmp("Alt_L", keysym, 5) == 0)
1567     {
1568       ev.key.keysym.sym = SDLK_LALT;
1569       ev.key.keysym.unicode = 0;        // FIXME is 0 the right value here?
1570       ev.type = SDL_KEYDOWN;
1571       SDL_PushEvent(&ev);
1572       ev.type = SDL_KEYUP;
1573       SDL_PushEvent(&ev);
1574 
1575       return 1;
1576     }
1577 
1578   /* Seems ISO_Level3_Shift and ISO_Next_Group are used too for right Alt */
1579   else if (strncmp("ISO_Level3_Shift", keysym, 16) == 0 ||
1580            strncmp("ISO_Next_Group", keysym, 14) == 0 || strncmp("ALT_R", keysym, 5) == 0)
1581     {
1582       if (mod & KMOD_RALT)
1583         {
1584           keyboard->modifiers = mod & 0xF0FF;
1585           keyboard->kmdf.altgr->stick = 0;
1586         }
1587       else
1588         {
1589           keyboard->modifiers = mod | KMOD_RALT;
1590           key->stick = 1;
1591           keyboard->kmdf.altgr = key;
1592 
1593           return 1;
1594         }
1595       return 0;
1596     }
1597 
1598   else if (strncmp("Caps_Lock", keysym, 9) == 0)
1599     {
1600       if (mod & KMOD_CAPS)
1601         {
1602           keyboard->modifiers = mod & 0x0FFF;
1603           key->stick = 0;
1604         }
1605       else
1606         {
1607           keyboard->modifiers = mod | KMOD_CAPS;
1608           key->stick = 1;
1609         }
1610 
1611 
1612       return 1;
1613     }
1614 
1615   if (mod & KMOD_CAPS)
1616     {
1617       keyboard->modifiers = KMOD_CAPS;
1618     }
1619   else
1620     keyboard->modifiers = KMOD_NONE;
1621 
1622   if (keyboard->kmdf.shift)
1623     keyboard->kmdf.shift->stick = 0;
1624   if (keyboard->kmdf.altgr)
1625     keyboard->kmdf.altgr->stick = 0;
1626 
1627   return 0;
1628 }
1629 
1630 /* set_dead_sticks and clear_dead_sticks deals with the persistence of
1631    the keys that are still affecting other key presses. */
set_dead_sticks(osk_key * key,on_screen_keyboard * keyboard)1632 static void set_dead_sticks(osk_key * key, on_screen_keyboard * keyboard)
1633 {
1634   key->stick = 1;
1635   if (!keyboard->kmdf.dead)
1636     keyboard->kmdf.dead = key;
1637   else if (!keyboard->kmdf.dead2)
1638     keyboard->kmdf.dead2 = key;
1639   else if (!keyboard->kmdf.dead3)
1640     keyboard->kmdf.dead3 = key;
1641   else if (!keyboard->kmdf.dead4)
1642     keyboard->kmdf.dead4 = key;
1643 }
1644 
clear_dead_sticks(on_screen_keyboard * keyboard)1645 static void clear_dead_sticks(on_screen_keyboard * keyboard)
1646 {
1647   if (keyboard->kmdf.dead)
1648     {
1649       keyboard->kmdf.dead->stick = 0;
1650       keyboard->kmdf.dead = NULL;
1651     }
1652   if (keyboard->kmdf.dead2)
1653     {
1654       keyboard->kmdf.dead2->stick = 0;
1655       keyboard->kmdf.dead2 = NULL;
1656     }
1657   if (keyboard->kmdf.dead3)
1658     {
1659       keyboard->kmdf.dead3->stick = 0;
1660       keyboard->kmdf.dead3 = NULL;
1661     }
1662   if (keyboard->kmdf.dead4)
1663     {
1664       keyboard->kmdf.dead4->stick = 0;
1665       keyboard->kmdf.dead4 = NULL;
1666     }
1667 }
1668 
osk_clicked(on_screen_keyboard * keyboard,int x,int y)1669 struct osk_keyboard *osk_clicked(on_screen_keyboard * keyboard, int x, int y)
1670 {
1671   int i;
1672   osk_key *key;
1673   SDL_Event event;
1674   char *keysym, *mnemo;
1675   char *name, *aux_name, *aux_list, *aux_list_ptr;
1676   wchar_t *wkeysym;
1677   wchar_t *ks;
1678   on_screen_keyboard *new_keyboard;
1679 
1680 #ifdef DEBUG
1681   printf("list: %s\n", keyboard->keyboard_list);
1682 #endif
1683 
1684   event.key.keysym.mod = KMOD_NONE;
1685   event.key.keysym.sym = 0;
1686   event.key.keysym.unicode = 0;
1687 
1688   key = find_key(keyboard, x, y);
1689 
1690   if (key)
1691     {
1692       /* First the reserved keycodes */
1693       /* Select next or previous keyboard */
1694       if (key->keycode == 1 || key->keycode == 2)
1695         {
1696           if (keyboard->disable_change)
1697             {
1698               //      free(key);
1699               return (keyboard);
1700             }
1701 
1702           aux_list = strdup(keyboard->keyboard_list);
1703           aux_list_ptr = aux_list;
1704 
1705 #ifdef DEBUG
1706           printf("auxlist: %s\n", aux_list);
1707           printf("kn %s\n", keyboard->name);
1708 #endif
1709 
1710           if (key->keycode == 1)
1711             {
1712               for (i = 0;; i++, aux_list = NULL)
1713                 {
1714                   name = strtok(aux_list, " \n\r\t");
1715 
1716                   if (i == 0)
1717                     aux_name = name;
1718 
1719                   if (strcmp(name, keyboard->name) == 0)
1720                     {
1721                       name = strtok(NULL, " \n\r\t");
1722                       if (name == NULL)
1723                         name = aux_name;
1724                       break;
1725                     }
1726                 }
1727             }
1728           else
1729             {
1730               aux_name = NULL;
1731               for (i = 0;; i++, aux_list = NULL)
1732                 {
1733                   name = strtok(aux_list, " \n\r\t");
1734 
1735                   if (name == NULL)
1736                     {
1737                       name = aux_name;
1738                       break;
1739                     }
1740 
1741                   if (strstr(name, keyboard->name))
1742                     {
1743                       name = aux_name;
1744                       if (name != NULL)
1745                         break;
1746                     }
1747 
1748                   aux_name = name;
1749                 }
1750             }
1751 
1752 
1753           new_keyboard =
1754             osk_create(name, keyboard->canvas_ptr,
1755                        keyboard->LG_button_up, keyboard->LG_button_down,
1756                        keyboard->LG_button_off, keyboard->LG_button_nav,
1757                        keyboard->LG_button_hold,
1758                        keyboard->LG_oskdel, keyboard->LG_osktab,
1759                        keyboard->LG_oskenter, keyboard->LG_oskcapslock,
1760                        keyboard->LG_oskshift,
1761                        keyboard->SM_button_up, keyboard->SM_button_down,
1762                        keyboard->SM_button_off, keyboard->SM_button_nav,
1763                        keyboard->SM_button_hold,
1764                        keyboard->SM_oskdel, keyboard->SM_osktab,
1765                        keyboard->SM_oskenter, keyboard->SM_oskcapslock,
1766                        keyboard->SM_oskshift,
1767                        keyboard->disable_change);
1768 
1769           free(aux_list_ptr);
1770 
1771           if (new_keyboard == NULL)
1772             {
1773               //      free(key);
1774               return (keyboard);        /* Don't break here, at least the old keyboard should work */
1775             }
1776           else
1777             {
1778               free(new_keyboard->keyboard_list);
1779               new_keyboard->keyboard_list = strdup(keyboard->keyboard_list);
1780               //      free(key);
1781               osk_free(keyboard);
1782               return (new_keyboard);
1783             }
1784         }
1785 
1786 
1787       keysym = find_keysym(*key, keyboard);
1788       if (!keysym)
1789         {
1790           return (keyboard);
1791         }
1792 
1793       draw_key(*key, keyboard, 1);
1794 
1795       if (handle_keymods(keysym, key, keyboard))
1796         {
1797           return (keyboard);    /* no more processing is needed */
1798         }
1799 
1800       wkeysym = malloc(sizeof(wchar_t) * (strlen(keysym) + 1));
1801 
1802       mbsrtowcs(wkeysym, (const char **)&keysym, strlen(keysym) + 1, NULL);
1803 
1804 #ifdef DEBUG
1805       printf("wkeysym %ls %i\n\n", wkeysym, (int)wcslen(wkeysym));
1806 #endif
1807 
1808 
1809       get_composed_keysym(keyboard, keyboard->composing, wkeysym);
1810 
1811       if (keyboard->composed)
1812         {
1813           keyboard->last_key_pressed = key;
1814           set_key(NULL, &keyboard->keymodifiers.compose, 0);
1815           ks = keyboard->composed;
1816 
1817 #ifdef DEBUG
1818           printf("keysym found %ls\n", ks);
1819 #endif
1820 
1821           mnemo = malloc(sizeof(char) * 32);
1822           snprintf(mnemo, 31, "%ls", ks);
1823 
1824           if (wcsncmp(L"Return", ks, 6) == 0)
1825             {
1826               event.key.keysym.sym = SDLK_RETURN;
1827               event.key.keysym.unicode = '\r';
1828             }
1829           else if (wcsncmp(L"Tab", ks, 3) == 0 || wcsncmp(L"ISO_Left_Tab", ks, 12) == 0)
1830             {
1831               event.key.keysym.sym = SDLK_TAB;
1832               event.key.keysym.unicode = '\t';
1833             }
1834           else if (wcsncmp(L"BackSpace", ks, 9) == 0)
1835             {
1836               event.key.keysym.sym = SDLK_BACKSPACE;
1837               event.key.keysym.unicode = '\b';
1838             }
1839           else if (wcsncmp(L"NoSymbol", ks, 8) == 0)
1840             return (keyboard);
1841 
1842           else if (keyboard->composed_type == 1)
1843             event.key.keysym.unicode = *keyboard->composed;
1844           else
1845             event.key.keysym.unicode = keysym2unicode(mnemo2keysym(mnemo, keyboard), keyboard);
1846 
1847           clear_dead_sticks(keyboard);
1848           event.type = SDL_KEYDOWN;
1849           SDL_PushEvent(&event);
1850           free(mnemo);
1851         }
1852       else
1853         {
1854           if (keyboard->composing == keyboard->layout->composemap)
1855             {
1856 #ifdef DEBUG
1857               printf("compose sequence resetted\n");
1858 #endif
1859               set_key(NULL, &keyboard->keymodifiers.compose, 0);
1860               keyboard->last_key_pressed = key;
1861               clear_dead_sticks(keyboard);
1862             }
1863           else
1864             {
1865               set_key(key, &keyboard->keymodifiers.compose, 0);
1866 #ifdef DEBUG
1867               printf("still composing\n");
1868 #endif
1869               set_dead_sticks(key, keyboard);
1870               /* Fixme: Would be nice if we can highlight next available-to-compose keys, but how? */
1871             }
1872         }
1873       free(wkeysym);
1874     }
1875 
1876   return (keyboard);
1877 }
1878 
osk_released(on_screen_keyboard * keyboard)1879 void osk_released(on_screen_keyboard * keyboard)
1880 {
1881   osk_key *key;
1882 
1883   key = keyboard->last_key_pressed;
1884   if (key)
1885     {
1886       draw_key(*key, keyboard, 0);
1887       //    free(key);
1888     }
1889   keyboard->last_key_pressed = NULL;
1890   draw_keyboard(keyboard);
1891 }
1892 
1893 
free_keymap(osk_keymap * keymap)1894 static void free_keymap(osk_keymap * keymap)
1895 {
1896   int i;
1897 
1898   for (i = 0; i < 256; i++)
1899     {
1900       if (keymap[i].plain)
1901         free(keymap[i].plain);
1902       if (keymap[i].caps)
1903         free(keymap[i].caps);
1904       if (keymap[i].altgr)
1905         free(keymap[i].altgr);
1906       if (keymap[i].shiftaltgr)
1907         free(keymap[i].shiftaltgr);
1908     }
1909   free(keymap);
1910 }
1911 
free_composemap(osk_composenode * composenode)1912 static void free_composemap(osk_composenode * composenode)
1913 {
1914   int i;
1915 
1916   for (i = 0; i < composenode->size; i++)
1917     {
1918       free_composemap(composenode->childs[i]);
1919       free(composenode->childs[i]);
1920     }
1921   if (composenode->result)
1922     free(composenode->result);
1923   else
1924     free(composenode->childs);
1925 
1926   if (composenode->keysym)
1927     free(composenode->keysym);
1928 }
1929 
free_keysymdefs(keysymdefs * ksd,int size)1930 static void free_keysymdefs(keysymdefs * ksd, int size)
1931 {
1932   int i;
1933 
1934   for (i = 0; i <= size; i++)
1935     free(ksd[i].mnemo);
1936 }
1937 
free_keys(osk_layout * layout)1938 static void free_keys(osk_layout * layout)
1939 {
1940   int i, j;
1941 
1942   for (j = 0; j < layout->height; j++)
1943     {
1944       for (i = 0; i < layout->width; i++)
1945         {
1946           if (layout->keys[j][i].plain_label)
1947             free(layout->keys[j][i].plain_label);
1948           if (layout->keys[j][i].top_label)
1949             free(layout->keys[j][i].top_label);
1950           if (layout->keys[j][i].altgr_label)
1951             free(layout->keys[j][i].altgr_label);
1952           if (layout->keys[j][i].shift_altgr_label)
1953             free(layout->keys[j][i].shift_altgr_label);
1954 
1955         }
1956       free(layout->keys[j]);
1957     }
1958   free(layout->keys);
1959 }
1960 
free_layout(osk_layout * layout)1961 static void free_layout(osk_layout * layout)
1962 {
1963   if (layout->name != NULL)
1964     free(layout->name);
1965   // free(layout->rows);
1966   free(layout->fontpath);
1967   free_keys(layout);
1968   free_keymap(layout->keymap);
1969   free_composemap(layout->composemap);
1970   free(layout->composemap);
1971 
1972   free_keysymdefs(layout->keysymdefs, layout->sizeofkeysymdefs);
1973   free(layout->keysymdefs);
1974   free(layout);
1975 }
1976 
osk_free(on_screen_keyboard * keyboard)1977 void osk_free(on_screen_keyboard * keyboard)
1978 {
1979   free(keyboard->name);
1980   free_layout(keyboard->layout);
1981   if (keyboard->composed)
1982     free(keyboard->composed);
1983   if (keyboard->last_key_pressed)
1984     free(keyboard->last_key_pressed);
1985   if (keyboard->keyboard_list)
1986     free(keyboard->keyboard_list);
1987   SDL_FreeSurface(keyboard->surface);
1988   set_key(NULL, &keyboard->keymodifiers.shift, 0);
1989   set_key(NULL, &keyboard->keymodifiers.altgr, 0);
1990   set_key(NULL, &keyboard->keymodifiers.compose, 0);
1991   set_key(NULL, &keyboard->keymodifiers.dead, 0);
1992   if (keyboard->osk_fonty != NULL)
1993     TTF_CloseFont(keyboard->osk_fonty);
1994 
1995   free(keyboard);
1996 }
1997 
1998 
1999 
2000 /* static void on_screen_keyboardd(void ) */
2001 /* { */
2002 /* 	int i; */
2003 /*     if (key_board != NULL) */
2004 /*         SDL_FreeSurface(key_board); */
2005 
2006 /* 	 key_board = SDL_CreateRGBSurface(canvas->flags, */
2007 /* 				key_width * 19, */
2008 /* 				key_height * 3, */
2009 /* 				canvas->format->BitsPerPixel, */
2010 /* 				canvas->format->Rmask, */
2011 /* 				canvas->format->Gmask, */
2012 /* 				canvas->format->Bmask, 0);	 */
2013 /*   		key_board_color_r = 255; */
2014 /*   		key_board_color_g = 255; */
2015 /*   		key_board_color_b = 255; */
2016 
2017 /*   	  SDL_FillRect(key_board, NULL, SDL_MapRGB(key_board->format, 255, 255, 255)); */
2018 /* 	  if (keybd_position == 0) */
2019 /* 	  { */
2020 /* 			initial_y = 400; */
2021 /* 	  } */
2022 /* 	  else */
2023 /* 	  { */
2024 /* 			initial_y = 5; */
2025 /* 	  } */
2026 /* 	  apply_surface( initial_x, initial_y, key_board, screen, NULL); */
2027 
2028 /* 	  keybd_prepare(); */
2029 
2030 /* 	  for (i = 1; i <= 15 ; i++) */
2031 /* 	  button (i, initial_x + (key_width)*(i-1), initial_y); */
2032 
2033 /* 	  for (i = 1; i <= 19; i++) */
2034 /* 	  button (i+15, initial_x + (key_width)*(i-1), initial_y + key_height); */
2035 
2036 /* 	  for (i = 1; i <= 19; i++) */
2037 /* 	  button (i+34, initial_x + (key_width)*(i-1), initial_y + 2*key_height); */
2038 
2039 /* 	  drawkeybd(); */
2040 
2041 /* 	  keybd_finish(); */
2042 
2043 /* 	  SDL_UpdateRect(screen, 0, 0, 640, 480);     */
2044 
2045 /* 	  /\* SDL_Delay(10); *\/ /\* FIXME: This should not be necessary! -bjk 2011.04.21 *\/ */
2046 
2047 /*       keybd_flag = 1;    */
2048 /* } */
2049 
2050 
2051 
2052 
2053 
2054 
2055 
2056 /* // Check whether current mouse position is within a rectangle */
2057 /* int regionhit(int x, int y, int w, int h) */
2058 /* { */
2059 /*   if (uistate.mousex < x || */
2060 /*     uistate.mousey < y || */
2061 /*     uistate.mousex >= x + w || */
2062 /*     uistate.mousey >= y + h) */
2063 /*     return 0; */
2064 /*   return 1; */
2065 /* } */
2066 
2067 
2068 
2069 
2070 /* void button(int id, int x, int y) */
2071 /* { */
2072 /*   SDL_Rect dest,desti; */
2073 /*   SDL_Surface *tmp_imgup; */
2074 /*   SDL_Event event; */
2075 /*   dest.x = x; */
2076 /*   dest.y = y; */
2077 
2078 /*   // Check whether the button should be hot */
2079 /*   if (regionhit(x, y, 24, 24)) */
2080 /*   { */
2081 /*     uistate.hotitem = id; */
2082 
2083 /* 	if (uistate.activeitem == 0 && uistate.mousedown) */
2084 /* 	{ */
2085 /* 		uistate.activeitem = id; */
2086 /* 		activeflag = 1; */
2087 /* 	} */
2088 /*   } */
2089 
2090 /*   // Render button  */
2091 /*   SDL_BlitSurface(img_btnsm_up, NULL, screen, &dest); */
2092 /*   if (caps_flag % 2 != 0) */
2093 /* 	{ */
2094 /* 		desti.x = initial_x; */
2095 /* 		desti.y = initial_y + key_height; */
2096 /* 		SDL_BlitSurface(img_btnsm_down, NULL, screen, &desti); */
2097 /* 	} */
2098 /*   if (uistate.hotitem == id) */
2099 /*   { */
2100 /*     if (uistate.activeitem == id) */
2101 /*     { */
2102 /*       // Button is both 'hot' and 'active' */
2103 /* 		if (activeflag == 1) */
2104 /* 		{ */
2105 /* 	  		ide = id; */
2106 /* 	  		gen_key_flag = 1; */
2107 /* 			activeflag = 0; */
2108 /* 			uistate.activeitem = 0; */
2109 /* 		} */
2110 /* 	  SDL_BlitSurface(img_btnsm_down, NULL, screen, &dest); */
2111 /*     } */
2112 /*     else */
2113 /*     { */
2114 /*       // Button is merely 'hot' */
2115 /* 	  SDL_BlitSurface(img_btnsm_down, NULL, screen, &dest); */
2116 /*     } */
2117 /*   } */
2118 /*   else */
2119 /*   {	 */
2120 /* 	// button is not hot, but it may be active     */
2121 /* 	SDL_BlitSurface(img_btnsm_up, NULL, screen, &dest); */
2122 /*   } */
2123 
2124 /*   if (gen_key_flag == 1) */
2125 /* 	{ */
2126 /* 		int i,j; */
2127 /* 		gen_key_flag = 0; */
2128 /* 		enter_flag = 0; */
2129 /* 		SDL_EnableUNICODE(1); */
2130 /* //		printf("\n entered here %d th time \n", k); */
2131 /* //		k++; */
2132 /* 		if (ide == 1) */
2133 /* 		{ */
2134 /* 			event.key.keysym.sym = SDLK_ESCAPE; */
2135 /* 			event.key.keysym.mod = KMOD_NONE; */
2136 /* 			event.key.keysym.unicode = 27; */
2137 
2138 /* 		} */
2139 /* 		else if (ide == 2) */
2140 /* 		{ */
2141 /* 			event.key.keysym.sym = SDLK_BACKQUOTE; */
2142 /* 			event.key.keysym.mod = KMOD_NONE; */
2143 /* 			event.key.keysym.unicode = 96; */
2144 /* 		} */
2145 
2146 
2147 //....................................................
2148 
2149 /* 		if (enter_flag == 0)  */
2150 /* 		{ */
2151 
2152                   /* event.key.type=SDL_KEYDOWN; */
2153                   /* SDL_PushEvent(&event); */
2154                   /* event.key.type=SDL_KEYUP; */
2155                   /* SDL_PushEvent(&event); */
2156 
2157 
2158 /* 	}	 */
2159 /* 	} */
2160 /* } */
2161