cscg24-guacamole

CSCG 2024 Challenge 'Guacamole Mashup'
git clone https://git.sinitax.com/sinitax/cscg24-guacamole
Log | Files | Refs | sfeed.txt

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