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
keyboardmouse(Control * c,Mouse * m)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
keyboardfree(Control * c)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
keyboardy(Keyboard * k,int row)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*
whichkey(Keyboard * k,Point p,int * rowp,int * colp,Rectangle * rp)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
keyrect(Keyboard * k,int row,int col)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
keydraw(Keyboard * k,int state)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
keyresize(Keyboard * k)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
keyboardshow(Keyboard * k)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
keydown(Keyboard * k,Point p)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
keylookup(char * s)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
keyup(Keyboard * k,Point p)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
keyboardctl(Control * c,CParse * cp)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*
createkeyboard(Controlset * cs,char * name)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 }
537