keydef.c (9243B)
1/* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, 13 * software distributed under the License is distributed on an 14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 * KIND, either express or implied. See the License for the 16 * specific language governing permissions and limitations 17 * under the License. 18 */ 19 20#include "config.h" 21#include "keydef.h" 22#include "log.h" 23 24#include <guacamole/mem.h> 25#include <guacamole/string.h> 26 27#include <assert.h> 28#include <stdbool.h> 29#include <stdio.h> 30#include <stdlib.h> 31#include <string.h> 32 33/** 34 * All known keys. 35 */ 36const guaclog_keydef known_keys[] = { 37 { 0xFE03, "AltGr", "", true }, 38 { 0xFF08, "Backspace" }, 39 { 0xFF09, "Tab" }, 40 { 0xFF0B, "Clear" }, 41 { 0xFF0D, "Return", "\n" }, 42 { 0xFF13, "Pause" }, 43 { 0xFF14, "Scroll" }, 44 { 0xFF15, "SysReq" }, 45 { 0xFF1B, "Escape" }, 46 { 0xFF50, "Home" }, 47 { 0xFF51, "Left" }, 48 { 0xFF52, "Up" }, 49 { 0xFF53, "Right" }, 50 { 0xFF54, "Down" }, 51 { 0xFF55, "Page Up" }, 52 { 0xFF56, "Page Down" }, 53 { 0xFF57, "End" }, 54 { 0xFF63, "Insert" }, 55 { 0xFF65, "Undo" }, 56 { 0xFF6A, "Help" }, 57 { 0xFF7F, "Num" }, 58 { 0xFF80, "Space", " " }, 59 { 0xFF8D, "Enter", "\n" }, 60 { 0xFF95, "Home" }, 61 { 0xFF96, "Left" }, 62 { 0xFF97, "Up" }, 63 { 0xFF98, "Right" }, 64 { 0xFF99, "Down" }, 65 { 0xFF9A, "Page Up" }, 66 { 0xFF9B, "Page Down" }, 67 { 0xFF9C, "End" }, 68 { 0xFF9E, "Insert" }, 69 { 0xFFAA, "*", "*" }, 70 { 0xFFAB, "+", "+" }, 71 { 0xFFAD, "-", "-" }, 72 { 0xFFAE, ".", "." }, 73 { 0xFFAF, "/", "/" }, 74 { 0xFFB0, "0", "0" }, 75 { 0xFFB1, "1", "1" }, 76 { 0xFFB2, "2", "2" }, 77 { 0xFFB3, "3", "3" }, 78 { 0xFFB4, "4", "4" }, 79 { 0xFFB5, "5", "5" }, 80 { 0xFFB6, "6", "6" }, 81 { 0xFFB7, "7", "7" }, 82 { 0xFFB8, "8", "8" }, 83 { 0xFFB9, "9", "9" }, 84 { 0xFFBE, "F1" }, 85 { 0xFFBF, "F2" }, 86 { 0xFFC0, "F3" }, 87 { 0xFFC1, "F4" }, 88 { 0xFFC2, "F5" }, 89 { 0xFFC3, "F6" }, 90 { 0xFFC4, "F7" }, 91 { 0xFFC5, "F8" }, 92 { 0xFFC6, "F9" }, 93 { 0xFFC7, "F10" }, 94 { 0xFFC8, "F11" }, 95 { 0xFFC9, "F12" }, 96 { 0xFFCA, "F13" }, 97 { 0xFFCB, "F14" }, 98 { 0xFFCC, "F15" }, 99 { 0xFFCD, "F16" }, 100 { 0xFFCE, "F17" }, 101 { 0xFFCF, "F18" }, 102 { 0xFFD0, "F19" }, 103 { 0xFFD1, "F20" }, 104 { 0xFFD2, "F21" }, 105 { 0xFFD3, "F22" }, 106 { 0xFFD4, "F23" }, 107 { 0xFFD5, "F24" }, 108 { 0xFFE1, "Shift", "", true }, 109 { 0xFFE2, "Shift", "", true }, 110 { 0xFFE3, "Ctrl", NULL, true }, 111 { 0xFFE4, "Ctrl", NULL, true }, 112 { 0xFFE5, "Caps" }, 113 { 0xFFE7, "Meta", NULL, true }, 114 { 0xFFE8, "Meta", NULL, true }, 115 { 0xFFE9, "Alt", NULL, true }, 116 { 0xFFEA, "Alt", NULL, true }, 117 { 0xFFEB, "Super", NULL, true }, 118 { 0xFFEC, "Super", NULL, true }, 119 { 0xFFED, "Hyper", NULL, true }, 120 { 0xFFEE, "Hyper", NULL, true }, 121 { 0xFFFF, "Delete" } 122}; 123 124/** 125 * Comparator for the standard bsearch() function which compares an integer 126 * keysym against the keysym associated with a guaclog_keydef. 127 * 128 * @param key 129 * The key value being compared against the member. This MUST be the 130 * keysym value, passed through typecasting to an intptr_t (NOT a pointer 131 * to the int itself). 132 * 133 * @param member 134 * The member within the known_keys array being compared against the given 135 * key. 136 * 137 * @return 138 * Zero if the given keysym is equal to that of the given member, a 139 * positive value if the given keysym is greater than that of the given 140 * member, or a negative value if the given keysym is less than that of the 141 * given member. 142 */ 143static int guaclog_keydef_bsearch_compare(const void* key, 144 const void* member) { 145 146 int keysym = (int) ((intptr_t) key); 147 guaclog_keydef* current = (guaclog_keydef*) member; 148 149 /* Compare given keysym to keysym of current member */ 150 return keysym - current->keysym; 151 152} 153 154/** 155 * Searches through the known_keys array of known keys for the name of the key 156 * having the given keysym, returning a pointer to the static guaclog_keydef 157 * within the array if found. 158 * 159 * @param keysym 160 * The X11 keysym of the key. 161 * 162 * @return 163 * A pointer to the static guaclog_keydef associated with the given keysym, 164 * or NULL if the key could not be found. 165 */ 166static guaclog_keydef* guaclog_get_known_key(int keysym) { 167 168 /* Search through known keys for given keysym */ 169 return bsearch((void*) ((intptr_t) keysym), 170 known_keys, sizeof(known_keys) / sizeof(known_keys[0]), 171 sizeof(known_keys[0]), guaclog_keydef_bsearch_compare); 172 173} 174 175/** 176 * Returns a statically-allocated guaclog_keydef representing an unknown key, 177 * deriving the name of the key from the hexadecimal value of the keysym. 178 * 179 * @param keysym 180 * The X11 keysym of the key. 181 * 182 * @return 183 * A statically-allocated guaclog_keydef representing the key associated 184 * with the given keysym. 185 */ 186static guaclog_keydef* guaclog_get_unknown_key(int keysym) { 187 188 static char unknown_keydef_name[64]; 189 static guaclog_keydef unknown_keydef; 190 191 /* Write keysym as hex */ 192 int size = snprintf(unknown_keydef_name, sizeof(unknown_keydef_name), 193 "0x%X", keysym); 194 195 /* Hex string is guaranteed to fit within the provided 64 bytes */ 196 assert(size < sizeof(unknown_keydef_name)); 197 198 /* Return static key definition */ 199 unknown_keydef.keysym = keysym; 200 unknown_keydef.name = unknown_keydef_name; 201 return &unknown_keydef; 202 203} 204 205/** 206 * Returns a statically-allocated guaclog_keydef representing the key 207 * associated with the given keysym, deriving the name and value of the key 208 * using its corresponding Unicode character. 209 * 210 * @param keysym 211 * The X11 keysym of the key. 212 * 213 * @return 214 * A statically-allocated guaclog_keydef representing the key associated 215 * with the given keysym, or NULL if the given keysym has no corresponding 216 * Unicode character. 217 */ 218static guaclog_keydef* guaclog_get_unicode_key(int keysym) { 219 220 static char unicode_keydef_name[8]; 221 222 static guaclog_keydef unicode_keydef; 223 224 int i; 225 int mask, bytes; 226 227 /* Translate only if keysym maps to Unicode */ 228 if (keysym < 0x00 || (keysym > 0xFF && (keysym | 0xFFFF) != 0x0100FFFF)) 229 return NULL; 230 231 int codepoint = keysym & 0xFFFF; 232 233 /* Determine size and initial byte mask */ 234 if (codepoint <= 0x007F) { 235 mask = 0x00; 236 bytes = 1; 237 } 238 else if (codepoint <= 0x7FF) { 239 mask = 0xC0; 240 bytes = 2; 241 } 242 else { 243 assert(codepoint <= 0xFFFF); 244 mask = 0xE0; 245 bytes = 3; 246 } 247 248 /* Offset buffer by size */ 249 char* key_name = unicode_keydef_name + bytes; 250 251 /* Add null terminator */ 252 *(key_name--) = '\0'; 253 254 /* Add trailing bytes, if any */ 255 for (i=1; i<bytes; i++) { 256 *(key_name--) = 0x80 | (codepoint & 0x3F); 257 codepoint >>= 6; 258 } 259 260 /* Set initial byte */ 261 *key_name = mask | codepoint; 262 263 /* Return static key definition */ 264 unicode_keydef.keysym = keysym; 265 unicode_keydef.name = unicode_keydef.value = unicode_keydef_name; 266 unicode_keydef.modifier = false; 267 return &unicode_keydef; 268 269} 270 271/** 272 * Copies the given guaclog_keydef into a newly-allocated guaclog_keydef 273 * structure. The resulting guaclog_keydef must eventually be freed through a 274 * call to guaclog_keydef_free(). 275 * 276 * @param keydef 277 * The guaclog_keydef to copy. 278 * 279 * @return 280 * A newly-allocated guaclog_keydef structure copied from the given 281 * guaclog_keydef. 282 */ 283static guaclog_keydef* guaclog_copy_key(guaclog_keydef* keydef) { 284 285 guaclog_keydef* copy = guac_mem_alloc(sizeof(guaclog_keydef)); 286 287 /* Always copy keysym and name */ 288 copy->keysym = keydef->keysym; 289 copy->name = guac_strdup(keydef->name); 290 copy->modifier = keydef->modifier; 291 292 /* Copy value only if defined */ 293 if (keydef->value != NULL) 294 copy->value = guac_strdup(keydef->value); 295 else 296 copy->value = NULL; 297 298 return copy; 299 300} 301 302guaclog_keydef* guaclog_keydef_alloc(int keysym) { 303 304 guaclog_keydef* keydef; 305 306 /* Check list of known keys first */ 307 keydef = guaclog_get_known_key(keysym); 308 if (keydef != NULL) 309 return guaclog_copy_key(keydef); 310 311 /* Failing that, attempt to translate straight into a Unicode character */ 312 keydef = guaclog_get_unicode_key(keysym); 313 if (keydef != NULL) 314 return guaclog_copy_key(keydef); 315 316 /* Key not known */ 317 guaclog_log(GUAC_LOG_DEBUG, "Definition not found for key 0x%X.", keysym); 318 return guaclog_copy_key(guaclog_get_unknown_key(keysym)); 319 320} 321 322void guaclog_keydef_free(guaclog_keydef* keydef) { 323 324 /* Ignore NULL keydef */ 325 if (keydef == NULL) 326 return; 327 328 guac_mem_free(keydef->name); 329 guac_mem_free(keydef->value); 330 guac_mem_free(keydef); 331 332} 333