Merge branch 'libkeymap'
[platform/upstream/kbd.git] / src / libkeymap / kmap.c
1 #include <stdlib.h>
2 #include <string.h>
3
4 #include "nls.h"
5 #include "kbd.h"
6
7 #include "keymap.h"
8
9 #include "contextP.h"
10 #include "ksyms.h"
11 #include "modifiers.h"
12
13 int
14 lk_map_exists(struct lk_ctx *ctx, unsigned int k_table)
15 {
16         return (lk_array_get_ptr(ctx->keymap, k_table) != NULL);
17 }
18
19 int
20 lk_key_exists(struct lk_ctx *ctx, unsigned int k_table, unsigned int k_index)
21 {
22         struct lk_array *map;
23         u_short *key;
24
25         map = lk_array_get_ptr(ctx->keymap, k_table);
26         if (!map) {
27                 return 0;
28         }
29
30         key = lk_array_get(map, k_index);
31         if (!key) {
32                 return 0;
33         }
34
35         return (*key > 0);
36 }
37
38 int
39 lk_add_map(struct lk_ctx *ctx, unsigned int k_table)
40 {
41         struct lk_array *keys;
42
43         if (lk_map_exists(ctx, k_table)) {
44                 return 0;
45         }
46
47         keys = malloc(sizeof(struct lk_array));
48         if (!keys) {
49                 ERR(ctx, _("out of memory"));
50                 return -1;
51         }
52
53         lk_array_init(keys, sizeof(unsigned int), 0);
54
55         if (lk_array_set(ctx->keymap, k_table, &keys) < 0) {
56                 free(keys);
57                 ERR(ctx, _("out of memory"));
58                 return -1;
59         }
60
61         return 0;
62 }
63
64 int
65 lk_get_key(struct lk_ctx *ctx, unsigned int k_table, unsigned int k_index)
66 {
67         struct lk_array *map;
68         unsigned int *key;
69
70         map = lk_array_get_ptr(ctx->keymap, k_table);
71         if (!map) {
72                 ERR(ctx, _("unable to keymap %d"), k_table);
73                 return -1;
74         }
75
76         key = lk_array_get(map, k_index);
77         if (!key || *key == 0) {
78                 return K_HOLE;
79         }
80
81         return (*key)-1;
82 }
83
84 int
85 lk_del_key(struct lk_ctx *ctx, unsigned int k_table, unsigned int k_index)
86 {
87         struct lk_array *map;
88
89         map = lk_array_get_ptr(ctx->keymap, k_table);
90         if (!map) {
91                 ERR(ctx, _("unable to get keymap %d"), k_table);
92                 return -1;
93         }
94
95         if (!lk_array_exists(map, k_index))
96                 return 0;
97
98         if (lk_array_unset(map, k_index) < 0) {
99                 ERR(ctx, _("unable to unset key %d for table %d"),
100                         k_index, k_table);
101                 return -1;
102         }
103
104         return 0;
105 }
106
107 int
108 lk_add_key(struct lk_ctx *ctx, unsigned int k_table, unsigned int k_index, int keycode)
109 {
110         struct lk_array *map;
111         unsigned int code = keycode + 1;
112
113         if (keycode == CODE_FOR_UNKNOWN_KSYM) {
114                 /* is safer not to be silent in this case, 
115                  * it can be caused by coding errors as well. */
116                 ERR(ctx, _("lk_add_key called with bad keycode %d"), keycode);
117                 return -1;
118         }
119
120         if (!k_index && keycode == K_NOSUCHMAP)
121                 return 0;
122
123         map = lk_array_get_ptr(ctx->keymap, k_table);
124         if (!map) {
125                 if (ctx->keywords & LK_KEYWORD_KEYMAPS) {
126                         ERR(ctx, _("adding map %d violates explicit keymaps line"),
127                             k_table);
128                         return -1;
129                 }
130
131                 if (lk_add_map(ctx, k_table) < 0)
132                         return -1;
133         }
134
135         if ((ctx->keywords & LK_KEYWORD_ALTISMETA) && keycode == K_HOLE &&
136             lk_key_exists(ctx, k_table, k_index))
137                 return 0;
138
139         map = lk_array_get_ptr(ctx->keymap, k_table);
140
141         if (lk_array_set(map, k_index, &code) < 0) {
142                 ERR(ctx, _("unable to set key %d for table %d"),
143                         k_index, k_table);
144                 return -1;
145         }
146
147         if (ctx->keywords & LK_KEYWORD_ALTISMETA) {
148                 unsigned int alttable = k_table | M_ALT;
149                 int type = KTYP(keycode);
150                 int val = KVAL(keycode);
151
152                 if (alttable != k_table && !lk_key_exists(ctx, alttable, k_index) &&
153                     (type == KT_LATIN || type == KT_LETTER) && val < 128) {
154                         if (lk_add_map(ctx, alttable) < 0)
155                                 return -1;
156                         if (lk_add_key(ctx, alttable, k_index, K(KT_META, val)) < 0)
157                                 return -1;
158                 }
159         }
160
161         return 0;
162 }
163
164 int
165 lk_get_func(struct lk_ctx *ctx, struct kbsentry *kbs)
166 {
167         char *s;
168
169         s = lk_array_get_ptr(ctx->func_table, kbs->kb_func);
170         if (!s) {
171                 ERR(ctx, _("func %d not allocated"), kbs->kb_func);
172                 return -1;
173         }
174
175         strncpy((char *)kbs->kb_string, s, sizeof(kbs->kb_string));
176         kbs->kb_string[sizeof(kbs->kb_string) - 1] = 0;
177
178         return 0;
179 }
180
181
182 int
183 lk_add_func(struct lk_ctx *ctx, struct kbsentry kbs)
184 {
185         char *s;
186
187         s = lk_array_get_ptr(ctx->func_table, kbs.kb_func);
188         if (s)
189                 free(s);
190
191         s = strdup((char *)kbs.kb_string);
192
193         if (lk_array_set(ctx->func_table, kbs.kb_func, &s) < 0) {
194                 free(s);
195                 ERR(ctx, _("out of memory"));
196                 return -1;
197         }
198
199         return 0;
200 }
201
202 int
203 lk_add_diacr(struct lk_ctx *ctx, unsigned int diacr, unsigned int base, unsigned int res)
204 {
205         struct kb_diacr *ptr;
206
207         ptr = malloc(sizeof(struct kb_diacr));
208         if (!ptr) {
209                 ERR(ctx, _("out of memory"));
210                 return -1;
211         }
212
213         ptr->diacr  = diacr;
214         ptr->base   = base;
215         ptr->result = res;
216
217         lk_array_append(ctx->accent_table, &ptr);
218
219         return 0;
220 }
221
222 int
223 lk_add_compose(struct lk_ctx *ctx,
224                unsigned int diacr,
225                unsigned int base,
226                unsigned int res)
227 {
228         int direction = TO_8BIT;
229
230 #ifdef KDSKBDIACRUC
231         if (ctx->flags & LK_FLAG_PREFER_UNICODE)
232                 direction = TO_UNICODE;
233 #endif
234         return lk_add_diacr(ctx,
235                 convert_code(ctx, diacr, direction),
236                 convert_code(ctx, base, direction),
237                 convert_code(ctx, res, direction)
238         );
239 }
240
241 static int
242 do_constant_key(struct lk_ctx *ctx, int i, u_short key)
243 {
244         int typ, val;
245         unsigned int j;
246
247         typ = KTYP(key);
248         val = KVAL(key);
249
250         if ((typ == KT_LATIN || typ == KT_LETTER) &&
251             ((val >= 'a' && val <= 'z') || (val >= 'A' && val <= 'Z'))) {
252                 u_short defs[16];
253                 defs[0] = K(KT_LETTER, val);
254                 defs[1] = K(KT_LETTER, val ^ 32);
255                 defs[2] = defs[0];
256                 defs[3] = defs[1];
257
258                 for (j = 4; j < 8; j++)
259                         defs[j] = K(KT_LATIN, val & ~96);
260
261                 for (j = 8; j < 16; j++)
262                         defs[j] = K(KT_META, KVAL(defs[j - 8]));
263
264                 for (j = 0; j < ctx->keymap->total; j++) {
265                         if (!lk_map_exists(ctx, j))
266                                 continue;
267
268                         if (j > 0 && lk_key_exists(ctx, j, i))
269                                 continue;
270
271                         if (lk_add_key(ctx, j, i, defs[j % 16]) < 0)
272                                 return -1;
273                 }
274
275         } else {
276                 /* do this also for keys like Escape,
277                    as promised in the man page */
278                 for (j = 1; j < ctx->keymap->total; j++) {
279                         if (!lk_map_exists(ctx, j))
280                                 continue;
281
282                         if (lk_key_exists(ctx, j, i))
283                                 continue;
284
285                         if (lk_add_key(ctx, j, i, key) < 0)
286                                 return -1;
287                 }
288         }
289         return 0;
290 }
291
292 int
293 lk_add_constants(struct lk_ctx *ctx)
294 {
295         unsigned int i, r0 = 0;
296
297         if (ctx->keywords & LK_KEYWORD_KEYMAPS) {
298                 while (r0 < ctx->keymap->total && !lk_map_exists(ctx, r0))
299                         r0++;
300         }
301
302         for (i = 0; i < ctx->key_constant->total; i++) {
303                 char *constant;
304                 u_short key;
305
306                 constant = lk_array_get(ctx->key_constant, i);
307                 if (!constant || !(*constant))
308                         continue;
309
310                 if (!lk_map_exists(ctx, r0)) {
311                         ERR(ctx, _("impossible error in lk_add_constants"));
312                         return -1;
313                 }
314
315                 key = lk_get_key(ctx, r0, i);
316
317                 if (do_constant_key(ctx, i, key) < 0)
318                         return -1;
319         }
320         return 0;
321 }