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* 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* 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* 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 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 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 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 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 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 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 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 207 usage(void) 208 { 209 fprint(2, "usage: kbmap [file...]\n"); 210 exits("usage"); 211 } 212 213 void 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