1 /* 2 * Copyright 2009 Dan Nicholson <dbn.lists (at) gmail.com> 3 * Copyright 2012 Intel Corporation 4 * Copyright 2012 Ran Benita <ran234 (at) gmail.com> 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 * AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 * 23 * Except as contained in this notice, the names of the authors or their 24 * institutions shall not be used in advertising or otherwise to promote the 25 * sale, use or other dealings in this Software without prior written 26 * authorization from the authors. 27 * 28 * Author: Dan Nicholson <dbn.lists (at) gmail.com> 29 * Daniel Stone <daniel (at) fooishbar.org> 30 * Ran Benita <ran234 (at) gmail.com> 31 */ 32 33 #include <limits.h> 34 #include <fcntl.h> 35 #include <unistd.h> 36 #include <sys/types.h> 37 #include <sys/stat.h> 38 39 #include "test.h" 40 41 /* 42 * Test a sequence of keysyms, resulting from a sequence of key presses, 43 * against the keysyms they're supposed to generate. 44 * 45 * - Each test runs with a clean state. 46 * - Each line in the test is made up of: 47 * + A keycode, given as a KEY_* from linux/input.h. 48 * + A direction - DOWN for press, UP for release, BOTH for 49 * immediate press + release, REPEAT to just get the syms. 50 * + A sequence of keysyms that should result from this keypress. 51 * 52 * The vararg format is: 53 * <KEY_*> <DOWN | UP | BOTH> <XKB_KEY_* (zero or more)> <NEXT | FINISH> 54 * 55 * See below for examples. 56 */ 57 int 58 test_key_seq_va(struct xkb_keymap *keymap, va_list ap) 59 { 60 struct xkb_state *state; 61 62 xkb_keycode_t kc; 63 int op; 64 xkb_keysym_t keysym; 65 66 const xkb_keysym_t *syms; 67 xkb_keysym_t sym; 68 unsigned int nsyms, i; 69 char ksbuf[64]; 70 71 fprintf(stderr, "----\n"); 72 73 state = xkb_state_new(keymap); 74 assert(state); 75 76 for (;;) { 77 kc = va_arg(ap, int) + EVDEV_OFFSET; 78 op = va_arg(ap, int); 79 80 nsyms = xkb_state_key_get_syms(state, kc, &syms); 81 if (nsyms == 1) { 82 sym = xkb_state_key_get_one_sym(state, kc); 83 syms = &sym; 84 } 85 86 fprintf(stderr, "got %u syms for key 0x%x: [", nsyms, kc); 87 88 if (op == DOWN || op == BOTH) 89 xkb_state_update_key(state, kc, XKB_KEY_DOWN); 90 if (op == UP || op == BOTH) 91 xkb_state_update_key(state, kc, XKB_KEY_UP); 92 93 for (i = 0; i < nsyms; i++) { 94 keysym = va_arg(ap, int); 95 xkb_keysym_get_name(syms[i], ksbuf, sizeof(ksbuf)); 96 fprintf(stderr, "%s%s", (i != 0) ? ", " : "", ksbuf); 97 98 if (keysym == FINISH || keysym == NEXT) { 99 xkb_keysym_get_name(syms[i], ksbuf, sizeof(ksbuf)); 100 fprintf(stderr, "Did not expect keysym: %s.\n", ksbuf); 101 goto fail; 102 } 103 104 if (keysym != syms[i]) { 105 xkb_keysym_get_name(keysym, ksbuf, sizeof(ksbuf)); 106 fprintf(stderr, "Expected keysym: %s. ", ksbuf);; 107 xkb_keysym_get_name(syms[i], ksbuf, sizeof(ksbuf)); 108 fprintf(stderr, "Got keysym: %s.\n", ksbuf);; 109 goto fail; 110 } 111 } 112 113 if (nsyms == 0) { 114 keysym = va_arg(ap, int); 115 if (keysym != XKB_KEY_NoSymbol) { 116 xkb_keysym_get_name(keysym, ksbuf, sizeof(ksbuf)); 117 fprintf(stderr, "Expected %s, but got no keysyms.\n", ksbuf); 118 goto fail; 119 } 120 } 121 122 fprintf(stderr, "]\n"); 123 124 keysym = va_arg(ap, int); 125 if (keysym == NEXT) 126 continue; 127 if (keysym == FINISH) 128 break; 129 130 xkb_keysym_get_name(keysym, ksbuf, sizeof(ksbuf)); 131 fprintf(stderr, "Expected keysym: %s. Didn't get it.\n", ksbuf); 132 goto fail; 133 } 134 135 xkb_state_unref(state); 136 return 1; 137 138 fail: 139 xkb_state_unref(state); 140 return 0; 141 } 142 143 int 144 test_key_seq(struct xkb_keymap *keymap, ...) 145 { 146 va_list ap; 147 int ret; 148 149 va_start(ap, keymap); 150 ret = test_key_seq_va(keymap, ap); 151 va_end(ap); 152 153 return ret; 154 } 155 156 char * 157 test_get_path(const char *path_rel) 158 { 159 char *path; 160 size_t path_len; 161 const char *srcdir = getenv("srcdir"); 162 163 path_len = strlen(srcdir ? srcdir : ".") + 164 strlen(path_rel ? path_rel : "") + 12; 165 path = malloc(path_len); 166 if (!path) { 167 fprintf(stderr, "Failed to allocate path (%d chars) for %s\n", 168 (int) path_len, path); 169 return NULL; 170 } 171 snprintf(path, path_len, 172 "%s/test/data/%s", srcdir ? srcdir : ".", 173 path_rel ? path_rel : ""); 174 175 return path; 176 } 177 178 char * 179 test_read_file(const char *path_rel) 180 { 181 struct stat info; 182 char *ret, *tmp, *path; 183 int fd, count, remaining; 184 185 path = test_get_path(path_rel); 186 if (!path) 187 return NULL; 188 189 fd = open(path, O_RDONLY); 190 free(path); 191 if (fd < 0) 192 return NULL; 193 194 if (fstat(fd, &info) != 0) { 195 close(fd); 196 return NULL; 197 } 198 199 ret = malloc(info.st_size + 1); 200 if (!ret) { 201 close(fd); 202 return NULL; 203 } 204 205 remaining = info.st_size; 206 tmp = ret; 207 while ((count = read(fd, tmp, remaining))) { 208 remaining -= count; 209 tmp += count; 210 } 211 ret[info.st_size] = '\0'; 212 close(fd); 213 214 if (remaining != 0) { 215 free(ret); 216 return NULL; 217 } 218 219 return ret; 220 } 221 222 struct xkb_context * 223 test_get_context(enum test_context_flags test_flags) 224 { 225 enum xkb_context_flags ctx_flags; 226 struct xkb_context *ctx; 227 char *path; 228 229 ctx_flags = XKB_CONTEXT_NO_DEFAULT_INCLUDES; 230 if (test_flags & CONTEXT_ALLOW_ENVIRONMENT_NAMES) { 231 unsetenv("XKB_DEFAULT_RULES"); 232 unsetenv("XKB_DEFAULT_MODEL"); 233 unsetenv("XKB_DEFAULT_LAYOUT"); 234 unsetenv("XKB_DEFAULT_VARIANT"); 235 unsetenv("XKB_DEFAULT_OPTIONS"); 236 } 237 else { 238 ctx_flags |= XKB_CONTEXT_NO_ENVIRONMENT_NAMES; 239 } 240 241 ctx = xkb_context_new(ctx_flags); 242 if (!ctx) 243 return NULL; 244 245 path = test_get_path(""); 246 if (!path) 247 return NULL; 248 249 xkb_context_include_path_append(ctx, path); 250 free(path); 251 252 return ctx; 253 } 254 255 struct xkb_keymap * 256 test_compile_file(struct xkb_context *context, const char *path_rel) 257 { 258 struct xkb_keymap *keymap; 259 FILE *file; 260 char *path; 261 262 path = test_get_path(path_rel); 263 if (!path) 264 return NULL; 265 266 file = fopen(path, "r"); 267 if (!file) { 268 fprintf(stderr, "Failed to open path: %s\n", path); 269 free(path); 270 return NULL; 271 } 272 assert(file != NULL); 273 274 keymap = xkb_keymap_new_from_file(context, file, 275 XKB_KEYMAP_FORMAT_TEXT_V1, 0); 276 fclose(file); 277 278 if (!keymap) { 279 fprintf(stderr, "Failed to compile path: %s\n", path); 280 free(path); 281 return NULL; 282 } 283 284 fprintf(stderr, "Successfully compiled path: %s\n", path); 285 free(path); 286 287 return keymap; 288 } 289 290 struct xkb_keymap * 291 test_compile_string(struct xkb_context *context, const char *string) 292 { 293 struct xkb_keymap *keymap; 294 295 keymap = xkb_keymap_new_from_string(context, string, 296 XKB_KEYMAP_FORMAT_TEXT_V1, 0); 297 if (!keymap) { 298 fprintf(stderr, "Failed to compile string\n"); 299 return NULL; 300 } 301 302 return keymap; 303 } 304 305 struct xkb_keymap * 306 test_compile_buffer(struct xkb_context *context, const char *buf, size_t len) 307 { 308 struct xkb_keymap *keymap; 309 310 keymap = xkb_keymap_new_from_buffer(context, buf, len, 311 XKB_KEYMAP_FORMAT_TEXT_V1, 0); 312 if (!keymap) { 313 fprintf(stderr, "Failed to compile keymap from memory buffer\n"); 314 return NULL; 315 } 316 317 return keymap; 318 } 319 320 struct xkb_keymap * 321 test_compile_rules(struct xkb_context *context, const char *rules, 322 const char *model, const char *layout, 323 const char *variant, const char *options) 324 { 325 struct xkb_keymap *keymap; 326 struct xkb_rule_names rmlvo = { 327 .rules = isempty(rules) ? NULL : rules, 328 .model = isempty(model) ? NULL : model, 329 .layout = isempty(layout) ? NULL : layout, 330 .variant = isempty(variant) ? NULL : variant, 331 .options = isempty(options) ? NULL : options 332 }; 333 334 if (!rules && !model && !layout && !variant && !options) 335 keymap = xkb_keymap_new_from_names(context, NULL, 0); 336 else 337 keymap = xkb_keymap_new_from_names(context, &rmlvo, 0); 338 339 if (!keymap) { 340 fprintf(stderr, 341 "Failed to compile RMLVO: '%s', '%s', '%s', '%s', '%s'\n", 342 rules, model, layout, variant, options); 343 return NULL; 344 } 345 346 return keymap; 347 } 348 349 void 350 test_print_keycode_state(struct xkb_state *state, 351 struct xkb_compose_state *compose_state, 352 xkb_keycode_t keycode) 353 { 354 struct xkb_keymap *keymap; 355 356 xkb_keysym_t sym; 357 const xkb_keysym_t *syms; 358 int nsyms; 359 char s[16]; 360 xkb_layout_index_t layout; 361 enum xkb_compose_status status; 362 363 keymap = xkb_state_get_keymap(state); 364 365 nsyms = xkb_state_key_get_syms(state, keycode, &syms); 366 367 if (nsyms <= 0) 368 return; 369 370 status = XKB_COMPOSE_NOTHING; 371 if (compose_state) 372 status = xkb_compose_state_get_status(compose_state); 373 374 if (status == XKB_COMPOSE_COMPOSING || status == XKB_COMPOSE_CANCELLED) 375 return; 376 377 if (status == XKB_COMPOSE_COMPOSED) { 378 sym = xkb_compose_state_get_one_sym(compose_state); 379 syms = &sym; 380 nsyms = 1; 381 } 382 else if (nsyms == 1) { 383 sym = xkb_state_key_get_one_sym(state, keycode); 384 syms = &sym; 385 } 386 387 printf("keysyms [ "); 388 for (int i = 0; i < nsyms; i++) { 389 xkb_keysym_get_name(syms[i], s, sizeof(s)); 390 printf("%-*s ", (int) sizeof(s), s); 391 } 392 printf("] "); 393 394 if (status == XKB_COMPOSE_COMPOSED) 395 xkb_compose_state_get_utf8(compose_state, s, sizeof(s)); 396 else 397 xkb_state_key_get_utf8(state, keycode, s, sizeof(s)); 398 printf("unicode [ %s ] ", s); 399 400 layout = xkb_state_key_get_layout(state, keycode); 401 printf("layout [ %s (%d) ] ", 402 xkb_keymap_layout_get_name(keymap, layout), layout); 403 404 printf("level [ %d ] ", 405 xkb_state_key_get_level(state, keycode, layout)); 406 407 printf("mods [ "); 408 for (xkb_mod_index_t mod = 0; mod < xkb_keymap_num_mods(keymap); mod++) { 409 if (xkb_state_mod_index_is_active(state, mod, 410 XKB_STATE_MODS_EFFECTIVE) <= 0) 411 continue; 412 if (xkb_state_mod_index_is_consumed(state, keycode, mod)) 413 printf("-%s ", xkb_keymap_mod_get_name(keymap, mod)); 414 else 415 printf("%s ", xkb_keymap_mod_get_name(keymap, mod)); 416 } 417 printf("] "); 418 419 printf("leds [ "); 420 for (xkb_led_index_t led = 0; led < xkb_keymap_num_leds(keymap); led++) { 421 if (xkb_state_led_index_is_active(state, led) <= 0) 422 continue; 423 printf("%s ", xkb_keymap_led_get_name(keymap, led)); 424 } 425 printf("] "); 426 427 printf("\n"); 428 } 429 430 void 431 test_print_state_changes(enum xkb_state_component changed) 432 { 433 if (changed == 0) 434 return; 435 436 printf("changed [ "); 437 if (changed & XKB_STATE_LAYOUT_EFFECTIVE) 438 printf("effective-layout "); 439 if (changed & XKB_STATE_LAYOUT_DEPRESSED) 440 printf("depressed-layout "); 441 if (changed & XKB_STATE_LAYOUT_LATCHED) 442 printf("latched-layout "); 443 if (changed & XKB_STATE_LAYOUT_LOCKED) 444 printf("locked-layout "); 445 if (changed & XKB_STATE_MODS_EFFECTIVE) 446 printf("effective-mods "); 447 if (changed & XKB_STATE_MODS_DEPRESSED) 448 printf("depressed-mods "); 449 if (changed & XKB_STATE_MODS_LATCHED) 450 printf("latched-mods "); 451 if (changed & XKB_STATE_MODS_LOCKED) 452 printf("locked-mods "); 453 if (changed & XKB_STATE_LEDS) 454 printf("leds "); 455 printf("]\n"); 456 } 457