--- /dev/null
+#!/usr/bin/env perl
+use 5.014;
+use warnings;
+use utf8;
+use re '/msx';
+use JSON ();
+use Data::Dump 'pp';
+
+our $VERSION = '1.00';
+
+my $symname = eval {
+ open my $keysymh, '<', 'data/keysymdef.json' or die $!;
+ local $/;
+ return JSON->new->decode(readline $keysymh);
+} or die "Could not read keysym definitions: $@\n";
+
+my %geochar = (
+ TLDE => ["`", "~"],
+ AE01 => ['1', "!"],
+ AE02 => ['2', "\@"],
+ AE03 => ['3', "#"],
+ AE04 => ['4', "\$"],
+ AE05 => ['5', "%"],
+ AE06 => ['6', "^"],
+ AE07 => ['7', "&"],
+ AE08 => ['8', "*"],
+ AE09 => ['9', "("],
+ AE10 => ['0', ")"],
+ AE11 => ["-", "_"],
+ AE12 => ["=", "+"],
+
+ AD01 => ["q", "Q"],
+ AD02 => ["w", "W"],
+ AD03 => ["e", "E"],
+ AD04 => ["r", "R"],
+ AD05 => ["t", "T"],
+ AD06 => ["y", "Y"],
+ AD07 => ["u", "U"],
+ AD08 => ["i", "I"],
+ AD09 => ["o", "O"],
+ AD10 => ["p", "P"],
+ AD11 => ["[", "{"],
+ AD12 => ["]", "}"],
+
+ AC01 => ["a", "A"],
+ AC02 => ["s", "S"],
+ AC03 => ["d", "D"],
+ AC04 => ["f", "F"],
+ AC05 => ["g", "G"],
+ AC06 => ["h", "H"],
+ AC07 => ["j", "J"],
+ AC08 => ["k", "K"],
+ AC09 => ["l", "L"],
+ AC10 => [";", ":"],
+ AC11 => ["'", '"'],
+
+ LSGT => ["§", "±"], # mac
+ AB01 => ["z", "Z"],
+ AB02 => ["x", "X"],
+ AB03 => ["c", "C"],
+ AB04 => ["v", "V"],
+ AB05 => ["b", "B"],
+ AB06 => ["n", "N"],
+ AB07 => ["m", "M"],
+ AB08 => [",", "<"],
+ AB09 => [".", ">"],
+ AB10 => ["/", "?"],
+ BKSL => ["\\","|"],
+);
+
+my %res;
+while (readline) {
+ my ($pos, $def) = m/^\h* key \h+ <(\w+)> \h+ \{ (.+?) \};/ or next;
+ my @mode = map { [split /,\h*/] } $def =~ m/\[ \h* (.*?) \h* \]/g;
+ for my $shift (0, 1) {
+ defined(my $chr = $mode[0]->[$shift + 2])
+ or warn "missing $pos +$shift\n";
+ if ($chr =~ m/^U ([A-F0-9]+) $/) {
+ $chr = chr hex $1;
+ }
+ elsif (defined $symname->{$chr}) {
+ $chr = $symname->{$chr};
+ }
+ else {
+ warn "unknown symbol $chr at $pos\n";
+ }
+ $res{$geochar{$pos}->[$shift] // $pos} = $chr;
+ #$res{$pos}[$shift] = $symname->{$chr} // $chr; # geochar
+ }
+}
+say pp \%res;
+
+__END__
+
+=head1 NAME
+
+mkkeyboard-xkb-symbols - Character map of an xkb symbols file
+
+=head1 SYNOPSIS
+
+ cat /usr/share/X11/xkb/symbols/us |
+ perl -ne 'print if /^xkb_symbols "intl"/../^\};/' |
+ mkkeyboard-xkb-symbols >map-us-intl.inc.pl
+
+=head1 DESCRIPTION
+
+Parses C<key> declarations inside an C<xkb_symbols> section
+and returns a perl hash of normalised qwerty input to unicode output
+of 3rd and 4th levels (altgr and shift+altgr modes)
+to be manually cleaned and integrated in a keyboard page include.
+
+=head1 AUTHOR
+
+Mischa POSLAWSKY <perl@shiar.org>
+
+=head1 LICENSE
+
+Licensed under the GNU Affero General Public License version 3.
+