|
|
1.1 ! root 1: #!/usr/bin/perl -w ! 2: # ! 3: # Copyright (C) 2011 Michael Brown <[email protected]>. ! 4: # ! 5: # This program is free software; you can redistribute it and/or ! 6: # modify it under the terms of the GNU General Public License as ! 7: # published by the Free Software Foundation; either version 2 of the ! 8: # License, or any later version. ! 9: # ! 10: # This program is distributed in the hope that it will be useful, but ! 11: # WITHOUT ANY WARRANTY; without even the implied warranty of ! 12: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ! 13: # General Public License for more details. ! 14: # ! 15: # You should have received a copy of the GNU General Public License ! 16: # along with this program; if not, write to the Free Software ! 17: # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ! 18: ! 19: =head1 NAME ! 20: ! 21: genkeymap.pl ! 22: ! 23: =head1 SYNOPSIS ! 24: ! 25: genkeymap.pl [options] <keymap name> ! 26: ! 27: Options: ! 28: ! 29: -f,--from=<name> Set BIOS keymap name (default "us") ! 30: -h,--help Display brief help message ! 31: -v,--verbose Increase verbosity ! 32: -q,--quiet Decrease verbosity ! 33: ! 34: =cut ! 35: ! 36: # With reference to: ! 37: # ! 38: # http://gunnarwrobel.de/wiki/Linux-and-the-keyboard.html ! 39: ! 40: use Getopt::Long; ! 41: use Pod::Usage; ! 42: use strict; ! 43: use warnings; ! 44: ! 45: use constant BIOS_KEYMAP => "us"; ! 46: use constant BKEYMAP_MAGIC => "bkeymap"; ! 47: use constant MAX_NR_KEYMAPS => 256; ! 48: use constant NR_KEYS => 128; ! 49: use constant KG_SHIFT => 0; ! 50: use constant KG_ALTGR => 1; ! 51: use constant KG_CTRL => 2; ! 52: use constant KG_ALT => 3; ! 53: use constant KG_SHIFTL => 4; ! 54: use constant KG_KANASHIFT => 4; ! 55: use constant KG_SHIFTR => 5; ! 56: use constant KG_CTRLL => 6; ! 57: use constant KG_CTRLR => 7; ! 58: use constant KG_CAPSSHIFT => 8; ! 59: use constant KT_LATIN => 0; ! 60: use constant KT_FN => 1; ! 61: use constant KT_SPEC => 2; ! 62: use constant KT_PAD => 3; ! 63: use constant KT_DEAD => 4; ! 64: use constant KT_CONS => 5; ! 65: use constant KT_CUR => 6; ! 66: use constant KT_SHIFT => 7; ! 67: use constant KT_META => 8; ! 68: use constant KT_ASCII => 9; ! 69: use constant KT_LOCK => 10; ! 70: use constant KT_LETTER => 11; ! 71: use constant KT_SLOCK => 12; ! 72: use constant KT_SPKUP => 14; ! 73: ! 74: my $verbosity = 1; ! 75: my $from_name = BIOS_KEYMAP; ! 76: ! 77: # Read named keymaps using "loadkeys -b" ! 78: # ! 79: sub read_keymaps { ! 80: my $name = shift; ! 81: my $keymaps = []; ! 82: ! 83: # Generate binary keymap ! 84: open my $pipe, "-|", "loadkeys", "-b", $name ! 85: or die "Could not load keymap \"".$name."\": $!\n"; ! 86: ! 87: # Check magic ! 88: read $pipe, my $magic, length BKEYMAP_MAGIC ! 89: or die "Could not read from \"".$name."\": $!\n"; ! 90: die "Bad magic value from \"".$name."\"\n" ! 91: unless $magic eq BKEYMAP_MAGIC; ! 92: ! 93: # Read list of included keymaps ! 94: read $pipe, my $included, MAX_NR_KEYMAPS ! 95: or die "Could not read from \"".$name."\": $!\n"; ! 96: my @included = unpack ( "C*", $included ); ! 97: die "Missing or truncated keymap list from \"".$name."\"\n" ! 98: unless @included == MAX_NR_KEYMAPS; ! 99: ! 100: # Read each keymap in turn ! 101: for ( my $keymap = 0 ; $keymap < MAX_NR_KEYMAPS ; $keymap++ ) { ! 102: if ( $included[$keymap] ) { ! 103: read $pipe, my $keysyms, ( NR_KEYS * 2 ) ! 104: or die "Could not read from \"".$name."\": $!\n"; ! 105: my @keysyms = unpack ( "S*", $keysyms ); ! 106: die "Missing or truncated keymap ".$keymap." from \"".$name."\"\n" ! 107: unless @keysyms == NR_KEYS; ! 108: push @$keymaps, \@keysyms; ! 109: } else { ! 110: push @$keymaps, undef; ! 111: } ! 112: } ! 113: ! 114: close $pipe; ! 115: return $keymaps; ! 116: } ! 117: ! 118: # Translate keysym value to ASCII ! 119: # ! 120: sub keysym_to_ascii { ! 121: my $keysym = shift; ! 122: ! 123: # Non-existent keysyms have no ASCII equivalent ! 124: return unless $keysym; ! 125: ! 126: # Sanity check ! 127: die "Unexpected keysym ".sprintf ( "0x%04x\n", $keysym )."\n" ! 128: if $keysym & 0xf000; ! 129: ! 130: # Extract type and value ! 131: my $type = ( $keysym >> 8 ); ! 132: my $value = ( $keysym & 0xff ); ! 133: ! 134: # Non-simple types have no ASCII equivalent ! 135: return unless ( ( $type == KT_LATIN ) || ( $type == KT_ASCII ) || ! 136: ( $type == KT_LETTER ) ); ! 137: ! 138: # High-bit-set characters cannot be generated on a US keyboard ! 139: return if $value & 0x80; ! 140: ! 141: return $value; ! 142: } ! 143: ! 144: # Translate ASCII to descriptive name ! 145: # ! 146: sub ascii_to_name { ! 147: my $ascii = shift; ! 148: ! 149: if ( $ascii == 0x5c ) { ! 150: return "'\\\\'"; ! 151: } elsif ( $ascii == 0x27 ) { ! 152: return "'\\\''"; ! 153: } elsif ( ( $ascii >= 0x20 ) && ( $ascii <= 0x7e ) ) { ! 154: return sprintf ( "'%c'", $ascii ); ! 155: } elsif ( $ascii <= 0x1a ) { ! 156: return sprintf ( "Ctrl-%c", ( 0x40 + $ascii ) ); ! 157: } else { ! 158: return sprintf ( "0x%02x", $ascii ); ! 159: } ! 160: } ! 161: ! 162: # Produce translation table between two keymaps ! 163: # ! 164: sub translate_keymaps { ! 165: my $from = shift; ! 166: my $to = shift; ! 167: my $map = {}; ! 168: ! 169: foreach my $keymap ( 0, 1 << KG_SHIFT, 1 << KG_CTRL ) { ! 170: for ( my $keycode = 0 ; $keycode < NR_KEYS ; $keycode++ ) { ! 171: my $from_ascii = keysym_to_ascii ( $from->[$keymap]->[$keycode] ) ! 172: or next; ! 173: my $to_ascii = keysym_to_ascii ( $to->[$keymap]->[$keycode] ) ! 174: or next; ! 175: my $new_map = ( ! exists $map->{$from_ascii} ); ! 176: my $update_map = ! 177: ( $new_map || ( $keycode < $map->{$from_ascii}->{keycode} ) ); ! 178: if ( ( $verbosity > 1 ) && ! 179: ( ( $from_ascii != $to_ascii ) || ! 180: ( $update_map && ! $new_map ) ) ) { ! 181: printf STDERR "In keymap %d: %s => %s%s\n", $keymap, ! 182: ascii_to_name ( $from_ascii ), ascii_to_name ( $to_ascii ), ! 183: ( $update_map ? ( $new_map ? "" : " (override)" ) ! 184: : " (ignored)" ); ! 185: } ! 186: if ( $update_map ) { ! 187: $map->{$from_ascii} = { ! 188: to_ascii => $to_ascii, ! 189: keycode => $keycode, ! 190: }; ! 191: } ! 192: } ! 193: } ! 194: return { map { $_ => $map->{$_}->{to_ascii} } keys %$map }; ! 195: } ! 196: ! 197: # Parse command-line options ! 198: Getopt::Long::Configure ( 'bundling', 'auto_abbrev' ); ! 199: GetOptions ( ! 200: 'verbose|v+' => sub { $verbosity++; }, ! 201: 'quiet|q+' => sub { $verbosity--; }, ! 202: 'from|f=s' => sub { shift; $from_name = shift; }, ! 203: 'help|h' => sub { pod2usage ( 1 ); }, ! 204: ) or die "Could not parse command-line options\n"; ! 205: pod2usage ( 1 ) unless @ARGV == 1; ! 206: my $to_name = shift; ! 207: ! 208: # Read and translate keymaps ! 209: my $from = read_keymaps ( $from_name ); ! 210: my $to = read_keymaps ( $to_name ); ! 211: my $map = translate_keymaps ( $from, $to ); ! 212: ! 213: # Generate output ! 214: ( my $to_name_c = $to_name ) =~ s/\W/_/g; ! 215: printf "/** \@file\n"; ! 216: printf " *\n"; ! 217: printf " * \"".$to_name."\" keyboard mapping\n"; ! 218: printf " *\n"; ! 219: printf " * This file is automatically generated; do not edit\n"; ! 220: printf " *\n"; ! 221: printf " */\n"; ! 222: printf "\n"; ! 223: printf "FILE_LICENCE ( PUBLIC_DOMAIN );\n"; ! 224: printf "\n"; ! 225: printf "#include <ipxe/keymap.h>\n"; ! 226: printf "\n"; ! 227: printf "/** \"".$to_name."\" keyboard mapping */\n"; ! 228: printf "struct key_mapping ".$to_name_c."_mapping[] __keymap = {\n"; ! 229: foreach my $from_sym ( sort { $a <=> $b } keys %$map ) { ! 230: my $to_sym = $map->{$from_sym}; ! 231: next if $from_sym == $to_sym; ! 232: printf "\t{ 0x%02x, 0x%02x },\t/* %s => %s */\n", $from_sym, $to_sym, ! 233: ascii_to_name ( $from_sym ), ascii_to_name ( $to_sym ); ! 234: } ! 235: printf "};\n";
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.