xref: /plan9/sys/src/cmd/kbmap.c (revision 67493d07e6e3eada393e3dcdcba5b898b5f3261a)
1 #include <u.h>
2 #include <libc.h>
3 #include <draw.h>
4 #include <event.h>
5 
6 typedef struct KbMap KbMap;
7 struct KbMap {
8 	char *name;
9 	char *file;
10 	Rectangle r;
11 	int current;
12 };
13 
14 KbMap *map;
15 int nmap;
16 Image *lightblue;
17 Image *justblue;
18 
19 enum {
20 	PAD = 3,
21 	MARGIN = 5
22 };
23 
24 char *dir = "/sys/lib/kbmap";
25 
26 void*
erealloc(void * v,ulong n)27 erealloc(void *v, ulong n)
28 {
29 	v = realloc(v, n);
30 	if(v == nil)
31 		sysfatal("out of memory reallocating %lud", n);
32 	return v;
33 }
34 
35 void*
emalloc(ulong n)36 emalloc(ulong n)
37 {
38 	void *v;
39 
40 	v = malloc(n);
41 	if(v == nil)
42 		sysfatal("out of memory allocating %lud", n);
43 	memset(v, 0, n);
44 	return v;
45 }
46 
47 char*
estrdup(char * s)48 estrdup(char *s)
49 {
50 	int l;
51 	char *t;
52 
53 	if (s == nil)
54 		return nil;
55 	l = strlen(s)+1;
56 	t = emalloc(l);
57 	memcpy(t, s, l);
58 
59 	return t;
60 }
61 
62 void
init(void)63 init(void)
64 {
65 	int i, fd, nr;
66 	Dir *pd;
67 	char buf[128];
68 
69 	if((fd = open(dir, OREAD)) < 0)
70 		return;
71 
72 	nmap = nr = dirreadall(fd, &pd);
73 	map = emalloc(nr * sizeof(KbMap));
74 	for(i=0; i<nr; i++){
75 		sprint(buf, "%s/%s", dir, pd[i].name);
76 		map[i].file = estrdup(buf);
77 		map[i].name = estrdup(pd[i].name);
78 		map[i].current = 0;
79 	}
80 	free(pd);
81 
82 	close(fd);
83 }
84 
85 void
drawmap(int i)86 drawmap(int i)
87 {
88 	if(map[i].current)
89 		draw(screen, map[i].r, justblue, nil, ZP);
90 	else
91 		draw(screen, map[i].r, lightblue, nil, ZP);
92 
93 	_string(screen, addpt(map[i].r.min, Pt(2,0)), display->black, ZP,
94 		font, map[i].name, nil, strlen(map[i].name),
95 		map[i].r, nil, ZP, SoverD);
96 	border(screen, map[i].r, 1, display->black, ZP);
97 }
98 
99 void
geometry(void)100 geometry(void)
101 {
102 	int i, rows;
103 	Rectangle r;
104 
105 	rows = (Dy(screen->r)-2*MARGIN+PAD)/(font->height+PAD);
106 
107 	r = Rect(0,0,(Dx(screen->r)-2*MARGIN), font->height);
108 	for(i=0; i<nmap; i++)
109 		map[i].r = rectaddpt(rectaddpt(r, Pt(MARGIN+(PAD+Dx(r))*(i/rows),
110 					MARGIN+(PAD+Dy(r))*(i%rows))), screen->r.min);
111 
112 }
113 
114 void
redraw(Image * screen)115 redraw(Image *screen)
116 {
117 	int i;
118 
119 	draw(screen, screen->r, lightblue, nil, ZP);
120 	for(i=0; i<nmap; i++)
121 		drawmap(i);
122 	flushimage(display, 1);
123 }
124 
125 void
eresized(int new)126 eresized(int new)
127 {
128 	if(new && getwindow(display, Refmesg) < 0)
129 		fprint(2,"can't reattach to window");
130 	geometry();
131 	redraw(screen);
132 }
133 
134 int
writemap(char * file)135 writemap(char *file)
136 {
137 	int i, fd, ofd;
138 	char buf[8192];
139 
140 	if((fd = open(file, OREAD)) < 0){
141 		fprint(2, "cannot open %s: %r", file);
142 		return -1;
143 	}
144 	if((ofd = open("/dev/kbmap", OWRITE)) < 0) {
145 		fprint(2, "cannot open /dev/kbmap: %r");
146 		close(fd);
147 		return -1;
148 	}
149 	while((i = read(fd, buf, sizeof buf)) > 0)
150 		if(write(ofd, buf, i) != i){
151 			fprint(2, "writing /dev/kbmap: %r");
152 			break;
153 		}
154 
155 	close(fd);
156 	close(ofd);
157 	return 0;
158 }
159 
160 void
click(Mouse m)161 click(Mouse m)
162 {
163 	int i, j;
164 	char buf[128];
165 
166 	if(m.buttons == 0 || (m.buttons & ~4))
167 		return;
168 
169 	for(i=0; i<nmap; i++)
170 		if(ptinrect(m.xy, map[i].r))
171 			break;
172 	if(i == nmap)
173 		return;
174 
175 	do
176 		m = emouse();
177 	while(m.buttons == 4);
178 
179 	if(m.buttons != 0){
180 		do
181 			m = emouse();
182 		while(m.buttons);
183 		return;
184 	}
185 
186 	for(j=0; j<nmap; j++)
187 		if(ptinrect(m.xy, map[j].r))
188 			break;
189 	if(j != i)
190 		return;
191 
192 	/* since maps are often just a delta of the distributed map... */
193 	snprint(buf, sizeof buf, "%s/ascii", dir);
194 	writemap(buf);
195 	writemap(map[i].file);
196 
197 	/* clean the previous current map */
198 	for(j=0; j<nmap; j++)
199 		map[j].current = 0;
200 
201 	map[i].current = 1;
202 
203 	redraw(screen);
204 }
205 
206 void
usage(void)207 usage(void)
208 {
209 	fprint(2, "usage: kbmap [file...]\n");
210 	exits("usage");
211 }
212 
213 void
main(int argc,char ** argv)214 main(int argc, char **argv)
215 {
216 	Event e;
217 	char *c;
218 
219 	if(argc > 1) {
220 		argv++; argc--;
221 		map = emalloc((argc)*sizeof(KbMap));
222 		while(argc--) {
223 			map[argc].file = estrdup(argv[argc]);
224 			c = strrchr(map[argc].file, '/');
225 			map[argc].name = (c == nil ? map[argc].file : c+1);
226 			map[argc].current = 0;
227 			nmap++;
228 		}
229 	} else
230 		init();
231 
232 	initdraw(0, 0, "kbmap");
233 	lightblue = allocimagemix(display, DPalebluegreen, DWhite);
234 	if(lightblue == nil)
235 		sysfatal("allocimagemix: %r");
236 	justblue = allocimagemix(display, DBlue, DWhite);
237 	if(justblue == nil)
238 		sysfatal("allocimagemix: %r");
239 
240 	eresized(0);
241 	einit(Emouse|Ekeyboard);
242 
243 	for(;;){
244 		switch(eread(Emouse|Ekeyboard, &e)){
245 		case Ekeyboard:
246 			if(e.kbdc==0x7F || e.kbdc=='q')
247 				exits(0);
248 			break;
249 		case Emouse:
250 			if(e.mouse.buttons)
251 				click(e.mouse);
252 			break;
253 		}
254 	}
255 }
256 
257