#! /usr/bin/perl -w use strict; use File::Find; if (@ARGV != 1) { print STDERR "Usage: $0 unpacked-console-keymaps-*-udeb\n"; exit 1; } my $consoledata = $ARGV[0]; my %keymaps; open LIST, '<:utf8', "$consoledata/usr/share/console/lists/console-keymaps-at" or die "$0: can't open $consoledata/usr/share/console/lists/console-keymaps-at"; while () { chomp; next if /^#/ or not /\S/; my ($locales, $keymap, $keymapname) = split /\t/; $keymapname =~ s/\s+$//; $keymaps{$keymap} = [[split(':', $locales)], $keymapname]; } binmode STDOUT, ':utf8'; print < 'keyIns', 0x01 => 'keyEnd', 0x02 => 'keyDown', 0x03 => 'keyPgDown', 0x04 => 'keyLeft', 0x06 => 'keyRight', 0x07 => 'keyHome', 0x08 => 'keyUp', 0x09 => 'keyPgUp', 0x10 => 'keyDel', ); sub map_keycode ($) { my $type = ($_[0] >> 8) & 0xff; my $code = $_[0] & 0xff; if ($type == 0xf0 or $type == 0xfb) { # KT_LATIN or KT_LETTER if ($code == 0x08 or $code == 0x7f) { # Backspace vs. Delete is a tricky case. gfxboot understands # both (0x08 for delete-left, keyDel for delete-right), so we # should map 0x7f to KeyDel. Unfortunately many keymaps only # appear to define Delete, and the situation in console-data # seems to be quite confused. Accordingly, we just ignore both # and let gfxboot work it out for itself, which seems to work # better. return '0x00'; } else { return sprintf '0x%02x', $code; } } elsif ($type == 0xf3) { # KT_PAD return $pad_map{$code} if exists $pad_map{$code}; } return '0x00'; } my %keycodes; for my $keymap (sort { $a cmp $b } keys %keymaps) { my $file; find( sub { return if defined $file; return if not -f; (my $name = $_) =~ s/\..*//; $file = $File::Find::name if $name eq $keymap; }, $consoledata ); next unless defined $file; my $table = `sudo loadkeys -m \Q$file\E 2>/dev/null`; for my $map (qw(plain shift altgr)) { if ($table =~ /${map}_map\[\] = {\s*(.*?)(?:\s|,)*}/s) { $keycodes{$keymap}{$map} = [map { map_keycode(hex) } split(/,\s+/, $1)]; } else { $keycodes{$keymap}{$map} = [('0x00') x 128]; } } } my %keymapfunc; for my $keymap (sort { $a cmp $b } keys %keymaps) { my $found = 0; for my $index (0 .. 127) { my $plain = $keycodes{$keymap}{plain}[$index]; my $shift = $keycodes{$keymap}{shift}[$index]; my $altgr = $keycodes{$keymap}{altgr}[$index]; if ($plain eq $keycodes{us}{plain}[$index] and $shift eq $keycodes{us}{shift}[$index] and $altgr eq $keycodes{us}{altgr}[$index]) { next; } if (($plain ne '0x00') or ($shift ne '0x00') or ($altgr ne '0x00')) { print "/keymap.$keymap [\n" unless $found; $found = 1; my $hexindex = sprintf '0x%02x', $index; print " [ $hexindex $plain $shift $altgr ]\n"; } } if ($found) { $keymapfunc{$keymap} = "keymap.$keymap"; } else { $keymapfunc{$keymap} = '.undef'; } print "] def\n\n" if $found; } print "/keymaps [\n"; for my $keymap (sort { $keymaps{$a}[1] cmp $keymaps{$b}[1] } keys %keymaps) { my $localelist = join(' ', map(qq{"$_"}, @{$keymaps{$keymap}[0]})); print qq{ [ "$keymap" $keymapfunc{$keymap} "$keymaps{$keymap}[1]" [ $localelist ] ]\n}; } print "] def\n\n";