xref: /plan9/sys/src/9/port/devkbmap.c (revision e29df7b0e1465888597fc56c7bb3d27bbfad66d2)
1 /*
2  *  keyboard map
3  */
4 
5 #include	"u.h"
6 #include	"../port/lib.h"
7 #include	"mem.h"
8 #include	"dat.h"
9 #include	"fns.h"
10 #include	"../port/error.h"
11 
12 enum{
13 	Qdir,
14 	Qdata,
15 };
16 Dirtab kbmaptab[]={
17 	".",		{Qdir, 0, QTDIR},	0,	0555,
18 	"kbmap",	{Qdata, 0},		0,	0600,
19 };
20 #define	NKBFILE	sizeof(kbmaptab)/sizeof(kbmaptab[0])
21 
22 #define	KBLINELEN	(3*NUMSIZE+1)	/* t code val\n */
23 
24 static Chan *
kbmapattach(char * spec)25 kbmapattach(char *spec)
26 {
27 	return devattach(L'κ', spec);
28 }
29 
30 static Walkqid*
kbmapwalk(Chan * c,Chan * nc,char ** name,int nname)31 kbmapwalk(Chan *c, Chan *nc, char **name, int nname)
32 {
33 	return devwalk(c, nc, name, nname, kbmaptab, NKBFILE, devgen);
34 }
35 
36 static int
kbmapstat(Chan * c,uchar * dp,int n)37 kbmapstat(Chan *c, uchar *dp, int n)
38 {
39 	return devstat(c, dp, n, kbmaptab, NKBFILE, devgen);
40 }
41 
42 static Chan*
kbmapopen(Chan * c,int omode)43 kbmapopen(Chan *c, int omode)
44 {
45 	if(!iseve())
46 		error(Eperm);
47 	return devopen(c, omode, kbmaptab, NKBFILE, devgen);
48 }
49 
50 static void
kbmapclose(Chan * c)51 kbmapclose(Chan *c)
52 {
53 	if(c->aux){
54 		free(c->aux);
55 		c->aux = nil;
56 	}
57 }
58 
59 static long
kbmapread(Chan * c,void * a,long n,vlong offset)60 kbmapread(Chan *c, void *a, long n, vlong offset)
61 {
62 	char *bp;
63 	char tmp[KBLINELEN+1];
64 	int t, sc;
65 	Rune r;
66 
67 	if(c->qid.type == QTDIR)
68 		return devdirread(c, a, n, kbmaptab, NKBFILE, devgen);
69 
70 	switch((int)(c->qid.path)){
71 	case Qdata:
72 		if(kbdgetmap(offset/KBLINELEN, &t, &sc, &r)) {
73 			bp = tmp;
74 			bp += readnum(0, bp, NUMSIZE, t, NUMSIZE);
75 			bp += readnum(0, bp, NUMSIZE, sc, NUMSIZE);
76 			bp += readnum(0, bp, NUMSIZE, r, NUMSIZE);
77 			*bp++ = '\n';
78 			*bp = 0;
79 			n = readstr(offset%KBLINELEN, a, n, tmp);
80 		} else
81 			n = 0;
82 		break;
83 	default:
84 		n=0;
85 		break;
86 	}
87 	return n;
88 }
89 
90 static long
kbmapwrite(Chan * c,void * a,long n,vlong)91 kbmapwrite(Chan *c, void *a, long n, vlong)
92 {
93 	char line[100], *lp, *b;
94 	int key, m, l;
95 	Rune r;
96 
97 	if(c->qid.type == QTDIR)
98 		error(Eperm);
99 
100 	switch((int)(c->qid.path)){
101 	case Qdata:
102 		b = a;
103 		l = n;
104 		lp = line;
105 		if(c->aux){
106 			strcpy(line, c->aux);
107 			lp = line+strlen(line);
108 			free(c->aux);
109 			c->aux = nil;
110 		}
111 		while(--l >= 0) {
112 			*lp++  = *b++;
113 			if(lp[-1] == '\n' || lp == &line[sizeof(line)-1]) {
114 				*lp = 0;
115 				if(*line == 0)
116 					error(Ebadarg);
117 				if(*line == '\n' || *line == '#'){
118 					lp = line;
119 					continue;
120 				}
121 				lp = line;
122 				while(*lp == ' ' || *lp == '\t')
123 					lp++;
124 				m = strtoul(line, &lp, 0);
125 				key = strtoul(lp, &lp, 0);
126 				while(*lp == ' ' || *lp == '\t')
127 					lp++;
128 				r = 0;
129 				if(*lp == '\'' && lp[1])
130 					chartorune(&r, lp+1);
131 				else if(*lp == '^' && lp[1]){
132 					chartorune(&r, lp+1);
133 					if(0x40 <= r && r < 0x60)
134 						r -= 0x40;
135 					else
136 						error(Ebadarg);
137 				}else if(*lp == 'M' && ('1' <= lp[1] && lp[1] <= '5'))
138 					r = 0xF900+lp[1]-'0';
139 				else if(*lp>='0' && *lp<='9') /* includes 0x... */
140 					r = strtoul(lp, &lp, 0);
141 				else
142 					error(Ebadarg);
143 				kbdputmap(m, key, r);
144 				lp = line;
145 			}
146 		}
147 		if(lp != line){
148 			l = lp-line;
149 			c->aux = lp = smalloc(l+1);
150 			memmove(lp, line, l);
151 			lp[l] = 0;
152 		}
153 		break;
154 	default:
155 		error(Ebadusefd);
156 	}
157 	return n;
158 }
159 
160 Dev kbmapdevtab = {
161 	L'κ',
162 	"kbmap",
163 
164 	devreset,
165 	devinit,
166 	devshutdown,
167 	kbmapattach,
168 	kbmapwalk,
169 	kbmapstat,
170 	kbmapopen,
171 	devcreate,
172 	kbmapclose,
173 	kbmapread,
174 	devbread,
175 	kbmapwrite,
176 	devbwrite,
177 	devremove,
178 	devwstat,
179 };
180