xref: /plan9/sys/src/libcontrol/keyboard.c (revision ac57dd0bdfb9d49ce3ebb32937bb07f2cec3da6c)
180ee5cbfSDavid du Colombier #include <u.h>
280ee5cbfSDavid du Colombier #include <libc.h>
380ee5cbfSDavid du Colombier #include <draw.h>
480ee5cbfSDavid du Colombier #include <thread.h>
580ee5cbfSDavid du Colombier #include <mouse.h>
680ee5cbfSDavid du Colombier #include <keyboard.h>
780ee5cbfSDavid du Colombier #include <control.h>
880ee5cbfSDavid du Colombier 
980ee5cbfSDavid du Colombier typedef struct Keyboard Keyboard;
1080ee5cbfSDavid du Colombier 
1180ee5cbfSDavid du Colombier enum{
1280ee5cbfSDavid du Colombier 	SRegular	= 0,
1380ee5cbfSDavid du Colombier 	SShift	= 1,
1480ee5cbfSDavid du Colombier 	SCaps	= 2,
1580ee5cbfSDavid du Colombier 	SMask	= 3,
1680ee5cbfSDavid du Colombier 	Nstate	= 4,
1780ee5cbfSDavid du Colombier 	SControl	= 4,
1880ee5cbfSDavid du Colombier };
1980ee5cbfSDavid du Colombier 
2080ee5cbfSDavid du Colombier struct Keyboard
2180ee5cbfSDavid du Colombier {
2280ee5cbfSDavid du Colombier 	Control;
2380ee5cbfSDavid du Colombier 	CImage	*image;
2480ee5cbfSDavid du Colombier 	CImage	*mask;
2580ee5cbfSDavid du Colombier 	CImage	*light;
2680ee5cbfSDavid du Colombier 	CImage	*textcolor;
2780ee5cbfSDavid du Colombier 	CImage	*bordercolor;
2880ee5cbfSDavid du Colombier 	CFont	*font;
2980ee5cbfSDavid du Colombier 	CFont	*ctlfont;
3080ee5cbfSDavid du Colombier 	Image	*im[Nstate];
3180ee5cbfSDavid du Colombier 	int		border;
3280ee5cbfSDavid du Colombier 	int		lastbut;
3380ee5cbfSDavid du Colombier 	int		state;
3480ee5cbfSDavid du Colombier 	char		*key;
3580ee5cbfSDavid du Colombier };
3680ee5cbfSDavid du Colombier 
3780ee5cbfSDavid du Colombier enum{
3880ee5cbfSDavid du Colombier 	EBorder,
3980ee5cbfSDavid du Colombier 	EBordercolor,
4080ee5cbfSDavid du Colombier 	EFocus,
4180ee5cbfSDavid du Colombier 	EFont,
4280ee5cbfSDavid du Colombier 	EFormat,
439a747e4fSDavid du Colombier 	EHide,
4480ee5cbfSDavid du Colombier 	EImage,
4580ee5cbfSDavid du Colombier 	ELight,
4680ee5cbfSDavid du Colombier 	EMask,
4780ee5cbfSDavid du Colombier 	ERect,
489a747e4fSDavid du Colombier 	EReveal,
4980ee5cbfSDavid du Colombier 	EShow,
509a747e4fSDavid du Colombier 	ESize,
5180ee5cbfSDavid du Colombier };
5280ee5cbfSDavid du Colombier 
5380ee5cbfSDavid du Colombier static char *cmds[] = {
5480ee5cbfSDavid du Colombier 	[EBorder] =	"border",
5580ee5cbfSDavid du Colombier 	[EBordercolor] = "bordercolor",
5680ee5cbfSDavid du Colombier 	[EFocus] = 	"focus",
5780ee5cbfSDavid du Colombier 	[EFont] =		"font",
5880ee5cbfSDavid du Colombier 	[EFormat] = 	"format",
599a747e4fSDavid du Colombier 	[EHide] =		"hide",
6080ee5cbfSDavid du Colombier 	[EImage] =	"image",
6180ee5cbfSDavid du Colombier 	[ELight] =		"light",
6280ee5cbfSDavid du Colombier 	[EMask] =		"mask",
6380ee5cbfSDavid du Colombier 	[ERect] =		"rect",
649a747e4fSDavid du Colombier 	[EReveal] =	"reveal",
6580ee5cbfSDavid du Colombier 	[EShow] =		"show",
669a747e4fSDavid du Colombier 	[ESize] =		"size",
6780ee5cbfSDavid du Colombier 	nil
6880ee5cbfSDavid du Colombier };
6980ee5cbfSDavid du Colombier 
7080ee5cbfSDavid du Colombier enum
7180ee5cbfSDavid du Colombier {
7280ee5cbfSDavid du Colombier 	Nrow = 5
7380ee5cbfSDavid du Colombier };
7480ee5cbfSDavid du Colombier 
7580ee5cbfSDavid du Colombier static uchar wid [Nrow][16] = {
7680ee5cbfSDavid du Colombier 	{16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 30, },
7780ee5cbfSDavid du Colombier 	{24, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 24, },
7880ee5cbfSDavid du Colombier 	{32, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, },
7980ee5cbfSDavid du Colombier 	{40, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, },
8080ee5cbfSDavid du Colombier 	{30, 30, 80, 40, 42, 24, },
8180ee5cbfSDavid du Colombier };
8280ee5cbfSDavid du Colombier 
8380ee5cbfSDavid du Colombier static char *keyregular[Nrow] = {
8480ee5cbfSDavid du Colombier 	"`\0001\0002\0003\0004\0005\0006\0007\0008\0009\0000\0-\0=\0\\\0<-\0\0",
8580ee5cbfSDavid du Colombier 	"->\0q\0w\0e\0r\0t\0y\0u\0i\0o\0p\0[\0]\0Del\0\0",
8680ee5cbfSDavid du Colombier 	"Caps\0a\0s\0d\0f\0g\0h\0j\0k\0l\0;\0'\0Enter\0\0",
8780ee5cbfSDavid du Colombier 	"Shift\0z\0x\0c\0v\0b\0n\0m\0,\0.\0/\0Shift\0\0",
8880ee5cbfSDavid du Colombier 	"Ctrl\0Alt\0 \0Scrib\0Menu\0Esc\0\0"
8980ee5cbfSDavid du Colombier };
9080ee5cbfSDavid du Colombier 
9180ee5cbfSDavid du Colombier static char *keyshift[Nrow] = {
9280ee5cbfSDavid du Colombier 	"~\0!\0@\0#\0$\0%\0^\0&\0*\0(\0)\0_\0+\0|\0<-\0\0",
9380ee5cbfSDavid du Colombier 	"->\0Q\0W\0E\0R\0T\0Y\0U\0I\0O\0P\0{\0}\0Del\0\0",
9480ee5cbfSDavid du Colombier 	"Caps\0A\0S\0D\0F\0G\0H\0J\0K\0L\0:\0\"\0Enter\0\0",
9580ee5cbfSDavid du Colombier 	"Shift\0Z\0X\0C\0V\0B\0N\0M\0<\0>\0?\0Shift\0\0",
9680ee5cbfSDavid du Colombier 	"Ctrl\0Alt\0 \0Scrib\0Menu\0Esc\0\0"
9780ee5cbfSDavid du Colombier };
9880ee5cbfSDavid du Colombier 
9980ee5cbfSDavid du Colombier static char *keycaps[Nrow] = {
10080ee5cbfSDavid du Colombier 	"`\0001\0002\0003\0004\0005\0006\0007\0008\0009\0000\0-\0=\0\\\0<-\0\0",
10180ee5cbfSDavid du Colombier 	"->\0Q\0W\0E\0R\0T\0Y\0U\0I\0O\0P\0[\0]\0Del\0\0",
10280ee5cbfSDavid du Colombier 	"Caps\0A\0S\0D\0F\0G\0H\0J\0K\0L\0;\0'\0Enter\0\0",
10380ee5cbfSDavid du Colombier 	"Shift\0Z\0X\0C\0V\0B\0N\0M\0,\0.\0/\0Shift\0\0",
10480ee5cbfSDavid du Colombier 	"Ctrl\0Alt\0 \0Scrib\0Menu\0Esc\0\0"
10580ee5cbfSDavid du Colombier };
10680ee5cbfSDavid du Colombier 
10780ee5cbfSDavid du Colombier static char *keycapsshift[Nrow] = {
10880ee5cbfSDavid du Colombier 	"~\0!\0@\0#\0$\0%\0^\0&\0*\0(\0)\0_\0+\0|\0<-\0\0",
10980ee5cbfSDavid du Colombier 	"->\0q\0w\0e\0r\0t\0y\0u\0i\0o\0p\0{\0}\0Del\0\0",
11080ee5cbfSDavid du Colombier 	"Caps\0a\0s\0d\0f\0g\0h\0j\0k\0l\0:\0\"\0Enter\0\0",
11180ee5cbfSDavid du Colombier 	"Shift\0z\0x\0c\0v\0b\0n\0m\0<\0>\0?\0Shift\0\0",
11280ee5cbfSDavid du Colombier 	"Ctrl\0Alt\0 \0Scrib\0Menu\0Esc\0\0"
11380ee5cbfSDavid du Colombier };
11480ee5cbfSDavid du Colombier 
11580ee5cbfSDavid du Colombier struct{
11680ee5cbfSDavid du Colombier 	char	*name;
11780ee5cbfSDavid du Colombier 	int	val;
11880ee5cbfSDavid du Colombier }keytab[] = {
11980ee5cbfSDavid du Colombier 	"Shift",	0,
12080ee5cbfSDavid du Colombier 	"Ctrl",	0,
12180ee5cbfSDavid du Colombier 	"Alt",		0,
12280ee5cbfSDavid du Colombier 	"Caps",	0,
12380ee5cbfSDavid du Colombier 	"Del",	'\177',
12480ee5cbfSDavid du Colombier 	"Enter",	'\n',
12580ee5cbfSDavid du Colombier 	"Esc",	'\033',
12680ee5cbfSDavid du Colombier 	"<-",		'\b',
12780ee5cbfSDavid du Colombier 	"->",		'\t',
12880ee5cbfSDavid du Colombier 	"Scrib",	0x10000,
12980ee5cbfSDavid du Colombier 	"Menu",	0x10001,
13080ee5cbfSDavid du Colombier 	nil,		0,
13180ee5cbfSDavid du Colombier };
13280ee5cbfSDavid du Colombier 
13380ee5cbfSDavid du Colombier static char **keyset[Nstate] = {
13480ee5cbfSDavid du Colombier 	keyregular,
13580ee5cbfSDavid du Colombier 	keyshift,
13680ee5cbfSDavid du Colombier 	keycaps,
13780ee5cbfSDavid du Colombier 	keycapsshift,
13880ee5cbfSDavid du Colombier };
13980ee5cbfSDavid du Colombier 
14080ee5cbfSDavid du Colombier static void	keyboardshow(Keyboard*);
14180ee5cbfSDavid du Colombier static void	keyup(Keyboard*, Point);
14280ee5cbfSDavid du Colombier static void	keydown(Keyboard*, Point);
14380ee5cbfSDavid du Colombier static void	keyresize(Keyboard*);
14480ee5cbfSDavid du Colombier 
14580ee5cbfSDavid du Colombier static void
keyboardmouse(Control * c,Mouse * m)1469a747e4fSDavid du Colombier keyboardmouse(Control *c, Mouse *m)
14780ee5cbfSDavid du Colombier {
14880ee5cbfSDavid du Colombier 	Keyboard *k;
14980ee5cbfSDavid du Colombier 
1509a747e4fSDavid du Colombier 	k = (Keyboard *)c;
1519a747e4fSDavid du Colombier 	if(m->buttons==1)
1529a747e4fSDavid du Colombier 		keydown(k, m->xy);
1539a747e4fSDavid du Colombier 	else if(k->lastbut==1 && m->buttons==0)
1549a747e4fSDavid du Colombier 		keyup(k, m->xy);
1559a747e4fSDavid du Colombier 	k->lastbut = m->buttons;
15680ee5cbfSDavid du Colombier }
15780ee5cbfSDavid du Colombier 
15880ee5cbfSDavid du Colombier static void
keyboardfree(Control * c)1599a747e4fSDavid du Colombier keyboardfree(Control *c)
16080ee5cbfSDavid du Colombier {
16180ee5cbfSDavid du Colombier 	int i;
1629a747e4fSDavid du Colombier 	Keyboard *k;
16380ee5cbfSDavid du Colombier 
1649a747e4fSDavid du Colombier 	k = (Keyboard *)c;
16580ee5cbfSDavid du Colombier 	_putctlimage(k->image);
16680ee5cbfSDavid du Colombier 	_putctlimage(k->mask);
16780ee5cbfSDavid du Colombier 	_putctlimage(k->light);
16880ee5cbfSDavid du Colombier 	_putctlimage(k->textcolor);
16980ee5cbfSDavid du Colombier 	_putctlimage(k->bordercolor);
17080ee5cbfSDavid du Colombier 	_putctlfont(k->font);
17180ee5cbfSDavid du Colombier 	_putctlfont(k->ctlfont);
17280ee5cbfSDavid du Colombier 	for(i=0; i<nelem(k->im); i++)
17380ee5cbfSDavid du Colombier 		freeimage(k->im[i]);
17480ee5cbfSDavid du Colombier 	free(k->format);
17580ee5cbfSDavid du Colombier }
17680ee5cbfSDavid du Colombier 
17780ee5cbfSDavid du Colombier static int
keyboardy(Keyboard * k,int row)17880ee5cbfSDavid du Colombier keyboardy(Keyboard *k, int row)
17980ee5cbfSDavid du Colombier {
18080ee5cbfSDavid du Colombier 	int dy;
18180ee5cbfSDavid du Colombier 
18280ee5cbfSDavid du Colombier 	if(row >= Nrow)
18380ee5cbfSDavid du Colombier 		return k->rect.max.y-k->border;
18480ee5cbfSDavid du Colombier 	dy = Dy(k->rect)-2*k->border;
18580ee5cbfSDavid du Colombier 	return k->rect.min.y+k->border+(row*dy+Nrow-1)/Nrow;
18680ee5cbfSDavid du Colombier }
18780ee5cbfSDavid du Colombier 
18880ee5cbfSDavid du Colombier static char*
whichkey(Keyboard * k,Point p,int * rowp,int * colp,Rectangle * rp)18980ee5cbfSDavid du Colombier whichkey(Keyboard *k, Point p, int *rowp, int *colp, Rectangle *rp)
19080ee5cbfSDavid du Colombier {
19180ee5cbfSDavid du Colombier 	uchar *wp;
19280ee5cbfSDavid du Colombier 	char *kp;
19380ee5cbfSDavid du Colombier 	int row, col, dx, dy, x, n, maxx;
19480ee5cbfSDavid du Colombier 	Rectangle r;
19580ee5cbfSDavid du Colombier 
19680ee5cbfSDavid du Colombier 	r = insetrect(k->rect, k->border);
19780ee5cbfSDavid du Colombier 	if(!ptinrect(p, r))
19880ee5cbfSDavid du Colombier 		return nil;
19980ee5cbfSDavid du Colombier 	maxx = r.max.x;
20080ee5cbfSDavid du Colombier 	dx = Dx(r);
20180ee5cbfSDavid du Colombier 	dy = Dy(r);
20280ee5cbfSDavid du Colombier 	row = (p.y - r.min.y)*Nrow/dy;
20380ee5cbfSDavid du Colombier 	if(row >= Nrow)
20480ee5cbfSDavid du Colombier 		row = Nrow-1;
20580ee5cbfSDavid du Colombier 	r.min.y = keyboardy(k, row);
20680ee5cbfSDavid du Colombier 	r.max.y = keyboardy(k, row+1);
20780ee5cbfSDavid du Colombier 	x = r.min.x;
20880ee5cbfSDavid du Colombier 	kp = keyset[k->state&SMask][row];
20980ee5cbfSDavid du Colombier 	wp = wid[row];
21080ee5cbfSDavid du Colombier 	for(col=0; *kp; col++,kp+=n+1){
21180ee5cbfSDavid du Colombier 		n = strlen(kp);
21280ee5cbfSDavid du Colombier 		r.min.x = x;
21380ee5cbfSDavid du Colombier 		r.max.x = x + (wp[col]*dx+255)/256;
21480ee5cbfSDavid du Colombier 		if(kp[n+1] == '\0')
21580ee5cbfSDavid du Colombier 			r.max.x = maxx;
21680ee5cbfSDavid du Colombier 		if(r.max.x > p.x)
21780ee5cbfSDavid du Colombier 			break;
21880ee5cbfSDavid du Colombier 		x = r.max.x;
21980ee5cbfSDavid du Colombier 	}
22080ee5cbfSDavid du Colombier 	*rp = insetrect(r, 1);
22180ee5cbfSDavid du Colombier 	*rowp = row;
22280ee5cbfSDavid du Colombier 	*colp = col;
22380ee5cbfSDavid du Colombier 	return kp;
22480ee5cbfSDavid du Colombier }
22580ee5cbfSDavid du Colombier 
22680ee5cbfSDavid du Colombier static Rectangle
keyrect(Keyboard * k,int row,int col)22780ee5cbfSDavid du Colombier keyrect(Keyboard *k, int row, int col)
22880ee5cbfSDavid du Colombier {
22980ee5cbfSDavid du Colombier 	uchar *wp;
23080ee5cbfSDavid du Colombier 	char *kp;
23180ee5cbfSDavid du Colombier 	int i, x, n, dx;
23280ee5cbfSDavid du Colombier 	Rectangle r;
23380ee5cbfSDavid du Colombier 	Point p;
23480ee5cbfSDavid du Colombier 
23580ee5cbfSDavid du Colombier 	r = insetrect(k->rect, k->border);
23680ee5cbfSDavid du Colombier 	p = r.min;
23780ee5cbfSDavid du Colombier 	dx = Dx(r);
23880ee5cbfSDavid du Colombier 	r.min.y = keyboardy(k, row);
23980ee5cbfSDavid du Colombier 	r.max.y = keyboardy(k, row+1);
24080ee5cbfSDavid du Colombier 	x = r.min.x;
24180ee5cbfSDavid du Colombier 	kp = keyset[0][row];
24280ee5cbfSDavid du Colombier 	wp = wid[row];
24380ee5cbfSDavid du Colombier 	for(i=0; *kp; i++,kp+=n+1){
24480ee5cbfSDavid du Colombier 		n = strlen(kp);
24580ee5cbfSDavid du Colombier 		r.min.x = x;
24680ee5cbfSDavid du Colombier 		r.max.x = x + (wp[i]*dx+255)/256;
24780ee5cbfSDavid du Colombier 		if(kp[n+1] == '\0')
24880ee5cbfSDavid du Colombier 			r.max.x = p.x+dx;
24980ee5cbfSDavid du Colombier 		if(i >= col)
25080ee5cbfSDavid du Colombier 			break;
25180ee5cbfSDavid du Colombier 		x = r.max.x;
25280ee5cbfSDavid du Colombier 	}
25380ee5cbfSDavid du Colombier 	return insetrect(r, 1);
25480ee5cbfSDavid du Colombier }
25580ee5cbfSDavid du Colombier 
25680ee5cbfSDavid du Colombier static void
keydraw(Keyboard * k,int state)25780ee5cbfSDavid du Colombier keydraw(Keyboard *k, int state)
25880ee5cbfSDavid du Colombier {
25980ee5cbfSDavid du Colombier 	Point p, q;
26080ee5cbfSDavid du Colombier 	int row, col, x, dx, dy, nexty, n;
26180ee5cbfSDavid du Colombier 	uchar *wp;
26280ee5cbfSDavid du Colombier 	char *kp;
26380ee5cbfSDavid du Colombier 	Rectangle r;
26480ee5cbfSDavid du Colombier 	Font *f, *f1, *f2;
26580ee5cbfSDavid du Colombier 	Image *im;
26680ee5cbfSDavid du Colombier 
26780ee5cbfSDavid du Colombier 	freeimage(k->im[state]);
26880ee5cbfSDavid du Colombier 	k->im[state] = nil;
26980ee5cbfSDavid du Colombier 	if(Dx(k->rect)-2*k->border <= 0)
27080ee5cbfSDavid du Colombier 		return;
27180ee5cbfSDavid du Colombier 
2729a747e4fSDavid du Colombier 	im = allocimage(display, k->rect, screen->chan, 0, ~0);
27380ee5cbfSDavid du Colombier 	if(im == nil)
27480ee5cbfSDavid du Colombier 		return;
27580ee5cbfSDavid du Colombier 	k->im[state] = im;
27680ee5cbfSDavid du Colombier 
27780ee5cbfSDavid du Colombier 	r = insetrect(k->rect, k->border);
27880ee5cbfSDavid du Colombier 	border(im, k->rect, k->border, k->bordercolor->image, ZP);
27980ee5cbfSDavid du Colombier 	draw(im, r, k->image->image, nil, ZP);
28080ee5cbfSDavid du Colombier 	dx = Dx(r);
28180ee5cbfSDavid du Colombier 	dy = Dy(r);
28280ee5cbfSDavid du Colombier 	p = r.min;
28380ee5cbfSDavid du Colombier 	f1 = k->font->font;
28480ee5cbfSDavid du Colombier 	f2 = k->ctlfont->font;
28580ee5cbfSDavid du Colombier 	nexty = p.y;
28680ee5cbfSDavid du Colombier 	for(row=0; row<Nrow; row++){
28780ee5cbfSDavid du Colombier 		x = p.x;
28880ee5cbfSDavid du Colombier 		kp = keyset[state][row];
28980ee5cbfSDavid du Colombier 		wp = wid[row];
29080ee5cbfSDavid du Colombier 		r.min.y = nexty;
29180ee5cbfSDavid du Colombier 		nexty = keyboardy(k, row+1);
29280ee5cbfSDavid du Colombier 		r.max.y = nexty;
29380ee5cbfSDavid du Colombier 		for(col=0; *kp; col++,kp+=n+1){
29480ee5cbfSDavid du Colombier 			r.min.x = x;
29580ee5cbfSDavid du Colombier 			r.max.x = x + (wp[col]*dx+255)/256;
29680ee5cbfSDavid du Colombier 			n = strlen(kp);
29780ee5cbfSDavid du Colombier 			if(kp[n+1] == '\0')
29880ee5cbfSDavid du Colombier 				r.max.x = p.x+dx;
29980ee5cbfSDavid du Colombier 			if(row == Nrow-1)
30080ee5cbfSDavid du Colombier 				r.max.y = p.y+dy;
30180ee5cbfSDavid du Colombier 			if(n > 1)
30280ee5cbfSDavid du Colombier 				f = f2;
30380ee5cbfSDavid du Colombier 			else
30480ee5cbfSDavid du Colombier 				f = f1;
30580ee5cbfSDavid du Colombier 			q = _ctlalignpoint(r, stringnwidth(f, kp, n), f->height, Acenter);
30680ee5cbfSDavid du Colombier 			_string(im, q, k->textcolor->image,
30780ee5cbfSDavid du Colombier 				ZP, f, kp, nil, n, r,
308*ac57dd0bSDavid du Colombier 				nil, ZP, SoverD);
30980ee5cbfSDavid du Colombier 			x = r.max.x;
31080ee5cbfSDavid du Colombier 			if(kp[n+1])
31180ee5cbfSDavid du Colombier 				draw(im, Rect(x, r.min.y, x+1, r.max.y),
31280ee5cbfSDavid du Colombier 					k->textcolor->image, nil, ZP);
31380ee5cbfSDavid du Colombier 		}
31480ee5cbfSDavid du Colombier 		if(row != Nrow-1)
31580ee5cbfSDavid du Colombier 			draw(im, Rect(p.x, r.max.y, p.x+dx, r.max.y+1),
31680ee5cbfSDavid du Colombier 				k->textcolor->image, nil, ZP);
31780ee5cbfSDavid du Colombier 	}
31880ee5cbfSDavid du Colombier }
31980ee5cbfSDavid du Colombier 
32080ee5cbfSDavid du Colombier static void
keyresize(Keyboard * k)32180ee5cbfSDavid du Colombier keyresize(Keyboard *k)
32280ee5cbfSDavid du Colombier {
32380ee5cbfSDavid du Colombier 	int i;
32480ee5cbfSDavid du Colombier 
32580ee5cbfSDavid du Colombier 	for(i=0; i<Nstate; i++)
32680ee5cbfSDavid du Colombier 		keydraw(k, i);
32780ee5cbfSDavid du Colombier }
32880ee5cbfSDavid du Colombier 
32980ee5cbfSDavid du Colombier static void
keyboardshow(Keyboard * k)33080ee5cbfSDavid du Colombier keyboardshow(Keyboard *k)
33180ee5cbfSDavid du Colombier {
33280ee5cbfSDavid du Colombier 	Rectangle r;
33380ee5cbfSDavid du Colombier 
3349a747e4fSDavid du Colombier 	if (k->hidden)
3359a747e4fSDavid du Colombier 		return;
33680ee5cbfSDavid du Colombier 	if(k->im[0]==nil || !eqrect(k->im[0]->r, k->rect))
33780ee5cbfSDavid du Colombier 		keyresize(k);
33880ee5cbfSDavid du Colombier 	if(k->im[k->state&SMask] == nil)
33980ee5cbfSDavid du Colombier 		return;
34080ee5cbfSDavid du Colombier 	draw(k->screen, k->rect, k->im[k->state&SMask], nil, k->rect.min);
34180ee5cbfSDavid du Colombier 	if(k->state & SShift){
34280ee5cbfSDavid du Colombier 		r = keyrect(k, 3, 0);
34380ee5cbfSDavid du Colombier 		draw(k->screen, r, k->light->image, k->mask->image, ZP);
34480ee5cbfSDavid du Colombier 		r = keyrect(k, 3, 11);
34580ee5cbfSDavid du Colombier 		draw(k->screen, r, k->light->image, k->mask->image, ZP);
34680ee5cbfSDavid du Colombier 	}
34780ee5cbfSDavid du Colombier 	if(k->state & SCaps){
34880ee5cbfSDavid du Colombier 		r = keyrect(k, 2, 0);
34980ee5cbfSDavid du Colombier 		draw(k->screen, r, k->light->image, k->mask->image, ZP);
35080ee5cbfSDavid du Colombier 	}
35180ee5cbfSDavid du Colombier 	if(k->state & SControl){
35280ee5cbfSDavid du Colombier 		r = keyrect(k, 4, 0);
35380ee5cbfSDavid du Colombier 		draw(k->screen, r, k->light->image, k->mask->image, ZP);
35480ee5cbfSDavid du Colombier 	}
35580ee5cbfSDavid du Colombier 	flushimage(display, 1);
35680ee5cbfSDavid du Colombier }
35780ee5cbfSDavid du Colombier 
35880ee5cbfSDavid du Colombier static void
keydown(Keyboard * k,Point p)35980ee5cbfSDavid du Colombier keydown(Keyboard *k, Point p)
36080ee5cbfSDavid du Colombier {
36180ee5cbfSDavid du Colombier 	int row, col;
36280ee5cbfSDavid du Colombier 	Rectangle r;
36380ee5cbfSDavid du Colombier 	char *s;
36480ee5cbfSDavid du Colombier 
36580ee5cbfSDavid du Colombier 	s = whichkey(k, p, &row, &col, &r);
36680ee5cbfSDavid du Colombier 	if(s == k->key)
36780ee5cbfSDavid du Colombier 		return;
36880ee5cbfSDavid du Colombier 	keyboardshow(k);
36980ee5cbfSDavid du Colombier 	if(s != nil)
37080ee5cbfSDavid du Colombier 		draw(k->screen, r, k->light->image, k->mask->image, ZP);
37180ee5cbfSDavid du Colombier 	flushimage(display, 1);
37280ee5cbfSDavid du Colombier 	k->key = s;
37380ee5cbfSDavid du Colombier }
37480ee5cbfSDavid du Colombier 
37580ee5cbfSDavid du Colombier static int
keylookup(char * s)37680ee5cbfSDavid du Colombier keylookup(char *s)
37780ee5cbfSDavid du Colombier {
37880ee5cbfSDavid du Colombier 	int i;
37980ee5cbfSDavid du Colombier 
38080ee5cbfSDavid du Colombier 	for(i=0; keytab[i].name; i++)
38180ee5cbfSDavid du Colombier 		if(strcmp(s, keytab[i].name) == 0)
38280ee5cbfSDavid du Colombier 			return keytab[i].val;
38380ee5cbfSDavid du Colombier 	return s[0];
38480ee5cbfSDavid du Colombier }
38580ee5cbfSDavid du Colombier 
38680ee5cbfSDavid du Colombier static void
keyup(Keyboard * k,Point p)38780ee5cbfSDavid du Colombier keyup(Keyboard *k, Point p)
38880ee5cbfSDavid du Colombier {
38980ee5cbfSDavid du Colombier 	int row, col;
39080ee5cbfSDavid du Colombier 	Rectangle r;
39180ee5cbfSDavid du Colombier 	char *s;
39280ee5cbfSDavid du Colombier 	int val;
39380ee5cbfSDavid du Colombier 
39480ee5cbfSDavid du Colombier 	s = whichkey(k, p, &row, &col, &r);
39580ee5cbfSDavid du Colombier 	if(s == nil)
39680ee5cbfSDavid du Colombier 		return;
39780ee5cbfSDavid du Colombier 	val = keylookup(s);
39880ee5cbfSDavid du Colombier 	if(k->state & SControl)
39980ee5cbfSDavid du Colombier 		if(' '<val && val<0177)
40080ee5cbfSDavid du Colombier 			val &= ~0x60;
40180ee5cbfSDavid du Colombier 	if(strcmp(s, "Alt") == 0)
4029a747e4fSDavid du Colombier 		{;}
40380ee5cbfSDavid du Colombier 	if(strcmp(s, "Ctrl") == 0){
40480ee5cbfSDavid du Colombier 		k->state ^= SControl;
40580ee5cbfSDavid du Colombier 	}else
40680ee5cbfSDavid du Colombier 		k->state &= ~SControl;
40780ee5cbfSDavid du Colombier 	if(strcmp(s, "Shift")==0 || strcmp(s, "Caps")==0){
40880ee5cbfSDavid du Colombier 		if(strcmp(s, "Shift") == 0)
40980ee5cbfSDavid du Colombier 			k->state ^= SShift;
41080ee5cbfSDavid du Colombier 		if(strcmp(s, "Caps") == 0)
41180ee5cbfSDavid du Colombier 			k->state ^= SCaps;
41280ee5cbfSDavid du Colombier 	}else
41380ee5cbfSDavid du Colombier 		k->state &= ~SShift;
41480ee5cbfSDavid du Colombier 	keyboardshow(k);
41580ee5cbfSDavid du Colombier 	if(val)
4169a747e4fSDavid du Colombier 		chanprint(k->event, k->format, k->name, val);
41780ee5cbfSDavid du Colombier 	k->key = nil;
41880ee5cbfSDavid du Colombier }
41980ee5cbfSDavid du Colombier 
42080ee5cbfSDavid du Colombier static void
keyboardctl(Control * c,CParse * cp)4219a747e4fSDavid du Colombier keyboardctl(Control *c, CParse *cp)
42280ee5cbfSDavid du Colombier {
42380ee5cbfSDavid du Colombier 	int cmd;
42480ee5cbfSDavid du Colombier 	Rectangle r;
42580ee5cbfSDavid du Colombier 	Keyboard *k;
42680ee5cbfSDavid du Colombier 
42780ee5cbfSDavid du Colombier 	k = (Keyboard*)c;
4289a747e4fSDavid du Colombier 	cmd = _ctllookup(cp->args[0], cmds, nelem(cmds));
42980ee5cbfSDavid du Colombier 	switch(cmd){
43080ee5cbfSDavid du Colombier 	default:
4319a747e4fSDavid du Colombier 		ctlerror("%q: unrecognized message '%s'", k->name, cp->str);
43280ee5cbfSDavid du Colombier 		break;
43380ee5cbfSDavid du Colombier 	case EBorder:
4349a747e4fSDavid du Colombier 		_ctlargcount(k, cp, 2);
4359a747e4fSDavid du Colombier 		if(cp->iargs[1] < 0)
4369a747e4fSDavid du Colombier 			ctlerror("%q: bad border: %c", k->name, cp->str);
4379a747e4fSDavid du Colombier 		k->border = cp->iargs[1];
43880ee5cbfSDavid du Colombier 		break;
43980ee5cbfSDavid du Colombier 	case EBordercolor:
4409a747e4fSDavid du Colombier 		_ctlargcount(k, cp, 2);
4419a747e4fSDavid du Colombier 		_setctlimage(k, &k->bordercolor, cp->args[1]);
44280ee5cbfSDavid du Colombier 		break;
44380ee5cbfSDavid du Colombier 	case EFocus:
44480ee5cbfSDavid du Colombier 		/* ignore focus change */
44580ee5cbfSDavid du Colombier 		break;
44680ee5cbfSDavid du Colombier 	case EFont:
4479a747e4fSDavid du Colombier 		if(cp->nargs!=2 && cp->nargs!=3)
4489a747e4fSDavid du Colombier 			ctlerror("%q: bad font message '%s'", k->name, cp->str);
4499a747e4fSDavid du Colombier 		_setctlfont(k, &k->font, cp->args[1]);
4509a747e4fSDavid du Colombier 		if(cp->nargs == 3)
4519a747e4fSDavid du Colombier 			_setctlfont(k, &k->ctlfont, cp->args[2]);
45280ee5cbfSDavid du Colombier 		else
4539a747e4fSDavid du Colombier 			_setctlfont(k, &k->ctlfont, cp->args[1]);
45480ee5cbfSDavid du Colombier 		break;
45580ee5cbfSDavid du Colombier 	case EFormat:
4569a747e4fSDavid du Colombier 		_ctlargcount(k, cp, 2);
4579a747e4fSDavid du Colombier 		k->format = ctlstrdup(cp->args[1]);
4589a747e4fSDavid du Colombier 		break;
4599a747e4fSDavid du Colombier 	case EHide:
4609a747e4fSDavid du Colombier 		_ctlargcount(k, cp, 1);
4619a747e4fSDavid du Colombier 		k->hidden = 1;
46280ee5cbfSDavid du Colombier 		break;
46380ee5cbfSDavid du Colombier 	case EImage:
4649a747e4fSDavid du Colombier 		_ctlargcount(k, cp, 2);
4659a747e4fSDavid du Colombier 		_setctlimage(k, &k->image, cp->args[1]);
46680ee5cbfSDavid du Colombier 		break;
46780ee5cbfSDavid du Colombier 	case ELight:
4689a747e4fSDavid du Colombier 		_ctlargcount(k, cp, 2);
4699a747e4fSDavid du Colombier 		_setctlimage(k, &k->light, cp->args[1]);
47080ee5cbfSDavid du Colombier 		break;
47180ee5cbfSDavid du Colombier 	case EMask:
4729a747e4fSDavid du Colombier 		_ctlargcount(k, cp, 2);
4739a747e4fSDavid du Colombier 		_setctlimage(k, &k->mask, cp->args[1]);
47480ee5cbfSDavid du Colombier 		break;
47580ee5cbfSDavid du Colombier 	case ERect:
4769a747e4fSDavid du Colombier 		_ctlargcount(k, cp, 5);
4779a747e4fSDavid du Colombier 		r.min.x = cp->iargs[1];
4789a747e4fSDavid du Colombier 		r.min.y = cp->iargs[2];
4799a747e4fSDavid du Colombier 		r.max.x = cp->iargs[3];
4809a747e4fSDavid du Colombier 		r.max.y = cp->iargs[4];
48180ee5cbfSDavid du Colombier 		if(Dx(r)<0 || Dy(r)<0)
4829a747e4fSDavid du Colombier 			ctlerror("%q: bad rectangle: %s", k->name, cp->str);
48380ee5cbfSDavid du Colombier 		k->rect = r;
48480ee5cbfSDavid du Colombier 		keyboardshow(k);
48580ee5cbfSDavid du Colombier 		break;
4869a747e4fSDavid du Colombier 	case EReveal:
4879a747e4fSDavid du Colombier 		_ctlargcount(k, cp, 1);
4889a747e4fSDavid du Colombier 		k->hidden = 0;
4899a747e4fSDavid du Colombier 		keyboardshow(k);
4909a747e4fSDavid du Colombier 		break;
4919a747e4fSDavid du Colombier 	case EShow:
4929a747e4fSDavid du Colombier 		_ctlargcount(k, cp, 1);
4939a747e4fSDavid du Colombier 		keyboardshow(k);
4949a747e4fSDavid du Colombier 		break;
4959a747e4fSDavid du Colombier 	case ESize:
4969a747e4fSDavid du Colombier 		if (cp->nargs == 3)
4979a747e4fSDavid du Colombier 			r.max = Pt(0x7fffffff, 0x7fffffff);
4989a747e4fSDavid du Colombier 		else{
4999a747e4fSDavid du Colombier 			_ctlargcount(k, cp, 5);
5009a747e4fSDavid du Colombier 			r.max.x = cp->iargs[3];
5019a747e4fSDavid du Colombier 			r.max.y = cp->iargs[4];
50280ee5cbfSDavid du Colombier 		}
5039a747e4fSDavid du Colombier 		r.min.x = cp->iargs[1];
5049a747e4fSDavid du Colombier 		r.min.y = cp->iargs[2];
5059a747e4fSDavid du Colombier 		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)
5069a747e4fSDavid du Colombier 			ctlerror("%q: bad sizes: %s", k->name, cp->str);
5079a747e4fSDavid du Colombier 		k->size.min = r.min;
5089a747e4fSDavid du Colombier 		k->size.max = r.max;
5099a747e4fSDavid du Colombier 		break;
5109a747e4fSDavid du Colombier 	}
5119a747e4fSDavid du Colombier }
5129a747e4fSDavid du Colombier 
5139a747e4fSDavid du Colombier Control*
createkeyboard(Controlset * cs,char * name)5149a747e4fSDavid du Colombier createkeyboard(Controlset *cs, char *name)
5159a747e4fSDavid du Colombier {
5169a747e4fSDavid du Colombier 	Keyboard *k;
5179a747e4fSDavid du Colombier 
5189a747e4fSDavid du Colombier 	k = (Keyboard *)_createctl(cs, "keyboard", sizeof(Keyboard), name);
5199a747e4fSDavid du Colombier 	k->image = _getctlimage("white");
5209a747e4fSDavid du Colombier 	k->mask = _getctlimage("opaque");
5219a747e4fSDavid du Colombier 	k->light = _getctlimage("yellow");
5229a747e4fSDavid du Colombier 	k->bordercolor = _getctlimage("black");
5239a747e4fSDavid du Colombier 	k->textcolor = _getctlimage("black");
5249a747e4fSDavid du Colombier 	k->font = _getctlfont("font");
5259a747e4fSDavid du Colombier 	k->ctlfont = _getctlfont("font");
5269a747e4fSDavid du Colombier 	k->format = ctlstrdup("%q: value 0x%x");
5279a747e4fSDavid du Colombier 	k->border = 0;
5289a747e4fSDavid du Colombier 	k->lastbut = 0;
5299a747e4fSDavid du Colombier 	k->key = nil;
5309a747e4fSDavid du Colombier 	k->state = SRegular;
5319a747e4fSDavid du Colombier 	k->ctl = keyboardctl;
5329a747e4fSDavid du Colombier 	k->mouse = keyboardmouse;
5339a747e4fSDavid du Colombier 	k->exit = keyboardfree;
5349a747e4fSDavid du Colombier 	k->size = Rect(246, 2 + 5 * (k->font->font->height + 1), 512, 256);
5359a747e4fSDavid du Colombier 	return k;
53680ee5cbfSDavid du Colombier }
537