]> git.lizzy.rs Git - plan9front.git/blob - sys/src/libcontrol/keyboard.c
fix fuckup
[plan9front.git] / sys / src / libcontrol / keyboard.c
1 #include <u.h>
2 #include <libc.h>
3 #include <draw.h>
4 #include <thread.h>
5 #include <mouse.h>
6 #include <keyboard.h>
7 #include <control.h>
8
9 typedef struct Keyboard Keyboard;
10
11 enum{
12         SRegular        = 0,
13         SShift  = 1,
14         SCaps   = 2,
15         SMask   = 3,
16         Nstate  = 4,
17         SControl        = 4,
18 };
19
20 struct Keyboard
21 {
22         Control;
23         CImage  *image;
24         CImage  *mask;
25         CImage  *light;
26         CImage  *textcolor;
27         CImage  *bordercolor;
28         CFont   *font;
29         CFont   *ctlfont;
30         Image   *im[Nstate];
31         int             border;
32         int             lastbut;
33         int             state;
34         char            *key;
35 };
36
37 enum{
38         EBorder,
39         EBordercolor,
40         EFocus,
41         EFont,
42         EFormat,
43         EHide,
44         EImage,
45         ELight,
46         EMask,
47         ERect,
48         EReveal,
49         EShow,
50         ESize,
51 };
52
53 static char *cmds[] = {
54         [EBorder] =     "border",
55         [EBordercolor] = "bordercolor",
56         [EFocus] =      "focus",
57         [EFont] =               "font",
58         [EFormat] =     "format",
59         [EHide] =               "hide",
60         [EImage] =      "image",
61         [ELight] =              "light",
62         [EMask] =               "mask",
63         [ERect] =               "rect",
64         [EReveal] =     "reveal",
65         [EShow] =               "show",
66         [ESize] =               "size",
67         nil
68 };
69
70 enum
71 {
72         Nrow = 5
73 };
74
75 static uchar wid [Nrow][16] = {
76         {16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 30, },
77         {24, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 24, },
78         {32, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, },
79         {40, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, },
80         {30, 30, 80, 40, 42, 24, },
81 };
82
83 static char *keyregular[Nrow] = {
84         "`\0001\0002\0003\0004\0005\0006\0007\0008\0009\0000\0-\0=\0\\\0<-\0\0",
85         "->\0q\0w\0e\0r\0t\0y\0u\0i\0o\0p\0[\0]\0Del\0\0",
86         "Caps\0a\0s\0d\0f\0g\0h\0j\0k\0l\0;\0'\0Enter\0\0",
87         "Shift\0z\0x\0c\0v\0b\0n\0m\0,\0.\0/\0Shift\0\0",
88         "Ctrl\0Alt\0 \0Scrib\0Menu\0Esc\0\0"
89 };
90
91 static char *keyshift[Nrow] = {
92         "~\0!\0@\0#\0$\0%\0^\0&\0*\0(\0)\0_\0+\0|\0<-\0\0",
93         "->\0Q\0W\0E\0R\0T\0Y\0U\0I\0O\0P\0{\0}\0Del\0\0",
94         "Caps\0A\0S\0D\0F\0G\0H\0J\0K\0L\0:\0\"\0Enter\0\0",
95         "Shift\0Z\0X\0C\0V\0B\0N\0M\0<\0>\0?\0Shift\0\0",
96         "Ctrl\0Alt\0 \0Scrib\0Menu\0Esc\0\0"
97 };
98
99 static char *keycaps[Nrow] = {
100         "`\0001\0002\0003\0004\0005\0006\0007\0008\0009\0000\0-\0=\0\\\0<-\0\0",
101         "->\0Q\0W\0E\0R\0T\0Y\0U\0I\0O\0P\0[\0]\0Del\0\0",
102         "Caps\0A\0S\0D\0F\0G\0H\0J\0K\0L\0;\0'\0Enter\0\0",
103         "Shift\0Z\0X\0C\0V\0B\0N\0M\0,\0.\0/\0Shift\0\0",
104         "Ctrl\0Alt\0 \0Scrib\0Menu\0Esc\0\0"
105 };
106
107 static char *keycapsshift[Nrow] = {
108         "~\0!\0@\0#\0$\0%\0^\0&\0*\0(\0)\0_\0+\0|\0<-\0\0",
109         "->\0q\0w\0e\0r\0t\0y\0u\0i\0o\0p\0{\0}\0Del\0\0",
110         "Caps\0a\0s\0d\0f\0g\0h\0j\0k\0l\0:\0\"\0Enter\0\0",
111         "Shift\0z\0x\0c\0v\0b\0n\0m\0<\0>\0?\0Shift\0\0",
112         "Ctrl\0Alt\0 \0Scrib\0Menu\0Esc\0\0"
113 };
114
115 struct{
116         char    *name;
117         int     val;
118 }keytab[] = {
119         "Shift",        0,
120         "Ctrl", 0,
121         "Alt",          0,
122         "Caps", 0,
123         "Del",  '\177',
124         "Enter",        '\n',
125         "Esc",  '\033',
126         "<-",           '\b',
127         "->",           '\t',
128         "Scrib",        0x10000,
129         "Menu", 0x10001,
130         nil,            0,
131 };
132
133 static char **keyset[Nstate] = {
134         keyregular,
135         keyshift,
136         keycaps,
137         keycapsshift,
138 };
139
140 static void     keyboardshow(Keyboard*);
141 static void     keyup(Keyboard*, Point);
142 static void     keydown(Keyboard*, Point);
143 static void     keyresize(Keyboard*);
144
145 static void
146 keyboardmouse(Control *c, Mouse *m)
147 {
148         Keyboard *k;
149
150         k = (Keyboard *)c;
151         if(m->buttons==1)
152                 keydown(k, m->xy);
153         else if(k->lastbut==1 && m->buttons==0)
154                 keyup(k, m->xy);
155         k->lastbut = m->buttons;
156 }
157
158 static void
159 keyboardfree(Control *c)
160 {
161         int i;
162         Keyboard *k;
163
164         k = (Keyboard *)c;
165         _putctlimage(k->image);
166         _putctlimage(k->mask);
167         _putctlimage(k->light);
168         _putctlimage(k->textcolor);
169         _putctlimage(k->bordercolor);
170         _putctlfont(k->font);
171         _putctlfont(k->ctlfont);
172         for(i=0; i<nelem(k->im); i++)
173                 freeimage(k->im[i]);
174         free(k->format);
175 }
176
177 static int
178 keyboardy(Keyboard *k, int row)
179 {
180         int dy;
181
182         if(row >= Nrow)
183                 return k->rect.max.y-k->border;
184         dy = Dy(k->rect)-2*k->border;
185         return k->rect.min.y+k->border+(row*dy+Nrow-1)/Nrow;
186 }
187
188 static char*
189 whichkey(Keyboard *k, Point p, int *rowp, int *colp, Rectangle *rp)
190 {
191         uchar *wp;
192         char *kp;
193         int row, col, dx, dy, x, n, maxx;
194         Rectangle r;
195
196         r = insetrect(k->rect, k->border);
197         if(!ptinrect(p, r))
198                 return nil;
199         maxx = r.max.x;
200         dx = Dx(r);
201         dy = Dy(r);
202         row = (p.y - r.min.y)*Nrow/dy;
203         if(row >= Nrow)
204                 row = Nrow-1;
205         r.min.y = keyboardy(k, row);
206         r.max.y = keyboardy(k, row+1);
207         x = r.min.x;
208         kp = keyset[k->state&SMask][row];
209         wp = wid[row];
210         for(col=0; *kp; col++,kp+=n+1){
211                 n = strlen(kp);
212                 r.min.x = x;
213                 r.max.x = x + (wp[col]*dx+255)/256;
214                 if(kp[n+1] == '\0')
215                         r.max.x = maxx;
216                 if(r.max.x > p.x)
217                         break;
218                 x = r.max.x;
219         }
220         *rp = insetrect(r, 1);
221         *rowp = row;
222         *colp = col;
223         return kp;
224 }
225
226 static Rectangle
227 keyrect(Keyboard *k, int row, int col)
228 {
229         uchar *wp;
230         char *kp;
231         int i, x, n, dx;
232         Rectangle r;
233         Point p;
234
235         r = insetrect(k->rect, k->border);
236         p = r.min;
237         dx = Dx(r);
238         r.min.y = keyboardy(k, row);
239         r.max.y = keyboardy(k, row+1);
240         x = r.min.x;
241         kp = keyset[0][row];
242         wp = wid[row];
243         for(i=0; *kp; i++,kp+=n+1){
244                 n = strlen(kp);
245                 r.min.x = x;
246                 r.max.x = x + (wp[i]*dx+255)/256;
247                 if(kp[n+1] == '\0')
248                         r.max.x = p.x+dx;
249                 if(i >= col)
250                         break;
251                 x = r.max.x;
252         }
253         return insetrect(r, 1);
254 }
255
256 static void
257 keydraw(Keyboard *k, int state)
258 {
259         Point p, q;
260         int row, col, x, dx, dy, nexty, n;
261         uchar *wp;
262         char *kp;
263         Rectangle r;
264         Font *f, *f1, *f2;
265         Image *im;
266
267         freeimage(k->im[state]);
268         k->im[state] = nil;
269         if(Dx(k->rect)-2*k->border <= 0)
270                 return;
271
272         im = allocimage(display, k->rect, screen->chan, 0, ~0);
273         if(im == nil)
274                 return;
275         k->im[state] = im;
276
277         r = insetrect(k->rect, k->border);
278         border(im, k->rect, k->border, k->bordercolor->image, ZP);
279         draw(im, r, k->image->image, nil, ZP);
280         dx = Dx(r);
281         dy = Dy(r);
282         p = r.min;
283         f1 = k->font->font;
284         f2 = k->ctlfont->font;
285         nexty = p.y;
286         for(row=0; row<Nrow; row++){
287                 x = p.x;
288                 kp = keyset[state][row];
289                 wp = wid[row];
290                 r.min.y = nexty;
291                 nexty = keyboardy(k, row+1);
292                 r.max.y = nexty;
293                 for(col=0; *kp; col++,kp+=n+1){
294                         r.min.x = x;
295                         r.max.x = x + (wp[col]*dx+255)/256;
296                         n = strlen(kp);
297                         if(kp[n+1] == '\0')
298                                 r.max.x = p.x+dx;
299                         if(row == Nrow-1)
300                                 r.max.y = p.y+dy;
301                         if(n > 1)
302                                 f = f2;
303                         else
304                                 f = f1;
305                         q = _ctlalignpoint(r, stringnwidth(f, kp, n), f->height, Acenter);
306                         _string(im, q, k->textcolor->image,
307                                 ZP, f, kp, nil, n, r,
308                                 nil, ZP, SoverD);
309                         x = r.max.x;
310                         if(kp[n+1])
311                                 draw(im, Rect(x, r.min.y, x+1, r.max.y),
312                                         k->textcolor->image, nil, ZP);
313                 }
314                 if(row != Nrow-1)
315                         draw(im, Rect(p.x, r.max.y, p.x+dx, r.max.y+1),
316                                 k->textcolor->image, nil, ZP);
317         }
318 }
319
320 static void
321 keyresize(Keyboard *k)
322 {
323         int i;
324
325         for(i=0; i<Nstate; i++)
326                 keydraw(k, i);
327 }
328
329 static void
330 keyboardshow(Keyboard *k)
331 {
332         Rectangle r;
333
334         if (k->hidden)
335                 return;
336         if(k->im[0]==nil || !eqrect(k->im[0]->r, k->rect))
337                 keyresize(k);
338         if(k->im[k->state&SMask] == nil)
339                 return;
340         draw(k->screen, k->rect, k->im[k->state&SMask], nil, k->rect.min);
341         if(k->state & SShift){
342                 r = keyrect(k, 3, 0);
343                 draw(k->screen, r, k->light->image, k->mask->image, ZP);
344                 r = keyrect(k, 3, 11);
345                 draw(k->screen, r, k->light->image, k->mask->image, ZP);
346         }
347         if(k->state & SCaps){
348                 r = keyrect(k, 2, 0);
349                 draw(k->screen, r, k->light->image, k->mask->image, ZP);
350         }
351         if(k->state & SControl){
352                 r = keyrect(k, 4, 0);
353                 draw(k->screen, r, k->light->image, k->mask->image, ZP);
354         }
355         flushimage(display, 1);
356 }
357
358 static void
359 keydown(Keyboard *k, Point p)
360 {
361         int row, col;
362         Rectangle r;
363         char *s;
364
365         s = whichkey(k, p, &row, &col, &r);
366         if(s == k->key)
367                 return;
368         keyboardshow(k);
369         if(s != nil)
370                 draw(k->screen, r, k->light->image, k->mask->image, ZP);
371         flushimage(display, 1);
372         k->key = s;
373 }
374
375 static int
376 keylookup(char *s)
377 {
378         int i;
379
380         for(i=0; keytab[i].name; i++)
381                 if(strcmp(s, keytab[i].name) == 0)
382                         return keytab[i].val;
383         return s[0];
384 }
385
386 static void
387 keyup(Keyboard *k, Point p)
388 {
389         int row, col;
390         Rectangle r;
391         char *s;
392         int val;
393
394         s = whichkey(k, p, &row, &col, &r);
395         if(s == nil)
396                 return;
397         val = keylookup(s);
398         if(k->state & SControl)
399                 if(' '<val && val<0177)
400                         val &= ~0x60;
401         if(strcmp(s, "Alt") == 0)
402                 {;}
403         if(strcmp(s, "Ctrl") == 0){
404                 k->state ^= SControl;
405         }else
406                 k->state &= ~SControl;
407         if(strcmp(s, "Shift")==0 || strcmp(s, "Caps")==0){
408                 if(strcmp(s, "Shift") == 0)
409                         k->state ^= SShift;
410                 if(strcmp(s, "Caps") == 0)
411                         k->state ^= SCaps;
412         }else
413                 k->state &= ~SShift;
414         keyboardshow(k);
415         if(val)
416                 chanprint(k->event, k->format, k->name, val);
417         k->key = nil;
418 }
419
420 static void
421 keyboardctl(Control *c, CParse *cp)
422 {
423         int cmd;
424         Rectangle r;
425         Keyboard *k;
426
427         k = (Keyboard*)c;
428         cmd = _ctllookup(cp->args[0], cmds, nelem(cmds));
429         switch(cmd){
430         default:
431                 ctlerror("%q: unrecognized message '%s'", k->name, cp->str);
432                 break;
433         case EBorder:
434                 _ctlargcount(k, cp, 2);
435                 if(cp->iargs[1] < 0)
436                         ctlerror("%q: bad border: %c", k->name, cp->str);
437                 k->border = cp->iargs[1];
438                 break;
439         case EBordercolor:
440                 _ctlargcount(k, cp, 2);
441                 _setctlimage(k, &k->bordercolor, cp->args[1]);
442                 break;
443         case EFocus:
444                 /* ignore focus change */
445                 break;
446         case EFont:
447                 if(cp->nargs!=2 && cp->nargs!=3)
448                         ctlerror("%q: bad font message '%s'", k->name, cp->str);
449                 _setctlfont(k, &k->font, cp->args[1]);
450                 if(cp->nargs == 3)
451                         _setctlfont(k, &k->ctlfont, cp->args[2]);
452                 else
453                         _setctlfont(k, &k->ctlfont, cp->args[1]);
454                 break;
455         case EFormat:
456                 _ctlargcount(k, cp, 2);
457                 k->format = ctlstrdup(cp->args[1]);
458                 break;
459         case EHide:
460                 _ctlargcount(k, cp, 1);
461                 k->hidden = 1;
462                 break;
463         case EImage:
464                 _ctlargcount(k, cp, 2);
465                 _setctlimage(k, &k->image, cp->args[1]);
466                 break;
467         case ELight:
468                 _ctlargcount(k, cp, 2);
469                 _setctlimage(k, &k->light, cp->args[1]);
470                 break;
471         case EMask:
472                 _ctlargcount(k, cp, 2);
473                 _setctlimage(k, &k->mask, cp->args[1]);
474                 break;
475         case ERect:
476                 _ctlargcount(k, cp, 5);
477                 r.min.x = cp->iargs[1];
478                 r.min.y = cp->iargs[2];
479                 r.max.x = cp->iargs[3];
480                 r.max.y = cp->iargs[4];
481                 if(Dx(r)<0 || Dy(r)<0)
482                         ctlerror("%q: bad rectangle: %s", k->name, cp->str);
483                 k->rect = r;
484                 keyboardshow(k);
485                 break;
486         case EReveal:
487                 _ctlargcount(k, cp, 1);
488                 k->hidden = 0;
489                 keyboardshow(k);
490                 break;
491         case EShow:
492                 _ctlargcount(k, cp, 1);
493                 keyboardshow(k);
494                 break;
495         case ESize:
496                 if (cp->nargs == 3)
497                         r.max = Pt(0x7fffffff, 0x7fffffff);
498                 else{
499                         _ctlargcount(k, cp, 5);
500                         r.max.x = cp->iargs[3];
501                         r.max.y = cp->iargs[4];
502                 }
503                 r.min.x = cp->iargs[1];
504                 r.min.y = cp->iargs[2];
505                 if(r.min.x<=0 || r.min.y<=0 || r.max.x<=0 || r.max.y<=0 || r.max.x < r.min.x || r.max.y < r.min.y)
506                         ctlerror("%q: bad sizes: %s", k->name, cp->str);
507                 k->size.min = r.min;
508                 k->size.max = r.max;
509                 break;
510         }
511 }
512
513 Control*
514 createkeyboard(Controlset *cs, char *name)
515 {
516         Keyboard *k;
517
518         k = (Keyboard *)_createctl(cs, "keyboard", sizeof(Keyboard), name);
519         k->image = _getctlimage("white");
520         k->mask = _getctlimage("opaque");
521         k->light = _getctlimage("yellow");
522         k->bordercolor = _getctlimage("black");
523         k->textcolor = _getctlimage("black");
524         k->font = _getctlfont("font");
525         k->ctlfont = _getctlfont("font");
526         k->format = ctlstrdup("%q: value 0x%x");
527         k->border = 0;
528         k->lastbut = 0;
529         k->key = nil;
530         k->state = SRegular;
531         k->ctl = keyboardctl;
532         k->mouse = keyboardmouse;
533         k->exit = keyboardfree;
534         k->size = Rect(246, 2 + 5 * (k->font->font->height + 1), 512, 256);
535         return k;
536 }