Blame scripts/xkb.pl

Packit 1fb8d4
#!/usr/bin/perl
Packit 1fb8d4
Packit 1fb8d4
#   FreeRDP: A Remote Desktop Protocol Implementation
Packit 1fb8d4
#   XKB database conversion script
Packit 1fb8d4
Packit 1fb8d4
#   Copyright 2009 Marc-Andre Moreau <marcandre.moreau@gmail.com>
Packit 1fb8d4
Packit 1fb8d4
#   Licensed under the Apache License, Version 2.0 (the "License");
Packit 1fb8d4
#   you may not use this file except in compliance with the License.
Packit 1fb8d4
#   You may obtain a copy of the License at
Packit 1fb8d4
Packit 1fb8d4
#       http://www.apache.org/licenses/LICENSE-2.0
Packit 1fb8d4
Packit 1fb8d4
#   Unless required by applicable law or agreed to in writing, software
Packit 1fb8d4
#   distributed under the License is distributed on an "AS IS" BASIS,
Packit 1fb8d4
#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 1fb8d4
#   See the License for the specific language governing permissions and
Packit 1fb8d4
#   limitations under the License.
Packit 1fb8d4
Packit 1fb8d4
Packit 1fb8d4
# Description:
Packit 1fb8d4
# Script to export XKB configuration files to keycode -> virtual key code keymaps that are
Packit 1fb8d4
# easy to use in FreeRDP. This makes keymap maintenance easier to make as all bugs can
Packit 1fb8d4
# simply be reported to the XKB Configuration Database project, and then this script can
Packit 1fb8d4
# be used to export newer (and fixed) version of the XKB Configuration Database.
Packit 1fb8d4
Packit 1fb8d4
use Cwd;
Packit 1fb8d4
Packit 1fb8d4
my %sym2virt = (
Packit 1fb8d4
	"AE00" => "VK_TILDE",
Packit 1fb8d4
	"AE01" => "VK_KEY_1",
Packit 1fb8d4
        "AE02" => "VK_KEY_2",
Packit 1fb8d4
        "AE03" => "VK_KEY_3",
Packit 1fb8d4
        "AE04" => "VK_KEY_4",
Packit 1fb8d4
        "AE05" => "VK_KEY_5",
Packit 1fb8d4
        "AE06" => "VK_KEY_6",
Packit 1fb8d4
        "AE07" => "VK_KEY_7",
Packit 1fb8d4
        "AE08" => "VK_KEY_8",
Packit 1fb8d4
        "AE09" => "VK_KEY_9",
Packit 1fb8d4
        "AE10" => "VK_KEY_0",
Packit 1fb8d4
        "AE11" => "VK_OEM_MINUS",
Packit 1fb8d4
        "AE12" => "VK_OEM_PLUS",
Packit 1fb8d4
Packit 1fb8d4
        "AD01" => "VK_KEY_Q",
Packit 1fb8d4
        "AD02" => "VK_KEY_W",
Packit 1fb8d4
        "AD03" => "VK_KEY_E",
Packit 1fb8d4
        "AD04" => "VK_KEY_R",
Packit 1fb8d4
        "AD05" => "VK_KEY_T",
Packit 1fb8d4
        "AD06" => "VK_KEY_Y",
Packit 1fb8d4
        "AD07" => "VK_KEY_U",
Packit 1fb8d4
        "AD08" => "VK_KEY_I",
Packit 1fb8d4
        "AD09" => "VK_KEY_O",
Packit 1fb8d4
        "AD10" => "VK_KEY_P",
Packit 1fb8d4
        "AD11" => "VK_OEM_4",
Packit 1fb8d4
        "AD12" => "VK_OEM_6",
Packit 1fb8d4
Packit 1fb8d4
        "AC01" => "VK_KEY_A",
Packit 1fb8d4
        "AC02" => "VK_KEY_S",
Packit 1fb8d4
        "AC03" => "VK_KEY_D",
Packit 1fb8d4
        "AC04" => "VK_KEY_F",
Packit 1fb8d4
        "AC05" => "VK_KEY_G",
Packit 1fb8d4
        "AC06" => "VK_KEY_H",
Packit 1fb8d4
        "AC07" => "VK_KEY_J",
Packit 1fb8d4
        "AC08" => "VK_KEY_K",
Packit 1fb8d4
        "AC09" => "VK_KEY_L",
Packit 1fb8d4
        "AC10" => "VK_OEM_1",
Packit 1fb8d4
        "AC11" => "VK_OEM_7",
Packit 1fb8d4
        "AC12" => "VK_OEM_5",
Packit 1fb8d4
Packit 1fb8d4
        "AB00" => "VK_LSHIFT",
Packit 1fb8d4
        "AB01" => "VK_KEY_Z",
Packit 1fb8d4
        "AB02" => "VK_KEY_X",
Packit 1fb8d4
        "AB03" => "VK_KEY_C",
Packit 1fb8d4
        "AB04" => "VK_KEY_V",
Packit 1fb8d4
        "AB05" => "VK_KEY_B",
Packit 1fb8d4
        "AB06" => "VK_KEY_N",
Packit 1fb8d4
        "AB07" => "VK_KEY_M",
Packit 1fb8d4
        "AB08" => "VK_OEM_COMMA",
Packit 1fb8d4
        "AB09" => "VK_OEM_PERIOD",
Packit 1fb8d4
        "AB10" => "VK_OEM_2",
Packit 1fb8d4
        "AB11" => "VK_ABNT_C1",
Packit 1fb8d4
Packit 1fb8d4
        "FK01" => "VK_F1",
Packit 1fb8d4
        "FK02" => "VK_F2",
Packit 1fb8d4
        "FK03" => "VK_F3",
Packit 1fb8d4
        "FK04" => "VK_F4",
Packit 1fb8d4
        "FK05" => "VK_F5",
Packit 1fb8d4
        "FK06" => "VK_F6",
Packit 1fb8d4
        "FK07" => "VK_F7",
Packit 1fb8d4
        "FK08" => "VK_F8",
Packit 1fb8d4
        "FK09" => "VK_F9",
Packit 1fb8d4
        "FK10" => "VK_F10",
Packit 1fb8d4
        "FK11" => "VK_F11",
Packit 1fb8d4
        "FK12" => "VK_F12",
Packit 1fb8d4
        "FK13" => "VK_F13",
Packit 1fb8d4
        "FK14" => "VK_F14",
Packit 1fb8d4
        "FK15" => "VK_F15",
Packit 1fb8d4
        "FK16" => "VK_F16",
Packit 1fb8d4
        "FK17" => "VK_F17",
Packit 1fb8d4
        "FK18" => "VK_F18",
Packit 1fb8d4
        "FK19" => "VK_F19",
Packit 1fb8d4
        "FK20" => "VK_F20",
Packit 1fb8d4
        "FK21" => "VK_F21",
Packit 1fb8d4
        "FK22" => "VK_F22",
Packit 1fb8d4
        "FK23" => "VK_F23",
Packit 1fb8d4
        "FK24" => "VK_F24",
Packit 1fb8d4
Packit 1fb8d4
        "KP0" => "VK_NUMPAD0",
Packit 1fb8d4
        "KP1" => "VK_NUMPAD1",
Packit 1fb8d4
        "KP2" => "VK_NUMPAD2",
Packit 1fb8d4
        "KP3" => "VK_NUMPAD3",
Packit 1fb8d4
        "KP4" => "VK_NUMPAD4",
Packit 1fb8d4
        "KP5" => "VK_NUMPAD5",
Packit 1fb8d4
        "KP6" => "VK_NUMPAD6",
Packit 1fb8d4
        "KP7" => "VK_NUMPAD7",
Packit 1fb8d4
        "KP8" => "VK_NUMPAD8",
Packit 1fb8d4
        "KP9" => "VK_NUMPAD9",
Packit 1fb8d4
Packit 1fb8d4
        "KPDV" => "VK_DIVIDE",
Packit 1fb8d4
        "KPMU" => "VK_MULTIPLY",
Packit 1fb8d4
        "KPSU" => "VK_SUBTRACT",
Packit 1fb8d4
        "KPAD" => "VK_ADD",
Packit 1fb8d4
        "KPDL" => "VK_DECIMAL",
Packit 1fb8d4
        "KPEN" => "VK_RETURN",
Packit 1fb8d4
Packit 1fb8d4
        "RTRN" => "VK_RETURN",
Packit 1fb8d4
        "SPCE" => "VK_SPACE",
Packit 1fb8d4
        "BKSP" => "VK_BACK",
Packit 1fb8d4
        "BKSL" => "VK_OEM_5",
Packit 1fb8d4
        "LSGT" => "VK_OEM_102",
Packit 1fb8d4
        "ESC" => "VK_ESCAPE",
Packit 1fb8d4
        "TLDE" => "VK_OEM_3",
Packit 1fb8d4
        "CAPS" => "VK_CAPITAL",
Packit 1fb8d4
        "TAB" => "VK_TAB",
Packit 1fb8d4
        "LFSH" => "VK_LSHIFT",
Packit 1fb8d4
        "RTSH" => "VK_RSHIFT",
Packit 1fb8d4
        "LCTL" => "VK_LCONTROL",
Packit 1fb8d4
        "RCTL" => "VK_RCONTROL",
Packit 1fb8d4
        "LWIN" => "VK_LWIN",
Packit 1fb8d4
        "RWIN" => "VK_RWIN",
Packit 1fb8d4
        "LALT" => "VK_LMENU",
Packit 1fb8d4
        "RALT" => "VK_RMENU",
Packit 1fb8d4
        "COMP" => "VK_APPS",
Packit 1fb8d4
        "MENU" => "VK_APPS",
Packit 1fb8d4
        "UP" => "VK_UP",
Packit 1fb8d4
        "DOWN" => "VK_DOWN",
Packit 1fb8d4
        "LEFT" => "VK_LEFT",
Packit 1fb8d4
        "RGHT" => "VK_RIGHT",
Packit 1fb8d4
        "INS" => "VK_INSERT",
Packit 1fb8d4
        "DELE" => "VK_DELETE",
Packit 1fb8d4
        "PGUP" => "VK_PRIOR",
Packit 1fb8d4
        "PGDN" => "VK_NEXT",
Packit 1fb8d4
        "HOME" => "VK_HOME",
Packit 1fb8d4
        "END" => "VK_END",
Packit 1fb8d4
        "PAUS" => "VK_PAUSE",
Packit 1fb8d4
        "NMLK" => "VK_NUMLOCK",
Packit 1fb8d4
        "SCLK" => "VK_SCROLL",
Packit 1fb8d4
Packit 1fb8d4
	# This page helps understanding the keys that follow:
Packit 1fb8d4
	# http://www.stanford.edu/class/cs140/projects/pintos/specs/kbd/scancodes-7.html
Packit 1fb8d4
 
Packit 1fb8d4
	"KANJ" => "VK_KANJI",
Packit 1fb8d4
	"HANJ" => "VK_HANJA",
Packit 1fb8d4
	"MUHE" => "VK_NONCONVERT",
Packit 1fb8d4
	"HIRA" => "VK_KANA",
Packit 1fb8d4
	"PRSC" => "VK_SNAPSHOT",
Packit 1fb8d4
Packit 1fb8d4
	"KPF1" => "VK_NUMLOCK",
Packit 1fb8d4
	"KPF2" => "VK_DIVIDE",
Packit 1fb8d4
	"KPF3" => "VK_MULTIPLY",
Packit 1fb8d4
	"KPF4" => "VK_SUBTRACT",
Packit 1fb8d4
	"KPCO" => "VK_ADD",
Packit 1fb8d4
Packit 1fb8d4
        "HELP" => "VK_HELP",
Packit 1fb8d4
        "SELE" => "VK_SELECT",
Packit 1fb8d4
Packit 1fb8d4
	# We can ignore LDM (Lock Down Modifier)
Packit 1fb8d4
	# What are LCMP/RCMP?
Packit 1fb8d4
	# DO, FIND?
Packit 1fb8d4
Packit 1fb8d4
);
Packit 1fb8d4
Packit 1fb8d4
my $inDir;
Packit 1fb8d4
my $outDir;
Packit 1fb8d4
Packit 1fb8d4
if(@ARGV < 1) {
Packit 1fb8d4
	$inDir = getcwd() . "/";
Packit 1fb8d4
	$outDir = $inDir;
Packit 1fb8d4
} elsif(@ARGV == 1) {
Packit 1fb8d4
	$inDir = $ARGV[0];
Packit 1fb8d4
	$outDir = getcwd() . "/";
Packit 1fb8d4
} elsif(@ARGV == 2) {
Packit 1fb8d4
	$inDir = $ARGV[0];
Packit 1fb8d4
	$outDir = $ARGV[1];
Packit 1fb8d4
} else {
Packit 1fb8d4
	print 	"Error: Too many arguments\n" .
Packit 1fb8d4
		"Usage:\n" .
Packit 1fb8d4
		"perl xkb.pl <XKB Directory>\n" .
Packit 1fb8d4
		"perl xkb.pl <XKB Directory> <Output Directory>\n\n" .
Packit 1fb8d4
		"In Linux, the XKB directory usually is /usr/share/X11/xkb/\n" .
Packit 1fb8d4
		"The latest version of XKB can always be downloaded at:\n" .
Packit 1fb8d4
		"http://freedesktop.org/wiki/Software/XKeyboardConfig\n";
Packit 1fb8d4
		exit 0;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
Packit 1fb8d4
Packit 1fb8d4
open("SPEC", $inDir . "xkeyboard-config.spec");
Packit 1fb8d4
Packit 1fb8d4
$xkbVersion = "";
Packit 1fb8d4
while($line = <SPEC>) {
Packit 1fb8d4
	if($line =~ m/Version:\s+(.\..)/) {
Packit 1fb8d4
		$xkbVersion = "version $1";
Packit 1fb8d4
	}
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
# Create directory if it does not exists
Packit 1fb8d4
if(not -e $outDir) {
Packit 1fb8d4
	mkdir $outDir or die("Error: Can't create directory $outDir\n");
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
open("KCD", $inDir . "keycodes/keycodes.dir") or die("Error: Can't open $inDir" . "keycodes/keycodes.dir\n");
Packit 1fb8d4
Packit 1fb8d4
$previousFile = "";
Packit 1fb8d4
while($line = <KCD>) {
Packit 1fb8d4
	if($line =~ m/........ -------- (.+)\((.+)\)/) {
Packit 1fb8d4
		if($1 ne $previousFile) {
Packit 1fb8d4
			push(@keymapFiles, $1);
Packit 1fb8d4
			$previousFile = $1;
Packit 1fb8d4
		}
Packit 1fb8d4
	}	
Packit 1fb8d4
}
Packit 1fb8d4
close("KCD");
Packit 1fb8d4
Packit 1fb8d4
foreach $keymapFile (@keymapFiles) {
Packit 1fb8d4
Packit 1fb8d4
		print "File $keymapFile:\n";
Packit 1fb8d4
Packit 1fb8d4
		@directories = split(/\//, $keymapFile);
Packit 1fb8d4
		splice(@directories, @directories - 1, 1); 
Packit 1fb8d4
Packit 1fb8d4
		if(@directories > 0) {
Packit 1fb8d4
			$directory = $outDir;		
Packit 1fb8d4
			for($i = 0; $i < @directories; $i++) {
Packit 1fb8d4
				$directory .= $directories[$i] . "/";
Packit 1fb8d4
				if(not -e $directory) {
Packit 1fb8d4
					mkdir $directory or die("Can't create directory $directory\n");				
Packit 1fb8d4
				}			
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		open("IN", $inDir . "keycodes/" . $keymapFile);
Packit 1fb8d4
		open("OUT", ">" . "$outDir" . $keymapFile);
Packit 1fb8d4
Packit 1fb8d4
		print OUT "# This file was generated with xkb.pl\n";
Packit 1fb8d4
		print OUT "# and is based on the X Keyboard Configuration Database $xkbVersion\n";
Packit 1fb8d4
		print OUT "# Please use xkb.pl to re-export newer versions of XKB\n";
Packit 1fb8d4
		print OUT "\n\n";
Packit 1fb8d4
Packit 1fb8d4
		while($line = <IN>) {
Packit 1fb8d4
			if($line =~ m/xkb_keycodes \"(\w+)\"/) {
Packit 1fb8d4
Packit 1fb8d4
				print "Exporting \"$1\"\n";
Packit 1fb8d4
				print OUT "keyboard \"$1\"";
Packit 1fb8d4
Packit 1fb8d4
Packit 1fb8d4
				while($line = <IN>) {
Packit 1fb8d4
					if($line =~ m/include\W+\"(.+)\"/) {
Packit 1fb8d4
						print OUT "\n: extends \"$1\"";
Packit 1fb8d4
						last;
Packit 1fb8d4
					} else {
Packit 1fb8d4
						last;
Packit 1fb8d4
					}
Packit 1fb8d4
				}
Packit 1fb8d4
				print OUT "\n{\n";		
Packit 1fb8d4
Packit 1fb8d4
				while($line = <IN>) {
Packit 1fb8d4
					if($line =~ m/<(\w{1,4})>\W+=\W+(\w+);/) {
Packit 1fb8d4
						if($sym2virt{$1} ne undef) {
Packit 1fb8d4
							$vkcode = $sym2virt{$1};
Packit 1fb8d4
							print OUT "\t$vkcode";
Packit 1fb8d4
Packit 1fb8d4
							if(length($vkcode) < 8) {
Packit 1fb8d4
								print OUT "\t";
Packit 1fb8d4
							}
Packit 1fb8d4
							print OUT "\t<$2>\n";
Packit 1fb8d4
						} else {
Packit 1fb8d4
							# If undef, then this symbolic key code is
Packit 1fb8d4
							# missing from the sym2virt hash table
Packit 1fb8d4
							# print "\t$1\t$2\n";
Packit 1fb8d4
						}
Packit 1fb8d4
					} elsif($line =~ m/};/) {
Packit 1fb8d4
						print OUT "};\n\n";
Packit 1fb8d4
						last;
Packit 1fb8d4
					}
Packit 1fb8d4
				}
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		close("IN");
Packit 1fb8d4
		close("OUT");
Packit 1fb8d4
}
Packit 1fb8d4