Imported Upstream version 2.0.4_rc1
[platform/upstream/kbd.git] / src / libkeymap / kmap.c
1 #include "config.h"
2
3 #include <stdlib.h>
4 #include <string.h>
5
6 #include "nls.h"
7 #include "kbd.h"
8
9 #include "keymap.h"
10
11 #include "contextP.h"
12 #include "ksyms.h"
13 #include "modifiers.h"
14
15 int lk_map_exists(struct lk_ctx *ctx, unsigned int k_table)
16 {
17         return (lk_array_get_ptr(ctx->keymap, k_table) != NULL);
18 }
19
20 int lk_get_keys_total(struct lk_ctx *ctx, unsigned int k_table)
21 {
22         struct lk_array *map;
23         map = lk_array_get_ptr(ctx->keymap, k_table);
24         if (!map) {
25                 return 0;
26         }
27         return map->total;
28 }
29
30 int lk_key_exists(struct lk_ctx *ctx, unsigned int k_table, unsigned int k_index)
31 {
32         struct lk_array *map;
33         unsigned int *key;
34
35         map = lk_array_get_ptr(ctx->keymap, k_table);
36         if (!map) {
37                 return 0;
38         }
39
40         key = lk_array_get(map, k_index);
41         if (!key) {
42                 return 0;
43         }
44
45         return (*key > 0);
46 }
47
48 int lk_add_map(struct lk_ctx *ctx, unsigned int k_table)
49 {
50         struct lk_array *keys;
51
52         if (lk_map_exists(ctx, k_table)) {
53                 return 0;
54         }
55
56         keys = malloc(sizeof(struct lk_array));
57         if (!keys) {
58                 ERR(ctx, _("out of memory"));
59                 return -1;
60         }
61
62         lk_array_init(keys, sizeof(unsigned int), 0);
63
64         if (lk_array_set(ctx->keymap, k_table, &keys) < 0) {
65                 free(keys);
66                 ERR(ctx, _("out of memory"));
67                 return -1;
68         }
69
70         return 0;
71 }
72
73 int lk_get_key(struct lk_ctx *ctx, unsigned int k_table, unsigned int k_index)
74 {
75         struct lk_array *map;
76         unsigned int *key;
77
78         map = lk_array_get_ptr(ctx->keymap, k_table);
79         if (!map) {
80                 ERR(ctx, _("unable to get keymap %d"), k_table);
81                 return -1;
82         }
83
84         key = lk_array_get(map, k_index);
85         if (!key || *key == 0) {
86                 return K_HOLE;
87         }
88
89         return (*key) - 1;
90 }
91
92 int lk_del_key(struct lk_ctx *ctx, unsigned int k_table, unsigned int k_index)
93 {
94         struct lk_array *map;
95
96         map = lk_array_get_ptr(ctx->keymap, k_table);
97         if (!map) {
98                 ERR(ctx, _("unable to get keymap %d"), k_table);
99                 return -1;
100         }
101
102         if (!lk_array_exists(map, k_index))
103                 return 0;
104
105         if (lk_array_unset(map, k_index) < 0) {
106                 ERR(ctx, _("unable to unset key %d for table %d"),
107                     k_index, k_table);
108                 return -1;
109         }
110
111         return 0;
112 }
113
114 int lk_add_key(struct lk_ctx *ctx, unsigned int k_table, unsigned int k_index, int keycode)
115 {
116         struct lk_array *map;
117         unsigned int code = keycode + 1;
118
119         if (keycode == CODE_FOR_UNKNOWN_KSYM) {
120                 /* is safer not to be silent in this case, 
121                  * it can be caused by coding errors as well. */
122                 ERR(ctx, _("lk_add_key called with bad keycode %d"), keycode);
123                 return -1;
124         }
125
126         map = lk_array_get_ptr(ctx->keymap, k_table);
127         if (!map) {
128                 if (ctx->keywords & LK_KEYWORD_KEYMAPS) {
129                         ERR(ctx, _("adding map %d violates explicit keymaps line"),
130                             k_table);
131                         return -1;
132                 }
133
134                 if (lk_add_map(ctx, k_table) < 0)
135                         return -1;
136         }
137
138         if ((ctx->keywords & LK_KEYWORD_ALTISMETA) && keycode == K_HOLE &&
139             lk_key_exists(ctx, k_table, k_index))
140                 return 0;
141
142         map = lk_array_get_ptr(ctx->keymap, k_table);
143
144         if (lk_array_set(map, k_index, &code) < 0) {
145                 ERR(ctx, _("unable to set key %d for table %d"),
146                     k_index, k_table);
147                 return -1;
148         }
149
150         if (ctx->keywords & LK_KEYWORD_ALTISMETA) {
151                 unsigned int alttable = k_table | M_ALT;
152                 int type              = KTYP(keycode);
153                 int val               = KVAL(keycode);
154
155                 if (alttable != k_table && lk_map_exists(ctx, alttable) &&
156                     !lk_key_exists(ctx, alttable, k_index) &&
157                     (type == KT_LATIN || type == KT_LETTER) &&
158                     val < 128) {
159                         if (lk_add_key(ctx, alttable, k_index, K(KT_META, val)) < 0)
160                                 return -1;
161                 }
162         }
163
164         return 0;
165 }
166
167 static int
168 do_constant_key(struct lk_ctx *ctx, int i, unsigned short key)
169 {
170         int typ, val;
171         unsigned int j;
172
173         typ = KTYP(key);
174         val = KVAL(key);
175
176         if ((typ == KT_LATIN || typ == KT_LETTER) &&
177             ((val >= 'a' && val <= 'z') || (val >= 'A' && val <= 'Z'))) {
178                 unsigned short defs[16];
179                 defs[0] = K(KT_LETTER, val);
180                 defs[1] = K(KT_LETTER, val ^ 32);
181                 defs[2] = defs[0];
182                 defs[3] = defs[1];
183
184                 for (j          = 4; j < 8; j++)
185                         defs[j] = K(KT_LATIN, val & ~96);
186
187                 for (j          = 8; j < 16; j++)
188                         defs[j] = K(KT_META, KVAL(defs[j - 8]));
189
190                 for (j = 0; j < ctx->keymap->total; j++) {
191                         if (!lk_map_exists(ctx, j))
192                                 continue;
193
194                         if (j > 0 && lk_key_exists(ctx, j, i))
195                                 continue;
196
197                         if (lk_add_key(ctx, j, i, defs[j % 16]) < 0)
198                                 return -1;
199                 }
200
201         } else {
202                 /* do this also for keys like Escape,
203                    as promised in the man page */
204                 for (j = 1; j < ctx->keymap->total; j++) {
205                         if (!lk_map_exists(ctx, j))
206                                 continue;
207
208                         if (lk_key_exists(ctx, j, i))
209                                 continue;
210
211                         if (lk_add_key(ctx, j, i, key) < 0)
212                                 return -1;
213                 }
214         }
215         return 0;
216 }
217
218 int lk_add_constants(struct lk_ctx *ctx)
219 {
220         unsigned int i, r0 = 0;
221
222         if (ctx->keywords & LK_KEYWORD_KEYMAPS) {
223                 while (r0 < ctx->keymap->total && !lk_map_exists(ctx, r0))
224                         r0++;
225         }
226
227         for (i = 0; i < ctx->key_constant->total; i++) {
228                 char *constant;
229                 unsigned short key;
230
231                 constant = lk_array_get(ctx->key_constant, i);
232                 if (!constant || !(*constant))
233                         continue;
234
235                 if (!lk_map_exists(ctx, r0)) {
236                         ERR(ctx, _("impossible error in lk_add_constants"));
237                         return -1;
238                 }
239
240                 key = lk_get_key(ctx, r0, i);
241
242                 if (do_constant_key(ctx, i, key) < 0)
243                         return -1;
244         }
245         return 0;
246 }