home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2007 September / PCWSEP07.iso / Software / Linux / Linux Mint 3.0 Light / LinuxMint-3.0-Light.iso / casper / filesystem.squashfs / usr / bin / ckbcomp < prev    next >
Encoding:
Text File  |  2007-04-10  |  83.4 KB  |  3,003 lines

  1. #!/usr/bin/perl
  2.  
  3. #     ckbcomp -- compile XKB keyboard definitions to loadkeys format
  4. #     Copyright ┬⌐ 2005,2006 Anton Zinoviev <anton@lml.bas.bg>
  5.  
  6. #     This program is free software; you can redistribute it and/or modify
  7. #     it under the terms of the GNU General Public License as published by
  8. #     the Free Software Foundation; either version 2 of the License, or
  9. #     (at your option) any later version.
  10.  
  11. #     This program is distributed in the hope that it will be useful,
  12. #     but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. #     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. #     GNU General Public License for more details.
  15.  
  16. #     If you have not received a copy of the GNU General Public License
  17. #     along with this program, write to the Free Software Foundation, Inc.,
  18. #     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  19.  
  20. use warnings 'all';
  21. use strict;
  22.  
  23. sub debug {
  24.     if (1) {
  25.     print STDERR "@_";
  26.     }
  27. }
  28.  
  29. sub warning {
  30.     print STDERR  "WARNING: @_";
  31. }
  32.  
  33. ########### ARGUMENTS ###############################################
  34.  
  35. my $charmap;
  36. my $acm;
  37.  
  38. my $verbosity = 0;
  39.  
  40. my @xdirs = ('/etc/console-setup/ckb',
  41.          '/usr/share/X11/xkb',
  42.          '/etc/X11/xkb',
  43.          '/usr/X11R6/lib/X11/xkb');
  44.  
  45. my $keycodes;
  46. my $symbols;
  47.  
  48. my $rules;
  49. my $model;
  50. my @layouts;
  51. my @variants = ();
  52. my @options = ();
  53. my $compact = 0;
  54.  
  55. while (@ARGV) {
  56.     $_ = shift @ARGV;
  57.     if (s/^-//) {
  58.     if (/^charmap$/) {
  59.         if ($charmap) {
  60.         die "$0: No more than one -charmap option is allowed\n";
  61.         }
  62.         $charmap = $ARGV[0];
  63.         shift @ARGV;
  64.     } elsif (/^v(erbose)?$/) {
  65.         if ($verbosity) {
  66.         die "$0: No more than one -verbose option is allowed\n";
  67.         }
  68.         if ($ARGV[0] =~ /^[0-9]|10$/) {
  69.         $verbosity = $ARGV[0];
  70.         shift @ARGV;
  71.         } else {
  72.         $verbosity = 5;
  73.         }
  74.     } elsif (/^I(.*)$/) {
  75.         @xdirs = ($1, @xdirs);
  76.     } elsif (/^keycodes$/) {
  77.         if ($keycodes) {
  78.         die "$0: No more than one -keycodes option is allowed\n";
  79.         }
  80.         $keycodes = $ARGV[0];
  81.         shift @ARGV;
  82.     } elsif (/^symbols$/) {
  83.         if ($symbols) {
  84.         die "$0: No more than one -symbols option is allowed\n";
  85.         }
  86.         $symbols = $ARGV[0];
  87.         shift @ARGV;
  88.     } elsif (/^rules$/) {
  89.         if ($rules) {
  90.         die "$0: No more than one -rules option is allowed\n";
  91.         }
  92.         $rules = $ARGV[0];
  93.         shift @ARGV;
  94.     } elsif (/^model$/) {
  95.         if ($model) {
  96.         die "$0: No more than one -model option is allowed\n";
  97.         }
  98.         $model = $ARGV[0];
  99.         shift @ARGV;
  100.     } elsif (/^layout$/) {
  101.         if (@layouts) {
  102.         die "$0: No more than one -layout option is allowed\n";
  103.         }
  104.         @layouts = split (/,/, $ARGV[0], -1);
  105.         shift @ARGV;
  106.     } elsif (/^variant$/) {
  107.         if (@variants) {
  108.         die "$0: No more than one -variant option is allowed\n";
  109.         }
  110.         @variants = split (/,/, $ARGV[0], -1);
  111.         shift @ARGV;
  112.     } elsif (/^option$/) {
  113.         @options = (@options, split (/,/, $ARGV[0], -1));
  114.         shift @ARGV;
  115.     } elsif (/^help$|^-help$|^\?$/) {
  116.         print <<EOT;
  117. Usage: ckbcomp [args] [<layout> [<variant> [<option> ... ]]]
  118. Where legal args are:
  119. -?,-help            Print this message
  120. -charmap <name>     Specifies the encoding to use
  121. -I<dir>             Add <dir> to list of directories to be used
  122. -keycodes <name>    Specifies keycodes component name
  123. -symbols <name>     Specifies symbols component name
  124. -rules <name>       Name of rules file to use
  125. -model <name>       Specifies model used to choose component names
  126. -layout <name>      Specifies layout used to choose component names
  127. -variant <name>     Specifies layout variant used to choose component names
  128. -v[erbose] [<lvl>]  Sets verbosity (1..10).  Higher values yield
  129.                     more messages
  130. -option <name>      Adds an option used to choose component names
  131. -compact            Generate compact keymap
  132. EOT
  133.             exit 0;
  134.     } elsif (/^compact$/) {
  135.         $compact = 1;
  136.     } else {
  137.         die "$0: Unknown option -$_\n";
  138.     }
  139.     } else {
  140.     if (! @layouts) {
  141.         @layouts = split (/,/, $_, -1);
  142.     } elsif (! @variants) {
  143.         @variants = split (/,/, $_, -1);
  144.         @variants = ('') if (! @variants);
  145.     } else {
  146.         @options = (@options, split (/,/, $_, -1));
  147.     }
  148.     }
  149. }
  150.  
  151. $rules = 'xorg' if (! $rules);
  152. $model = 'pc104' if (! $model);
  153.  
  154. ########### GLOBAL VARIABLES #########################################
  155.  
  156. my %rules_variables = (); # The variables defined in the rules file
  157.  
  158. my $arch = 'at'; # The name of a mapping between X key codes and kernel
  159.                  # keycodes
  160.  
  161. my %acmtable; # Unicode -> legacy code (defined only when -charmap is given)
  162.  
  163. my %keycodes_table; # x keysym -> x key code
  164. my %aliases;        # x keysym -> x keysym
  165.  
  166. my %symbols_table;   # x key code -> [[symbols for group0,...],
  167.                      #               [symbols for group1,...], ...]
  168. my %types_table;     # x key code -> key type (i.e. "PC_BREAK" or "TWO_LEVEL")
  169.  
  170. my $augment_method = 1;   # Constants for different XKB include methods
  171. my $override_method = 2;
  172. my $replace_method = 3;
  173. my $alternate_method = 4;
  174. my $ignore_method = 5;    # This is not a XKB method and means "don't include"
  175.  
  176. my $filename;       # The name of the currently read file
  177. my $stream = '';    # The contents of $filename that still has not been parsed
  178. my $method = $override_method; # The current method (by default "override")
  179. my $base_group = 0; # The base group to include in (for "symbols" files only)
  180.  
  181. my %kernel_modifiers = ('Shift' => 0x01,
  182.             'Shift_Lock' => 0x01,
  183.             'AltGr' => 0x02,
  184.             'AltGr_Lock' => 0x02,
  185.             'Control' => 0x04,
  186.             'Control_Lock' => 0x04,
  187.             'Alt' => 0x08,
  188.             'Alt_Lock' => 0x08,
  189.             'ShiftL' => 0x10,
  190.             'ShiftL_Lock' => 0x10,
  191.             'ShiftR' => 0x20,
  192.             'ShiftR_Lock' => 0x20);
  193.  
  194. my @modifier_combinations = ('plain',
  195.                              'shift',
  196.                              'altgr',
  197.                              'altgr shift',
  198.                              'control',
  199.                              'control shift',
  200.                              'control altgr',
  201.                              'control altgr shift',
  202.                              'alt',
  203.                              'alt shift',
  204.                              'alt altgr',
  205.                              'alt altgr shift',
  206.                              'alt control',
  207.                              'alt control shift',
  208.                              'alt control altgr',
  209.                              'alt control altgr shift',
  210.                              'shiftl',
  211.                              'shiftl shift',
  212.                              'shiftl altgr',
  213.                              'shiftl altgr shift',
  214.                              'shiftl control',
  215.                              'shiftl control shift',
  216.                              'shiftl control altgr',
  217.                              'shiftl control altgr shift',
  218.                              'shiftl alt',
  219.                              'shiftl alt shift',
  220.                              'shiftl alt altgr',
  221.                              'shiftl alt altgr shift',
  222.                              'shiftl alt control',
  223.                              'shiftl alt control shift',
  224.                              'shiftl alt control altgr',
  225.                              'shiftl alt control altgr shift',
  226.                              'shiftr',
  227.                              'shiftr shift',
  228.                              'shiftr altgr',
  229.                              'shiftr altgr shift',
  230.                              'shiftr control',
  231.                              'shiftr control shift',
  232.                              'shiftr control altgr',
  233.                              'shiftr control altgr shift',
  234.                              'shiftr alt',
  235.                              'shiftr alt shift',
  236.                              'shiftr alt altgr',
  237.                              'shiftr alt altgr shift',
  238.                              'shiftr alt control',
  239.                              'shiftr alt control shift',
  240.                              'shiftr alt control altgr',
  241.                              'shiftr alt control altgr shift',
  242.                              'shiftr shiftl',
  243.                              'shiftr shiftl shift',
  244.                              'shiftr shiftl altgr',
  245.                              'shiftr shiftl altgr shift',
  246.                              'shiftr shiftl control',
  247.                              'shiftr shiftl control shift',
  248.                              'shiftr shiftl control altgr',
  249.                              'shiftr shiftl control altgr shift',
  250.                              'shiftr shiftl alt',
  251.                              'shiftr shiftl alt shift',
  252.                              'shiftr shiftl alt altgr',
  253.                              'shiftr shiftl alt altgr shift',
  254.                              'shiftr shiftl alt control',
  255.                              'shiftr shiftl alt control shift',
  256.                              'shiftr shiftl alt control altgr',
  257.                              'shiftr shiftl alt control altgr shift',
  258.                 );
  259.  
  260. # Some Unicodes cause the kernel/loadkeys to issue "Segmentation fault"
  261. my %forbidden;
  262. {
  263.     for my $i (0xfd00..0xfdff) {
  264.     $forbidden{$i} = 1;
  265.     }
  266. }
  267.  
  268. my %xkbsym_table = (
  269. # Control symbols
  270.     'BackSpace' => 'Delete',  # 0008
  271.     'Tab' => 'Tab',           # 0009
  272.     'Linefeed' => 'Linefeed', # 000a
  273.     'Return' => 'Return',     # 000d
  274.     'Escape' => 'Escape',     # 001b
  275. # Alphanumeric symbols
  276.     'space' => '0020',
  277.     'exclam' => '0021',
  278.     'quotedbl' => '0022',
  279.     'numbersign' => '0023',
  280.     'dollar' => '0024',
  281.     'percent' => '0025',
  282.     'ampersand' => '0026',
  283.     'apostrophe' => '0027',
  284.     'quoteright' => '0027',
  285.     'parenleft' => '0028',
  286.     'parenlef' => '0028', # Is this recognised by X ? (speling error)
  287.     'parenright' => '0029',
  288.     'asterisk' => '002a',
  289.     'asterix' => '002a', # Is this recognised by X ? (speling error)
  290.     'plus' => '002b',
  291.     'comma' => '002c',
  292.     'minus' => '002d',
  293.     'period' => '002e',
  294.     'slash' => '002f',
  295.     '0' => '0030',
  296.     '1' => '0031',
  297.     '2' => '0032',
  298.     '3' => '0033',
  299.     '4' => '0034',
  300.     '5' => '0035',
  301.     '6' => '0036',
  302.     '7' => '0037',
  303.     '8' => '0038',
  304.     '9' => '0039',
  305.     'colon' => '003a',
  306.     'semicolon' => '003b',
  307.     'less' => '003c',
  308.     'equal' => '003d',
  309.     'greater' => '003e',
  310.     'question' => '003f',
  311.     'at' => '0040',
  312.     'A' => '0041',
  313.     'B' => '0042',
  314.     'C' => '0043',
  315.     'D' => '0044',
  316.     'E' => '0045',
  317.     'F' => '0046',
  318.     'G' => '0047',
  319.     'H' => '0048',
  320.     'I' => '0049',
  321.     'J' => '004a',
  322.     'K' => '004b',
  323.     'L' => '004c',
  324.     'M' => '004d',
  325.     'N' => '004e',
  326.     'O' => '004f',
  327.     'P' => '0050',
  328.     'Q' => '0051',
  329.     'R' => '0052',
  330.     'S' => '0053',
  331.     'T' => '0054',
  332.     'U' => '0055',
  333.     'V' => '0056',
  334.     'W' => '0057',
  335.     'X' => '0058',
  336.     'Y' => '0059',
  337.     'Z' => '005a',
  338.     'bracketleft' => '005b',
  339.     'backslash' => '005c',
  340.     'bracketright' => '005d',
  341.     'asciicircum' => '005e',
  342.     'underscore' => '005f',
  343.     'grave' => '0060',
  344.     'quoteleft' => '0060',
  345.     'a' => '0061',
  346.     'b' => '0062',
  347.     'c' => '0063',
  348.     'd' => '0064',
  349.     'e' => '0065',
  350.     'f' => '0066',
  351.     'g' => '0067',
  352.     'h' => '0068',
  353.     'i' => '0069',
  354.     'j' => '006a',
  355.     'k' => '006b',
  356.     'l' => '006c',
  357.     'm' => '006d',
  358.     'n' => '006e',
  359.     'o' => '006f',
  360.     'p' => '0070',
  361.     'q' => '0071',
  362.     'r' => '0072',
  363.     's' => '0073',
  364.     't' => '0074',
  365.     'u' => '0075',
  366.     'v' => '0076',
  367.     'w' => '0077',
  368.     'x' => '0078',
  369.     'y' => '0079',
  370.     'z' => '007a',
  371.     'braceleft' => '007b',
  372.     'bar' => '007c',
  373.     'braceright' => '007d',
  374.     'asciitilde' => '007e',
  375.     'nobreakspace' => '00a0',
  376.     'exclamdown' => '00a1',
  377.     'cent' => '00a2',
  378.     'sterling' => '00a3',
  379.     'currency' => '00a4',
  380.     'yen' => '00a5',
  381.     'brokenbar' => '00a6',
  382.     'section' => '00a7',
  383.     'diaeresis' => '00a8',
  384.     'copyright' => '00a9',
  385.     'ordfeminine' => '00aa',
  386.     'guillemotleft' => '00ab',
  387.     'notsign' => '00ac',
  388.     'hyphen' => '00ad',
  389.     'registered' => '00ae',
  390.     'macron' => '00af',
  391.     'overbar' => '00af',
  392.     'degree' => '00b0',
  393.     'plusminus' => '00b1',
  394.     'twosuperior' => '00b2',
  395.     'threesuperior' => '00b3',
  396.     'acute' => '0027', # APOSTROPHE instead of ACUTE ACCENT
  397.     'mu' => '00b5',
  398.     'paragraph' => '00b6',
  399.     'periodcentered' => '00b7',
  400.     'cedilla' => '00b8',
  401.     'onesuperior' => '00b9',
  402.     'masculine' => '00ba',
  403.     'guillemotright' => '00bb',
  404.     'onequarter' => '00bc',
  405.     'onehalf' => '00bd',
  406.     'threequarters' => '00be',
  407.     'questiondown' => '00bf',
  408.     'Agrave' => '00c0',
  409.     'Aacute' => '00c1',
  410.     'Acircumflex' => '00c2',
  411.     'Atilde' => '00c3',
  412.     'Adiaeresis' => '00c4',
  413.     'Aring' => '00c5',
  414.     'AE' => '00c6',
  415.     'Ccedilla' => '00c7',
  416.     'Egrave' => '00c8',
  417.     'Eacute' => '00c9',
  418.     'Ecircumflex' => '00ca',
  419.     'Ediaeresis' => '00cb',
  420.     'Igrave' => '00cc',
  421.     'Iacute' => '00cd',
  422.     'Icircumflex' => '00ce',
  423.     'Idiaeresis' => '00cf',
  424.     'ETH' => '00d0',
  425.     'Eth' => '00d0',
  426.     'Ntilde' => '00d1',
  427.     'Ograve' => '00d2',
  428.     'Oacute' => '00d3',
  429.     'Ocircumflex' => '00d4',
  430.     'Otilde' => '00d5',
  431.     'Odiaeresis' => '00d6',
  432.     'multiply' => '00d7',
  433.     'Ooblique' => '00d8',
  434.     'Oslash' => '00d8',
  435.     'Ugrave' => '00d9',
  436.     'Uacute' => '00da',
  437.     'Ucircumflex' => '00db',
  438.     'Udiaeresis' => '00dc',
  439.     'Yacute' => '00dd',
  440.     'THORN' => '00de',
  441.     'Thorn' => '00de',
  442.     'ssharp' => '00df',
  443.     'agrave' => '00e0',
  444.     'aacute' => '00e1',
  445.     'acircumflex' => '00e2',
  446.     'atilde' => '00e3',
  447.     'adiaeresis' => '00e4',
  448.     'aring' => '00e5',
  449.     'ae' => '00e6',
  450.     'ccedilla' => '00e7',
  451.     'egrave' => '00e8',
  452.     'eacute' => '00e9',
  453.     'ecircumflex' => '00ea',
  454.     'ediaeresis' => '00eb',
  455.     'igrave' => '00ec',
  456.     'iacute' => '00ed',
  457.     'icircumflex' => '00ee',
  458.     'idiaeresis' => '00ef',
  459.     'eth' => '00f0',
  460.     'ntilde' => '00f1',
  461.     'ograve' => '00f2',
  462.     'oacute' => '00f3',
  463.     'ocircumflex' => '00f4',
  464.     'otilde' => '00f5',
  465.     'odiaeresis' => '00f6',
  466.     'division' => '00f7',
  467.     'oslash' => '00f8',
  468.     'ooblique' => '00f8',
  469.     'ugrave' => '00f9',
  470.     'uacute' => '00fa',
  471.     'ucircumflex' => '00fb',
  472.     'udiaeresis' => '00fc',
  473.     'yacute' => '00fd',
  474.     'thorn' => '00fe',
  475.     'ydiaeresis' => '00ff',
  476.     'Amacron' => '0100',
  477.     'amacron' => '0101',
  478.     'Abreve' => '0102',
  479.     'abreve' => '0103',
  480.     'Aogonek' => '0104',
  481.     'aogonek' => '0105',
  482.     'Cacute' => '0106',
  483.     'cacute' => '0107',
  484.     'Ccircumflex' => '0108',
  485.     'ccircumflex' => '0109',
  486.     'Cabovedot' => '010a',
  487.     'cabovedot' => '010b',
  488.     'Ccaron' => '010c',
  489.     'ccaron' => '010d',
  490.     'Dcaron' => '010e',
  491.     'dcaron' => '010f',
  492.     'Dstroke' => '0110',
  493.     'dstroke' => '0111',
  494.     'Emacron' => '0112',
  495.     'emacron' => '0113',
  496.     'Eabovedot' => '0116',
  497.     'eabovedot' => '0117',
  498.     'Eogonek' => '0118',
  499.     'eogonek' => '0119',
  500.     'Ecaron' => '011a',
  501.     'ecaron' => '011b',
  502.     'Gcircumflex' => '011c',
  503.     'gcircumflex' => '011d',
  504.     'Gbreve' => '011e',
  505.     'gbreve' => '011f',
  506.     'Gabovedot' => '0120',
  507.     'gabovedot' => '0121',
  508.     'Gcedilla' => '0122',
  509.     'gcedilla' => '0123',
  510.     'Hcircumflex' => '0124',
  511.     'hcircumflex' => '0125',
  512.     'Hstroke' => '0126',
  513.     'hstroke' => '0127',
  514.     'Itilde' => '0128',
  515.     'itilde' => '0129',
  516.     'Imacron' => '012a',
  517.     'imacron' => '012b',
  518.     'Iogonek' => '012e',
  519.     'iogonek' => '012f',
  520.     'Iabovedot' => '0130',
  521.     'idotless' => '0131',
  522.     'Jcircumflex' => '0134',
  523.     'jcircumflex' => '0135',
  524.     'Kcedilla' => '0136',
  525.     'kcedilla' => '0137',
  526.     'kra' => '0138',
  527.     'Lacute' => '0139',
  528.     'lacute' => '013a',
  529.     'Lcedilla' => '013b',
  530.     'lcedilla' => '013c',
  531.     'Lcaron' => '013d',
  532.     'lcaron' => '013e',
  533.     'Lstroke' => '0141',
  534.     'lstroke' => '0142',
  535.     'Nacute' => '0143',
  536.     'nacute' => '0144',
  537.     'Ncedilla' => '0145',
  538.     'ncedilla' => '0146',
  539.     'Ncaron' => '0147',
  540.     'ncaron' => '0148',
  541.     'ENG' => '014a',
  542.     'eng' => '014b',
  543.     'Omacron' => '014c',
  544.     'omacron' => '014d',
  545.     'Odoubleacute' => '0150',
  546.     'odoubleacute' => '0151',
  547.     'OE' => '0152',
  548.     'oe' => '0153',
  549.     'Racute' => '0154',
  550.     'racute' => '0155',
  551.     'Rcedilla' => '0156',
  552.     'rcedilla' => '0157',
  553.     'Rcaron' => '0158',
  554.     'rcaron' => '0159',
  555.     'Sacute' => '015a',
  556.     'sacute' => '015b',
  557.     'Scircumflex' => '015c',
  558.     'scircumflex' => '015d',
  559.     'Scedilla' => '015e',
  560.     'scedilla' => '015f',
  561.     'Scaron' => '0160',
  562.     'scaron' => '0161',
  563.     'Tcedilla' => '0162',
  564.     'tcedilla' => '0163',
  565.     'Tcaron' => '0164',
  566.     'tcaron' => '0165',
  567.     'Tslash' => '0166',
  568.     'tslash' => '0167',
  569.     'Utilde' => '0168',
  570.     'utilde' => '0169',
  571.     'Umacron' => '016a',
  572.     'umacron' => '016b',
  573.     'Ubreve' => '016c',
  574.     'ubreve' => '016d',
  575.     'Uring' => '016e',
  576.     'uring' => '016f',
  577.     'Udoubleacute' => '0170',
  578.     'udoubleacute' => '0171',
  579.     'Uogonek' => '0172',
  580.     'uogonek' => '0173',
  581.     'Ydiaeresis' => '0178',
  582.     'Zacute' => '0179',
  583.     'zacute' => '017a',
  584.     'Zabovedot' => '017b',
  585.     'zabovedot' => '017c',
  586.     'Zcaron' => '017d',
  587.     'zcaron' => '017e',
  588.     'SCHWA' => '018f', # Is this recognised by X ?
  589.     'Schwa' => '018f', # Is this recognised by X ?
  590.     'function' => '0192',
  591.     'Ohorn' => '01a0', # Is this recognised by X ?
  592.     'ohorn' => '01a1', # Is this recognised by X ?
  593.     'Uhorn' => '01af', # Is this recognised by X ?
  594.     'uhorn' => '01b0', # Is this recognised by X ?
  595.     'Gcaron' => '01e6', # Is this recognised by X ?
  596.     'gcaron' => '01e7', # Is this recognised by X ?
  597.     'schwa' => '0259', # Is this recognised by X ?
  598.     'caron' => '02c7',
  599.     'breve' => '02d8',
  600.     'abovedot' => '02d9',
  601.     'ogonek' => '02db',
  602.     'doubleacute' => '02dd',
  603.     'Greek_accentdieresis' => '0385',
  604.     'Greek_ALPHAaccent' => '0386',
  605.     'Greek_EPSILONaccent' => '0388',
  606.     'Greek_ETAaccent' => '0389',
  607.     'Greek_IOTAaccent' => '038a',
  608.     'Greek_OMICRONaccent' => '038c',
  609.     'Greek_UPSILONaccent' => '038e',
  610.     'Greek_OMEGAaccent' => '038f',
  611.     'Greek_iotaaccentdieresis' => '0390',
  612.     'Greek_ALPHA' => '0391',
  613.     'Greek_BETA' => '0392',
  614.     'Greek_GAMMA' => '0393',
  615.     'Greek_DELTA' => '0394',
  616.     'Greek_EPSILON' => '0395',
  617.     'Greek_ZETA' => '0396',
  618.     'Greek_ETA' => '0397',
  619.     'Greek_THETA' => '0398',
  620.     'Greek_IOTA' => '0399',
  621.     'Greek_KAPPA' => '039a',
  622.     'Greek_LAMBDA' => '039b',
  623.     'Greek_LAMDA' => '039b',   # Is this recognised by X ? (speling error)
  624.     'Greek_MU' => '039c',
  625.     'Greek_NU' => '039d',
  626.     'Greek_XI' => '039e',
  627.     'Greek_OMICRON' => '039f',
  628.     'Greek_PI' => '03a0',
  629.     'Greek_RHO' => '03a1',
  630.     'Greek_SIGMA' => '03a3',
  631.     'Greek_TAU' => '03a4',
  632.     'Greek_UPSILON' => '03a5',
  633.     'Greek_PHI' => '03a6',
  634.     'Greek_CHI' => '03a7',
  635.     'Greek_PSI' => '03a8',
  636.     'Greek_OMEGA' => '03a9',
  637.     'Greek_IOTAdiaeresis' => '03aa',
  638.     'Greek_UPSILONdieresis' => '03ab',
  639.     'Greek_alphaaccent' => '03ac',
  640.     'Greek_epsilonaccent' => '03ad',
  641.     'Greek_etaaccent' => '03ae',
  642.     'Greek_iotaaccent' => '03af',
  643.     'Greek_upsilonaccentdieresis' => '03b0',
  644.     'Greek_alpha' => '03b1',
  645.     'Greek_beta' => '03b2',
  646.     'Greek_gamma' => '03b3',
  647.     'Greek_delta' => '03b4',
  648.     'Greek_epsilon' => '03b5',
  649.     'Greek_zeta' => '03b6',
  650.     'Greek_eta' => '03b7',
  651.     'Greek_theta' => '03b8',
  652.     'Greek_iota' => '03b9',
  653.     'Greek_kappa' => '03ba',
  654.     'Greek_lambda' => '03bb',
  655.     'Greek_lamda' => '03bb', # Is this recognised by X ? (speling error)
  656.     'Greek_mu' => '03bc',
  657.     'Greek_nu' => '03bd',
  658.     'Greek_xi' => '03be',
  659.     'Greek_omicron' => '03bf',
  660.     'Greek_pi' => '03c0',
  661.     'Greek_rho' => '03c1',
  662.     'Greek_finalsmallsigma' => '03c2',
  663.     'Greek_sigma' => '03c3',
  664.     'Greek_tau' => '03c4',
  665.     'Greek_upsilon' => '03c5',
  666.     'Greek_phi' => '03c6',
  667.     'Greek_chi' => '03c7',
  668.     'Greek_psi' => '03c8',
  669.     'Greek_omega' => '03c9',
  670.     'Greek_iotadieresis' => '03ca',
  671.     'Greek_upsilondieresis' => '03cb',
  672.     'Greek_omicronaccent' => '03cc',
  673.     'Greek_upsilonaccent' => '03cd',
  674.     'Greek_omegaaccent' => '03ce',
  675.     'Cyrillic_IO' => '0401',
  676.     'Serbian_DJE' => '0402',
  677.     'Macedonia_GJE' => '0403',
  678.     'Ukrainian_IE' => '0404',
  679.     'Macedonia_DSE' => '0405',
  680.     'Ukrainian_I' => '0406',
  681.     'Ukrainian_YI' => '0407',
  682.     'Cyrillic_JE' => '0408',
  683.     'Cyrillic_LJE' => '0409',
  684.     'Cyrillic_NJE' => '040a',
  685.     'Serbian_TSHE' => '040b',
  686.     'Macedonia_KJE' => '040c',
  687.     'Byelorussian_SHORTU' => '040e',
  688.     'Cyrillic_DZHE' => '040f',
  689.     'Cyrillic_A' => '0410',
  690.     'Cyrillic_BE' => '0411',
  691.     'Cyrillic_VE' => '0412',
  692.     'Cyrillic_GHE' => '0413',
  693.     'Cyrillic_DE' => '0414',
  694.     'Cyrillic_IE' => '0415',
  695.     'Cyrillic_ZHE' => '0416',
  696.     'Cyrillic_ZE' => '0417',
  697.     'Cyrillic_I' => '0418',
  698.     'Cyrillic_SHORTI' => '0419',
  699.     'Cyrillic_KA' => '041a',
  700.     'Cyrillic_EL' => '041b',
  701.     'Cyrillic_EM' => '041c',
  702.     'Cyrillic_EN' => '041d',
  703.     'Cyrillic_O' => '041e',
  704.     'Cyrillic_PE' => '041f',
  705.     'Cyrillic_ER' => '0420',
  706.     'Cyrillic_ES' => '0421',
  707.     'Cyrillic_TE' => '0422',
  708.     'Cyrillic_U' => '0423',
  709.     'Cyrillic_EF' => '0424',
  710.     'Cyrillic_HA' => '0425',
  711.     'Cyrillic_TSE' => '0426',
  712.     'Cyrillic_CHE' => '0427',
  713.     'Cyrillic_SHA' => '0428',
  714.     'Cyrillic_SHCHA' => '0429',
  715.     'Cyrillic_HARDSIGN' => '042a',
  716.     'Cyrillic_YERU' => '042b',
  717.     'Cyrillic_SOFTSIGN' => '042c',
  718.     'Cyrillic_E' => '042d',
  719.     'Cyrillic_YU' => '042e',
  720.     'Cyrillic_YA' => '042f',
  721.     'Cyrillic_a' => '0430',
  722.     'Cyrillic_be' => '0431',
  723.     'Cyrillic_ve' => '0432',
  724.     'Cyrillic_ghe' => '0433',
  725.     'Cyrillic_de' => '0434',
  726.     'Cyrillic_ie' => '0435',
  727.     'Cyrillic_zhe' => '0436',
  728.     'Cyrillic_ze' => '0437',
  729.     'Cyrillic_i' => '0438',
  730.     'Cyrillic_shorti' => '0439',
  731.     'Cyrillic_ka' => '043a',
  732.     'Cyrillic_el' => '043b',
  733.     'Cyrillic_em' => '043c',
  734.     'Cyrillic_en' => '043d',
  735.     'Cyrillic_o' => '043e',
  736.     'Cyrillic_pe' => '043f',
  737.     'Cyrillic_er' => '0440',
  738.     'Cyrillic_es' => '0441',
  739.     'Cyrillic_te' => '0442',
  740.     'Cyrillic_u' => '0443',
  741.     'Cyrillic_ef' => '0444',
  742.     'Cyrillic_ha' => '0445',
  743.     'Cyrillic_tse' => '0446',
  744.     'Cyrillic_che' => '0447',
  745.     'Cyrillic_sha' => '0448',
  746.     'Cyrillic_shcha' => '0449',
  747.     'Cyrillic_hardsign' => '044a',
  748.     'Cyrillic_yeru' => '044b',
  749.     'Cyrillic_softsign' => '044c',
  750.     'Cyrillic_e' => '044d',
  751.     'Cyrillic_yu' => '044e',
  752.     'Cyrillic_ya' => '044f',
  753.     'Cyrillic_io' => '0451',
  754.     'Serbian_dje' => '0452',
  755.     'Macedonia_gje' => '0453',
  756.     'Ukrainian_ie' => '0454',
  757.     'Macedonia_dse' => '0455',
  758.     'Ukrainian_i' => '0456',
  759.     'Ukrainian_yi' => '0457',
  760.     'Cyrillic_je' => '0458',
  761.     'Cyrillic_lje' => '0459',
  762.     'Cyrillic_nje' => '045a',
  763.     'Serbian_tshe' => '045b',
  764.     'Macedonia_kje' => '045c',
  765.     'Byelorussian_shortu' => '045e',
  766.     'Cyrillic_dzhe' => '045f',
  767.     'Ukrainian_GHE_WITH_UPTURN' => '0490', # Is this recognised by X ?
  768.     'Ukrainian_ghe_with_upturn' => '0491', # Is this recognised by X ?
  769.     'Cyrillic_GHE_bar' => '0492', # Is this recognised by X ?
  770.     'Cyrillic_ghe_bar' => '0493', # Is this recognised by X ?
  771.     'Cyrillic_KA_descender' => '049a', # Is this recognised by X ?
  772.     'Cyrillic_ka_descender' => '049b', # Is this recognised by X ?
  773.     'Cyrillic_KA_vertstroke' => '049c', # Is this recognised by X ?
  774.     'Cyrillic_ka_vertstroke' => '049d', # Is this recognised by X ?
  775.     'Cyrillic_EN_descender' => '04a2', # Is this recognised by X ?
  776.     'Cyrillic_en_descender' => '04a3', # Is this recognised by X ?
  777.     'Cyrillic_U_straight' => '04ae', # Is this recognised by X ?
  778.     'Cyrillic_u_straight' => '04af', # Is this recognised by X ?
  779.     'Cyrillic_U_straight_bar' => '04b0', # Is this recognised by X ?
  780.     'Cyrillic_u_straight_bar' => '04b1', # Is this recognised by X ?
  781.     'Cyrillic_HA_descender' => '04b2', # Is this recognised by X ?
  782.     'Cyrillic_ha_descender' => '04b3', # Is this recognised by X ?
  783.     'Cyrillic_CHE_vertstroke' => '04b8', # Is this recognised by X ?
  784.     'Cyrillic_che_vertstroke' => '04b9', # Is this recognised by X ?
  785.     'Cyrillic_SHHA' => '04ba', # Is this recognised by X ?
  786.     'Cyrillic_shha' => '04bb', # Is this recognised by X ?
  787.     'Cyrillic_SCHWA' => '04d8', # Is this recognised by X ?
  788.     'Cyrillic_schwa' => '04d9', # Is this recognised by X ?
  789.     'Cyrillic_O_bar' => '04e8', # Is this recognised by X ?
  790.     'Cyrillic_o_bar' => '04e9', # Is this recognised by X ?
  791.     'hebrew_aleph' => '05d0',
  792.     'hebrew_bet' => '05d1',
  793.     'hebrew_gimel' => '05d2',
  794.     'hebrew_dalet' => '05d3',
  795.     'hebrew_he' => '05d4',
  796.     'hebrew_waw' => '05d5',
  797.     'hebrew_zain' => '05d6',
  798.     'hebrew_chet' => '05d7',
  799.     'hebrew_tet' => '05d8',
  800.     'hebrew_yod' => '05d9',
  801.     'hebrew_finalkaph' => '05da',
  802.     'hebrew_kaph' => '05db',
  803.     'hebrew_lamed' => '05dc',
  804.     'hebrew_finalmem' => '05dd',
  805.     'hebrew_mem' => '05de',
  806.     'hebrew_finalnun' => '05df',
  807.     'hebrew_nun' => '05e0',
  808.     'hebrew_samech' => '05e1',
  809.     'hebrew_ayin' => '05e2',
  810.     'hebrew_finalpe' => '05e3',
  811.     'hebrew_pe' => '05e4',
  812.     'hebrew_finalzade' => '05e5',
  813.     'hebrew_zade' => '05e6',
  814.     'hebrew_qoph' => '05e7',
  815.     'hebrew_resh' => '05e8',
  816.     'hebrew_shin' => '05e9',
  817.     'hebrew_taw' => '05ea',
  818.     'Arabic_comma' => '060c',
  819.     'Arabic_semicolon' => '061b',
  820.     'Arabic_question_mark' => '061f',
  821.     'Arabic_hamza' => '0621',
  822.     'Arabic_maddaonalef' => '0622',
  823.     'Arabic_hamzaonalef' => '0623',
  824.     'Arabic_hamzaonwaw' => '0624',
  825.     'Arabic_hamzaunderalef' => '0625',
  826.     'Arabic_hamzaonyeh' => '0626',
  827.     'Arabic_alef' => '0627',
  828.     'Arabic_beh' => '0628',
  829.     'Arabic_tehmarbuta' => '0629',
  830.     'Arabic_teh' => '062a',
  831.     'Arabic_theh' => '062b',
  832.     'Arabic_jeem' => '062c',
  833.     'Arabic_hah' => '062d',
  834.     'Arabic_khah' => '062e',
  835.     'Arabic_dal' => '062f',
  836.     'Arabic_thal' => '0630',
  837.     'Arabic_ra' => '0631',
  838.     'Arabic_zain' => '0632',
  839.     'Arabic_seen' => '0633',
  840.     'Arabic_sheen' => '0634',
  841.     'Arabic_sad' => '0635',
  842.     'Arabic_dad' => '0636',
  843.     'Arabic_tah' => '0637',
  844.     'Arabic_zah' => '0638',
  845.     'Arabic_ain' => '0639',
  846.     'Arabic_ghain' => '063a',
  847.     'Arabic_tatweel' => '0640',
  848.     'Arabic_feh' => '0641',
  849.     'Arabic_qaf' => '0642',
  850.     'Arabic_kaf' => '0643',
  851.     'Arabic_lam' => '0644',
  852.     'Arabic_meem' => '0645',
  853.     'Arabic_noon' => '0646',
  854.     'Arabic_ha' => '0647',
  855.     'Arabic_heh' => '0647', # Is this recognised by X ?
  856.     'Arabic_waw' => '0648',
  857.     'Arabic_alefmaksura' => '0649',
  858.     'Arabic_yeh' => '064a',
  859.     'Arabic_fathatan' => '064b',
  860.     'Arabic_dammatan' => '064c',
  861.     'Arabic_kasratan' => '064d',
  862.     'Arabic_fatha' => '064e',
  863.     'Arabic_damma' => '064f',
  864.     'Arabic_kasra' => '0650',
  865.     'Arabic_shadda' => '0651',
  866.     'Arabic_sukun' => '0652',
  867.     'Arabic_madda_above' => '0653', # Is this recognised by X ?
  868.     'Arabic_hamza_above' => '0654', # Is this recognised by X ?
  869.     'Arabic_hamza_below' => '0655', # Is this recognised by X ?
  870.     'Arabic_superscript_alef' => '0670', # Is this recognised by X ?
  871.     'Thai_kokai' => '0e01',
  872.     'Thai_khokhai' => '0e02',
  873.     'Thai_khokhuat' => '0e03',
  874.     'Thai_khokhwai' => '0e04',
  875.     'Thai_khokhon' => '0e05',
  876.     'Thai_khorakhang' => '0e06',
  877.     'Thai_ngongu' => '0e07',
  878.     'Thai_chochan' => '0e08',
  879.     'Thai_choching' => '0e09',
  880.     'Thai_chochang' => '0e0a',
  881.     'Thai_soso' => '0e0b',
  882.     'Thai_chochoe' => '0e0c',
  883.     'Thai_yoying' => '0e0d',
  884.     'Thai_dochada' => '0e0e',
  885.     'Thai_topatak' => '0e0f',
  886.     'Thai_thothan' => '0e10',
  887.     'Thai_thonangmontho' => '0e11',
  888.     'Thai_thophuthao' => '0e12',
  889.     'Thai_nonen' => '0e13',
  890.     'Thai_dodek' => '0e14',
  891.     'Thai_totao' => '0e15',
  892.     'Thai_thothung' => '0e16',
  893.     'Thai_thothahan' => '0e17',
  894.     'Thai_thothong' => '0e18',
  895.     'Thai_nonu' => '0e19',
  896.     'Thai_bobaimai' => '0e1a',
  897.     'Thai_popla' => '0e1b',
  898.     'Thai_phophung' => '0e1c',
  899.     'Thai_fofa' => '0e1d',
  900.     'Thai_phophan' => '0e1e',
  901.     'Thai_fofan' => '0e1f',
  902.     'Thai_phosamphao' => '0e20',
  903.     'Thai_moma' => '0e21',
  904.     'Thai_yoyak' => '0e22',
  905.     'Thai_rorua' => '0e23',
  906.     'Thai_ru' => '0e24',
  907.     'Thai_loling' => '0e25',
  908.     'Thai_lu' => '0e26',
  909.     'Thai_wowaen' => '0e27',
  910.     'Thai_sosala' => '0e28',
  911.     'Thai_sorusi' => '0e29',
  912.     'Thai_sosua' => '0e2a',
  913.     'Thai_hohip' => '0e2b',
  914.     'Thai_lochula' => '0e2c',
  915.     'Thai_oang' => '0e2d',
  916.     'Thai_honokhuk' => '0e2e',
  917.     'Thai_paiyannoi' => '0e2f',
  918.     'Thai_saraa' => '0e30',
  919.     'Thai_maihanakat' => '0e31',
  920.     'Thai_saraaa' => '0e32',
  921.     'Thai_saraam' => '0e33',
  922.     'Thai_sarai' => '0e34',
  923.     'Thai_saraii' => '0e35',
  924.     'Thai_saraue' => '0e36',
  925.     'Thai_sarauee' => '0e37',
  926.     'Thai_sarau' => '0e38',
  927.     'Thai_sarauu' => '0e39',
  928.     'Thai_phinthu' => '0e3a',
  929.     'Thai_baht' => '0e3f',
  930.     'Thai_sarae' => '0e40',
  931.     'Thai_saraae' => '0e41',
  932.     'Thai_sarao' => '0e42',
  933.     'Thai_saraaimaimuan' => '0e43',
  934.     'Thai_saraaimaimalai' => '0e44',
  935.     'Thai_lakkhangyao' => '0e45',
  936.     'Thai_maiyamok' => '0e46',
  937.     'Thai_maitaikhu' => '0e47',
  938.     'Thai_maiek' => '0e48',
  939.     'Thai_maitho' => '0e49',
  940.     'Thai_maitri' => '0e4a',
  941.     'Thai_maichattawa' => '0e4b',
  942.     'Thai_thanthakhat' => '0e4c',
  943.     'Thai_nikhahit' => '0e4d',
  944.     'Thai_leksun' => '0e50',
  945.     'Thai_leknung' => '0e51',
  946.     'Thai_leksong' => '0e52',
  947.     'Thai_leksam' => '0e53',
  948.     'Thai_leksi' => '0e54',
  949.     'Thai_lekha' => '0e55',
  950.     'Thai_lekhok' => '0e56',
  951.     'Thai_lekchet' => '0e57',
  952.     'Thai_lekpaet' => '0e58',
  953.     'Thai_lekkao' => '0e59',
  954.     'Hangul_J_Kiyeog' => '11a8',
  955.     'Hangul_J_SsangKiyeog' => '11a9',
  956.     'Hangul_J_KiyeogSios' => '11aa',
  957.     'Hangul_J_Nieun' => '11ab',
  958.     'Hangul_J_NieunJieuj' => '11ac',
  959.     'Hangul_J_NieunHieuh' => '11ad',
  960.     'Hangul_J_Dikeud' => '11ae',
  961.     'Hangul_J_Rieul' => '11af',
  962.     'Hangul_J_RieulKiyeog' => '11b0',
  963.     'Hangul_J_RieulMieum' => '11b1',
  964.     'Hangul_J_RieulPieub' => '11b2',
  965.     'Hangul_J_RieulSios' => '11b3',
  966.     'Hangul_J_RieulTieut' => '11b4',
  967.     'Hangul_J_RieulPhieuf' => '11b5',
  968.     'Hangul_J_RieulHieuh' => '11b6',
  969.     'Hangul_J_Mieum' => '11b7',
  970.     'Hangul_J_Pieub' => '11b8',
  971.     'Hangul_J_PieubSios' => '11b9',
  972.     'Hangul_J_Sios' => '11ba',
  973.     'Hangul_J_SsangSios' => '11bb',
  974.     'Hangul_J_Ieung' => '11bc',
  975.     'Hangul_J_Jieuj' => '11bd',
  976.     'Hangul_J_Cieuc' => '11be',
  977.     'Hangul_J_Khieuq' => '11bf',
  978.     'Hangul_J_Tieut' => '11c0',
  979.     'Hangul_J_Phieuf' => '11c1',
  980.     'Hangul_J_Hieuh' => '11c2',
  981.     'Hangul_J_PanSios' => '11eb',
  982.     'Hangul_J_KkogjiDalrinIeung' => '11f0',
  983.     'Hangul_J_YeorinHieuh' => '11f9',
  984.     'Babovedot' => '1e02', # Is this recognised by X ?
  985.     'babovedot' => '1e03', # Is this recognised by X ?
  986.     'Dabovedot' => '1e0a', # Is this recognised by X ?
  987.     'dabovedot' => '1e0b', # Is this recognised by X ?
  988.     'Fabovedot' => '1e1e', # Is this recognised by X ?
  989.     'fabovedot' => '1e1f', # Is this recognised by X ?
  990.     'Mabovedot' => '1e40', # Is this recognised by X ?
  991.     'mabovedot' => '1e41', # Is this recognised by X ?
  992.     'Pabovedot' => '1e56', # Is this recognised by X ?
  993.     'pabovedot' => '1e57', # Is this recognised by X ?
  994.     'Sabovedot' => '1e60', # Is this recognised by X ?
  995.     'sabovedot' => '1e61', # Is this recognised by X ?
  996.     'Tabovedot' => '1e6a', # Is this recognised by X ?
  997.     'tabovedot' => '1e6b', # Is this recognised by X ?
  998.     'enspace' => '2002',
  999.     'emspace' => '2003',
  1000.     'em3space' => '2004',
  1001.     'em4space' => '2005',
  1002.     'digitspace' => '2007',
  1003.     'punctspace' => '2008',
  1004.     'thinspace' => '2009',
  1005.     'hairspace' => '200a',
  1006.     'figdash' => '2012',
  1007.     'endash' => '2013',
  1008.     'emdash' => '2014',
  1009.     'Greek_horizbar' => '2015',
  1010.     'hebrew_doublelowline' => '2017',
  1011.     'leftsinglequotemark' => '2018',
  1012.     'rightsinglequotemark' => '2019',
  1013.     'singlelowquotemark' => '201a',
  1014.     'leftdoublequotemark' => '201c',
  1015.     'rightdoublequotemark' => '201d',
  1016.     'doublelowquotemark' => '201e',
  1017.     'dagger' => '2020',
  1018.     'doubledagger' => '2021',
  1019.     'enfilledcircbullet' => '2022',
  1020.     'doubbaselinedot' => '2025',
  1021.     'ellipsis' => '2026',
  1022.     'minutes' => '2032',
  1023.     'seconds' => '2033',
  1024.     'caret' => '2038',
  1025.     'overline' => '203e',
  1026.     'Korean_Won' => '20a9',
  1027.     'DongSign' => '20ab', # Is this recognised by X ?
  1028.     'EuroSign' => '20ac',
  1029.     'Euro' => '20ac',
  1030.     'careof' => '2105',
  1031.     'numerosign' => '2116',
  1032.     'phonographcopyright' => '2117',
  1033.     'prescription' => '211e',
  1034.     'trademark' => '2122',
  1035.     'onethird' => '2153',
  1036.     'twothirds' => '2154',
  1037.     'onefifth' => '2155',
  1038.     'twofifths' => '2156',
  1039.     'threefifths' => '2157',
  1040.     'fourfifths' => '2158',
  1041.     'onesixth' => '2159',
  1042.     'fivesixths' => '215a',
  1043.     'oneeighth' => '215b',
  1044.     'threeeighths' => '215c',
  1045.     'fiveeighths' => '215d',
  1046.     'seveneighths' => '215e',
  1047.     'leftarrow' => '2190',
  1048.     'uparrow' => '2191',
  1049.     'rightarrow' => '2192',
  1050.     'downarrow' => '2193',
  1051.     'implies' => '21d2',
  1052.     'ifonlyif' => '21d4',
  1053.     'partialderivative' => '2202',
  1054.     'nabla' => '2207',
  1055.     'jot' => '2218',
  1056.     'radical' => '221a',
  1057.     'variation' => '221d',
  1058.     'infinity' => '221e',
  1059.     'logicaland' => '2227',
  1060.     'upcaret' => '2227',
  1061.     'downcaret' => '2228',
  1062.     'logicalor' => '2228',
  1063.     'intersection' => '2229',
  1064.     'upshoe' => '2229',
  1065.     'downshoe' => '222a',
  1066.     'union' => '222a',
  1067.     'integral' => '222b',
  1068.     'therefore' => '2234',
  1069.     'approximate' => '223c',
  1070.     'similarequal' => '2243',
  1071.     'notequal' => '2260',
  1072.     'identical' => '2261',
  1073.     'lessthanequal' => '2264',
  1074.     'greaterthanequal' => '2265',
  1075.     'includedin' => '2282',
  1076.     'leftshoe' => '2282',
  1077.     'includes' => '2283',
  1078.     'rightshoe' => '2283',
  1079.     'lefttack' => '22a2',
  1080.     'righttack' => '22a3',
  1081.     'uptack' => '22a4',
  1082.     'downtack' => '22a5',
  1083.     'upstile' => '2308',
  1084.     'downstile' => '230a',
  1085.     'telephonerecorder' => '2315',
  1086.     'topintegral' => '2320',
  1087.     'botintegral' => '2321',
  1088.     'leftanglebracket' => '2329',
  1089.     'rightanglebracket' => '232a',
  1090.     'quad' => '2395',
  1091.     'topleftparens' => '239b',
  1092.     'botleftparens' => '239d',
  1093.     'toprightparens' => '239e',
  1094.     'botrightparens' => '23a0',
  1095.     'topleftsqbracket' => '23a1',
  1096.     'botleftsqbracket' => '23a3',
  1097.     'toprightsqbracket' => '23a4',
  1098.     'botrightsqbracket' => '23a6',
  1099.     'leftmiddlecurlybrace' => '23a8',
  1100.     'rightmiddlecurlybrace' => '23ac',
  1101.     'leftradical' => '23b7',
  1102.     'horizlinescan1' => '23ba',
  1103.     'horizlinescan3' => '23bb',
  1104.     'horizlinescan7' => '23bc',
  1105.     'horizlinescan9' => '23bd',
  1106.     'ht' => '2409',
  1107.     'lf' => '240a',
  1108.     'vt' => '240b',
  1109.     'ff' => '240c',
  1110.     'cr' => '240d',
  1111.     'nl' => '2424',
  1112.     'horizconnector' => '2500',
  1113.     'horizlinescan5' => '2500',
  1114.     'vertbar' => '2502',
  1115.     'vertconnector' => '2502',
  1116.     'topleftradical' => '250c',
  1117.     'upleftcorner' => '250c',
  1118.     'uprightcorner' => '2510',
  1119.     'lowleftcorner' => '2514',
  1120.     'lowrightcorner' => '2518',
  1121.     'leftt' => '251c',
  1122.     'rightt' => '2524',
  1123.     'topt' => '252c',
  1124.     'bott' => '2534',
  1125.     'crossinglines' => '253c',
  1126.     'checkerboard' => '2592',
  1127.     'enfilledsqbullet' => '25aa',
  1128.     'enopensquarebullet' => '25ab',
  1129.     'filledrectbullet' => '25ac',
  1130.     'openrectbullet' => '25ad',
  1131.     'emfilledrect' => '25ae',
  1132.     'emopenrectangle' => '25af',
  1133.     'filledtribulletup' => '25b2',
  1134.     'opentribulletup' => '25b3',
  1135.     'filledrighttribullet' => '25b6',
  1136.     'rightopentriangle' => '25b7',
  1137.     'filledtribulletdown' => '25bc',
  1138.     'opentribulletdown' => '25bd',
  1139.     'filledlefttribullet' => '25c0',
  1140.     'leftopentriangle' => '25c1',
  1141.     'soliddiamond' => '25c6',
  1142.     'circle' => '25cb',
  1143.     'emopencircle' => '25cb',
  1144.     'emfilledcircle' => '25cf',
  1145.     'enopencircbullet' => '25e6',
  1146.     'openstar' => '2606',
  1147.     'telephone' => '260e',
  1148.     'signaturemark' => '2613',
  1149.     'leftpointer' => '261c',
  1150.     'rightpointer' => '261e',
  1151.     'femalesymbol' => '2640',
  1152.     'malesymbol' => '2642',
  1153.     'club' => '2663',
  1154.     'heart' => '2665',
  1155.     'diamond' => '2666',
  1156.     'musicalflat' => '266d',
  1157.     'musicalsharp' => '266f',
  1158.     'checkmark' => '2713',
  1159.     'ballotcross' => '2717',
  1160.     'latincross' => '271d',
  1161.     'maltesecross' => '2720',
  1162.     'kana_comma' => '3001',
  1163.     'kana_fullstop' => '3002',
  1164.     'kana_openingbracket' => '300c',
  1165.     'kana_closingbracket' => '300d',
  1166.     'voicedsound' => '309b',
  1167.     'semivoicedsound' => '309c',
  1168.     'kana_a' => '30a1',
  1169.     'kana_A' => '30a2',
  1170.     'kana_i' => '30a3',
  1171.     'kana_I' => '30a4',
  1172.     'kana_u' => '30a5',
  1173.     'kana_U' => '30a6',
  1174.     'kana_e' => '30a7',
  1175.     'kana_E' => '30a8',
  1176.     'kana_o' => '30a9',
  1177.     'kana_O' => '30aa',
  1178.     'kana_KA' => '30ab',
  1179.     'kana_KI' => '30ad',
  1180.     'kana_KU' => '30af',
  1181.     'kana_KE' => '30b1',
  1182.     'kana_KO' => '30b3',
  1183.     'kana_SA' => '30b5',
  1184.     'kana_SHI' => '30b7',
  1185.     'kana_SU' => '30b9',
  1186.     'kana_SE' => '30bb',
  1187.     'kana_SO' => '30bd',
  1188.     'kana_TA' => '30bf',
  1189.     'kana_CHI' => '30c1',
  1190.     'kana_tsu' => '30c3',
  1191.     'kana_TSU' => '30c4',
  1192.     'kana_TE' => '30c6',
  1193.     'kana_TO' => '30c8',
  1194.     'kana_NA' => '30ca',
  1195.     'kana_NI' => '30cb',
  1196.     'kana_NU' => '30cc',
  1197.     'kana_NE' => '30cd',
  1198.     'kana_NO' => '30ce',
  1199.     'kana_HA' => '30cf',
  1200.     'kana_HI' => '30d2',
  1201.     'kana_FU' => '30d5',
  1202.     'kana_HE' => '30d8',
  1203.     'kana_HO' => '30db',
  1204.     'kana_MA' => '30de',
  1205.     'kana_MI' => '30df',
  1206.     'kana_MU' => '30e0',
  1207.     'kana_ME' => '30e1',
  1208.     'kana_MO' => '30e2',
  1209.     'kana_ya' => '30e3',
  1210.     'kana_YA' => '30e4',
  1211.     'kana_yu' => '30e5',
  1212.     'kana_YU' => '30e6',
  1213.     'kana_yo' => '30e7',
  1214.     'kana_YO' => '30e8',
  1215.     'kana_RA' => '30e9',
  1216.     'kana_RI' => '30ea',
  1217.     'kana_RU' => '30eb',
  1218.     'kana_RE' => '30ec',
  1219.     'kana_RO' => '30ed',
  1220.     'kana_WA' => '30ef',
  1221.     'kana_WO' => '30f2',
  1222.     'kana_N' => '30f3',
  1223.     'kana_conjunctive' => '30fb',
  1224.     'kana_middledot' => '30fb', # Is this recognised by X ?
  1225.     'prolongedsound' => '30fc',
  1226.     'Hangul_Kiyeog' => '3131',
  1227.     'Hangul_SsangKiyeog' => '3132',
  1228.     'Hangul_KiyeogSios' => '3133',
  1229.     'Hangul_Nieun' => '3134',
  1230.     'Hangul_NieunJieuj' => '3135',
  1231.     'Hangul_NieunHieuh' => '3136',
  1232.     'Hangul_Dikeud' => '3137',
  1233.     'Hangul_SsangDikeud' => '3138',
  1234.     'Hangul_Rieul' => '3139',
  1235.     'Hangul_RieulKiyeog' => '313a',
  1236.     'Hangul_RieulMieum' => '313b',
  1237.     'Hangul_RieulPieub' => '313c',
  1238.     'Hangul_RieulSios' => '313d',
  1239.     'Hangul_RieulTieut' => '313e',
  1240.     'Hangul_RieulPhieuf' => '313f',
  1241.     'Hangul_RieulHieuh' => '3140',
  1242.     'Hangul_Mieum' => '3141',
  1243.     'Hangul_Pieub' => '3142',
  1244.     'Hangul_SsangPieub' => '3143',
  1245.     'Hangul_PieubSios' => '3144',
  1246.     'Hangul_Sios' => '3145',
  1247.     'Hangul_SsangSios' => '3146',
  1248.     'Hangul_Ieung' => '3147',
  1249.     'Hangul_Jieuj' => '3148',
  1250.     'Hangul_SsangJieuj' => '3149',
  1251.     'Hangul_Cieuc' => '314a',
  1252.     'Hangul_Khieuq' => '314b',
  1253.     'Hangul_Tieut' => '314c',
  1254.     'Hangul_Phieuf' => '314d',
  1255.     'Hangul_Hieuh' => '314e',
  1256.     'Hangul_A' => '314f',
  1257.     'Hangul_AE' => '3150',
  1258.     'Hangul_YA' => '3151',
  1259.     'Hangul_YAE' => '3152',
  1260.     'Hangul_EO' => '3153',
  1261.     'Hangul_E' => '3154',
  1262.     'Hangul_YEO' => '3155',
  1263.     'Hangul_YE' => '3156',
  1264.     'Hangul_O' => '3157',
  1265.     'Hangul_WA' => '3158',
  1266.     'Hangul_WAE' => '3159',
  1267.     'Hangul_OE' => '315a',
  1268.     'Hangul_YO' => '315b',
  1269.     'Hangul_U' => '315c',
  1270.     'Hangul_WEO' => '315d',
  1271.     'Hangul_WE' => '315e',
  1272.     'Hangul_WI' => '315f',
  1273.     'Hangul_YU' => '3160',
  1274.     'Hangul_EU' => '3161',
  1275.     'Hangul_YI' => '3162',
  1276.     'Hangul_I' => '3163',
  1277.     'Hangul_RieulYeorinHieuh' => '316d',
  1278.     'Hangul_SunkyeongeumMieum' => '3171',
  1279.     'Hangul_SunkyeongeumPieub' => '3178',
  1280.     'Hangul_PanSios' => '317f',
  1281.     'Hangul_KkogjiDalrinIeung' => '3181',
  1282.     'Hangul_SunkyeongeumPhieuf' => '3184',
  1283.     'Hangul_YeorinHieuh' => '3186',
  1284.     'Hangul_AraeA' => '318d',
  1285.     'Hangul_AraeAE' => '318e',
  1286. # Keypad keys
  1287.     'KP_Home' => 'VoidSymbol',
  1288.     'KP_Left' => 'VoidSymbol',
  1289.     'KP_Up' => 'VoidSymbol',
  1290.     'KP_Right' => 'VoidSymbol',
  1291.     'KP_Down' => 'VoidSymbol',
  1292.     'KP_Prior' => 'VoidSymbol',
  1293.     'KP_Page_Up' => 'VoidSymbol',
  1294.     'KP_Next' => 'VoidSymbol',
  1295.     'KP_Page_Down' => 'VoidSymbol',
  1296.     'KP_End' => 'VoidSymbol',
  1297.     'KP_Begin' => 'VoidSymbol',
  1298.     'KP_Insert' => 'VoidSymbol',
  1299.     'KP_Delete' => 'VoidSymbol',
  1300.     'KP_Multiply' => 'KP_Multiply',
  1301.     'KP_Add' => 'KP_Add',
  1302.     'KP_Seprator' => 'KP_Comma', # Is this recognised by X ?
  1303.     'KP_Separator' => 'KP_Comma',
  1304.     'KP_Subtract' => 'KP_Subtract',
  1305.     'KP_Decimal' => 'KP_Period',
  1306.     'KP_Divide' => 'KP_Divide',
  1307.     'KP_0' => 'KP_0',
  1308.     'KP_1' => 'KP_1',
  1309.     'KP_2' => 'KP_2',
  1310.     'KP_3' => 'KP_3',
  1311.     'KP_4' => 'KP_4',
  1312.     'KP_5' => 'KP_5',
  1313.     'KP_6' => 'KP_6',
  1314.     'KP_7' => 'KP_7',
  1315.     'KP_8' => 'KP_8',
  1316.     'KP_9' => 'KP_9',
  1317.     'KP_Enter' => 'KP_Enter',
  1318. # Keypad keys with missing support in the kernel
  1319.     'KP_Space' => 'space',
  1320.     'KP_Equal' => 'equal',
  1321.     'KP_Tab' => 'Tab',
  1322.     'KP_F1' => 'F1',
  1323.     'KP_F2' => 'F2',
  1324.     'KP_F3' => 'F3',
  1325.     'KP_F4' => 'F4',
  1326. # Dead symbols
  1327.     'dead_grave' => 'dead_grave',
  1328.     'SunFA_Grave' => 'dead_grave', # Is this recognised by X ?
  1329.     'dead_acute' => 'dead_acute',
  1330.     'SunFA_Acute' => 'dead_acute', # Is this recognised by X ?
  1331.     'dead_circumflex' => 'dead_circumflex',
  1332.     'SunFA_Circum' => 'dead_circumflex', # Is this recognised by X ?
  1333.     'dead_tilde' => 'dead_tilde',
  1334.     'SunFA_Tilde' => 'dead_tilde',
  1335.     'dead_breve' => 'dead_breve',
  1336.     'dead_diaeresis' => 'dead_diaeresis',
  1337.     'SunFA_Diaeresis' => 'dead_diaeresis', # Is this recognised by X ?
  1338.     'dead_doubleacute' => 'dead_doubleacute',
  1339.     'dead_caron' => 'dead_caron',
  1340.     'dead_cedilla' => 'dead_cedilla',
  1341.     'SunFA_Cedilla' => 'dead_cedilla', # Is this recognised by X ?
  1342.     'dead_ogonek' => 'dead_ogonek',
  1343. # Dead symbols with no support in the kernel
  1344.     'dead_macron' => '005f',         # underscore
  1345.     'dead_abovedot' => '002e',       # period
  1346.     'dead_abovering' => '002a',      # asterisk
  1347.     'dead_belowdot' => '0323',       # ???? Vietnamese
  1348.     'dead_hook' => '0309',           # ???? Vietnamese
  1349.     'dead_iota' => '03b9',           # ???? Greek
  1350.     'dead_horn' => '031b',           # ???? Greek
  1351. # Modifiers
  1352.     'Multi_key' => 'Compose',
  1353.     'Mode_switch' => 'ShiftL',
  1354.     'script_switch' => 'VoidSymbol',
  1355.     'Shift_L' => 'Shift',
  1356.     'Shift_R' => 'Shift',
  1357.     'Control_L' => 'Control',
  1358.     'Control_R' => 'Control',
  1359.     'Caps_Lock' => 'Caps_Lock',
  1360.     'Shift_Lock' => 'Shift_Lock',
  1361.     'Meta_L' => 'Alt',
  1362.     'Meta_R' => 'Alt',
  1363.     'Alt_L' => 'Alt',
  1364.     'Alt_R' => 'Alt',
  1365.     'Super_L' => 'Alt',
  1366.     'Super_R' => 'Alt',
  1367.     'Hyper_L' => 'Alt',
  1368.     'Hyper_R' => 'Alt',
  1369.     'ISO_Lock' => 'Caps_Lock',
  1370.     'ISO_Level2_Latch' => 'Shift',
  1371.     'ISO_Level3_Shift' => 'AltGr',
  1372.     'ISO_Level3_Latch' => 'AltGr',
  1373.     'ISO_Level3_Lock' => 'AltGr_Lock',
  1374.     'ISO_Group_Shift' => 'ShiftL',
  1375.     'ISO_Group_Latch' => 'ShiftL',
  1376.     'ISO_Group_Lock' => 'ShiftL_Lock',
  1377.     'ISO_Next_Group' => 'ShiftL_Lock',
  1378.     'ISO_Next_Group_Lock' => 'ShiftL_Lock',
  1379.     'ISO_Prev_Group' => 'ShiftL_Lock',
  1380.     'ISO_Prev_Group_Lock' => 'ShiftL_Lock',
  1381.     'ISO_First_Group' => 'ShiftL_Lock',
  1382.     'ISO_First_Group_Lock' => 'ShiftL_Lock',
  1383.     'ISO_Last_Group' => 'ShiftL_Lock',
  1384.     'ISO_Last_Group_Lock' => 'ShiftL_Lock',
  1385. # Other symbols
  1386.     'Nosymbol' => 'NoSymbol', # Is this recognised by X ?
  1387.     'NoSymbol' => 'NoSymbol',
  1388.     'any' => 'NoSymbol', # Is this recognised by X ?
  1389.     'VoidSymbol' => 'VoidSymbol',
  1390.     'voidsymbol' => 'VoidSymbol', # Is this recognised by X ?
  1391.     'ISO_Left_Tab' => 'Tab',
  1392.     'Clear' => 'VoidSymbol',
  1393.     'Pause' => 'Pause',
  1394.     'Scroll_Lock' => 'Scroll_Lock',
  1395.     'Sys_Req' => 'VoidSymbol',
  1396.     'Delete' => 'Remove',
  1397.     'Codeinput' => 'VoidSymbol',
  1398.     'SingleCandidate' => 'VoidSymbol',
  1399.     'MultipleCandidate' => 'VoidSymbol',
  1400.     'PreviousCandidate' => 'VoidSymbol',
  1401.     'Home' => 'Home',
  1402.     'Left' => 'Left',
  1403.     'Up' => 'Up',
  1404.     'Right' => 'Right',
  1405.     'Down' => 'Down',
  1406.     'Prior' => 'Prior',
  1407.     'Page_Up' => 'PageUp',
  1408.     'Next' => 'Next',
  1409.     'Page_Down' => 'PageDown',
  1410.     'End' => 'End',
  1411.     'Begin' => 'VoidSymbol',
  1412.     'Select' => 'Select',
  1413.     'Print' => 'VoidSymbol',
  1414.     'Execute' => 'VoidSymbol',
  1415.     'Insert' => 'Insert',
  1416.     'Undo' => 'VoidSymbol',
  1417.     'Redo' => 'VoidSymbol',
  1418.     'Menu' => 'VoidSymbol',
  1419.     'Find' => 'Find',
  1420.     'Cancel' => 'VoidSymbol',
  1421.     'Help' => 'Help',
  1422.     'Break' => 'Pause',
  1423.     'Num_Lock' => 'Num_Lock',
  1424.     'F1' => 'F1',
  1425.     'F2' => 'F2',
  1426.     'F3' => 'F3',
  1427.     'F4' => 'F4',
  1428.     'F5' => 'F5',
  1429.     'F6' => 'F6',
  1430.     'F7' => 'F7',
  1431.     'F8' => 'F8',
  1432.     'F9' => 'F9',
  1433.     'F10' => 'F10',
  1434.     'F11' => 'F11',
  1435.     'L1' => 'F11',
  1436.     'F12' => 'F12',
  1437.     'L2' => 'F12',
  1438.     'F13' => 'F13',
  1439.     'L3' => 'F13',
  1440.     'F14' => 'F14',
  1441.     'L4' => 'F14',
  1442.     'F15' => 'F15',
  1443.     'L5' => 'F15',
  1444.     'F16' => 'F16',
  1445.     'L6' => 'F16',
  1446.     'F17' => 'F17',
  1447.     'L7' => 'F17',
  1448.     'F18' => 'F18',
  1449.     'L8' => 'F18',
  1450.     'F19' => 'F19',
  1451.     'L9' => 'F19',
  1452.     'F20' => 'F20',
  1453.     'L10' => 'F20',
  1454.     'F21' => 'F21',
  1455.     'R1' => 'F21',
  1456.     'F22' => 'F22',
  1457.     'R2' => 'F22',
  1458.     'F23' => 'F23',
  1459.     'R3' => 'F23',
  1460.     'F24' => 'F24',
  1461.     'R4' => 'F24',
  1462.     'F25' => 'F25',
  1463.     'R5' => 'F25',
  1464.     'F26' => 'F26',
  1465.     'R6' => 'F26',
  1466.     'F27' => 'F27',
  1467.     'R7' => 'F27',
  1468.     'F28' => 'F28',
  1469.     'R8' => 'F28',
  1470.     'F29' => 'F29',
  1471.     'R9' => 'F29',
  1472.     'F30' => 'F30',
  1473.     'R10' => 'F30',
  1474.     'F31' => 'F31',
  1475.     'R11' => 'F31',
  1476.     'F32' => 'F32',
  1477.     'R12' => 'F32',
  1478.     'F33' => 'F33',
  1479.     'R13' => 'F33',
  1480.     'F34' => 'F34',
  1481.     'R14' => 'F34',
  1482.     'F35' => 'F35',
  1483.     'R15' => 'F35',
  1484.     'Terminate_Server' => 'VoidSymbol',
  1485.     'Pointer_EnableKeys' => 'VoidSymbol',
  1486.     'XF86_Switch_VT_1' => 'VoidSymbol',
  1487.     'XF86_Switch_VT_2' => 'VoidSymbol',
  1488.     'XF86_Switch_VT_3' => 'VoidSymbol',
  1489.     'XF86_Switch_VT_4' => 'VoidSymbol',
  1490.     'XF86_Switch_VT_5' => 'VoidSymbol',
  1491.     'XF86_Switch_VT_6' => 'VoidSymbol',
  1492.     'XF86_Switch_VT_7' => 'VoidSymbol',
  1493.     'XF86_Switch_VT_8' => 'VoidSymbol',
  1494.     'XF86_Switch_VT_9' => 'VoidSymbol',
  1495.     'XF86_Switch_VT_10' => 'VoidSymbol',
  1496.     'XF86_Switch_VT_11' => 'VoidSymbol',
  1497.     'XF86_Switch_VT_12' => 'VoidSymbol',
  1498.     'XF86_ClearGrab' => 'VoidSymbol',
  1499.     'XF86_Ungrab' => 'VoidSymbol',
  1500.     'XF86_Next_VMode' => 'VoidSymbol',
  1501.     'XF86_Prev_VMode' => 'VoidSymbol',
  1502. # I do not know the Unicodes of these
  1503.     'leftcaret' => 'VoidSymbol', # Is this recognised by X ?
  1504.     '0x13a4' => 'VoidSymbol', # Spelling error ?
  1505.     'guj_rra' => 'VoidSymbol', # Is this recognised by X ?
  1506.     'guj_nnna' => 'VoidSymbol', # Is this recognised by X ?
  1507.     'guj_llla' => 'VoidSymbol', # Is this recognised by X ?
  1508.     'gur_visarga' => 'VoidSymbol', # Is this recognised by X ?
  1509.     'gur_v_r' => 'VoidSymbol', # Is this recognised by X ?
  1510.     'gur_v_r_s' => 'VoidSymbol', # Is this recognised by X ?
  1511.     'Eisu_toggle' => 'VoidSymbol', # Is this recognised by X ?
  1512.     'Zenkaku_Hankaku' => 'VoidSymbol', # Is this recognised by X ?
  1513.     'Kanji' => 'VoidSymbol', # Is this recognised by X ?
  1514. # XFree86 does not recognise these
  1515.     'SunAudioLowerVolume' => 'VoidSymbol',
  1516.     'SunAudioMute' => 'VoidSymbol',
  1517.     'SunAudioRaiseVolume' => 'VoidSymbol',
  1518.     'SunCopy' => 'VoidSymbol',
  1519.     'SunCut' => 'VoidSymbol',
  1520.     'SunAgain' => 'VoidSymbol',
  1521.     'SunUndo' => 'VoidSymbol',
  1522.     'SunFind' => 'VoidSymbol',
  1523.     'SunStop' => 'VoidSymbol',
  1524.     'SunF36' => 'VoidSymbol',
  1525.     'SunF37' => 'VoidSymbol',
  1526.     'SunFront' => 'VoidSymbol',
  1527.     'SunOpen' => 'VoidSymbol',
  1528.     'SunPaste' => 'VoidSymbol',
  1529.     'SunPowerSwitch' => 'VoidSymbol',
  1530.     'SunPowerSwitchShift' => 'VoidSymbol',
  1531.     'SunProps' => 'VoidSymbol',
  1532.     'SunSys_Req' => 'VoidSymbol',
  1533.     'SunVideoDegauss' => 'VoidSymbol',
  1534.     'SunVideoLowerBrightness' => 'VoidSymbol',
  1535.     'SunVideoRaiseBrightness' => 'VoidSymbol',
  1536. );
  1537.  
  1538. if ($compact) {
  1539.     $xkbsym_table{'Mode_switch'} = 'AltGr';
  1540.     $xkbsym_table{'ISO_Group_Shift'} = 'AltGr';
  1541.     $xkbsym_table{'ISO_Group_Latch'} = 'AltGr';
  1542.     $xkbsym_table{'ISO_Group_Lock'} = 'AltGr_Lock';
  1543.     $xkbsym_table{'ISO_Next_Group'} = 'AltGr_Lock';
  1544.     $xkbsym_table{'ISO_Next_Group_Lock'} = 'AltGr_Lock';
  1545.     $xkbsym_table{'ISO_Prev_Group'} = 'AltGr_Lock';
  1546.     $xkbsym_table{'ISO_Prev_Group_Lock'} = 'AltGr_Lock';
  1547.     $xkbsym_table{'ISO_First_Group'} = 'AltGr_Lock';
  1548.     $xkbsym_table{'ISO_First_Group_Lock'} = 'AltGr_Lock';
  1549.     $xkbsym_table{'ISO_Last_Group'} = 'AltGr_Lock';
  1550.     $xkbsym_table{'ISO_Last_Group_Lock'} = 'AltGr_Lock';
  1551. }
  1552.  
  1553. my @controlsyms;
  1554. my @metasyms;
  1555. my @metacontrolsyms;
  1556.  
  1557. {
  1558.     my %controlsyms_hash = (
  1559.     '@' => 'nul',
  1560.     'h' => 'BackSpace',
  1561.     'i' => 'Tab',
  1562.     'j' => 'Linefeed',
  1563.     '[' => 'Escape',
  1564.     '\\' => 'Control_backslash',
  1565.     ']' => 'Control_bracketright',
  1566.     '^' => 'Control_asciicircum',
  1567.     '_' => 'Control_underscore',
  1568.     chr(0x08) => 'BackSpace',
  1569.     chr(0x09) => 'Tab',
  1570.     chr(0x0a) => 'Linefeed',
  1571.     chr(0x0d) => 'Control_m',
  1572.     chr(0x1b) => 'Escape',
  1573.     chr(0x7f) => 'BackSpace', # instead of 'Delete'
  1574. # The following are Linux specific
  1575.     '2' => 'nul',
  1576.     '3' => 'Escape',
  1577.     '4' => 'Control_backslash',
  1578.     '5' => 'Control_bracketright',
  1579.     '6' => 'Control_asciicircum',
  1580.     '7' => 'Control_underscore',
  1581.     '8' => 'Delete',
  1582.     '\'' => 'Control_g', # apostrophe
  1583.     '`' => 'nul', # grave
  1584.     '.' => 'Compose',
  1585.     '?' => 'Delete',
  1586.     ' ' => 'nul',
  1587.     );
  1588.     for my $code (0 .. 255) {
  1589.     my $sym = chr ((0x41 <= $code && 0x5a >= $code) ? $code + 0x20 : $code);
  1590.     if (defined (my $special = $controlsyms_hash{$sym})) {
  1591.         $controlsyms[$code + 1] = $special;
  1592.     } elsif (0x40 <= $code && 0x5f >= $code      
  1593.         || 0x61 <= $code && 0x7a >= $code) {
  1594.         $controlsyms[$code + 1] = "Control_". $sym;
  1595.     } else {
  1596.         $controlsyms[$code + 1] = 'VoidSymbol';
  1597.     }
  1598.     }
  1599.     $controlsyms[0] = 'NoSymbol';
  1600.  
  1601.     my %metasyms_hash = (
  1602.     ' ' => 'space',
  1603.     '`' => 'grave',
  1604.     '^' => 'asciicircum',
  1605.     '~' => 'asciitilde',
  1606.     '<' => 'less',
  1607.     '=' => 'equal',
  1608.     '>' => 'greater',
  1609.     '|' => 'bar',
  1610.     '_' => 'underscore',
  1611.     '-' => 'minus',
  1612.     ',' => 'comma',
  1613.     ';' => 'semicolon',
  1614.     ':' => 'colon',
  1615.     '!' => 'exclam',
  1616.     '?' => 'question',
  1617.     '/' => 'slash',
  1618.     '.' => 'period',
  1619.     '\'' => 'apostrophe',
  1620.     '"' => 'quotedbl',
  1621.     '(' => 'parenleft',
  1622.     ')' => 'parenright',
  1623.     '[' => 'bracketleft',
  1624.     ']' => 'bracketright',
  1625.     '{' => 'braceleft',
  1626.     '}' => 'braceright',
  1627.     '@' => 'at',
  1628.     '$' => 'dollar',
  1629.     '*' => 'asterisk',
  1630.     '\\' => 'backslash',
  1631.     '&' => 'ampersand',
  1632.     '#' => 'numbersign',
  1633.     '%' => 'percent',
  1634.     '+' => 'plus',
  1635.     '0' => 'zero',
  1636.     '1' => 'one',
  1637.     '2' => 'two',
  1638.     '3' => 'three',
  1639.     '4' => 'four',
  1640.     '5' => 'five',
  1641.     '6' => 'six',
  1642.     '7' => 'seven',
  1643.     '8' => 'eight',
  1644.     '9' => 'nine',
  1645.     chr(0x08) => 'BackSpace',
  1646.     chr(0x09) => 'Tab',
  1647.     chr(0x0a) => 'Linefeed',
  1648.     chr(0x0d) => 'Control_m',
  1649.     chr(0x1b) => 'Escape',
  1650.     chr(0x7f) => 'Delete',
  1651.     );
  1652.     
  1653.     for my $code (0 .. 255) {
  1654.     my $sym = chr($code);
  1655.     if (defined (my $special = $metasyms_hash{$sym})) {
  1656.         $sym = $special;
  1657.     }
  1658.     $metasyms[$code + 1] = "Meta_". $sym;
  1659.     }
  1660.  
  1661.     $metasyms[0] = 'NoSymbol';
  1662.  
  1663.     for my $code (1 .. 256) {
  1664.     my $control = $controlsyms[$code];
  1665.     if ($control eq 'Compose') {
  1666.         $metacontrolsyms[$code] = 'Compose';
  1667.     } elsif ($control eq 'NoSymbol') {
  1668.         $metacontrolsyms[$code] = 'NoSymbol';
  1669.     } elsif ($control eq 'VoidSymbol') {
  1670.         $metacontrolsyms[$code] = 'VoidSymbol';
  1671.     } else {
  1672.         $metacontrolsyms[$code] = 'Meta_'. $control;
  1673.     }
  1674.     }
  1675.  
  1676.     $metacontrolsyms[0] = 'NoSymbol';
  1677.  
  1678. }
  1679.  
  1680. ############ GLOBAL FUNCTIONS #########################################
  1681.  
  1682. # Looks for $_[0] in the known directories and returns ready to use
  1683. # file name
  1684. sub xfilename {
  1685.     my $file = $_[0];
  1686.     (my $base = $file) =~ s/.*\/(.+)/$1/;
  1687.     for my $dir (@xdirs) {
  1688.     if (-f "$dir/$file") {
  1689.         return "$dir/$file";
  1690.     }
  1691.     if (-f "$dir/$base") {
  1692.         return "$dir/$base";
  1693.     }
  1694.     }
  1695.     die "$0: Can not find file \"$file\" in any known directory\n";
  1696. }
  1697.  
  1698. ########### READ THE RULES FILE #######################################
  1699.  
  1700. # The string $_[0] matches the pattern $_[1]. 
  1701. # The pattern may be "*", a variable name, or a plain string.
  1702. # If the string is 'OPTIONS' then match the pattern against any of the
  1703. # options from @options.
  1704. sub matches_pattern {
  1705.     my ($string, $pattern) = @_;
  1706.     if ($string eq 'OPTIONS') {
  1707.     for my $option (@options) {
  1708.         next if ($option eq '');
  1709.         if ($pattern eq $option) {
  1710.         return 1;
  1711.         }
  1712.     }
  1713.     } else {
  1714.     if ($pattern eq '*') {
  1715.         return $string ne '';
  1716.     }
  1717.     if ($pattern =~ /^\$([a-zA-Z0-9]+)$/) {
  1718.         for my $member (@{$rules_variables{$1}}) {
  1719.         if ($string eq $member) {
  1720.             return 1;
  1721.         }
  1722.         }
  1723.         return 0;
  1724.     }
  1725.     if ($string eq $pattern) {
  1726.         return 1;
  1727.     }
  1728.     }
  1729.     return 0;
  1730. }
  1731.  
  1732. if (@layouts) {
  1733.     for my $i (0 .. $#layouts) {
  1734.     if (! defined $variants[$i]) {
  1735.         $variants[$i] = '';
  1736.     }
  1737.     }
  1738.     my $rules_keycodes;
  1739.     my $rules_symbols;
  1740.     open (RULES, xfilename ("rules/$rules"))
  1741.     or die "$0: ". xfilename ("rules/$rules") .": $!\n";
  1742.     my $oldline = '';
  1743.     my @antecedents;
  1744.     my $consequent_name;
  1745.     my $match_found = 0;
  1746.     while (<RULES>) {
  1747.     next if (/^\s*\/\//);
  1748.     next if (/^\s*$/);
  1749.     chomp;
  1750.     s/^\s*//;
  1751.     s/\s+/ /g;
  1752.     if ($oldline) {
  1753.         $_ = $oldline . $_;
  1754.         $oldline = '';
  1755.     }
  1756.     if (s/\\$/ /) {
  1757.         $oldline = $_;
  1758.         next;
  1759.     }
  1760.     if (/^! ?\$([a-zA-Z0-9]+) ?= ?(.+)$/) {
  1761.         $rules_variables{$1} = [ split ' ', $2 ];
  1762.         next;
  1763.     }
  1764.     if (/^! ?(.+)= ?(.+)$/) {
  1765.         @antecedents = split ' ', $1;
  1766.         ($consequent_name = $2) =~ s/ //g;
  1767.         foreach my $i (0 .. $#antecedents) {
  1768.         if ($antecedents[$i] eq 'model') {
  1769.             $antecedents[$i] = $model;
  1770.         } elsif ($antecedents[$i] eq 'layout' && @layouts == 1) {
  1771.             $antecedents[$i] = $layouts[0];
  1772.         } elsif ($antecedents[$i] =~ /layout\[([1-4])\]/) {
  1773.             if (@layouts > 1) {
  1774.             $antecedents[$i] = $layouts[$1 - 1];
  1775.             } else {
  1776.             $antecedents[$i] = '';
  1777.             }
  1778.         } elsif ($antecedents[$i] eq 'variant' && @variants == 1) {
  1779.             $antecedents[$i] = $variants[0];
  1780.         } elsif ($antecedents[$i] =~ /variant\[([1-4])\]/) {
  1781.             if (@variants > 1) {
  1782.             $antecedents[$i] = $variants[$1 - 1];
  1783.             } else {
  1784.             $antecedents[$i] = '';
  1785.             }
  1786.         } elsif ($antecedents[$i] eq 'option') {
  1787.             $antecedents[$i] = 'OPTIONS';
  1788.         } elsif ($antecedents[$i] eq 'layout'
  1789.              || $antecedents[$i] eq 'variant') {
  1790.             $antecedents[$i] = '';
  1791.         } else {
  1792.             die "Unknown name $antecedents[$i]\n";
  1793.         }
  1794.         if (! defined $antecedents[$i]) {
  1795.             $antecedents[$i] = '';
  1796.         }
  1797.         }
  1798.         $match_found = 0;
  1799.         next;
  1800.     }
  1801.     if (/^(.+)= ?(.+)$/) {
  1802.         next if ($match_found);
  1803.         my @antecedent_patterns = split ' ', $1;
  1804.         my $consequent = $2;
  1805.         @antecedent_patterns == @antecedents 
  1806.         or die "Bad number of antecedents";
  1807.         my $matches = 1;
  1808.         for my $i (0 .. $#antecedents) {
  1809.         if (! matches_pattern ($antecedents[$i], 
  1810.                        $antecedent_patterns[$i])) {
  1811.             $matches = 0;
  1812.             last;
  1813.         }
  1814.         }
  1815.         if ($matches) {
  1816.         $match_found = $antecedents[0] ne 'OPTIONS';
  1817.         $consequent =~ s/ //g;
  1818.         $consequent =~ s/%\(/\(%/g;
  1819.         $consequent =~ s/%_/_%/g;
  1820.         $consequent =~ s/%m/$model/g;
  1821.         $consequent =~ s/%l\[1\]/$layouts[0]/g;
  1822.         $consequent =~ s/%l\[2\]/$layouts[1]/g;
  1823.         $consequent =~ s/%l\[3\]/$layouts[2]/g;
  1824.         $consequent =~ s/%l\[4\]/$layouts[3]/g;
  1825.         $consequent =~ s/%l/$layouts[0]/g;
  1826.         $consequent =~ s/%v\[1\]/$variants[0]/g;
  1827.         $consequent =~ s/%v\[2\]/$variants[1]/g;
  1828.         $consequent =~ s/%v\[3\]/$variants[2]/g;
  1829.         $consequent =~ s/%v\[4\]/$variants[3]/g;
  1830.         $consequent =~ s/%v/$variants[0]/g;
  1831.         $consequent =~ s/\(\)//g;
  1832.         if ($consequent =~ /^\+/) {
  1833.             if ($consequent_name eq 'keycodes') {
  1834.             $rules_keycodes = $rules_keycodes . $consequent;
  1835.             } elsif ($consequent_name eq 'symbols') {
  1836.             $rules_symbols = $rules_symbols . $consequent;
  1837.             }
  1838.         } else {
  1839.             if ($consequent_name eq 'keycodes') {
  1840.             if (! $rules_keycodes) {
  1841.                 $rules_keycodes = $consequent;
  1842.             }
  1843.             } elsif ($consequent_name eq 'symbols') {
  1844.             if (! $rules_symbols) {
  1845.                 $rules_symbols = $consequent;
  1846.             }
  1847.             }
  1848.         }
  1849.         }
  1850.         next;
  1851.     }    
  1852.     die "Syntax error in the rules file: $_\n";
  1853.     }
  1854.     close RULES;
  1855.  
  1856.     if ($verbosity >= 1) {
  1857.     print STDERR  "Acording to the rules file:\n"
  1858.         ." keycodes = $rules_keycodes\n"
  1859.         ." symbols = $rules_symbols\n";
  1860.     }
  1861.  
  1862.     if (! $keycodes) {
  1863.     $keycodes = $rules_keycodes;
  1864.     }
  1865.     if (! $symbols) {
  1866.     $symbols = $rules_symbols;
  1867.     }
  1868. }
  1869.  
  1870. if (! $keycodes) {
  1871.     die "$0: No keycodes, nor layout specified\n";
  1872. }
  1873. if (! $symbols) {
  1874.     die "$0: No symbols, nor layout specified\n";
  1875. }
  1876.  
  1877. ########### COMPUTE ARCH ###########################################
  1878.  
  1879. if ($keycodes =~ /(^|\+|\|)macintosh\(old\)($|\+|\|)/) {
  1880.     $arch = 'macintosh';
  1881. } elsif ($keycodes =~ /(^|\+|\|)ataritt(\([^\)]*\))?($|\+|\|)/) {
  1882.     $arch = 'ataritt';
  1883. } elsif ($keycodes =~ /(^|\+|\|)amiga(\([^\)]*\))?($|\+|\|)/) {
  1884.     $arch = 'amiga';
  1885. } elsif ($keycodes =~ /(^|\+|\|)sun(\(type[45][^\)]*\))?($|\+|\|)/) {
  1886.     $arch = 'sun';
  1887. }
  1888.  
  1889. ########### READ ACM ###############################################
  1890.  
  1891. if ($charmap) {
  1892.     for my $acmfile ("${charmap}", "${charmap}.gz",
  1893.              "${charmap}.acm", "${charmap}.acm.gz",
  1894.              "/usr/share/consoletrans/${charmap}",
  1895.              "/usr/share/consoletrans/${charmap}.gz",
  1896.              "/usr/share/consoletrans/${charmap}.acm",
  1897.              "/usr/share/consoletrans/${charmap}.acm.gz",
  1898.              "acm/${charmap}.acm") {
  1899.     if (-f $acmfile) {
  1900.         $acm = $acmfile;
  1901.         last;
  1902.     }
  1903.     }
  1904.     (-f $acm) or die "$0: no ACM for ${charmap} exists\n";
  1905.     if ($acm =~ /gz$/) {
  1906.     open (ACM, '-|:utf8', "zcat $acm") or die "$0: $acm: $!\n";
  1907.     } else {
  1908.     open (ACM, '<:utf8', $acm) or die "$0: $acm: $!\n";
  1909.     }
  1910.     while (<ACM>) {
  1911.     s/\#.*//;
  1912.     chomp;
  1913.     next unless (/[^\s]/);
  1914.     if (/^\s*0x([0-9a-fA-F]{1,2})\s+\'([^\']+)\'\s*$/) {
  1915.         my $uni = ord ($2);
  1916.         my $c = hex ($1);
  1917.         $acmtable{$uni} = $c;
  1918.     } else {
  1919.         die "$0: Syntax error in ACM file: $_\n";
  1920.     }
  1921.     }
  1922.     close ACM;
  1923. }
  1924.  
  1925. # A hack to work around a bug in the kernel/loadkeys
  1926. # Disabled for Ubuntu because the cure is worse than the disease:
  1927. #   https://bugs.launchpad.net/ubuntu/+source/console-setup/+bug/69725
  1928. # However, Turkish still needs this behaviour.
  1929. if (! $acm && grep { $_ eq 'tr' } @layouts) {
  1930.     $xkbsym_table{'Caps_Lock'} = 'Shift_Lock';
  1931.     $xkbsym_table{'ISO_Lock'} = 'Shift_Lock';
  1932. }
  1933.  
  1934. ########### PARSING ###############################################
  1935.  
  1936. # Report a syntax error in $filename. $_[0] should describe what was
  1937. # expected at $stream.
  1938. sub syntax_error {
  1939.     die "$0: instead of \"". (substr ($stream, 0, 50))
  1940.     ."\" in $filename expected $_[0].\n";
  1941. }
  1942.  
  1943. # Opens the text file $_[0], reads it and saves its contents in $stream
  1944. # The comments are removed, all new lines are replaced by spaces and
  1945. # all redundant spaces are removed.
  1946. sub file_to_string {
  1947.     my $file = $_[0];
  1948.     my $string = '';
  1949.     open (FILE, "$file") or die "$0: $file: $!\n";
  1950.     while (<FILE>) {
  1951.     chop;
  1952.     s{//.*}{};
  1953.     $string = $string . $_ .' ';
  1954.     }
  1955.     close FILE;
  1956.     
  1957.     my $normalized = '';
  1958.     my $final_letter = 0;
  1959.     while ($string) {
  1960.     if ($string =~ s/^\s+// && $final_letter && $string =~ /^[a-zA-Z0-9]/) {
  1961.         $normalized = $normalized .' ';
  1962.         $final_letter = 0;
  1963.     }
  1964.     if ($string =~ s/^([^\"\s]+)//) {
  1965.         $normalized = $normalized . $1;
  1966.         $final_letter = ($1 =~ /[a-zA-Z0-9]$/);
  1967.         next;
  1968.     }
  1969.     if ($string =~ s/^(\"[^\"]*(\"|$))//) {
  1970.         $normalized = $normalized . $1;
  1971.         $final_letter = 0;
  1972.         if ($2 ne '"') {
  1973.         die "$0: missing quote in ". (substr ($1, 0, 50)) ."...\n";
  1974.         }
  1975.         next;
  1976.     }
  1977.     (! $string ) or die "Internal error";
  1978.     }
  1979.     $stream = $normalized;
  1980. }
  1981.  
  1982. # removes from $stream initial sequence of xkb flags (default, partial,
  1983. # hidden, etc.) Returns true if the "default" flag was among them.
  1984. sub xkb_flags {
  1985.     my $default = 0;
  1986.     while ($stream =~ s/^(default|partial|hidden
  1987.               |alphanumeric_keys|modifier_keys
  1988.               |keypad_keys|function_keys
  1989.               |alternate_group)\s?(.*)/$2/ix) {
  1990.     $default = 1 if ($1 =~ /default/i);
  1991.     }
  1992.     return $default;
  1993. }
  1994.  
  1995. # Removes and returns identifier from $stream. 
  1996. sub xkb_identifier {
  1997.     if ($stream =~ s/^([a-zA-Z0-1_]+) ?(.*)/$2/) {
  1998.     return $1;
  1999.     } else {
  2000.     syntax_error "identifier";
  2001.     }
  2002. }
  2003.  
  2004. # Removes and returns a string from $stream.
  2005. sub xkb_string {
  2006.     if ($stream =~ /^\"([^\"]*)\"(.*)/) {
  2007.     $stream = $2;
  2008.     return $1;
  2009.     } else {
  2010.     syntax_error "string";
  2011.     }
  2012. }
  2013.  
  2014. # Removes an include method name from $stream and returns $alternate_method,
  2015. # $augment_method, $replace_method, or $override_method.  If $stream
  2016. # does not start with a method name, return the default method (i.e. $method)
  2017. sub xkb_method {
  2018.     if ($stream =~ s/^alternate ?(.*)/$1/i) {
  2019.     return $alternate_method;
  2020.     } elsif ($stream =~ s/^augment ?(.*)/$1/i) {
  2021.     return $augment_method;
  2022.     } elsif ($stream =~ s/^replace ?(.*)/$1/i) {
  2023.     return $replace_method;
  2024.     } elsif ($stream =~ s/^override ?(.*)/$1/i) {
  2025.     return $override_method;
  2026.     } else {
  2027.     return $method;
  2028.     }
  2029. }
  2030.  
  2031. # If $stream starts with an include statement - process it and return true.
  2032. # Otherwise return false. $_[0] is the file type ("symbols" or "keycodes")
  2033. sub xkb_include {
  2034.     my $file_type = $_[0];
  2035.     if ($stream =~ s/^(include|replace|augment|override)\"([^\"]*)\";?
  2036.                         (.*)/$3/ix) {
  2037.     my $method_name = $1;
  2038.     my $include_request = $2;
  2039.     if ($method != $ignore_method) {
  2040.         my $oldmethod = $method;
  2041.         if ($method_name =~ /replace/i) {
  2042.         $method = $replace_method;
  2043.         } elsif ($method_name =~ /augment/i) {
  2044.         $method = $augment_method;
  2045.         } elsif ($method_name =~ /override/i) {
  2046.         $method = $override_method;
  2047.         }
  2048.         &include_xkb_file ($file_type, $include_request);
  2049.         $method = $oldmethod;
  2050.     }
  2051.     return 1;
  2052.     } else {
  2053.     return 0;
  2054.     }
  2055. }
  2056.  
  2057. sub xkb_keycodes_definitions {
  2058.     my $oldmethod = $method;
  2059.     while ($stream) {
  2060.     $method = $oldmethod;
  2061.  
  2062.     if (xkb_include ('keycodes')) {
  2063.         next;
  2064.     }
  2065.  
  2066.     $method = xkb_method ();
  2067.     
  2068.     if ($stream =~ (s/^(minimum|maximum|indicator|virtual\sindicator)
  2069.             [^;]*;(.*)/$2/ix)) {
  2070.         next;
  2071.     }
  2072.  
  2073.     if ($stream =~ /^<([^>]*)>=/) {
  2074.         $stream =~ s/^<([^>]+)>=([0-9]*);(.*)/$3/
  2075.         or syntax_error "keycode definition";
  2076.         my $key = $1;
  2077.         my $code = $2;
  2078.         if ($method == $replace_method
  2079.         || $method == $override_method
  2080.         || ($method == $augment_method
  2081.             && ! defined $keycodes_table{$key})) {
  2082.         $keycodes_table{$key} = [ $code ];
  2083.         delete $aliases{$key};
  2084.         } elsif ($method == $alternate_method) {
  2085.         push @{$keycodes_table{$key}}, $code;
  2086.         }
  2087.         next;
  2088.     }
  2089.     if ($stream =~ /^alias/) {
  2090.         $stream =~ s/^alias<([^>]+)>=<([^>]+)>;(.*)/$3/
  2091.         or syntax_error "alias definition";
  2092.         my $alias = $1;
  2093.         my $key = $2;
  2094.         if ($method == $replace_method
  2095.         || $method == $override_method
  2096.         || ($method == $augment_method
  2097.             && ! defined $keycodes_table{$alias})) {
  2098.         $keycodes_table{$alias} = [];
  2099.         $aliases{$alias} = $key;
  2100.         }
  2101.         next;
  2102.     }
  2103.     last;
  2104.     }
  2105.     $method = $oldmethod;
  2106. }
  2107.  
  2108. # Fill @{$symbols_table{$code}[$group]} with symbols
  2109. sub symbols_for_group {
  2110.     my $code = shift;
  2111.     my $group = shift;
  2112.     if ($method == $replace_method
  2113.     || ($method == $override_method
  2114.         && (@_ || ! defined $symbols_table{$code}[$group]))
  2115.     || ($method == $augment_method &&
  2116.         ! defined $symbols_table{$code})) {
  2117.     my $level = 0;
  2118.     for my $symbol (@_) {
  2119.         if ($symbol !~ /\(/ && $symbol =~ /./
  2120.         && ($symbol !~ /^nosymbol$/i
  2121.             || ! defined $symbols_table{$code}[$group][$level])) {
  2122.         $symbols_table{$code}[$group][$level] = $symbol;
  2123.         }
  2124.         $level++;
  2125.     }
  2126.     }
  2127. }
  2128.  
  2129. sub xkb_key {
  2130.     if ($stream =~ /^key</i) {
  2131.     $stream =~ s/^key<([^>]+)>\{([^\}]*?)\};(.*)/$3/i
  2132.         or syntax_error "key definition";
  2133.     my $key = $1;
  2134.     my $list = $2 .",";
  2135.     if ($verbosity >= 4 && ! defined $keycodes_table{$key}) {
  2136.         warning "No scan code for <$key> is defined.\n";
  2137.     }
  2138.     for my $code (@{$keycodes_table{$key}}) {
  2139.         if ($method == $replace_method) {
  2140.         $symbols_table{$code} = [];
  2141.         }
  2142.         my $group = $base_group;
  2143.         while ($list =~ /[^ ]/) {
  2144.         # [ X1, X2, ... ]
  2145.         if ($list =~ s/^\[([^\]]*?)\],(.*)/$2/) {
  2146.             (my $symbols = $1) =~ s/,/ /g;
  2147.             my @groupsymbols = split ' ', $symbols;
  2148.             symbols_for_group $code, $group, @groupsymbols;
  2149.             $group++;
  2150.             next;
  2151.         }
  2152.         # symbols[GroupN] = [ X1, X2, ... ]
  2153.         if ($list =~ (s/^symbols\[Group([1-4])\]
  2154.                   =\[([^\]]*?)\],(.*)/$3/x)) {
  2155.             my $group = $1 - 1 + $base_group;
  2156.             (my $symbols = $2) =~ s/,/ /g;
  2157.             my @groupsymbols = split ' ', $symbols;
  2158.             symbols_for_group $code, $group, @groupsymbols;
  2159.             next;
  2160.         }
  2161.         # type = "...."
  2162.         if ($list =~ (s/^type=\"([^\"]+)\",(.*)/$2/)) {
  2163.             if ($method == $replace_method
  2164.             || $method == $override_method
  2165.             || ($method == $augment_method
  2166.                 && ! defined $types_table{$code})) {
  2167.             $types_table{$code} = $1;    
  2168.             }
  2169.             next;
  2170.         }
  2171.         # abracadabra
  2172.         # abracadabra = abra<cad>abra
  2173.         next if ($list =~ s/^[a-zA-Z0-9_]+(=[a-zA-Z0-9_<>]+)?,
  2174.                                    (.*)/$2/x);
  2175.         # abracadabra = "...."
  2176.         next if ($list =~ s/^[a-zA-Z0-9_]+=\"[^\"]+\",(.*)/$1/);
  2177.         # type[...] = "..."
  2178.         next if ($list =~ s/^type\[[a-zA-Z0-9_]+\]=\"[^\"]+\",
  2179.                                     (.*)/$1/x);
  2180.         die "$0: garbage in a key definition: \"$list\""
  2181.             ." in $filename.\n";
  2182.         }
  2183.     }
  2184.     return 1;
  2185.     } else {
  2186.     return 0;
  2187.     }
  2188. }
  2189.  
  2190. sub xkb_symbols_definitions {
  2191.     my $oldmethod = $method;
  2192.     while ($stream) {
  2193.     $method = $oldmethod;
  2194.  
  2195.     if (xkb_include ('symbols')) {
  2196.         next;
  2197.     }
  2198.  
  2199.     $method = xkb_method ();
  2200.  
  2201.     if ($stream =~ /^name/i) {
  2202.         $stream =~ s/^name\[[a-zA-Z0-9]+\]=\"[^\"]*\";(.*)/$1/i
  2203.         or syntax_error "group name";
  2204.         next;
  2205.     }
  2206.  
  2207.     if ($stream =~ s/^[a-zA-Z0-9]+\.[a-zA-Z0-9]+=.*?;(.*)/$1/i) {
  2208.         next;
  2209.     }
  2210.  
  2211.     if ($stream =~ s/^[a-zA-Z0-9]+\.[a-zA-Z0-9]+\[[a-zA-Z0-9]+\]
  2212.                        =.*?;(.*)/$1/ix) {
  2213.         next;
  2214.     }
  2215.  
  2216.     if (xkb_key) {
  2217.         next;
  2218.     }
  2219.  
  2220.     if ($stream =~ /^(modifier_map|modmap|mod_map)/i) {
  2221.         $stream =~ (s/^(modifier_map|modmap|mod_map)\s?[a-zA-Z0-9_]+
  2222.             \{[^\}]*\};(.*)/$2/ix)
  2223.         or syntax_error "modifier_map";
  2224.         next;
  2225.     }
  2226.  
  2227.     if ($stream =~ /^virtual_modifiers/i) {
  2228.         $stream =~ (s/^virtual_modifiers\s?[a-zA-Z0-9_]+;(.*)/$1/ix)
  2229.         or syntax_error "virtual_modifiers";
  2230.         next;
  2231.     }
  2232.     last;
  2233.     }
  2234.     $method = $oldmethod;
  2235. }
  2236.  
  2237. sub xkb_definitions {
  2238.     my $file_type = $_[0];
  2239.     if ($file_type eq 'symbols') {
  2240.     xkb_symbols_definitions();
  2241.     } elsif ($file_type eq 'keycodes') {
  2242.     xkb_keycodes_definitions();
  2243.     } else {
  2244.     die "$0: Bad xkb file type $file_type\n";
  2245.     }
  2246. }
  2247.  
  2248. # Remove from $stream the characters up to the first unmatched "}"
  2249. sub skip_to_brace {
  2250.     while ($stream && ($stream =~ s/^[^\}\{]*\{//)) {
  2251.     &skip_to_brace;
  2252.     }
  2253.     $stream =~ s/^[^\}\{]*(\}|$)//;
  2254. }
  2255.  
  2256. sub xkb_block_list {
  2257.     my $file_type = $_[0];
  2258.     my $block = $_[1];
  2259.     my $first = 1;
  2260.     my $ok = 0;
  2261.     my $mystream = $stream;
  2262.     while ($stream) {
  2263.     my $default = xkb_flags();
  2264.     xkb_identifier() eq "xkb_". $file_type
  2265.         or syntax_error "xkb_". $file_type;
  2266.     my $name = xkb_string();
  2267.     my $structured;
  2268.     if ($stream =~ s/^\{//) {
  2269.         $structured = 1;
  2270.     } else {
  2271.         $structured = 0;
  2272.     }
  2273.     if ($name eq $block || ($first && ! $block)) {
  2274.         xkb_definitions ($file_type);
  2275.         if ($structured) {
  2276.         $stream =~ s/^\};.*// or syntax_error "};";
  2277.         } else {
  2278.         $stream = '';
  2279.         }
  2280.         $ok = 1;
  2281.     } else {
  2282.         if ($structured) {
  2283.         skip_to_brace;
  2284.         $stream =~ s/^;// or syntax_error ";";
  2285.         } else {
  2286.         last;
  2287.         }
  2288.     }
  2289.     $first = 0;
  2290.     }
  2291.     if (! $ok) {
  2292.     $stream = $mystream;
  2293.     }
  2294.     return $ok;
  2295. }
  2296.  
  2297. sub include_xkb_file {
  2298.     my $file_type = $_[0];
  2299.     my $include_list = '^'. $_[1];
  2300.  
  2301.     my $oldmethod = $method;
  2302.     my $oldbase_group = $base_group;
  2303.     while ($include_list) {
  2304.     my $file;
  2305.     my $block;
  2306.     if ($include_list =~ (s/^(\^|\+|\|)([^\(\|\+]+)\(([^\)]+)\)
  2307.                   :([1234])(.*)/$5/x)) {
  2308.         if ($1 eq '+') {
  2309.         $method = $override_method;
  2310.         } elsif ($1 eq '|') {
  2311.         $method = $augment_method;
  2312.         }
  2313.         $file = $2;
  2314.         $block = $3;
  2315.         $base_group = $4 - 1 + $base_group;
  2316.     } elsif ($include_list =~ (s/^(\^|\+|\|)([^\(\|\+]+)\(([^\)]+)\)
  2317.                    (.*)/$4/x)) {
  2318.         if ($1 eq '+') {
  2319.         $method = $override_method;
  2320.         } elsif ($1 eq '|') {
  2321.         $method = $augment_method;
  2322.         }
  2323.         $file = $2;
  2324.         $block = $3;
  2325.     } elsif ($include_list =~ s/^(\^|\+|\|)([^\(\|\+]+):([1234])(.*)/$4/) {
  2326.         if ($1 eq '+') {
  2327.         $method = $override_method;
  2328.         } elsif ($1 eq '|') {
  2329.         $method = $augment_method;
  2330.         }
  2331.         $file = $2;
  2332.         $block = '';
  2333.         $base_group = $3 - 1 + $base_group;
  2334.     } elsif ($include_list =~ s/^(\^|\+|\|)([^\(\|\+]+)(.*)/$3/) {
  2335.         if ($1 eq '+') {
  2336.         $method = $override_method;
  2337.         } elsif ($1 eq '|') {
  2338.         $method = $augment_method;
  2339.         }
  2340.         $file = $2;
  2341.         $block = '';
  2342.     } else {
  2343.         die "$0: bad include list $include_list.\n";
  2344.     }
  2345.     
  2346.     my $oldstream = $stream;
  2347.     if ($file =~ /^\.?\//) {
  2348.         $stream = file_to_string ("$file");
  2349.     } else {
  2350.         $stream = file_to_string (xfilename "$file_type/$file");
  2351.     }
  2352.     my $oldfilename = $filename;
  2353.     $filename = $file;
  2354.     if (!xkb_block_list ($file_type, $block)) {
  2355.         warning "Can not found \"$block\" in \"$file\".\n";
  2356.         xkb_block_list ($file_type, '');
  2357.     }
  2358.     $stream = $oldstream;
  2359.     $filename = $oldfilename;
  2360.     $method = $oldmethod;
  2361.     $base_group = $oldbase_group;
  2362.     }
  2363. }
  2364.  
  2365. include_xkb_file 'keycodes', $keycodes;
  2366.  
  2367. foreach my $alias (keys %aliases) {
  2368.     if (! defined $keycodes_table{$aliases{$alias}}) {
  2369.     die "$0: undefined keyname $aliases{$alias} in ".
  2370.         "an keycode alias definition in $filename.\n";
  2371.     }
  2372.     $keycodes_table{$alias} = [ @{$keycodes_table{$alias}},
  2373.                 @{$keycodes_table{$aliases{$alias}}} ];
  2374. }
  2375.  
  2376. include_xkb_file 'symbols', $symbols;
  2377.  
  2378. foreach my $key (keys %symbols_table) {
  2379.     foreach my $group (0 .. $#{$symbols_table{$key}}) {
  2380.     if (! defined $symbols_table{$key}[$group]) {
  2381.         $symbols_table{$key}[$group] = [];
  2382.     } else {
  2383.         foreach my $level (0 .. $#{$symbols_table{$key}[$group]}) {
  2384.         if (! defined $symbols_table{$key}[$group][$level]) {
  2385.             $symbols_table{$key}[$group][$level] = 'NoSymbol';
  2386.         }
  2387.         }
  2388.     }
  2389.     }
  2390.     if (! defined $types_table{$key}) {
  2391.     $types_table{$key} = 'DEFAULT';
  2392.     }
  2393. }
  2394.  
  2395. sub distance {
  2396.     my $x = $_[0];
  2397.     my $y = $_[1];
  2398.     my $bottom = $x & $y;
  2399.     # If groups differ prefer the zero group
  2400.     if (($x | 0x0f) != ($y | 0x0f)) {
  2401.     $bottom = $bottom & 0x0f;
  2402.     }
  2403.     return  (($y - $bottom) << 6) | ($x - $bottom);
  2404. }
  2405.  
  2406. sub uni_to_legacy {
  2407.     my $uni = $_[0];
  2408.     if ($acm) {
  2409.     if ($uni <= 0x7f) {
  2410.         return sprintf "0x%02x", $uni;
  2411.     } elsif (defined $acmtable{$uni}) {
  2412.         return sprintf "0x%02x", $acmtable{$uni};
  2413.     } else {
  2414.         if ($verbosity >= 8) {
  2415.         warning sprintf ("Unicode U+%04x does not exist "
  2416.                  ."in the legacy encoding\n", $uni);
  2417.         }
  2418.         return 'VoidSymbol';
  2419.     }
  2420.     } else {
  2421.     return 'U+'. sprintf ("%04x", $uni);
  2422.     }
  2423. }
  2424.  
  2425. sub x_to_kernelsym {
  2426.     my $xkeysym = $_[0];
  2427.     my $kernelkeysym = $xkbsym_table{$xkeysym};
  2428.     if (defined $kernelkeysym) {
  2429.         if ($kernelkeysym !~ /^[0-9a-fA-F]{4}$/) {
  2430.         return $kernelkeysym;
  2431.     }
  2432.     } else {
  2433.     $kernelkeysym = ($xkeysym =~ /^0x0?100([0-9a-fA-F]{4})/
  2434.              ? $1
  2435.              : ($xkeysym =~ /^U([0-9a-fA-F]+)/
  2436.                 ? $1 
  2437.                 : undef));
  2438.     }
  2439.     if (defined $kernelkeysym) {
  2440.     my $uni = hex ($kernelkeysym);
  2441.     if (defined $forbidden{$uni}) {
  2442. #        warning "Forbidden Unicode \"U+$kernelkeysym\"\n";
  2443.         return 'VoidSymbol';
  2444.     } else {
  2445.         if (chr($uni) =~ /\p{IsAlpha}/) {
  2446.         my $legacy = uni_to_legacy ($uni);
  2447.         if ($legacy ne 'VoidSymbol') {
  2448.             return '+'. $legacy;
  2449.         } else {
  2450.             return $legacy;
  2451.         }
  2452.         } elsif ($uni <= 0x1f) {
  2453.         return $controlsyms[$uni + 1];
  2454.         } else {
  2455.         return uni_to_legacy ($uni);
  2456.         }
  2457.     }
  2458.     } else {
  2459.     warning "Unknown X keysym \"$xkeysym\"\n";
  2460.     return 'VoidSymbol';
  2461.     }
  2462. }
  2463.  
  2464. sub x_to_ascii {
  2465.     my $xkeysym = $_[0];
  2466.     my $kernelkeysym = $xkbsym_table{$xkeysym};
  2467.     if (defined $kernelkeysym) {
  2468.     if ($kernelkeysym eq 'Delete') {
  2469.         return 0x7f;
  2470.     } elsif ($kernelkeysym eq 'BackSpace') {
  2471.         return 0x08;
  2472.     } elsif ($kernelkeysym eq 'Tab') {
  2473.         return 0x09;
  2474.     } elsif ($kernelkeysym eq 'Linefeed') {
  2475.         return 0x0a;
  2476.     } elsif ($kernelkeysym eq 'Return') {
  2477.         return 0x0d;
  2478.     } elsif ($kernelkeysym eq 'Escape') {
  2479.         return 0x1b;
  2480.     } elsif ($kernelkeysym eq 'NoSymbol') {
  2481.         return -1;
  2482.     } elsif ($kernelkeysym !~ /^[0-9a-fA-F]{4}$/) {
  2483.         return undef;
  2484.     }
  2485.     } else {
  2486.     $kernelkeysym = ($xkeysym =~ /^0x0?100([0-9a-fA-F]{4})/
  2487.              ? $1
  2488.              : ($xkeysym =~ /^U([0-9a-fA-F]+)/
  2489.                 ? $1 
  2490.                 : undef));
  2491.     }
  2492.     if (defined $kernelkeysym) {
  2493.     my $uni = hex ($kernelkeysym);
  2494.     if (0x00 <= $uni && 0x7f >= $uni) {
  2495.         return $uni;
  2496.     }
  2497.     }
  2498.     return undef;
  2499. }
  2500.  
  2501. # A vector of symbol codes for a key
  2502. my @vector;
  2503. # A vector with same length as @vector.  Measures how well each element of
  2504. # @vector represents the xkb symbol for the particular key.  Bigger values
  2505. # mean lower quality.
  2506. my @quality;
  2507.  
  2508. sub approximate {
  2509.     my ($coord, $new_sym, $new_quality) = @_;
  2510.     # $new_sym represents the xkb symbol for position $coord in @vector
  2511.     # with quality $new_quality
  2512.     if ((! defined $quality[$coord] 
  2513.      || $quality[$coord] > $new_quality)
  2514.     && $new_sym ne 'VoidSymbol') {
  2515.     $vector[$coord] = $new_sym;
  2516.     $quality[$coord] = $new_quality;
  2517.     }
  2518. }
  2519.  
  2520. # Fill @vector with data for key number $_[0]
  2521. sub flatten {
  2522.     my $key = $_[0];
  2523.     @vector = ();
  2524.     @quality = ();
  2525.     for my $group (0..3) {
  2526.     my $real_group = $group;
  2527.     if ($real_group == 3) {
  2528.         $real_group = 2;
  2529.     } elsif ($real_group == 2) {
  2530.         $real_group = 3;
  2531.     }
  2532.     while ($real_group > $#{$symbols_table{$key}}) {
  2533.         if ($real_group >= 2) {
  2534.         $real_group = $real_group - 2;
  2535.         } else {
  2536.         $real_group = $real_group - 1;
  2537.         }
  2538.     }
  2539.     next if ($real_group < 0);
  2540.     for my $level (0..3) {
  2541.         my $coord = $level + ($group << 4);
  2542.         my $real_level = $level;
  2543.         if ($types_table{$key} =~ /PC_BREAK|PC_SYSRQ
  2544.                                        |CTRL\+ALT|SHIFT\+ALT/x) {
  2545.         $real_level = 0;
  2546.         }
  2547.         while ($real_level > $#{$symbols_table{$key}[$real_group]}) {
  2548.         if ($real_level == 2) {
  2549.             $real_level = $real_level - 2;
  2550.         } else {
  2551.             $real_level = $real_level - 1;
  2552.         }
  2553.         }
  2554.         next if ($real_level < 0);
  2555.         my $xkeysym = $symbols_table{$key}[$real_group][$real_level];
  2556.         my $kernelkeysym = x_to_kernelsym ($xkeysym);
  2557.         $vector[$coord] = $kernelkeysym;
  2558.         my $ascii = x_to_ascii ($xkeysym);
  2559.         next unless (defined $ascii);
  2560.         for my $approximated_group (0 .. 3) {
  2561.         for my $approximated_level (0 .. 3) {
  2562.             my $approximated_coord = ($approximated_level
  2563.                           + ($approximated_group << 4));
  2564.             my $distance = distance ($approximated_coord, $coord);
  2565.             approximate (($approximated_coord | 0x08), 
  2566.                  $metasyms[$ascii + 1], $distance);
  2567.             approximate (($approximated_coord | 0x04), 
  2568.                  $controlsyms[$ascii + 1], $distance);
  2569.             approximate (($approximated_coord | 0x0c), 
  2570.                  $metacontrolsyms[$ascii + 1], $distance);
  2571.         }
  2572.         }
  2573.     }
  2574.     if ($types_table{$key} eq 'PC_BREAK' 
  2575.         && $#{$symbols_table{$key}[$real_group]} >= 1) {
  2576.         my $xkeysym = $symbols_table{$key}[$real_group][1];
  2577.         my $kernelkeysym = x_to_kernelsym ($xkeysym);
  2578.         if ($kernelkeysym ne 'VoidSymbol') {
  2579.         my $coord = ($group << 4);
  2580.         $vector[$coord + 4] = $kernelkeysym;
  2581.         $vector[$coord + 5] = $kernelkeysym;
  2582.         $vector[$coord + 6] = $kernelkeysym;
  2583.         $vector[$coord + 7] = $kernelkeysym;
  2584.         $vector[$coord + 12] = $kernelkeysym;
  2585.         $vector[$coord + 13] = $kernelkeysym;
  2586.         $vector[$coord + 14] = $kernelkeysym;
  2587.         $vector[$coord + 15] = $kernelkeysym;
  2588.         }
  2589.     } elsif ($types_table{$key} eq 'PC_SYSRQ' 
  2590.         && $#{$symbols_table{$key}[$real_group]} >= 1) {
  2591.         my $xkeysym = $symbols_table{$key}[$real_group][1];
  2592.         my $kernelkeysym = x_to_kernelsym ($xkeysym);
  2593.         if ($kernelkeysym ne 'VoidSymbol') {
  2594.         my $coord = ($group << 4);
  2595.         $vector[$coord + 8] = $kernelkeysym;
  2596.         $vector[$coord + 9] = $kernelkeysym;
  2597.         $vector[$coord + 10] = $kernelkeysym;
  2598.         $vector[$coord + 11] = $kernelkeysym;
  2599.         $vector[$coord + 12] = $kernelkeysym;
  2600.         $vector[$coord + 13] = $kernelkeysym;
  2601.         $vector[$coord + 14] = $kernelkeysym;
  2602.         $vector[$coord + 15] = $kernelkeysym;
  2603.         }
  2604.     } elsif ($types_table{$key} eq 'CTRL+ALT' 
  2605.         && $#{$symbols_table{$key}[$real_group]} >= 1) {
  2606.         my $xkeysym = $symbols_table{$key}[$real_group][1];
  2607.         my $kernelkeysym = x_to_kernelsym ($xkeysym);
  2608.         if ($kernelkeysym ne 'VoidSymbol') {
  2609.         my $coord = ($group << 4);
  2610.         $vector[$coord + 12] = $kernelkeysym;
  2611.         $vector[$coord + 13] = $kernelkeysym;
  2612.         $vector[$coord + 14] = $kernelkeysym;
  2613.         $vector[$coord + 15] = $kernelkeysym;
  2614.         }
  2615.     } elsif ($types_table{$key} eq 'SHIFT+ALT' 
  2616.         && $#{$symbols_table{$key}[$real_group]} >= 1) {
  2617.         my $xkeysym = $symbols_table{$key}[$real_group][1];
  2618.         my $kernelkeysym = x_to_kernelsym ($xkeysym);
  2619.         if ($kernelkeysym ne 'VoidSymbol') {
  2620.         my $coord = ($group << 4);
  2621.         $vector[$coord + 9] = $kernelkeysym;
  2622.         $vector[$coord + 11] = $kernelkeysym;
  2623.         $vector[$coord + 13] = $kernelkeysym;
  2624.         $vector[$coord + 15] = $kernelkeysym;
  2625.         }
  2626.     }
  2627.     }
  2628.     for my $coord (0 .. 63) {
  2629.     if (! defined $vector[$coord]) {
  2630.         $vector[$coord] = 'VoidSymbol';
  2631.     }
  2632.     }
  2633.  
  2634.     for my $coord (0 .. 63) {
  2635.     next if ($coord & 0x0c); # If Control and/or Alt
  2636.     my $mask = $kernel_modifiers{$vector[$coord]};
  2637.     next unless (defined $mask);
  2638.     for my $mod (4, 8, 12) {
  2639.         if ($vector[$coord + $mod] eq 'VoidSymbol'
  2640.         && ($vector[($coord + $mod) | $mask] eq 'VoidSymbol')) {
  2641.         $vector[$coord + $mod] = $vector[$coord];
  2642.         }
  2643.     }
  2644.     }
  2645.     
  2646.     for my $coord (0 .. 63) {
  2647.     my $mask = $kernel_modifiers{$vector[$coord]};
  2648.     if (defined $mask) {
  2649.         $vector[$coord | $mask] = $vector[$coord];
  2650.     }
  2651.     }
  2652.     
  2653.     for my $coord (16 .. 63) {
  2654.     if ($vector[$coord] eq 'ShiftL') {
  2655.         $vector[$coord] = 'VoidSymbol';
  2656.     } elsif ($vector[$coord] eq 'ShiftL_Lock') {
  2657.         $vector[$coord] = 'VoidSymbol';
  2658.     }
  2659.     }
  2660.  
  2661.     for my $coord (0 .. 15) {
  2662.     if ($vector[$coord] eq 'ShiftL') {
  2663.         $vector[$coord + 16] = 'ShiftR';
  2664.         $vector[$coord + 32] = 'ShiftR';
  2665.         $vector[$coord + 48] = 'ShiftL';
  2666.     } elsif ($vector[$coord] eq 'ShiftL_Lock') {
  2667.         $vector[$coord + 16] = 'ShiftR_Lock';
  2668.         $vector[$coord + 32] = 'ShiftR_Lock';
  2669.         $vector[$coord + 48] = 'ShiftL_Lock';
  2670.     }
  2671.     }
  2672.  
  2673.     for my $group (0 .. 3) {
  2674.     my $kp = undef;
  2675.     for my $x (0 .. 15) {
  2676.         my $coord = 16 * $group + $x;
  2677.         if ($vector[$coord] =~ /^KP_/ && ! defined $kp) {
  2678.         $kp = $vector[$coord];
  2679.         }
  2680.     }
  2681.     if ($kp) {
  2682.         for my $x (0 .. 15) {
  2683.         my $coord = 16 * $group + $x;
  2684.         if ($vector[$coord] eq 'VoidSymbol') {
  2685.             $vector[$coord] = $kp;
  2686.         }
  2687.         }
  2688.     }
  2689.     }
  2690.  
  2691.     for my $group (0 .. 3) {
  2692.     my $coord = $group << 4;
  2693.     my $mainsym = $vector[$coord];
  2694.     if ($mainsym =~ /^F([0-9]+)$/) {
  2695.         my $num = $1;
  2696.         $vector[$coord + 1] = 'F'. ($num + 10);
  2697.         $vector[$coord + 2] = 'F'. ($num + 40);
  2698.         $vector[$coord + 3] = 'F'. ($num + 50);
  2699.         $vector[$coord + 4] = 'F'. ($num + 20);
  2700.         $vector[$coord + 5] = 'F'. ($num + 30);
  2701.         $vector[$coord + 6] = 'F'. ($num + 60);
  2702.         $vector[$coord + 7] = 'F'. ($num + 70);
  2703.         $vector[$coord + 8] = 'Console_'. $num;
  2704.         $vector[$coord + 9] = 'Console_'. ($num + 10);
  2705.         $vector[$coord + 12] = 'Console_'. $num;
  2706.         $vector[$coord + 13] = 'Console_'. ($num + 10);
  2707.     } elsif ($mainsym eq 'Scroll_Lock' || $mainsym eq 'Help') {
  2708.         $vector[$coord + 1] = 'Show_Memory';
  2709.         $vector[$coord + 2] = 'Show_Registers';
  2710.         $vector[$coord + 4] = 'Show_State';
  2711.         $vector[$coord + 8] = $mainsym; # or better 'Show_Registers' ?
  2712.     } elsif ($mainsym =~ /^KP_([0-9])$/) {
  2713.         my $num = $1;
  2714.         $vector[$coord + 2] = 'Hex_'. $num;
  2715.         $vector[$coord + 9] = 'Hex_'. $num;
  2716.         $vector[$coord + 8] = 'Ascii_'. $num;
  2717.     } elsif ($mainsym eq 'Num_Lock') {
  2718.         $vector[$coord + 2] = 'Hex_A';
  2719.         $vector[$coord + 9] = 'Hex_A';
  2720.     } elsif ($mainsym eq 'KP_Divide') {
  2721.         $vector[$coord + 2] = 'Hex_B';
  2722.         $vector[$coord + 9] = 'Hex_B';
  2723.     } elsif ($mainsym eq 'KP_Multiply') {
  2724.         $vector[$coord + 2] = 'Hex_C';
  2725.         $vector[$coord + 9] = 'Hex_C';
  2726.     } elsif ($mainsym eq 'KP_Subtract') {
  2727.         $vector[$coord + 2] = 'Hex_D';
  2728.         $vector[$coord + 9] = 'Hex_D';
  2729.     } elsif ($mainsym eq 'KP_Add') {
  2730.         $vector[$coord + 2] = 'Hex_E';
  2731.         $vector[$coord + 9] = 'Hex_E';
  2732.     } elsif ($mainsym eq 'KP_Enter') {
  2733.         $vector[$coord + 2] = 'Hex_F';
  2734.         $vector[$coord + 9] = 'Hex_F';
  2735.     } elsif ($mainsym eq 'Prior' || $mainsym eq 'PageUp') {
  2736.         $vector[$coord + 1] = 'Scroll_Backward';
  2737.     } elsif ($mainsym eq 'Next' || $mainsym eq 'PageDown') {
  2738.         $vector[$coord + 1] = 'Scroll_Forward';
  2739.     } elsif ($mainsym eq 'Left') {
  2740.         $vector[$coord + 8] = 'Decr_Console';
  2741.     } elsif ($mainsym eq 'Right') {
  2742.         $vector[$coord + 8] = 'Incr_Console';
  2743.     }
  2744.     }
  2745.     return @vector;
  2746. }
  2747.  
  2748. sub print_vector {
  2749.     my $kernel_code = $_[0];
  2750.     my $no_NoSymbol = 1;
  2751.     for my $mask (0 .. 63) {
  2752.     if ($vector[$mask] eq 'NoSymbol') {
  2753.         $no_NoSymbol = 0;
  2754.         last;
  2755.     }
  2756.     }
  2757.     if ($compact) {
  2758.     my $line = ($symbols =~ /:2/ # true if the keymap is non-latin
  2759.             ? "@vector[0, 1, 16, 17, 4, 20, 8, 24, 12, 28]"
  2760.             : "@vector[0, 1, 2, 3, 4, 6, 8, 10, 12, 14]");
  2761.     $line =~ s/NoSymbol/VoidSymbol/g;
  2762.     print "keycode $kernel_code = $line\n";
  2763.     } elsif ($no_NoSymbol) {
  2764.     print "keycode $kernel_code = @vector\n";
  2765.     } else {
  2766.     for my $mask (0 .. 63) {
  2767.         if ($vector[$mask] ne 'NoSymbol') {
  2768.         print "$modifier_combinations[$mask] keycode $kernel_code"
  2769.             ." = $vector[$mask]\n";
  2770.         }
  2771.     }
  2772.     }
  2773. }
  2774.  
  2775. my %at_scancodes = (
  2776.     9 => 1,
  2777.     10 => 2,
  2778.     11 => 3,
  2779.     12 => 4,
  2780.     13 => 5,
  2781.     14 => 6,
  2782.     15 => 7,
  2783.     16 => 8,
  2784.     17 => 9,
  2785.     18 => 10,
  2786.     19 => 11,
  2787.     20 => 12,
  2788.     21 => 13,
  2789.     22 => 14,
  2790.     23 => 15,
  2791.     24 => 16,
  2792.     25 => 17,
  2793.     26 => 18,
  2794.     27 => 19,
  2795.     28 => 20,
  2796.     29 => 21,
  2797.     30 => 22,
  2798.     31 => 23,
  2799.     32 => 24,
  2800.     33 => 25,
  2801.     34 => 26,
  2802.     35 => 27,
  2803.     36 => 28,
  2804.     37 => 29,
  2805.     38 => 30,
  2806.     39 => 31,
  2807.     40 => 32,
  2808.     41 => 33,
  2809.     42 => 34,
  2810.     43 => 35,
  2811.     44 => 36,
  2812.     45 => 37,
  2813.     46 => 38,
  2814.     47 => 39,
  2815.     48 => 40,
  2816.     49 => 41,
  2817.     50 => 42,
  2818.     51 => 43,
  2819.     52 => 44,
  2820.     53 => 45,
  2821.     54 => 46,
  2822.     55 => 47,
  2823.     56 => 48,
  2824.     57 => 49,
  2825.     58 => 50,
  2826.     59 => 51,
  2827.     60 => 52,
  2828.     61 => 53,
  2829.     62 => 54,
  2830.     63 => 55,
  2831.     64 => 56,
  2832.     65 => 57,
  2833.     66 => 58,
  2834.     67 => 59,
  2835.     68 => 60,
  2836.     69 => 61,
  2837.     70 => 62,
  2838.     71 => 63,
  2839.     72 => 64,
  2840.     73 => 65,
  2841.     74 => 66,
  2842.     75 => 67,
  2843.     76 => 68,
  2844.     77 => 69,
  2845.     78 => 70,
  2846.     79 => 71,
  2847.     80 => 72,
  2848.     81 => 73,
  2849.     82 => 74,
  2850.     83 => 75,
  2851.     84 => 76,
  2852.     85 => 77,
  2853.     86 => 78,
  2854.     87 => 79,
  2855.     88 => 80,
  2856.     89 => 81,
  2857.     90 => 82,
  2858.     91 => 83,
  2859.     92 => 84,
  2860.     93 => -1, # fake key (KP_Equal)
  2861.     94 => 86,
  2862.     95 => 87,
  2863.     96 => 88,
  2864.     97 => 102,
  2865.     98 => 103,
  2866.     99 => 104,
  2867.     100 => 105,
  2868.     102 => 106,
  2869.     103 => 107,
  2870.     104 => 108,
  2871.     105 => 109,
  2872.     106 => 110,
  2873.     107 => 111,
  2874.     108 => 96,
  2875.     109 => 97,
  2876.     110 => 119,
  2877.     111 => 99,
  2878.     112 => 98,
  2879.     113 => 100,
  2880.     114 => 101,
  2881.     115 => 125,
  2882.     116 => 126,
  2883.     117 => 127,
  2884.     118 => -1,  # Japanese
  2885.     119 => -1,  # Japanese
  2886.     120 => -1,  # Japanese
  2887.     123 => -1,
  2888.     124 => -1,  # fake key
  2889.     125 => -1,  # fake key
  2890.     126 => -1,  # fake key
  2891.     127 => -1,  # fake key
  2892.     128 => -1,  # fake key
  2893.     129 => -1,  # Japanese
  2894.     131 => -1,  # Japanese
  2895.     133 => 124, # Japanese
  2896.     134 => 121, # Brasilian ABNT2
  2897.     144 => -1,  # Japanese
  2898.     156 => -1,  # fake key
  2899.     208 => -1,  # Japanese
  2900.     211 => 89,  # Brasilian ABNT2
  2901. );
  2902.  
  2903. if ($compact) {
  2904.     print "keymaps 0-4,6,8,10,12,14\n";
  2905. } else {
  2906.     print "keymaps 0-63\n";
  2907. }
  2908. if ($arch eq 'at') {
  2909.     foreach my $key (sort {$a <=> $b} (keys %symbols_table)) {
  2910.     my $kernel_code = $at_scancodes{$key};
  2911.     if (! defined $kernel_code) {
  2912.         warning "Undefined kernel key code for $key\n";
  2913.         next;
  2914.     }
  2915.     next if ($kernel_code < 0);
  2916.      if ($kernel_code == 84) {
  2917.          @vector = ('Last_Console') x 64;
  2918.      } elsif ($kernel_code == 99) {
  2919.          @vector = ('Control_backslash') x 64;
  2920.      } elsif ($kernel_code == 101) {
  2921.          @vector = ('Break') x 64;
  2922.      } elsif ($kernel_code == 119) {
  2923.          @vector = ('Pause') x 64;
  2924.      } else {
  2925.          @vector = flatten ($key);
  2926.      }
  2927.     if ($kernel_code == 83 || $kernel_code == 111) {
  2928.         for my $coord (0, 16, 32, 48) {
  2929.         $vector[$coord + 6] = 'Boot';
  2930.         $vector[$coord + 12] = 'Boot';
  2931.         $vector[$coord + 14] = 'Boot';
  2932.         }
  2933.     }
  2934.     print_vector $kernel_code;
  2935.     }
  2936. } elsif ($arch eq 'macintosh') {
  2937.     foreach my $key (sort {$a <=> $b} (keys %symbols_table)) {
  2938.     my $kernel_code = $key - 8;
  2939.     @vector = flatten ($key);
  2940.     print_vector $kernel_code;
  2941.     }
  2942.     print <<EOT
  2943. keycode 127 =
  2944.         shift   control keycode 127 = Boot
  2945. EOT
  2946. } elsif ($arch eq 'ataritt') {
  2947.     foreach my $key (sort {$a <=> $b} (keys %symbols_table)) {
  2948.     my $kernel_code = $key - 8;
  2949.     if ($kernel_code == 97) {
  2950.         @vector = ('F246', 'Break', 'F246', 'F246',
  2951.                'F246', 'F246', 'F246', 'F246', 
  2952.                'Last_Console', 'F246', 'F246', 'F246', 
  2953.                'F246', 'F246', 'F246', 'F246') x 4;
  2954.     } else {
  2955.         @vector = flatten ($key);
  2956.     }
  2957.     if ($kernel_code == 83 || $kernel_code == 113) {
  2958.         for my $coord (0, 16, 32, 48) {
  2959.         $vector[$coord + 6] = 'Boot';
  2960.         $vector[$coord + 12] = 'Boot';
  2961.         $vector[$coord + 14] = 'Boot';
  2962.         }
  2963.     }
  2964.     print_vector $kernel_code;
  2965.     }
  2966. } elsif ($arch eq 'amiga') {
  2967.     foreach my $key (sort {$a <=> $b} (keys %symbols_table)) {
  2968.     my $kernel_code = $key - 8;
  2969.     @vector = flatten ($key);
  2970.     if ($kernel_code == 60) {
  2971.         for my $coord (0, 16, 32, 48) {
  2972.         $vector[$coord + 6] = 'Boot';
  2973.         $vector[$coord + 12] = 'Boot';
  2974.         $vector[$coord + 14] = 'Boot';
  2975.         }
  2976.     }
  2977.     print_vector $kernel_code;
  2978.     }
  2979. } elsif ($arch eq 'sun') {
  2980.     foreach my $key (sort {$a <=> $b} (keys %symbols_table)) {
  2981.     my $kernel_code = $key - 7;
  2982.     @vector = flatten ($key);
  2983.     if ($kernel_code == 50) {
  2984.         for my $coord (0, 16, 32, 48) {
  2985.         $vector[$coord + 6] = 'Boot';
  2986.         $vector[$coord + 12] = 'Boot';
  2987.         $vector[$coord + 14] = 'Boot';
  2988.         }
  2989.     }
  2990.     print_vector $kernel_code;
  2991.     }
  2992. } else {
  2993.     die "$0: Unsupported keyboard type $arch\n";
  2994. }
  2995.  
  2996. print "strings as usual\n";
  2997.  
  2998. if ($charmap && -f "/etc/console-setup/compose.${charmap}.inc") {
  2999.     system("cat /etc/console-setup/compose.${charmap}.inc");
  3000. }
  3001.  
  3002. exit 0;
  3003.