http://mulliner.org/bluetooth/xkbdbthid-0.1_src.tar.gz
[xkbdbthid.git] / xkbd-0.8.15_bthid / src / kb.c
1 /* 
2    xkbd - xlib based onscreen keyboard.
3
4    Copyright (C) 2001 Matthew Allum
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2, or (at your option)
9    any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 */
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <X11/Xlib.h>
21 #include <X11/Xutil.h>
22 #include <X11/extensions/XTest.h>
23 #include <X11/keysym.h>
24
25 #ifdef USE_XFT
26 #include <X11/Xft/Xft.h>
27 #endif
28 #include "structs.h"
29 #include "kb.h"
30 #include "box.h"
31 #include "button.h"
32
33 #include "libvirtkeys.h"
34
35 #include "hidcd.h"
36
37 #ifdef DEBUG
38 #define DBG(txt, args... ) fprintf(stderr, "DEBUG" txt "\n", ##args )
39 #else
40 #define DBG(txt, args... ) /* nothing */
41 #endif
42
43 #define TRUE  1
44 #define FALSE 0
45
46
47 static Bool
48 load_a_single_font(keyboard *kb, char *fontname )
49 {
50 #ifdef USE_XFT
51   if ((kb->xftfont = XftFontOpenName(kb->display, 
52                                      DefaultScreen(kb->display), 
53                                      fontname)) != NULL)
54     { 
55       return True;
56     }
57 #else
58   if ((kb->font_info = XLoadQueryFont(kb->display, fontname)) != NULL)
59     {
60       XSetFont(kb->display, kb->gc, kb->font_info->fid);
61       return True;
62     }
63 #endif
64   return False;
65 }
66
67 void _kb_load_font(keyboard *kb, char *defstr )
68 {
69   const char delim[] = "|";
70   char *str, *token;
71   
72   if ((strchr(defstr, delim[0]) != NULL))
73     {
74       str = strdup(defstr);
75       while( (token = strsep (&str, delim)) != NULL )
76           if (load_a_single_font(kb, token)) 
77             return;
78     }
79   else
80     {
81       if (load_a_single_font(kb, defstr )) return;
82     }
83
84   fprintf(stderr, "xkbd: unable to find suitable font in '%s'\n", defstr);
85   exit(1);
86 }
87
88 keyboard* kb_new(Window win, Display *display, int kb_x, int kb_y,
89                  int kb_width, int kb_height, char *conf_file, 
90                  char *font_name, int font_is_xft)
91 {
92   keyboard *kb = NULL;
93
94   list *listp;
95   
96   int max_width = 0; /* required for sizing code */
97   //int cy = 0;        /* ditto                    */
98   
99   FILE *rcfp;
100   char rcbuf[255];              /* buffer for conf file */
101   char *tp;                     /* tmp pointer */
102
103   char tmpstr_A[128];
104   char tmpstr_C[128];
105
106   box *tmp_box = NULL;
107   button *tmp_but = NULL;
108   int line_no = 0;
109   enum { none, kbddef, rowdef, keydef } context;  
110    
111   int font_loaded = 0;
112   Colormap cmp;
113   int max_single_char_width = 0;
114   int max_single_char_height = 0;
115   int j;
116
117 #ifdef USE_XFT
118   XRenderColor colortmp;
119 #endif
120
121   kb = malloc(sizeof(keyboard));
122   kb->win = win;
123   kb->display = display;
124
125   cmp = DefaultColormap(display, DefaultScreen(display));
126
127   /* create lots and lots of gc's */ 
128   kb->gc = _createGC(display, win);
129   XSetForeground(display, kb->gc, 
130                  BlackPixel(display, DefaultScreen(display) ));
131   XSetBackground(display, kb->gc, 
132                  WhitePixel(display, DefaultScreen(display) ));
133
134   kb->rev_gc = _createGC(display, win);
135   XSetForeground(display, kb->rev_gc, 
136                  WhitePixel(display, DefaultScreen(display) ));
137   XSetBackground(display, kb->rev_gc, 
138                  BlackPixel(display, DefaultScreen(display) ));
139
140   kb->txt_gc = _createGC(display, win);
141   XSetForeground(display, kb->txt_gc, 
142                  BlackPixel(display, DefaultScreen(display) ));
143   XSetBackground(display, kb->txt_gc, 
144                  WhitePixel(display, DefaultScreen(display) ));
145
146   kb->txt_rev_gc = _createGC(display, win);
147   XSetForeground(display, kb->txt_rev_gc, 
148                  WhitePixel(display, DefaultScreen(display) ));
149   XSetBackground(display, kb->rev_gc, 
150                  BlackPixel(display, DefaultScreen(display) ));
151
152   kb->bdr_gc = _createGC(display, win);
153   XSetForeground(display, kb->bdr_gc, 
154                  BlackPixel(display, DefaultScreen(display) ));
155   XSetBackground(display, kb->bdr_gc, 
156                  WhitePixel(display, DefaultScreen(display) ));
157
158 #ifdef USE_XFT
159   kb->render_type = xft;
160 #else
161   kb->render_type = oldskool;
162 #endif
163   if (font_name != NULL)
164     {
165       if (font_is_xft)
166       {
167          kb->render_type = xft;
168       }
169       _kb_load_font(kb, font_name );
170       font_loaded = 1;
171     } 
172
173 #ifdef USE_XFT
174
175   /* -- xft bits -------------------------------------------- */
176
177   colortmp.red   = 0xFFFF;
178   colortmp.green = 0xFFFF;
179   colortmp.blue  = 0xFFFF;
180   colortmp.alpha = 0xFFFF;
181   XftColorAllocValue(display,
182                      DefaultVisual(display, DefaultScreen(display)), 
183                      DefaultColormap(display,DefaultScreen(display)),
184                      &colortmp,
185                      &kb->color_bg);
186   
187   colortmp.red   = 0x0000;
188   colortmp.green = 0x0000;
189   colortmp.blue  = 0x0000;
190   colortmp.alpha = 0xFFFF;          
191   XftColorAllocValue(display,
192                      DefaultVisual(display, DefaultScreen(display)), 
193                      DefaultColormap(display,DefaultScreen(display)),
194                      &colortmp,
195                      &kb->color_fg);
196
197   /* --- end xft bits -------------------------- */
198
199   kb->xftdraw = NULL;
200 #endif
201
202   /* Defaults */
203   kb->state            = KB_STATE_NORMAL;
204   kb->state_locked     = KB_STATE_NORMAL;
205   kb->theme            = rounded;
206   kb->slide_margin     = 0;
207   kb->key_delay_repeat = 10;
208   kb->key_repeat       = 5;
209   
210   kb->total_layouts = 0;
211
212
213   kb->backing = 0;
214
215   if ((rcfp = fopen(conf_file, "r")) == NULL)
216     { 
217       fprintf(stderr, "xkbd: Cant open conf file: %s\n", conf_file);
218       exit(1);
219     }
220     
221   context = none;
222     
223   while(fgets(rcbuf, sizeof(rcbuf), rcfp) != NULL)
224     {
225       tp = &rcbuf[0];
226       
227       /* strip init spaces */
228       while(*tp == ' ' || *tp == '\t') tp++;
229       
230       /* ignore comments and blank lines */
231       if (*tp == '\n' || *tp == '#') { DBG("Config: got hash\n"); continue; }
232       
233       if (*tp == '<') /* a 'tag' - set the context */
234         {
235           if (*(tp+1) == '/') /* closing tag */
236             { 
237               switch (context) {
238                 case kbddef:
239                   if (!font_loaded)
240                     _kb_load_font(kb, "fixed" );
241                   break;
242                 case rowdef:
243                   
244                   break;
245                 case keydef:
246                   button_calc_c_width(tmp_but);
247                   button_calc_c_height(tmp_but);
248                   break;
249                 case none:
250                   break;
251               }
252               context = none; 
253               continue; 
254             }
255           if (sscanf(tp, "<%s", tmpstr_A) == 1)  /* get tag name */
256             {
257               if (strncmp(tmpstr_A, "global", 5) == 0)
258                 {
259                   context=kbddef;
260                   continue;
261                 }
262               if (strncmp(tmpstr_A, "layout", 6) == 0)
263                 {
264                   kb->total_layouts++;
265                   kb->kbd_layouts[kb->total_layouts-1] = box_new();
266                   kb->vbox = kb->kbd_layouts[kb->total_layouts-1];
267                   kb->vbox->act_width  = kb_width;
268                   kb->vbox->act_height = kb_height;
269                   kb->vbox->min_height = 0;
270                   kb->vbox->min_width = 0;
271                   kb->vbox->x = kb_x;
272                   kb->vbox->y = kb_y;
273                   continue;
274                 }
275               if (strncmp(tmpstr_A, "row", 3) == 0)
276                 {
277                   if (kb->total_layouts == 0)
278                     {
279                       /* 
280                          Minor Kludge :-)
281                          So older configs work we can work with
282                          out a <layout> tag 
283                       */
284                       kb->total_layouts++;
285                       kb->kbd_layouts[kb->total_layouts-1] = box_new();
286                       kb->vbox = kb->kbd_layouts[kb->total_layouts-1];
287                       kb->vbox->act_width  = kb_width;
288                       kb->vbox->act_height = kb_height;
289                       kb->vbox->min_height = 0;
290                       kb->vbox->min_width = 0;
291                       kb->vbox->x = kb_x;
292                       kb->vbox->y = kb_y;
293                     }
294                   context=rowdef;
295                   tmp_box = box_add_box(kb->vbox, box_new());
296                   
297                   continue;
298                 }
299               if (strncmp(tmpstr_A, "key", 3) == 0)
300                 {
301                   /* check here for NULL tmp_button */
302                   tmp_but = box_add_button(tmp_box, button_new(kb) );
303                   context=keydef;
304                   continue;
305                 }
306               
307             } else {
308               fprintf(stderr,"Config file parse failed (tag) at line: %i\n",
309                       line_no);
310               exit(1);
311             }
312         }
313       else             /* a key=value setting */
314         {
315           if (sscanf(tp, "%s %s", tmpstr_A,tmpstr_C) == 2) {
316             
317             switch (context) {
318               case none:
319                 break;
320               case kbddef: /* 
321                 if (strcmp(tmpstr_A, "render") == 0)
322                   {
323                     if ((strncmp(tmpstr_C, "xft", 3) == 0)
324                         && !font_loaded)
325                       {
326                         kb->render_type = xft;
327                       }
328                   }
329                 else 
330                            */
331                 if ((strcmp(tmpstr_A, "font") == 0)
332                          && !font_loaded)
333                   {
334                      _kb_load_font(kb,tmpstr_C );
335                      font_loaded=1;
336                   }
337                 else if (strcmp(tmpstr_A, "button_style") == 0)
338                   {
339                     if (strcmp(tmpstr_C, "square") == 0)
340                       kb->theme = square;
341                     else if (strcmp(tmpstr_C, "plain") == 0)
342                       kb->theme = plain;
343                   }
344                 else if (strcmp(tmpstr_A, "col") == 0)
345                   {
346                     XColor col;
347                     if (_XColorFromStr(kb->display, &col, tmpstr_C) == 0)
348                       {
349                         perror("color allocation failed\n"); exit(1);
350                       }
351                     XSetForeground(kb->display, kb->rev_gc, col.pixel );
352                   }
353                 else if (strcmp(tmpstr_A, "border_col") == 0)
354                   {
355                     XColor col;
356                     if (_XColorFromStr(kb->display, &col, tmpstr_C) == 0)
357                       {
358                         perror("color allocation failed\n"); exit(1);
359                       }
360                     XSetForeground(kb->display, kb->bdr_gc, col.pixel );
361                   }
362                 else if (strcmp(tmpstr_A, "down_col") == 0)
363                   {
364                     XColor col;
365                     if (_XColorFromStr(kb->display, &col, tmpstr_C) == 0)
366                       {
367                         perror("color allocation failed\n"); exit(1);
368                       }
369                     XSetForeground(kb->display, kb->gc, col.pixel );
370                   }
371                 else if (strcmp(tmpstr_A, "width") == 0)
372                   {
373                     /* TODO fix! seg's as kb->vbox does not yet exist 
374                      if (!kb->vbox->act_width) 
375                         kb->vbox->act_width = atoi(tmpstr_C);
376                     */
377                   }
378                 else if (strcmp(tmpstr_A, "height") == 0)
379                   {
380                     /* TODO fix! seg's as kb->vbox does not yet exist 
381                      if (!kb->vbox->act_height) 
382                         kb->vbox->act_height = atoi(tmpstr_C);
383                     */
384                   }
385                 else if (strcmp(tmpstr_A, "slide_margin") == 0)
386                   {
387                      kb->slide_margin = atoi(tmpstr_C);
388                   }
389                 else if (strcmp(tmpstr_A, "repeat_delay") == 0)
390                   {
391                      kb->key_delay_repeat = atoi(tmpstr_C);
392                   }
393                 else if (strcmp(tmpstr_A, "repeat_time") == 0)
394                   {
395                      kb->key_repeat = atoi(tmpstr_C);
396                   }
397
398                 else if (strcmp(tmpstr_A, "txt_col") == 0)
399                   {
400                     XColor col;
401                     if (_XColorFromStr(kb->display, &col, tmpstr_C) == 0)
402                       {
403                         perror("color allocation failed\n"); exit(1);
404                       }
405 #ifdef USE_XFT          
406                     if (kb->render_type == oldskool)
407                       {
408 #endif
409                         XSetForeground(kb->display, kb->txt_gc, col.pixel );
410 #ifdef USE_XFT          
411                       }
412                     else
413                       {
414                         
415                         colortmp.red   = col.red;
416                         colortmp.green = col.green;
417                         colortmp.blue  = col.blue;
418                         colortmp.alpha = 0xFFFF;          
419                         XftColorAllocValue(display,
420                                            DefaultVisual(display, 
421                                                       DefaultScreen(display)), 
422                                            DefaultColormap(display,
423                                                       DefaultScreen(display)),
424                                            &colortmp,
425                                            &kb->color_fg);
426                       }
427 #endif
428                   }
429
430                 break;
431               case rowdef: /* no rowdefs as yet */
432                 break;
433               case keydef:
434                 if (strcmp(tmpstr_A, "default") == 0)
435                   button_set_txt(tmp_but, tmpstr_C);
436                 else if (strcmp(tmpstr_A, "shift") == 0)
437                   button_set_shift_txt(tmp_but, tmpstr_C);
438                 else if (strcmp(tmpstr_A, "switch") == 0)
439                   button_set_layout(tmp_but, tmpstr_C);
440                 else if (strcmp(tmpstr_A, "mod") == 0)
441                   button_set_mod_txt(tmp_but, tmpstr_C); 
442                 else if (strcmp(tmpstr_A, "default_ks") == 0)
443                   button_set_txt_ks(tmp_but, tmpstr_C);
444                 else if (strcmp(tmpstr_A, "shift_ks") == 0)
445                   button_set_shift_ks(tmp_but, tmpstr_C);
446                 else if (strcmp(tmpstr_A, "mod_ks") == 0)
447                   button_set_mod_ks(tmp_but, tmpstr_C); 
448 #ifdef USE_XPM
449                 else if (strcmp(tmpstr_A, "img") == 0)
450                   { button_set_pixmap(tmp_but, tmpstr_C); }
451 #endif
452                 else if (strcmp(tmpstr_A, "bg") == 0)
453                   { button_set_bg_col(tmp_but, tmpstr_C); }
454                 else if (strcmp(tmpstr_A, "fg") == 0)
455                   { button_set_fg_col(tmp_but, tmpstr_C); }
456                 else if (strcmp(tmpstr_A, "slide_up_ks") == 0)
457                   button_set_slide_ks(tmp_but, tmpstr_C, UP);
458                 else if (strcmp(tmpstr_A, "slide_down_ks") == 0)
459                   button_set_slide_ks(tmp_but, tmpstr_C, DOWN);
460                 else if (strcmp(tmpstr_A, "slide_left_ks") == 0)
461                   button_set_slide_ks(tmp_but, tmpstr_C, LEFT);
462                 else if (strcmp(tmpstr_A, "slide_right_ks") == 0)
463                   button_set_slide_ks(tmp_but, tmpstr_C, RIGHT);
464                 else if (strcmp(tmpstr_A, "scancode") == 0)
465                   button_set_scancode(tmp_but, tmpstr_C);
466                 else if (strcmp(tmpstr_A, "width") == 0)
467                 {
468                    tmp_but->is_width_spec = True;
469                     tmp_but->c_width = atoi(tmpstr_C);
470                 }
471                 else if (strcmp(tmpstr_A, "key_span_width") == 0)
472                 {
473                    tmp_but->is_width_spec = True;
474                    tmp_but->key_span_width = atoi(tmpstr_C);
475                 }
476
477                 else if (strcmp(tmpstr_A, "height") == 0)
478                   tmp_but->c_height = atoi(tmpstr_C);
479                 else if (strcmp(tmpstr_A, "obey_capslock") == 0)
480                 {
481                   if (strcmp(tmpstr_C, "yes") == 0)
482                     tmp_but->options |= OPT_OBEYCAPS;
483                   else if (strcmp(tmpstr_C, "no") == 0)
484                     tmp_but->options &= ~OPT_OBEYCAPS;
485                   else
486                   {
487                     perror("invalid value for obey_capslock\n"); exit(1);
488                   }
489                 }
490                 break;
491             }
492             
493           } else {
494              fprintf(stderr,"Config file parse failed at line: %i\n",
495                      line_no);
496              exit(1);
497           } 
498         }
499       line_no++;
500     }
501
502   fclose(rcfp);
503
504   kb->vbox = kb->kbd_layouts[0];
505
506   /* pass 1 - calculate min dimentions  */
507   
508   listp = kb->vbox->root_kid;
509
510
511   /* find the max single char width */
512   
513   while (listp != NULL)
514     {
515       list *ip;
516       tmp_box = (box *)listp->data;
517       ip = tmp_box->root_kid;
518
519       while (ip != NULL)
520         {
521            button *b;
522            b = (button *)ip->data;
523            if (b->is_width_spec  == False)
524            {
525               if ( ( b->default_txt == NULL || (strlen(b->default_txt) == 1))
526                    && (b->shift_txt == NULL || (strlen(b->shift_txt) == 1))
527                    && (b->mod_txt == NULL || (strlen(b->mod_txt) == 1))
528                      && b->pixmap == NULL
529                    )
530               {
531                  if (b->c_width > max_single_char_width)
532                     max_single_char_width = b->c_width;
533
534               }
535               if (b->c_height > max_single_char_height)
536                  max_single_char_height = b->c_height;
537
538            }
539
540           ip = ip->next;
541         }
542       listp = listp->next;
543     }
544
545   /* Set all single char widths to the max one, figure out minimum sizes */
546
547   max_single_char_height += 2;
548
549   for(j=0;j<kb->total_layouts;j++)
550     {
551       kb->vbox = kb->kbd_layouts[j];
552       listp = kb->vbox->root_kid;
553   
554       while (listp != NULL)
555         {
556           list *ip;
557           int tmp_width = 0;
558           int tmp_height = 0;
559           int max_height = 0;
560        
561           tmp_box = (box *)listp->data;
562           ip = tmp_box->root_kid;
563           
564           while (ip != NULL)
565             {
566               button *b;
567               b = (button *)ip->data;
568               if (!b->is_width_spec)
569                 {
570                   if ((b->default_txt == NULL || (strlen(b->default_txt) == 1))
571                       && (b->shift_txt == NULL || (strlen(b->shift_txt) == 1))
572                       && (b->mod_txt == NULL || (strlen(b->mod_txt) == 1))
573                       && b->pixmap == NULL )
574                     {
575                       b->c_width = max_single_char_width;
576                     }
577                 }
578               b->c_height = max_single_char_height;
579               //printf("width is %i\n", b->c_width);
580               if (b->key_span_width)
581                 b->c_width = b->key_span_width * max_single_char_width;
582               
583               tmp_width += ( ((button *)ip->data)->c_width + 
584                              (((button *)ip->data)->b_size*2) );
585               tmp_height = ( ((button *)ip->data)->c_height + 
586                              (((button *)ip->data)->b_size*2));
587               if (tmp_height >= max_height) max_height = tmp_height;
588               ip = ip->next;
589             }
590           if (tmp_width > max_width) max_width = tmp_width;
591           if (tmp_height >= max_height) max_height = tmp_height;
592           tmp_box->min_width  = tmp_width;
593           tmp_box->min_height = max_height;
594           kb->vbox->min_height += max_height; // +1;
595
596
597
598           listp = listp->next;
599         }
600           if ((j > 0) && kb->vbox->min_height > kb->kbd_layouts[0]->min_height)
601             kb->kbd_layouts[0]->min_height = kb->vbox->min_height;
602
603       kb->vbox->min_width = max_width;
604     }
605   
606   /* TODO: copy all temp vboxs  */
607
608
609   kb->vbox = kb->kbd_layouts[0];
610   //setupKeyboardVariables(kb->display);
611   
612   return kb;
613   
614 }
615
616 void kb_size(keyboard *kb)
617 {
618
619    /* let the fun begin :) */
620    list *listp;
621    int cy = 0;
622    box *tmp_box = NULL;
623    
624    if ( kb->vbox->act_width == 0)
625       kb->vbox->act_width = kb->vbox->min_width ; /* by default add a 
626                                                      little to this on init */ 
627    if ( kb->vbox->act_height == 0)
628       kb->vbox->act_height = kb->vbox->min_height ;
629    
630    if (kb->backing != None)
631       XFreePixmap(kb->display, kb->backing);
632    
633    kb->backing = XCreatePixmap(kb->display, kb->win, 
634                                kb->vbox->act_width, kb->vbox->act_height, 
635                                DefaultDepth(kb->display,
636                                             DefaultScreen(kb->display)) );
637    
638    XFillRectangle(kb->display, kb->backing, 
639                   kb->rev_gc, 0, 0, 
640                   kb->vbox->act_width, kb->vbox->act_height);
641
642 #ifdef USE_XFT             
643    if (kb->xftdraw != NULL) XftDrawDestroy(kb->xftdraw);
644
645
646    kb->xftdraw = XftDrawCreate(kb->display, (Drawable) kb->backing, 
647                                DefaultVisual(kb->display,
648                                              DefaultScreen(kb->display)), 
649                                DefaultColormap(kb->display,
650                                                DefaultScreen(kb->display)));
651 #endif
652
653
654   listp = kb->vbox->root_kid;
655   while (listp != NULL)
656     {
657       list *ip;
658       int cx = 0;
659       //int total = 0;
660       int y_pad = 0;
661       button *tmp_but = NULL;
662       tmp_box = (box *)listp->data;
663       tmp_box->y = cy;
664       tmp_box->x = 0;
665       ip = tmp_box->root_kid;
666       y_pad =  (int)( 
667                      ( (float)(tmp_box->min_height)/kb->vbox->min_height ) 
668                      * kb->vbox->act_height ); 
669
670       
671       while (ip != NULL)
672         {
673           int but_total_width;
674
675           tmp_but = (button *)ip->data;
676
677           tmp_but->x = cx; /*remember relative to holding box ! */
678
679           but_total_width = tmp_but->c_width+(2*tmp_but->b_size);
680
681           tmp_but->x_pad = (int)(((float)but_total_width/tmp_box->min_width)
682             * kb->vbox->act_width);
683
684           tmp_but->x_pad -= but_total_width;
685
686           tmp_but->act_width = tmp_but->c_width + tmp_but->x_pad 
687                                + (2*tmp_but->b_size);
688
689           cx += (tmp_but->act_width );
690
691           tmp_but->y = 0;
692           tmp_but->y_pad = y_pad - tmp_but->c_height - (2*tmp_but->b_size);
693           tmp_but->act_height = y_pad;
694           ip = ip->next;
695
696           /*  hack for using all screen space */
697           if (listp->next == NULL) tmp_but->act_height--; 
698
699         }
700       
701       /*  another hack for using up all space */
702       tmp_but->x_pad += (kb->vbox->act_width-cx) -1 ;
703       tmp_but->act_width += (kb->vbox->act_width-cx) -1;
704
705       cy += y_pad ; //+ 1;    
706       tmp_box->act_height = y_pad;
707       tmp_box->act_width = kb->vbox->act_width;
708       
709       listp = listp->next;
710
711     }
712
713 }
714
715 void 
716 kb_switch_layout(keyboard *kb, int kbd_layout_num)
717 {
718   int w = kb->vbox->act_width; 
719   int h = kb->vbox->act_height;
720   int mw = kb->vbox->min_width; 
721   int mh = kb->vbox->min_height;
722
723   kb->vbox = kb->kbd_layouts[kbd_layout_num];
724
725   kb->vbox->act_width = w; 
726   kb->vbox->act_height = h;
727   kb->vbox->min_width = mw; 
728   kb->vbox->min_height = mh;
729   
730   kb_size(kb);
731   kb_render(kb);
732   kb_paint(kb);
733 }
734
735 void kb_render(keyboard *kb)
736 {
737   list *listp;
738   box *tmp_box = NULL;
739   
740   listp = kb->vbox->root_kid;
741   while (listp != NULL)
742     {
743       list *ip;
744       
745       button *tmp_but = NULL;
746       tmp_box = (box *)listp->data;
747       
748       ip = tmp_box->root_kid;
749       
750       while (ip != NULL)
751         {
752           tmp_but = (button *)ip->data;
753           if (tmp_but->modifier & kb->state_locked)
754             {
755
756               button_render(tmp_but, BUTTON_LOCKED);
757             }
758           else if (tmp_but->modifier & kb->state)
759             {
760
761               button_render(tmp_but, BUTTON_PRESSED);
762             } else {
763
764               button_render(tmp_but, BUTTON_RELEASED);
765             }
766           ip = ip->next;
767         }
768       listp = listp->next;
769     }
770 }
771
772 void kb_paint(keyboard *kb)
773 {
774   XCopyArea(kb->display, kb->backing, kb->win, kb->gc, 
775             0, 0, kb->vbox->act_width, kb->vbox->act_height, 
776             kb->vbox->x, kb->vbox->y);
777 }
778
779 button *kb_handle_events(keyboard *kb, XEvent an_event) 
780 {
781   static button *active_but;
782   
783   switch (an_event.type) 
784     {
785       case ButtonPress:
786         active_but = kb_find_button(kb, 
787                                     an_event.xmotion.x, 
788                                     an_event.xmotion.y );
789         if (active_but != NULL)
790           {
791             button_render(active_but, BUTTON_PRESSED);
792             button_paint(active_but);
793             /* process state here 
794                send keypress via kbd state 
795             */
796
797             bthid_process_keypress(active_but, 1);
798           }
799         break;
800       case ButtonRelease:
801         if (active_but != NULL)
802           {
803             int new_state;
804             
805             kb_set_slide(active_but, an_event.xmotion.x, 
806                          an_event.xmotion.y );
807
808             new_state = bthid_process_keypress(active_but, 0);
809             //new_state = kb_process_keypress(active_but);
810
811             if (new_state != active_but->kb->state ||
812                 new_state & active_but->modifier)
813               {
814                 /* if the states changed repaint the entire kbd
815                    as its chars have probably changed */
816                 
817                 active_but->kb->state = new_state;
818                 kb_render(active_but->kb);
819                 kb_paint(active_but->kb);
820               } else {
821                 button_render(active_but, BUTTON_RELEASED);
822                 button_paint(active_but);
823               }
824             /* check for slide */
825
826             active_but->slide = none;
827
828             if (active_but->layout_switch > -1)
829               {
830                 DBG("switching layout\n");
831                 kb_switch_layout(active_but->kb, active_but->layout_switch);
832               }
833             
834             active_but = NULL;
835           }
836         break;
837     }    
838
839   return active_but;
840 }
841
842 void kb_set_slide(button *active_but, int x, int y)
843 {
844   if (x < (button_get_abs_x(active_but)-active_but->kb->slide_margin))
845     { active_but->slide = left; return; }
846
847   if (x > ( button_get_abs_x(active_but)
848             + active_but->act_width + -active_but->kb->slide_margin ))
849     { active_but->slide = right; return; }
850
851   if (y < (button_get_abs_y(active_but)-active_but->kb->slide_margin))
852     { active_but->slide = up; return; }
853
854   if (y > ( button_get_abs_y(active_but) + active_but->act_height )
855       + -active_but->kb->slide_margin )
856     { active_but->slide = down; return; }
857
858
859 }
860
861 void kb_do_repeat(keyboard *kb, button *active_but)
862 {
863   static int timer;
864   static Bool delay;
865   if (active_but == NULL) 
866     {
867       timer = 0; 
868       delay = False;
869       return; /* reset everything */
870     }
871   timer++;
872   if ((delay && timer == kb->key_repeat)
873       || (!delay && timer == kb->key_delay_repeat))
874     {
875       //kb_process_keypress(active_but);
876                         bthid_process_keypress(active_but, 2);
877       timer = 0;
878       delay = True;
879     }
880 }
881
882 int kb_process_keypress(button *active_but)
883 {
884   /* holder for new keyboard state */
885   int new_state = active_but->kb->state;
886   
887   DBG("got release state %i %i %i %i \n", 
888       new_state, KB_STATE_SHIFT, KB_STATE_MOD, KB_STATE_CTRL );
889   
890
891   if  (active_but->modifier/* is a shift / ctrl / mod pressed */
892        && !(active_but->modifier & BUT_CAPS) ) 
893     {
894       if (active_but->kb->state_locked & active_but->modifier)
895         {
896           /* was locked then unset & unlock */
897           active_but->kb->state_locked ^= active_but->modifier;
898           new_state ^= active_but->modifier;
899         }
900       else if (new_state & active_but->modifier)
901         {
902           /* was set then lock */
903           active_but->kb->state_locked ^= active_but->modifier;
904         }
905       else
906         {
907           /* was unset then set */
908           new_state ^= active_but->modifier;
909         }
910       DBG("got a modifier key - %i \n", new_state);
911     } 
912   else if (active_but->modifier & BUT_CAPS)
913     /* deal with caps key - maybe this can go above now ?*/
914     {
915       new_state ^= KB_STATE_CAPS; /* turn caps on/off */
916       DBG("got caps key - %i \n", new_state);
917     }
918   else if (    (active_but->kb->state & KB_STATE_SHIFT)
919                || (active_but->kb->state & KB_STATE_MOD)
920                || (active_but->kb->state & KB_STATE_CTRL)
921                || (active_but->kb->state & KB_STATE_META)
922                || (active_but->kb->state & KB_STATE_ALT) )
923     /* check if the kbd is already in a state and reset it
924        leaving caps key state alone */
925     {
926       new_state &= KB_STATE_CAPS;
927       new_state |= active_but->kb->state_locked;
928       DBG("kbd is shifted, unshifting - %i \n", new_state);
929     }
930   
931   kb_send_keypress(active_but);
932   DBG("%s clicked \n", active_but->default_txt);
933   
934   return new_state;
935 }
936
937 int kb_find_keycode(keyboard *kb, KeySym keysym, 
938                     KeyCode *code_ret, int *col_ret)
939 { /* Thanks carl ! */
940   int col;
941   int keycode;
942   KeySym k;
943   int min_kc, max_kc;
944
945   XDisplayKeycodes(kb->display, &min_kc, &max_kc);
946
947   for (keycode = min_kc; keycode <= max_kc; keycode++) {
948     for (col = 0; (k = XKeycodeToKeysym (kb->display, keycode, col)) 
949            != NoSymbol; col++)
950       if (k == keysym) {
951         *code_ret = keycode;
952         if (col_ret) *col_ret = col;
953         return 1;
954       }
955   }
956   return 0;
957 }
958
959
960 void kb_send_keypress(button *b)
961 {
962   KeySym ks = 0;  
963   int slide_flag = 0;
964
965   struct keycodeEntry vk_keycodes[10];
966
967   if (b->kb->state & KB_STATE_SHIFT || b->kb->state & KB_STATE_CAPS)
968   {
969     if (b->kb->state & KB_STATE_SHIFT && b->kb->state & KB_STATE_CAPS)
970       {
971         if (b->options & OPT_OBEYCAPS)
972           ks = b->default_ks;
973         else 
974           ks = b->shift_ks;
975       }
976     else if (b->kb->state & KB_STATE_CAPS)
977       {
978         if (b->options & OPT_OBEYCAPS)
979           ks = b->shift_ks;
980       } else ks = b->shift_ks;
981   }
982   else if (b->kb->state & KB_STATE_MOD)
983     ks = b->mod_ks;
984
985   if (b->slide != none)
986     {
987       switch (b->slide)
988         {
989           case up :
990             ks = b->slide_up_ks;
991             if (ks == 0) ks = b->shift_ks;
992             break;
993           case down : /* hold ctrl */
994             ks = b->slide_down_ks;
995             if (ks == 0) slide_flag = KB_STATE_CTRL;
996             break;
997           case left : /* hold alt */
998             ks = b->slide_left_ks;
999             if (ks == 0) 
1000               {
1001                 ks = b->mod_ks;
1002                 slide_flag = KB_STATE_MOD;
1003               }
1004             break;
1005           case right : /* hold alt */
1006             ks = b->slide_right_ks;
1007             break;
1008           case none:
1009             break;
1010         }
1011     }
1012
1013   if (ks == 0) ks = b->default_ks;
1014
1015   if (ks == 0) return; /* no keysym defined, abort */
1016 /*
1017   if (lookupKeyCodeSequence(ks, vk_keycodes, NULL))
1018      sendKeySequence(vk_keycodes,
1019           ( (b->kb->state & KB_STATE_CTRL)  || (slide_flag == KB_STATE_CTRL) ),
1020           ( (b->kb->state & KB_STATE_META)  || (slide_flag == KB_STATE_META) ),
1021           ( (b->kb->state & KB_STATE_ALT)   || (slide_flag == KB_STATE_ALT)  ),
1022                      0 */ /* ( (b->kb->state & KB_STATE_SHIFT) || (slide_flag == KB_STATE_SHIFT) ) */
1023 /*                );
1024 */
1025 }
1026
1027
1028
1029 button * kb_find_button(keyboard *kb, int x, int y)
1030 {
1031   list *listp;
1032   box *tmp_box = NULL;
1033   int offset_x, offset_y;
1034
1035   offset_x = kb->vbox->x;
1036   offset_y = kb->vbox->y;
1037
1038   if (x >= offset_x &&
1039       y >= offset_y &&
1040       x <= (offset_x+kb->vbox->act_width) &&
1041       y <= (offset_y+kb->vbox->act_height) )
1042     {
1043       listp = kb->vbox->root_kid;
1044       while (listp != NULL)
1045         {
1046           list *ip;
1047           
1048           button *tmp_but = NULL;
1049           tmp_box = (box *)listp->data;
1050           if (y > (offset_y + tmp_box->y) && 
1051               y < (offset_y + tmp_box->y + tmp_box->act_height))
1052             {
1053               ip = tmp_box->root_kid;
1054               while (ip != NULL) /* now the row is found, find the key */
1055                 {
1056                   tmp_but = (button *)ip->data;
1057                   if (x > (tmp_but->x+offset_x+tmp_box->x) &&
1058                       x < (tmp_but->x+offset_x+tmp_box->x+tmp_but->act_width) &&
1059                       y > (tmp_but->y+offset_y+tmp_box->y) &&
1060                       y < (tmp_but->y+offset_y+tmp_box->y+tmp_but->act_height)
1061                       )
1062                     {
1063                       return tmp_but;
1064                     }
1065                   
1066                   ip = ip->next;
1067                 }
1068             }
1069           listp = listp->next;
1070         }
1071     }
1072   return NULL;
1073     
1074 }
1075
1076 void kb_destroy(keyboard *kb)
1077 {
1078   XFreeGC(kb->display, kb->gc);
1079   /* -- to do -- somwthing like this
1080   while (listp != NULL)
1081     {
1082     
1083       
1084       button *tmp_but = NULL;
1085       tmp_box = (box *)listp->data;
1086       box_destroy(tmp_box) -- this will destroy the buttons
1087     
1088     }
1089   */
1090
1091   free(kb);
1092 }
1093
1094
1095
1096
1097
1098
1099
1100
1101