cscg24-guacamole

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

generate.pl (8669B)


      1#!/usr/bin/env perl
      2#
      3# Licensed to the Apache Software Foundation (ASF) under one
      4# or more contributor license agreements.  See the NOTICE file
      5# distributed with this work for additional information
      6# regarding copyright ownership.  The ASF licenses this file
      7# to you under the Apache License, Version 2.0 (the
      8# "License"); you may not use this file except in compliance
      9# with the License.  You may obtain a copy of the License at
     10#
     11#   http://www.apache.org/licenses/LICENSE-2.0
     12#
     13# Unless required by applicable law or agreed to in writing,
     14# software distributed under the License is distributed on an
     15# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
     16# KIND, either express or implied.  See the License for the
     17# specific language governing permissions and limitations
     18# under the License.
     19#
     20
     21#
     22# generate.pl
     23#
     24# Parse .keymap files, producing corresponding .c files that can be included
     25# into the RDP plugin source.
     26#
     27
     28# We need at least Perl 5.8 for Unicode's sake
     29use 5.008;
     30
     31sub keymap_symbol {
     32    my $name = shift;
     33    $name =~ s/-/_/g;
     34    return 'guac_rdp_keymap_' . $name;
     35}
     36
     37#
     38# _generated_keymaps.c
     39#
     40
     41my @keymaps = ();
     42
     43open OUTPUT, ">", "_generated_keymaps.c";
     44print OUTPUT 
     45       '#include "config.h"'                                . "\n"
     46     . '#include "keymap.h"'                                . "\n"
     47     . '#include <freerdp/input.h>'                         . "\n"
     48     . '#include <freerdp/locale/keyboard.h>'               . "\n"
     49     .                                                        "\n"
     50     . '#include <stddef.h>'                                . "\n"
     51     .                                                        "\n";
     52
     53for my $filename (@ARGV) {
     54
     55    my $content = "";
     56    my $parent = "";
     57    my $layout_name = "";
     58    my $freerdp = "";
     59
     60    # Parse file
     61    open INPUT, '<', "$filename";
     62    binmode INPUT, ":encoding(utf8)";
     63    while (<INPUT>) {
     64
     65        chomp;
     66
     67        # Comments
     68        if (m/^\s*#/) {}
     69
     70        # Name
     71        elsif ((my $name) = m/^\s*name\s+"(.*)"\s*(?:#.*)?$/) {
     72            $layout_name = $name;
     73        }
     74
     75        # Parent map
     76        elsif ((my $name) = m/^\s*parent\s+"(.*)"\s*(?:#.*)?$/) {
     77            $parent = keymap_symbol($name);
     78        }
     79
     80        # FreeRDP equiv 
     81        elsif ((my $name) = m/^\s*freerdp\s+"(.*)"\s*(?:#.*)?$/) {
     82            $freerdp = $name;
     83        }
     84
     85        # Map
     86        elsif ((my $range, my $onto) =
     87               m/^\s*map\s+([^~]*)\s+~\s+(".*"|0x[0-9A-Fa-f]+)\s*(?:#.*)?$/) {
     88
     89            my @keysyms   = ();
     90            my @scancodes = ();
     91
     92            my $ext_flags = 0;
     93            my $set_shift = 0;
     94            my $set_altgr = 0;
     95            my $set_caps  = 0;
     96            my $set_num   = 0;
     97
     98            my $clear_shift = 0;
     99            my $clear_altgr = 0;
    100            my $clear_caps  = 0;
    101            my $clear_num   = 0;
    102
    103            # Parse ranges and options
    104            foreach $_ (split(/\s+/, $range)) {
    105
    106                # Set option/modifier
    107                if ((my $opt) = m/^\+([a-z]+)$/) {
    108                    if    ($opt eq "shift") { $set_shift = 1; }
    109                    elsif ($opt eq "altgr") { $set_altgr = 1; }
    110                    elsif ($opt eq "caps")  { $set_caps  = 1; }
    111                    elsif ($opt eq "num")   { $set_num   = 1; }
    112                    elsif ($opt eq "ext")   { $ext_flags = 1; }
    113                    else {
    114                        die "$filename: $.: ERROR: "
    115                          . "Invalid set option\n";
    116                    }
    117                }
    118
    119                # Clear option/modifier
    120                elsif ((my $opt) = m/^-([a-z]+)$/) {
    121                    if    ($opt eq "shift") { $clear_shift = 1; }
    122                    elsif ($opt eq "altgr") { $clear_altgr = 1; }
    123                    elsif ($opt eq "caps")  { $clear_caps  = 1; }
    124                    elsif ($opt eq "num")   { $clear_num   = 1; }
    125                    else {
    126                        die "$filename: $.: ERROR: "
    127                          . "Invalid clear option\n";
    128                    }
    129                }
    130
    131                # Single scancode
    132                elsif ((my $scancode) = m/^(0x[0-9A-Fa-f]+)$/) {
    133                    $scancodes[++$#scancodes] = hex($scancode);
    134                }
    135
    136                # Range of scancodes
    137                elsif ((my $start, my $end) =
    138                       m/^(0x[0-9A-Fa-f]+)\.\.(0x[0-9A-Fa-f]+)$/) {
    139                    for (my $i=hex($start); $i<=hex($end); $i++) {
    140                        $scancodes[++$#scancodes] = $i;
    141                    }
    142                }
    143
    144                # Invalid token
    145                else {
    146                    die "$filename: $.: ERROR: "
    147                      . "Invalid token\n";
    148                }
    149
    150            }
    151
    152            # Parse onto
    153            if ($onto =~ m/^0x/) {
    154                $keysyms[0] = hex($onto);
    155            }
    156            else {
    157                foreach my $char (split('',
    158                                  substr($onto, 1, length($onto)-2))) {
    159                    my $codepoint = ord($char);
    160                    if ($codepoint >= 0x0100) {
    161                        $keysyms[++$#keysyms] = 0x01000000 | $codepoint;
    162                    }
    163                    else {
    164                        $keysyms[++$#keysyms] = $codepoint;
    165                    }
    166                }
    167            }
    168
    169            # Check mapping
    170            if ($#keysyms != $#scancodes) {
    171                die "$filename: $.: ERROR: "
    172                  . "Keysym and scancode range lengths differ\n";
    173            }
    174
    175            # Write keysym/scancode pairs
    176            for (my $i=0; $i<=$#keysyms; $i++) {
    177
    178                $content .= "    {"
    179                         .  " .keysym = "   . $keysyms[$i] . ","
    180                         .  " .scancode = " . $scancodes[$i];
    181
    182                # Modifiers that must be active
    183                $content .= ", .set_modifiers = 0";
    184                $content .= " | GUAC_RDP_KEYMAP_MODIFIER_SHIFT" if $set_shift;
    185                $content .= " | GUAC_RDP_KEYMAP_MODIFIER_ALTGR" if $set_altgr;
    186
    187                # Modifiers that must be inactive
    188                $content .= ", .clear_modifiers = 0";
    189                $content .= " | GUAC_RDP_KEYMAP_MODIFIER_SHIFT" if $clear_shift;
    190                $content .= " | GUAC_RDP_KEYMAP_MODIFIER_ALTGR" if $clear_altgr;
    191
    192                # Locks that must be set
    193                $content .= ", .set_locks = 0";
    194                $content .= " | KBD_SYNC_NUM_LOCK" if $set_num;
    195                $content .= " | KBD_SYNC_CAPS_LOCK" if $set_caps;
    196
    197                # Locks that must NOT be set
    198                $content .= ", .clear_locks = 0";
    199                $content .= " | KBD_SYNC_NUM_LOCK" if $clear_num;
    200                $content .= " | KBD_SYNC_CAPS_LOCK" if $clear_caps;
    201
    202                # Flags
    203                if ($ext_flags) {
    204                    $content .= ", .flags = KBD_FLAGS_EXTENDED";
    205                }
    206
    207                $content .= " },\n";
    208
    209            }
    210
    211        }
    212
    213        # Invalid token
    214        elsif (m/\S/) {
    215            die "$filename: $.: ERROR: "
    216              . "Invalid token\n";
    217        }
    218
    219    }
    220    close INPUT;
    221
    222    # Header
    223    my $sym = keymap_symbol($layout_name);
    224    print OUTPUT
    225                                                                  "\n"
    226         . '/* Autogenerated from ' . $filename . ' */'         . "\n"
    227         . 'static guac_rdp_keysym_desc __' . $sym . '[] = {'   . "\n"
    228         .      $content
    229         . '    {0}'                                            . "\n"
    230         . '};'                                                 . "\n";
    231
    232    # Desc header
    233    print OUTPUT                                                   "\n"
    234          . 'static const guac_rdp_keymap ' . $sym . ' = { '     . "\n";
    235
    236    # Layout name
    237    print OUTPUT "    .name = \"$layout_name\",\n";
    238
    239    # Parent layout (if any)
    240    if ($parent) {
    241        print OUTPUT "    .parent = &$parent,\n";
    242    }
    243
    244    # FreeRDP layout (if any)
    245    if ($freerdp) {
    246        print OUTPUT "    .freerdp_keyboard_layout = $freerdp,\n";
    247    }
    248
    249    # Desc footer
    250    print OUTPUT
    251            '    .mapping = __' . $sym                           . "\n"
    252          . '};'                                                 . "\n";
    253
    254    $keymaps[++$#keymaps] = $sym;
    255    print STDERR "Added: $layout_name\n";
    256
    257}
    258
    259print OUTPUT                                                   "\n"
    260      . 'const guac_rdp_keymap* GUAC_KEYMAPS[] = {'          . "\n";
    261
    262foreach my $keymap (@keymaps) {
    263    print OUTPUT "    &$keymap,\n";
    264}
    265print OUTPUT
    266        '    NULL'                                           . "\n"
    267      . '};'                                                 . "\n";
    268
    269close OUTPUT;
    270