[Pkg-libvirt-commits] [gtk-vnc] 01/05: New upstream version 0.7.1

Guido Guenther agx at moszumanska.debian.org
Tue Aug 1 15:06:29 UTC 2017


This is an automated email from the git hooks/post-receive script.

agx pushed a commit to annotated tag debian/0.7.1-1
in repository gtk-vnc.

commit a223999238a90c96f9723926568648b7621b9f5f
Author: Guido Günther <agx at sigxcpu.org>
Date:   Tue Aug 1 11:28:20 2017 -0300

    New upstream version 0.7.1
---
 AUTHORS                                |   5 +
 ChangeLog                              | 249 +++++++++++++
 Makefile.in                            |   8 +-
 NEWS                                   |  31 ++
 README                                 |   2 +-
 aclocal.m4                             |   4 +-
 build-aux/test-driver                  | 148 ++++++++
 cfg.mk                                 |   2 +-
 configure                              | 235 ++++++------
 configure.ac                           |  18 +-
 examples/gvncviewer.c                  |  14 +
 gtk-vnc.spec                           |  12 +-
 gtk-vnc.spec.in                        |  10 +-
 po/LINGUAS                             |   1 +
 po/fur.po                              |  31 ++
 po/pl.po                               |  24 +-
 src/Makefile.am                        |  38 +-
 src/Makefile.in                        | 455 ++++++++++++++++++++++--
 src/keycodemapdb/data/keymaps.csv      | 511 +++++++++++++++++++++++++++
 src/keycodemapdb/tools/keymap-gen      | 578 ++++++++++++++++++++++++++++++
 src/keymap-gen.pl                      | 214 -----------
 src/keymaps.csv                        | 490 -------------------------
 src/libgtk-vnc_sym.version             |   3 +
 src/vnccolormap.c                      |   4 +-
 src/vncconnection.c                    | 225 +++++++++---
 src/vncconnection.h                    |   2 +-
 src/vncconnectiontest.c                | 628 +++++++++++++++++++++++++++++++++
 src/vncdisplay.c                       | 117 +++++-
 src/vncdisplay.h                       |   3 +
 src/vncdisplaykeymap_osx2rfb.c         | 117 ------
 src/vncdisplaykeymap_win322rfb.c       | 141 --------
 src/vncdisplaykeymap_x112rfb.c         | 132 -------
 src/vncdisplaykeymap_xorgevdev2rfb.c   | 240 -------------
 src/vncdisplaykeymap_xorgkbd2rfb.c     | 112 ------
 src/vncdisplaykeymap_xorgxquartz2rfb.c | 117 ------
 src/vncdisplaykeymap_xorgxwin2rfb.c    | 112 ------
 src/vncgrabsequence.c                  |   1 +
 vapi/Makefile.am                       |  12 +-
 vapi/Makefile.in                       |  14 +-
 39 files changed, 3101 insertions(+), 1959 deletions(-)

diff --git a/AUTHORS b/AUTHORS
index a900668..db86a2b 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -39,9 +39,12 @@ Daniel P. Berrange <dan at berrange.com>
 Doug Goldstein <cardoe at cardoe.com>
 Emilio Pozuelo Monfort <pochu27 at gmail.com>
 Enrico Nicoletto <enriconlto at src.gnome.org>
+Eric R. Schulz <eric at ers35.com>
 Fabiano Fidêncio <fabiano at fidencio.org>
 Fabiano Fidêncio <fidencio at redhat.com>
+Fabio Tomat <f.t.public at gmail.com>
 Federico Mena Quintero <federico at gnome.org>
+Felix E. Klee <felix.klee at inka.de>
 Fran Diéguez <fran.dieguez at glug.es>
 Gabor Kelemen <kelemeng at gnome.hu>
 George Stefanakis <george.stefanakis at gmail.com>
@@ -83,7 +86,9 @@ Peter Korsgaard <peter at korsgaard.com>
 Philip Withnall <philip at tecnocode.co.uk>
 Piotr Drąg <piotrdrag at gmail.com>
 Praveen Illa <mail2ipn at gmail.com>
+Rafael Fontenelle <rafaelff at gnome.org>
 Richard W.M. Jones <rjones at redhat.com>
+Rico Tzschichholz <ricotz at t-online.de>
 Rūdolfs Mazurs <rudolfsm at src.gnome.org>
 Samir Ribic <samir.ribic at etf.unsa.ba>
 Saori Fukuta <fukuta.saori at jp.fujitsu.com>
diff --git a/ChangeLog b/ChangeLog
index 088fed8..edb7ef6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,252 @@
+2017-05-19  Daniel P. Berrange  <berrange at redhat.com>
+
+	Bump to 0.7.1 for new release
+
+2017-04-12  Daniel P. Berrange  <berrange at redhat.com>
+
+	Fix incompatibility with libvncserver websockets handling
+	The previous commit:
+
+	  commit 7f4f2fe8da72ed9fef5dd4319e19feb2b4f3d62e
+	  Author: Daniel P. Berrange <berrange at redhat.com>
+	  Date:   Thu Jan 26 09:31:40 2017 +0000
+
+	    Add workaround to avoid hangs when connecting to SPICE
+
+	changed the code so that it would send the bytes "RFB " to the
+	server before we received its own greeting. This works fine for
+	VNC servers which follow the RFB protocol spec exclusively. The
+	libvncserver code though tries to implement websockets tunnelling
+	support on the same port as the normal RFB service. The way it
+	does this is by waiting 100ms after the client connects to see
+	if the client sends any data. If the client sends data, then it
+	tries to interpret this as an HTTP GET request to initiate the
+	websockets connection. This breaks when it sees our "RFB " bytes
+	being sent. Ideally the libvncserver would have just run a normal
+	RFB connection in this case, but that's not what happens, and
+	given the libvncserver code is in the wild we need a workaround.
+
+	So instead of immediately sending the 'RFB ' bytes to the VNC
+	server, we introduce a 2 second wait. ie, we'll wait for the
+	normal VNC server greeting and if it doesn't arrive after 2 seconds,
+	we'll send our 'RFB ' bytes proactively, and continue waiting. If we
+	are on a real VNC server, we'll get our connection initialized
+	eventually. If connecting to a SPICE server by mistake, we'll get a
+	clean disconnect, and we'll avoid upsetting libvncserver, because its
+	100ms wait for HTTP GET will have long since finished.
+
+	Report a proper error message if hitting connection timeout
+
+	Fix crash when no error is set after connection failure
+
+	Fix crash when opening connection from a GSocketAddress
+
+	Avoid sign extension warnings from coverity
+	 src/vncconnection.c:3082: sign_extension:
+	 Suspicious implicit sign extension: "height" with type "unsigned short"
+	 (16 bits, unsigned) is promoted in "rowlen * height" to type "int"
+	 (32 bits, signed), then sign-extended to type "unsigned long"
+	 (64 bits, unsigned). If "rowlen * height" is greater than 0x7FFFFFFF,
+	 the upper bits of the result will all be 1.
+
+	The 'rowlen' variable is initialization from the unsigned width
+	variable, so should have used uint instead of int.
+
+	Fix inverted args when creating framebuffer for test suite
+	The local & remote format args were inverted in the test
+	suite. This is currently harmless since we are not trying
+	to validate the rendered framebuffer content.
+
+	Restore correct size of reserved data
+	A previous commit
+
+	  commit 7a9271620c894931cc22d6587d58e46c5996dac3
+	  Author: Lei Li <lilei at linux.vnet.ibm.com>
+	  Date:   Mon May 20 11:45:59 2013 +0100
+
+	    Add support for LED state extension to gvnc
+
+	removed 4 elements from the reserved data field, when adding
+	one pointer. This is because it mistakenly thought the reserved
+	elements were 1 byte in length, when they are in fact one pointer
+	in size.
+
+	The original change was technically an ABI incompatible change,
+	as is this fix. In practice, however, GObject classes are never
+	instantiated statically at compile time. Instead a call to
+	g_type_register_static is made at runtime. So this change in the
+	class size won't have a negative effect unless someone has
+	subclassed the VncConnectionClass type. Even if subclassing, this
+	should be harmless as we've merely increased the memory allocation
+	by 3 words.
+
+2017-03-05  Fabio Tomat  <f.t.public at gmail.com>
+
+	Add Friulian translation
+
+2017-02-22  Rafael Fontenelle  <rafaelff at gnome.org>
+
+	Fix path for keymap-gen when doing VPATH builds
+
+2017-02-16  Daniel P. Berrange  <berrange at redhat.com>
+
+	Fix some deps in spec file & new URL & missing group tags
+
+2017-02-15  Daniel P. Berrange  <berrange at redhat.com>
+
+	Switch to use keycodemapdb submodule
+
+2017-02-14  Guido Günther  <agx at sigxcpu.org>
+
+	Link against GIO_LIBS explicitly
+	to avoid
+
+	libtool: link: gcc -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -g -O2 -fdebug-prefix-map=/build/gtk-vnc-0.6.0=. -fstack-protector-strong -Wformat -Werror=format-security -Wl,-z -Wl,relro
+	 -Wl,-z -Wl,now -o .libs/vncconnectiontest vncconnectiontest-vncconnectiontest.o  ./.libs/libgvnc-1.0.so -lz -pthread
+	/usr/bin/ld: vncconnectiontest-vncconnectiontest.o: undefined reference to symbol 'g_io_stream_get_output_stream'
+	//usr/lib/x86_64-linux-gnu/libgio-2.0.so.0: error adding symbols: DSO missing from command line
+
+	Also make the use of *_CFLAGS and *_LIBS match.
+
+2017-02-09  Daniel P. Berrange  <berrange at redhat.com>
+
+	Bump to 0.7.0 for new release
+
+2017-02-08  Daniel P. Berrange  <berrange at redhat.com>
+
+	Clamp cursor hot-pixel to be within cursor region
+	Some broken VNC servers send hot-pixel outside bounds of the
+	cursor. We could disconnect and report an error, but it is
+	more user friendly to just clamp the hot pixel coords
+
+	https://bugzilla.gnome.org/show_bug.cgi?id=775394
+
+2017-02-08  Eric R. Schulz  <eric at ers35.com>
+
+	Fix memory leaks
+	Call gnutls_deinit() after gnutls_bye().
+	Call g_free() in finalize().
+	Call g_free() in vnc_grab_sequence_free().
+
+2017-02-08  Daniel P. Berrange  <berrange at redhat.com>
+
+	Fix some misc warnings & mem leak in test case
+
+2017-02-08  Christophe Fergeau  <cfergeau at redhat.com>
+
+	README: Update URL to home page
+	The old page no longer seems to exist in GNOME's wiki.
+
+	Add preconditions to VncDisplay public methods
+	This should catch invalid arguments being passed to these. This required
+	moving the VncDisplayPrivate *priv = display->priv; assignment as the
+	VNC_IS_DISPLAY(display) check is also a NULL check which we want to
+	happen before dereferencing it.
+
+	Avoid crash if attempt to connect to an invalid host or port
+	If vnc_display_open_host() is called with a NULL port or host,
+	vnc_connection_open_host_internal() will eventually crash.
+	This commits adds runtime checks to return early with
+	g_return_val_if_fail() when this happens rather than
+	crashing
+
+	 #0  0x00007ffff37de3d3 in __strchr_sse2 () at ../sysdeps/x86_64/strchr.S:32
+	 #1  0x00007ffff4661a17 in g_inet_socket_address_new_from_string (address=0x0, port=0)
+	     at ginetsocketaddress.c:416
+	 #2  0x00007ffff466b784 in g_network_address_parse_sockaddr (addr=addr at entry=0x969f50 [GNetworkAddress])
+	     at gnetworkaddress.c:245
+	 #3  0x00007ffff466ba94 in g_network_address_address_enumerator_next (enumerator=0x972ca0 [GNetworkAddressAddressEnumerator], cancellable=0x0, error=<optimized out>) at gnetworkaddress.c:919
+	 #4  0x00007ffff727130b in vnc_connection_open_host_internal (conn=0x99bbf0 [VncConnection])
+	     at vncconnection.c:5395
+	 #5  0x00007ffff7271523 in vnc_connection_coroutine (opaque=0x99bbf0) at vncconnection.c:5448
+	 #6  0x00007ffff7272e54 in coroutine_trampoline (cc=0x998080) at coroutine_ucontext.c:55
+	 #7  0x00007ffff7272b65 in continuation_trampoline (i0=10059904, i1=0) at continuation.c:43
+	 #8  0x00007ffff379dc00 in __start_context () at /lib64/libc.so.6
+	 #9  0x0000000000998448 in  ()
+	 #10 0x0000000000000000 in  ()
+
+2017-02-08  Rico Tzschichholz  <ricotz at t-online.de>
+
+	Add missing vala .deps files for gvnc & gvncpulse
+	https://bugzilla.gnome.org/show_bug.cgi?id=772322
+
+2017-02-07  Daniel P. Berrange  <berrange at redhat.com>
+
+	Correctly validate color map range indexes
+	The color map index could wrap around to zero causing negative
+	array index accesses.
+
+	https://bugzilla.gnome.org/show_bug.cgi?id=778050
+
+	CVE-2017-5885
+
+	Don't accept color map entries for true-color pixel format
+	The color map entries should only be sent by the server
+	when true-color flag is false.
+
+	Fix bounds checking for RRE, hextile & copyrect encodings
+	While the client would bounds check the overall update
+	region, it failed to bounds check the payload data
+	parameters.
+
+	Add a test case to validate bounds checking.
+
+	https://bugzilla.gnome.org/show_bug.cgi?id=778048
+
+	CVE-2017-5884
+
+2017-01-26  Daniel P. Berrange  <berrange at redhat.com>
+
+	Add workaround to avoid hangs when connecting to SPICE
+	When used with QEMU at least, both SPICE and VNC live in the same port
+	range (5900+). It is thus not entirely uncommon for a user to mistakenly
+	connect to a SPICE server with a VNC client, or vica-verca.
+
+	When connecting to VNC server with a SPICE client, you quickly get an
+	error. This is because the VNC server sends its short greeting and then
+	sees the RedLinkMess from the SPICE client, realizes its garbage and
+	drops the connection.
+
+	When connecting to a SPICE server with a VNC client though, you get an
+	indefinite hang. The VNC client is waiting for the VNC greeting, which
+	the SPICE server will never send. The SPICE server is waiting for the
+	RedLinkMess which the VNC client will never send.
+
+	In VNC the protocol starts with the follow data sent:
+
+	 Server: "RFB 003.008\n"
+	 Client: "RFB 003.008\n"
+
+	This can be tweaked so the client proactively sends the first four
+	bytes
+
+	 Client: "RFB "
+	 Server: "RFB 003.008\n"
+	 Client: "003.008\n"
+
+	From the VNC server POV, it'll still be receiving the same 12 bytes from
+	the client - it just happens that 4 of them might arrive a tiny bit
+	earlier than the other 8 of them. IOW nothing should break in the VNC
+	server from this change.
+
+	The SPICE server, waiting for its RedLinkMess message will see these
+	four bytes "RFB " and interpret them as the SPICE magic number. This
+	will be invalid and so the SPICE server will drop the connection.
+	This avoids the VNC client hanging forever when connecting to a SPICE
+	server by mistake.
+
+2016-10-26  Felix E. Klee  <felix.klee at inka.de>
+
+	Added menu option for smooth scaling
+
+	Added option for smooth scaling
+	Smooth scaling can now be turned off by setting the option "smoothing"
+	to false.
+
+2016-08-18  Piotr Drąg  <piotrdrag at gmail.com>
+
+	Updated Polish translation
+
 2016-08-18  Daniel P. Berrange  <berrange at redhat.com>
 
 	Update for 0.6.0 release
diff --git a/Makefile.in b/Makefile.in
index ca864d2..fdd6e8d 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -791,7 +791,7 @@ distdir: $(DISTFILES)
 	  ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \
 	|| chmod -R a+r "$(distdir)"
 dist-gzip: distdir
-	tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
+	tardir=$(distdir) && $(am__tar) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).tar.gz
 	$(am__post_remove_distdir)
 
 dist-bzip2: distdir
@@ -816,7 +816,7 @@ dist-shar: distdir
 	@echo WARNING: "Support for shar distribution archives is" \
 	               "deprecated." >&2
 	@echo WARNING: "It will be removed altogether in Automake 2.0" >&2
-	shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
+	shar $(distdir) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).shar.gz
 	$(am__post_remove_distdir)
 
 dist-zip: distdir
@@ -834,7 +834,7 @@ dist dist-all:
 distcheck: dist
 	case '$(DIST_ARCHIVES)' in \
 	*.tar.gz*) \
-	  GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\
+	  eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).tar.gz | $(am__untar) ;;\
 	*.tar.bz2*) \
 	  bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\
 	*.tar.lz*) \
@@ -844,7 +844,7 @@ distcheck: dist
 	*.tar.Z*) \
 	  uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
 	*.shar.gz*) \
-	  GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\
+	  eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).shar.gz | unshar ;;\
 	*.zip*) \
 	  unzip $(distdir).zip ;;\
 	esac
diff --git a/NEWS b/NEWS
index 6e9ea2d..44bef26 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,37 @@
     GTK VNC News
     ============
 
+May 19, 2017: Release 0.7.1
+===========================
+
+ o Explicitly link to GIO instead of relying
+   on implicit linkage
+ o Switch to use new keycodemap database module
+ o Fix size of reserved data in class struct
+ o Fix inverted framebuffer args in test case
+ o Avoid sign extension in integer arithmetic
+ o Avoid crash when opening a GSocketAddress
+ o Fix crash if server connection times out
+ o Fix incompatibility with libvncserver
+
+Feb  9, 2017: Release 0.7.0
+===========================
+
+ o CVE-2017-5884 - fix bounds checking for RRE, hextile and
+   copyrect encodings
+ o CVE-2017-5885 - fix color map index bounds checking
+ o Add API to allow smooth scaling to be disabled
+ o Workaround to help SPICE servers quickly drop VNC clients
+   which mistakenly connect, by sending "RFB " signature bytes
+   early
+ o Don't accept color map entries for true-color pixel formats
+ o Add missing vala .deps files for gvnc & gvncpulse
+ o Avoid crash if host/port is NULL
+ o Add precondition checks to some public APIs
+ o Fix link to home page in README file
+ o Fix misc memory leaks
+ o Clamp cursor hot-pixel to within cursor region
+
 Aug 18, 2016: Release 0.6.0
 ===========================
 
diff --git a/README b/README
index afb50f9..d045b5b 100644
--- a/README
+++ b/README
@@ -15,7 +15,7 @@ Introspection system.
 
 For information about the project visit the webpage at:
 
-  http://live.gnome.org/gtk-vnc
+  https://wiki.gnome.org/Projects/gtk-vnc
 
 To contact developers use the project mailing list at:
 
diff --git a/aclocal.m4 b/aclocal.m4
index 48662c8..faf8820 100644
--- a/aclocal.m4
+++ b/aclocal.m4
@@ -744,7 +744,7 @@ AC_DEFUN([AM_NLS],
 ])
 
 dnl pkg.m4 - Macros to locate and utilise pkg-config.   -*- Autoconf -*-
-dnl serial 11 (pkg-config-0.29)
+dnl serial 11 (pkg-config-0.29.1)
 dnl
 dnl Copyright © 2004 Scott James Remnant <scott at netsplit.com>.
 dnl Copyright © 2012-2015 Dan Nicholson <dbn.lists at gmail.com>
@@ -786,7 +786,7 @@ dnl
 dnl See the "Since" comment for each macro you use to see what version
 dnl of the macros you require.
 m4_defun([PKG_PREREQ],
-[m4_define([PKG_MACROS_VERSION], [0.29])
+[m4_define([PKG_MACROS_VERSION], [0.29.1])
 m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1,
     [m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])])
 ])dnl PKG_PREREQ
diff --git a/build-aux/test-driver b/build-aux/test-driver
new file mode 100755
index 0000000..8e575b0
--- /dev/null
+++ b/build-aux/test-driver
@@ -0,0 +1,148 @@
+#! /bin/sh
+# test-driver - basic testsuite driver script.
+
+scriptversion=2013-07-13.22; # UTC
+
+# Copyright (C) 2011-2014 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <bug-automake at gnu.org> or send patches to
+# <automake-patches at gnu.org>.
+
+# Make unconditional expansion of undefined variables an error.  This
+# helps a lot in preventing typo-related bugs.
+set -u
+
+usage_error ()
+{
+  echo "$0: $*" >&2
+  print_usage >&2
+  exit 2
+}
+
+print_usage ()
+{
+  cat <<END
+Usage:
+  test-driver --test-name=NAME --log-file=PATH --trs-file=PATH
+              [--expect-failure={yes|no}] [--color-tests={yes|no}]
+              [--enable-hard-errors={yes|no}] [--]
+              TEST-SCRIPT [TEST-SCRIPT-ARGUMENTS]
+The '--test-name', '--log-file' and '--trs-file' options are mandatory.
+END
+}
+
+test_name= # Used for reporting.
+log_file=  # Where to save the output of the test script.
+trs_file=  # Where to save the metadata of the test run.
+expect_failure=no
+color_tests=no
+enable_hard_errors=yes
+while test $# -gt 0; do
+  case $1 in
+  --help) print_usage; exit $?;;
+  --version) echo "test-driver $scriptversion"; exit $?;;
+  --test-name) test_name=$2; shift;;
+  --log-file) log_file=$2; shift;;
+  --trs-file) trs_file=$2; shift;;
+  --color-tests) color_tests=$2; shift;;
+  --expect-failure) expect_failure=$2; shift;;
+  --enable-hard-errors) enable_hard_errors=$2; shift;;
+  --) shift; break;;
+  -*) usage_error "invalid option: '$1'";;
+   *) break;;
+  esac
+  shift
+done
+
+missing_opts=
+test x"$test_name" = x && missing_opts="$missing_opts --test-name"
+test x"$log_file"  = x && missing_opts="$missing_opts --log-file"
+test x"$trs_file"  = x && missing_opts="$missing_opts --trs-file"
+if test x"$missing_opts" != x; then
+  usage_error "the following mandatory options are missing:$missing_opts"
+fi
+
+if test $# -eq 0; then
+  usage_error "missing argument"
+fi
+
+if test $color_tests = yes; then
+  # Keep this in sync with 'lib/am/check.am:$(am__tty_colors)'.
+  red='' # Red.
+  grn='' # Green.
+  lgn='' # Light green.
+  blu='' # Blue.
+  mgn='' # Magenta.
+  std=''     # No color.
+else
+  red= grn= lgn= blu= mgn= std=
+fi
+
+do_exit='rm -f $log_file $trs_file; (exit $st); exit $st'
+trap "st=129; $do_exit" 1
+trap "st=130; $do_exit" 2
+trap "st=141; $do_exit" 13
+trap "st=143; $do_exit" 15
+
+# Test script is run here.
+"$@" >$log_file 2>&1
+estatus=$?
+
+if test $enable_hard_errors = no && test $estatus -eq 99; then
+  tweaked_estatus=1
+else
+  tweaked_estatus=$estatus
+fi
+
+case $tweaked_estatus:$expect_failure in
+  0:yes) col=$red res=XPASS recheck=yes gcopy=yes;;
+  0:*)   col=$grn res=PASS  recheck=no  gcopy=no;;
+  77:*)  col=$blu res=SKIP  recheck=no  gcopy=yes;;
+  99:*)  col=$mgn res=ERROR recheck=yes gcopy=yes;;
+  *:yes) col=$lgn res=XFAIL recheck=no  gcopy=yes;;
+  *:*)   col=$red res=FAIL  recheck=yes gcopy=yes;;
+esac
+
+# Report the test outcome and exit status in the logs, so that one can
+# know whether the test passed or failed simply by looking at the '.log'
+# file, without the need of also peaking into the corresponding '.trs'
+# file (automake bug#11814).
+echo "$res $test_name (exit status: $estatus)" >>$log_file
+
+# Report outcome to console.
+echo "${col}${res}${std}: $test_name"
+
+# Register the test result, and other relevant metadata.
+echo ":test-result: $res" > $trs_file
+echo ":global-test-result: $res" >> $trs_file
+echo ":recheck: $recheck" >> $trs_file
+echo ":copy-in-global-log: $gcopy" >> $trs_file
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/cfg.mk b/cfg.mk
index 524a330..cd4a264 100644
--- a/cfg.mk
+++ b/cfg.mk
@@ -109,7 +109,7 @@ sc_copyright_format:
 prev_version_file = /dev/null
 
 
-exclude_file_name_regexp--sc_bindtextdomain = ^examples/
+exclude_file_name_regexp--sc_bindtextdomain = ^examples/|src/.*test.c
 
 exclude_file_name_regexp--sc_preprocessor_indentation = ^*/*.[ch]
 
diff --git a/configure b/configure
index 6974f35..308f931 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for gtk-vnc 0.6.0.
+# Generated by GNU Autoconf 2.69 for gtk-vnc 0.7.1.
 #
 # Report bugs to <https://bugzilla.gnome.org/enter_bug.cgi?product=gtk-vnc>.
 #
@@ -591,8 +591,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='gtk-vnc'
 PACKAGE_TARNAME='gtk-vnc'
-PACKAGE_VERSION='0.6.0'
-PACKAGE_STRING='gtk-vnc 0.6.0'
+PACKAGE_VERSION='0.7.1'
+PACKAGE_STRING='gtk-vnc 0.7.1'
 PACKAGE_BUGREPORT='https://bugzilla.gnome.org/enter_bug.cgi?product=gtk-vnc'
 PACKAGE_URL='http://live.gnome.org/gtk-vnc/'
 
@@ -657,6 +657,8 @@ WITH_PYTHON_TRUE
 REBUILD
 PERL
 PYTHON_INCLUDES
+PYGTK_LIBS
+PYGTK_CFLAGS
 pkgpyexecdir
 pyexecdir
 pkgpythondir
@@ -666,8 +668,6 @@ PYTHON_EXEC_PREFIX
 PYTHON_PREFIX
 PYTHON_VERSION
 PYTHON
-PYGTK_LIBS
-PYGTK_CFLAGS
 WITH_UCONTEXT_FALSE
 WITH_UCONTEXT_TRUE
 GTHREAD_LIBS
@@ -952,9 +952,9 @@ GNUTLS_CFLAGS
 GNUTLS_LIBS
 GTHREAD_CFLAGS
 GTHREAD_LIBS
+PYTHON
 PYGTK_CFLAGS
-PYGTK_LIBS
-PYTHON'
+PYGTK_LIBS'
 
 
 # Initialize some variables set by options.
@@ -1495,7 +1495,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures gtk-vnc 0.6.0 to adapt to many kinds of systems.
+\`configure' configures gtk-vnc 0.7.1 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1565,7 +1565,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of gtk-vnc 0.6.0:";;
+     short | recursive ) echo "Configuration of gtk-vnc 0.7.1:";;
    esac
   cat <<\_ACEOF
 
@@ -1667,10 +1667,10 @@ Some influential environment variables:
               C compiler flags for GTHREAD, overriding pkg-config
   GTHREAD_LIBS
               linker flags for GTHREAD, overriding pkg-config
+  PYTHON      the Python interpreter
   PYGTK_CFLAGS
               C compiler flags for PYGTK, overriding pkg-config
   PYGTK_LIBS  linker flags for PYGTK, overriding pkg-config
-  PYTHON      the Python interpreter
 
 Use these variables to override the choices made by `configure' or to help
 it to find libraries and programs with nonstandard names/locations.
@@ -1739,7 +1739,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-gtk-vnc configure 0.6.0
+gtk-vnc configure 0.7.1
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2108,7 +2108,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by gtk-vnc $as_me 0.6.0, which was
+It was created by gtk-vnc $as_me 0.7.1, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -2975,7 +2975,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='gtk-vnc'
- VERSION='0.6.0'
+ VERSION='0.7.1'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -17124,101 +17124,7 @@ else
 fi
 
 
-if test "$WITH_PYTHON" = "yes"; then
-
-pkg_failed=no
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for PYGTK" >&5
-$as_echo_n "checking for PYGTK... " >&6; }
-
-if test -n "$PYGTK_CFLAGS"; then
-    pkg_cv_PYGTK_CFLAGS="$PYGTK_CFLAGS"
- elif test -n "$PKG_CONFIG"; then
-    if test -n "$PKG_CONFIG" && \
-    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"pygtk-2.0 >= \$PYGTK_REQUIRED\""; } >&5
-  ($PKG_CONFIG --exists --print-errors "pygtk-2.0 >= $PYGTK_REQUIRED") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; then
-  pkg_cv_PYGTK_CFLAGS=`$PKG_CONFIG --cflags "pygtk-2.0 >= $PYGTK_REQUIRED" 2>/dev/null`
-		      test "x$?" != "x0" && pkg_failed=yes
-else
-  pkg_failed=yes
-fi
- else
-    pkg_failed=untried
-fi
-if test -n "$PYGTK_LIBS"; then
-    pkg_cv_PYGTK_LIBS="$PYGTK_LIBS"
- elif test -n "$PKG_CONFIG"; then
-    if test -n "$PKG_CONFIG" && \
-    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"pygtk-2.0 >= \$PYGTK_REQUIRED\""; } >&5
-  ($PKG_CONFIG --exists --print-errors "pygtk-2.0 >= $PYGTK_REQUIRED") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; then
-  pkg_cv_PYGTK_LIBS=`$PKG_CONFIG --libs "pygtk-2.0 >= $PYGTK_REQUIRED" 2>/dev/null`
-		      test "x$?" != "x0" && pkg_failed=yes
-else
-  pkg_failed=yes
-fi
- else
-    pkg_failed=untried
-fi
-
-
-
-if test $pkg_failed = yes; then
-   	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
-        _pkg_short_errors_supported=yes
-else
-        _pkg_short_errors_supported=no
-fi
-        if test $_pkg_short_errors_supported = yes; then
-	        PYGTK_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "pygtk-2.0 >= $PYGTK_REQUIRED" 2>&1`
-        else
-	        PYGTK_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "pygtk-2.0 >= $PYGTK_REQUIRED" 2>&1`
-        fi
-	# Put the nasty error message in config.log where it belongs
-	echo "$PYGTK_PKG_ERRORS" >&5
-
-	as_fn_error $? "Package requirements (pygtk-2.0 >= $PYGTK_REQUIRED) were not met:
-
-$PYGTK_PKG_ERRORS
-
-Consider adjusting the PKG_CONFIG_PATH environment variable if you
-installed software in a non-standard prefix.
-
-Alternatively, you may set the environment variables PYGTK_CFLAGS
-and PYGTK_LIBS to avoid the need to call pkg-config.
-See the pkg-config man page for more details." "$LINENO" 5
-elif test $pkg_failed = untried; then
-     	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-	{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "The pkg-config script could not be found or is too old.  Make sure it
-is in your PATH or set the PKG_CONFIG environment variable to the full
-path to pkg-config.
-
-Alternatively, you may set the environment variables PYGTK_CFLAGS
-and PYGTK_LIBS to avoid the need to call pkg-config.
-See the pkg-config man page for more details.
-
-To get pkg-config, see <http://pkg-config.freedesktop.org/>.
-See \`config.log' for more details" "$LINENO" 5; }
-else
-	PYGTK_CFLAGS=$pkg_cv_PYGTK_CFLAGS
-	PYGTK_LIBS=$pkg_cv_PYGTK_LIBS
-        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-fi
-
-
-
+# Needed for keycodemap generator
 
 
 
@@ -17427,6 +17333,101 @@ $as_echo "$am_cv_python_pyexecdir" >&6; }
 
 
 
+if test "$WITH_PYTHON" = "yes"; then
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for PYGTK" >&5
+$as_echo_n "checking for PYGTK... " >&6; }
+
+if test -n "$PYGTK_CFLAGS"; then
+    pkg_cv_PYGTK_CFLAGS="$PYGTK_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"pygtk-2.0 >= \$PYGTK_REQUIRED\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "pygtk-2.0 >= $PYGTK_REQUIRED") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_PYGTK_CFLAGS=`$PKG_CONFIG --cflags "pygtk-2.0 >= $PYGTK_REQUIRED" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+if test -n "$PYGTK_LIBS"; then
+    pkg_cv_PYGTK_LIBS="$PYGTK_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"pygtk-2.0 >= \$PYGTK_REQUIRED\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "pygtk-2.0 >= $PYGTK_REQUIRED") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_PYGTK_LIBS=`$PKG_CONFIG --libs "pygtk-2.0 >= $PYGTK_REQUIRED" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+   	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
+else
+        _pkg_short_errors_supported=no
+fi
+        if test $_pkg_short_errors_supported = yes; then
+	        PYGTK_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "pygtk-2.0 >= $PYGTK_REQUIRED" 2>&1`
+        else
+	        PYGTK_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "pygtk-2.0 >= $PYGTK_REQUIRED" 2>&1`
+        fi
+	# Put the nasty error message in config.log where it belongs
+	echo "$PYGTK_PKG_ERRORS" >&5
+
+	as_fn_error $? "Package requirements (pygtk-2.0 >= $PYGTK_REQUIRED) were not met:
+
+$PYGTK_PKG_ERRORS
+
+Consider adjusting the PKG_CONFIG_PATH environment variable if you
+installed software in a non-standard prefix.
+
+Alternatively, you may set the environment variables PYGTK_CFLAGS
+and PYGTK_LIBS to avoid the need to call pkg-config.
+See the pkg-config man page for more details." "$LINENO" 5
+elif test $pkg_failed = untried; then
+     	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+	{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "The pkg-config script could not be found or is too old.  Make sure it
+is in your PATH or set the PKG_CONFIG environment variable to the full
+path to pkg-config.
+
+Alternatively, you may set the environment variables PYGTK_CFLAGS
+and PYGTK_LIBS to avoid the need to call pkg-config.
+See the pkg-config man page for more details.
+
+To get pkg-config, see <http://pkg-config.freedesktop.org/>.
+See \`config.log' for more details" "$LINENO" 5; }
+else
+	PYGTK_CFLAGS=$pkg_cv_PYGTK_CFLAGS
+	PYGTK_LIBS=$pkg_cv_PYGTK_LIBS
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+fi
+
+
+
   { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $PYTHON version >= $PYTHON_REQUIRED" >&5
 $as_echo_n "checking whether $PYTHON version >= $PYTHON_REQUIRED... " >&6; }
   HAVE_PYTHON_REQUIRED=no
@@ -17741,20 +17742,6 @@ else
 fi
 
 
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for Text::CSV Perl module" >&5
-$as_echo_n "checking for Text::CSV Perl module... " >&6; }
-perl -MText::CSV -e "" >/dev/null 2>&1
-if test $? -ne 0 ; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5
-$as_echo "not found" >&6; }
-  if test ! -e "$srcdir/src/vncdisplaykeymap_osx2rfb.c"; then
-    as_fn_error $? "Text::CSV Perl module is required to compile this package" "$LINENO" 5
-  fi
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5
-$as_echo "found" >&6; }
-fi
-
 ac_config_files="$ac_config_files Makefile src/Makefile tools/Makefile examples/Makefile po/Makefile.in vapi/Makefile gvnc-1.0.pc gvncpulse-1.0.pc gtk-vnc-1.0.pc gtk-vnc-2.0.pc gtk-vnc.spec mingw-gtk-vnc.spec"
 
 
@@ -18340,7 +18327,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by gtk-vnc $as_me 0.6.0, which was
+This file was extended by gtk-vnc $as_me 0.7.1, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -18411,7 +18398,7 @@ _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-gtk-vnc config.status 0.6.0
+gtk-vnc config.status 0.7.1
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
diff --git a/configure.ac b/configure.ac
index a208501..bebbe46 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2,7 +2,7 @@
 
 AC_PREREQ(2.63)
 
-AC_INIT([gtk-vnc],[0.6.0],[https://bugzilla.gnome.org/enter_bug.cgi?product=gtk-vnc],[gtk-vnc],[http://live.gnome.org/gtk-vnc/])
+AC_INIT([gtk-vnc],[0.7.1],[https://bugzilla.gnome.org/enter_bug.cgi?product=gtk-vnc],[gtk-vnc],[http://live.gnome.org/gtk-vnc/])
 AC_CONFIG_SRCDIR([src/vncconnection.c])
 AC_CONFIG_AUX_DIR([build-aux])
 AC_CONFIG_HEADERS([config.h])
@@ -364,13 +364,14 @@ AC_SUBST(GTHREAD_LIBS)
 AC_DEFINE_UNQUOTED([WITH_UCONTEXT],[$WITH_UCONTEXT], [Whether to use ucontext coroutine impl])
 AM_CONDITIONAL(WITH_UCONTEXT, [test "$WITH_UCONTEXT" != "0"])
 
+# Needed for keycodemap generator
+AM_PATH_PYTHON
+
 if test "$WITH_PYTHON" = "yes"; then
   PKG_CHECK_MODULES(PYGTK, pygtk-2.0 >= $PYGTK_REQUIRED)
   AC_SUBST(PYGTK_CFLAGS)
   AC_SUBST(PYGTK_LIBS)
 
-  AM_PATH_PYTHON
-
   AC_MSG_CHECKING([whether $PYTHON version >= $PYTHON_REQUIRED])
   HAVE_PYTHON_REQUIRED=no
   AM_PYTHON_CHECK_VERSION([$PYTHON], [$PYTHON_REQUIRED],
@@ -435,17 +436,6 @@ if test "x$found_introspection" = "xyes" ; then
 fi
 AM_CONDITIONAL([WITH_VALA], [test "x$enable_vala" = "xyes"])
 
-AC_MSG_CHECKING([for Text::CSV Perl module])
-perl -MText::CSV -e "" >/dev/null 2>&1
-if test $? -ne 0 ; then
-  AC_MSG_RESULT([not found])
-  if test ! -e "$srcdir/src/vncdisplaykeymap_osx2rfb.c"; then
-    AC_MSG_ERROR([Text::CSV Perl module is required to compile this package])
-  fi
-else
-  AC_MSG_RESULT([found])
-fi
-
 AC_CONFIG_FILES(
   Makefile
   src/Makefile
diff --git a/examples/gvncviewer.c b/examples/gvncviewer.c
index 8dc2ab7..0af0ac3 100644
--- a/examples/gvncviewer.c
+++ b/examples/gvncviewer.c
@@ -382,6 +382,14 @@ static void do_scaling(GtkWidget *menu, GtkWidget *vncdisplay)
         vnc_display_set_scaling(VNC_DISPLAY(vncdisplay), FALSE);
 }
 
+static void do_smoothing(GtkWidget *menu, GtkWidget *vncdisplay)
+{
+    if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menu)))
+        vnc_display_set_smoothing(VNC_DISPLAY(vncdisplay), TRUE);
+    else
+        vnc_display_set_smoothing(VNC_DISPLAY(vncdisplay), FALSE);
+}
+
 static void dialog_update_keysyms(GtkWidget *window, guint *keysyms, guint numsyms)
 {
     gchar *keys;
@@ -672,6 +680,7 @@ int main(int argc, char **argv)
     GtkWidget *cab;
     GtkWidget *fullscreen;
     GtkWidget *scaling;
+    GtkWidget *smoothing;
     GtkWidget *showgrabkeydlg;
     const char *help_msg = "Run 'gvncviewer --help' to see a full list of available command line options";
     GSList *accels;
@@ -749,9 +758,12 @@ int main(int argc, char **argv)
 
     fullscreen = gtk_check_menu_item_new_with_mnemonic("_Full Screen");
     scaling = gtk_check_menu_item_new_with_mnemonic("Scaled display");
+    smoothing = gtk_check_menu_item_new_with_mnemonic("Smooth scaling");
+    gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(smoothing), TRUE);
 
     gtk_menu_shell_append(GTK_MENU_SHELL(submenu), fullscreen);
     gtk_menu_shell_append(GTK_MENU_SHELL(submenu), scaling);
+    gtk_menu_shell_append(GTK_MENU_SHELL(submenu), smoothing);
 
     gtk_menu_item_set_submenu(GTK_MENU_ITEM(view), submenu);
 
@@ -885,6 +897,8 @@ int main(int argc, char **argv)
                      G_CALLBACK(do_fullscreen), window);
     g_signal_connect(scaling, "toggled",
                      G_CALLBACK(do_scaling), vnc);
+    g_signal_connect(smoothing, "toggled",
+                     G_CALLBACK(do_smoothing), vnc);
 #if WITH_LIBVIEW
     g_signal_connect(window, "window-state-event",
                      G_CALLBACK(window_state_event), layout);
diff --git a/gtk-vnc.spec b/gtk-vnc.spec
index 043f709..4c4f03b 100644
--- a/gtk-vnc.spec
+++ b/gtk-vnc.spec
@@ -30,13 +30,13 @@
 
 Summary: A GTK2 widget for VNC clients
 Name: gtk-vnc
-Version: 0.6.0
+Version: 0.7.1
 Release: 1%{?dist}%{?extra_release}
 License: LGPLv2+
 Group: Development/Libraries
 Source: http://ftp.gnome.org/pub/GNOME/sources/%{name}/0.5/%{name}-%{version}.tar.xz
 BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
-URL: http://live.gnome.org/gtk-vnc
+URL: https://wiki.gnome.org/Projects/gtk-vnc
 Requires: gvnc = %{version}-%{release}
 BuildRequires: gtk2-devel >= 2.14
 BuildRequires: pygtk2-devel python-devel zlib-devel
@@ -73,7 +73,7 @@ Libraries, includes, etc. to compile with the gtk-vnc library
 %package python
 Summary: Python bindings for the gtk-vnc library
 Group: Development/Libraries
-Requires: %{name} = %{version}
+Requires: %{name} = %{version}-%{release}
 
 %description python
 gtk-vnc is a VNC viewer widget for GTK2. It is built using coroutines
@@ -83,6 +83,7 @@ A module allowing use of the GTK-VNC widget from python
 
 %package -n gvnc
 Summary: A GObject for VNC connections
+Group: Development/Libraries
 
 %description -n gvnc
 gvnc is a GObject for managing a VNC connection. It provides all the
@@ -104,6 +105,8 @@ Libraries, includes, etc. to compile with the gvnc library
 
 %package -n gvncpulse
 Summary: A Pulse Audio bridge for VNC connections
+Group: Development/Libraries
+Requires: gvnc = %{version}-%{release}
 
 %description -n gvncpulse
 gvncpulse is a bridge to the Pulse Audio system for VNC.
@@ -126,6 +129,7 @@ Libraries, includes, etc. to compile with the gvnc library
 %package -n gvnc-tools
 Summary: Command line VNC tools
 Group: Applications/Internet
+Requires: gvnc = %{version}-%{release}
 
 %description -n gvnc-tools
 Provides useful command line utilities for interacting with
@@ -255,6 +259,7 @@ rm -fr %{buildroot}
 %{_libdir}/girepository-1.0/GVnc-1.0.typelib
 %endif
 %if %{with_vala}
+%{_datadir}/vala/vapi/gvnc-1.0.deps
 %{_datadir}/vala/vapi/gvnc-1.0.vapi
 %endif
 
@@ -275,6 +280,7 @@ rm -fr %{buildroot}
 %{_libdir}/girepository-1.0/GVncPulse-1.0.typelib
 %endif
 %if %{with_vala}
+%{_datadir}/vala/vapi/gvncpulse-1.0.deps
 %{_datadir}/vala/vapi/gvncpulse-1.0.vapi
 %endif
 
diff --git a/gtk-vnc.spec.in b/gtk-vnc.spec.in
index cd149d9..5b22c25 100644
--- a/gtk-vnc.spec.in
+++ b/gtk-vnc.spec.in
@@ -36,7 +36,7 @@ License: LGPLv2+
 Group: Development/Libraries
 Source: http://ftp.gnome.org/pub/GNOME/sources/%{name}/0.5/%{name}-%{version}.tar.xz
 BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
-URL: http://live.gnome.org/gtk-vnc
+URL: https://wiki.gnome.org/Projects/gtk-vnc
 Requires: gvnc = %{version}-%{release}
 BuildRequires: gtk2-devel >= 2.14
 BuildRequires: pygtk2-devel python-devel zlib-devel
@@ -73,7 +73,7 @@ Libraries, includes, etc. to compile with the gtk-vnc library
 %package python
 Summary: Python bindings for the gtk-vnc library
 Group: Development/Libraries
-Requires: %{name} = %{version}
+Requires: %{name} = %{version}-%{release}
 
 %description python
 gtk-vnc is a VNC viewer widget for GTK2. It is built using coroutines
@@ -83,6 +83,7 @@ A module allowing use of the GTK-VNC widget from python
 
 %package -n gvnc
 Summary: A GObject for VNC connections
+Group: Development/Libraries
 
 %description -n gvnc
 gvnc is a GObject for managing a VNC connection. It provides all the
@@ -104,6 +105,8 @@ Libraries, includes, etc. to compile with the gvnc library
 
 %package -n gvncpulse
 Summary: A Pulse Audio bridge for VNC connections
+Group: Development/Libraries
+Requires: gvnc = %{version}-%{release}
 
 %description -n gvncpulse
 gvncpulse is a bridge to the Pulse Audio system for VNC.
@@ -126,6 +129,7 @@ Libraries, includes, etc. to compile with the gvnc library
 %package -n gvnc-tools
 Summary: Command line VNC tools
 Group: Applications/Internet
+Requires: gvnc = %{version}-%{release}
 
 %description -n gvnc-tools
 Provides useful command line utilities for interacting with
@@ -255,6 +259,7 @@ rm -fr %{buildroot}
 %{_libdir}/girepository-1.0/GVnc-1.0.typelib
 %endif
 %if %{with_vala}
+%{_datadir}/vala/vapi/gvnc-1.0.deps
 %{_datadir}/vala/vapi/gvnc-1.0.vapi
 %endif
 
@@ -275,6 +280,7 @@ rm -fr %{buildroot}
 %{_libdir}/girepository-1.0/GVncPulse-1.0.typelib
 %endif
 %if %{with_vala}
+%{_datadir}/vala/vapi/gvncpulse-1.0.deps
 %{_datadir}/vala/vapi/gvncpulse-1.0.vapi
 %endif
 
diff --git a/po/LINGUAS b/po/LINGUAS
index 321b319..cee69b7 100644
--- a/po/LINGUAS
+++ b/po/LINGUAS
@@ -11,6 +11,7 @@ eo
 es
 eu
 fr
+fur
 gd
 gl
 guc
diff --git a/po/fur.po b/po/fur.po
new file mode 100644
index 0000000..53840b1
--- /dev/null
+++ b/po/fur.po
@@ -0,0 +1,31 @@
+# Friulian translation for gtk-vnc.
+# Copyright (C) 2017 gtk-vnc's COPYRIGHT HOLDER
+# This file is distributed under the same license as the gtk-vnc package.
+# Fabio Tomat <f.t.public at gmail.com>, 2017.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: gtk-vnc master\n"
+"Report-Msgid-Bugs-To: https://bugzilla.gnome.org/enter_bug.cgi?product=gtk-"
+"vnc&keywords=I18N+L10N&component=general\n"
+"POT-Creation-Date: 2017-02-22 21:37+0000\n"
+"PO-Revision-Date: 2017-03-05 15:21+0100\n"
+"Language-Team: Friulian <fur at li.org>\n"
+"Language: fur\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Last-Translator: Fabio Tomat <f.t.public at gmail.com>\n"
+"X-Generator: Poedit 1.8.12\n"
+
+#: ../src/vncdisplay.c:182
+msgid "Enables debug output"
+msgstr "Al abilite la jessude di debug"
+
+#: ../src/vncdisplay.c:3241
+msgid "GTK-VNC Options:"
+msgstr "Opzions GTK-VNC:"
+
+#: ../src/vncdisplay.c:3241
+msgid "Show GTK-VNC Options"
+msgstr "Mostre lis Opzions di GTK-VNC"
diff --git a/po/pl.po b/po/pl.po
index 85d32e9..78ad7fd 100644
--- a/po/pl.po
+++ b/po/pl.po
@@ -1,36 +1,32 @@
-# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
-# Aviary.pl
-# Jeśli masz jakiekolwiek uwagi odnoszące się do tłumaczenia lub chcesz
-# pomóc w jego rozwijaniu i pielęgnowaniu, napisz do nas:
-# gnomepl at aviary.pl
-# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+# Polish translation for gtk-vnc.
+# Copyright © 2009-2012 the gtk-vnc authors.
+# This file is distributed under the same license as the gtk-vnc package.
 # Piotr Drąg <piotrdrag at gmail.com>, 2009-2012.
-# Aviary.pl <gnomepl at aviary.pl>, 2009-2012.
+# Aviary.pl <community-poland at mozilla.org>, 2009-2012.
+#
 msgid ""
 msgstr ""
 "Project-Id-Version: gtk-vnc\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2012-09-04 15:45+0200\n"
+"POT-Creation-Date: 2016-08-18 22:11+0200\n"
 "PO-Revision-Date: 2012-09-04 15:48+0200\n"
 "Last-Translator: Piotr Drąg <piotrdrag at gmail.com>\n"
-"Language-Team: Polish <gnomepl at aviary.pl>\n"
+"Language-Team: Polish <community-poland at mozilla.org>\n"
 "Language: pl\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
 "|| n%100>=20) ? 1 : 2);\n"
-"X-Poedit-Language: Polish\n"
-"X-Poedit-Country: Poland\n"
 
-#: ../src/vncdisplay.c:166
+#: ../src/vncdisplay.c:180
 msgid "Enables debug output"
 msgstr "Włącza wyjście debugowania"
 
-#: ../src/vncdisplay.c:2473
+#: ../src/vncdisplay.c:3142
 msgid "GTK-VNC Options:"
 msgstr "Opcje biblioteki GTK-VNC:"
 
-#: ../src/vncdisplay.c:2473
+#: ../src/vncdisplay.c:3142
 msgid "Show GTK-VNC Options"
 msgstr "Wyświetla opcje biblioteki GTK-VNC"
diff --git a/src/Makefile.am b/src/Makefile.am
index 996f5e0..ef2295e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,6 +1,10 @@
 
 EXTRA_DIST = libgvnc_sym.version libgvncpulse_sym.version libgtk-vnc_sym.version vncmarshal.txt
 
+TESTS = vncconnectiontest
+
+noinst_PROGRAMS = $(TESTS)
+
 lib_LTLIBRARIES = libgvnc-1.0.la
 
 BUILT_SOURCES =
@@ -197,9 +201,10 @@ nodist_libgtk_vnc_2_0_la_SOURCES = $(nodist_gtk_vnc_SOURCES)
 nodist_libgtk_vnc_2_0_la_HEADERS = $(nodist_gtk_vnc_HDRS)
 endif
 
-EXTRA_DIST += keymap-gen.pl keymaps.csv
+KEYMAP_GEN = keycodemapdb/tools/keymap-gen
+KEYMAP_CSV = keycodemapdb/data/keymaps.csv
 
-KEYMAP_GEN = $(srcdir)/keymap-gen.pl
+EXTRA_DIST += $(KEYMAP_CSV) $(KEYMAP_GEN)
 
 KEYMAPS = \
 	vncdisplaykeymap_xorgevdev2rfb.c \
@@ -210,35 +215,32 @@ KEYMAPS = \
 	vncdisplaykeymap_win322rfb.c \
 	vncdisplaykeymap_x112rfb.c
 
-$(KEYMAPS): $(KEYMAP_GEN) keymaps.csv
+$(KEYMAPS): $(srcdir)/$(KEYMAP_GEN) $(srcdir)/$(KEYMAP_CSV)
 BUILT_SOURCES += $(KEYMAPS)
-
-# Avoid need for perl(Text::CSV) by end users
-EXTRA_DIST += $(KEYMAPS)
-MAINTAINERCLEANFILES = $(KEYMAPS)
+CLEANFILES = $(KEYMAPS)
 
 vncdisplaykeymap.c: $(KEYMAPS)
 
 vncdisplaykeymap_xorgevdev2rfb.c:
-	$(AM_V_GEN)$(PERL) $(KEYMAP_GEN) $(srcdir)/keymaps.csv xorgevdev rfb > $@ || rm $@
+	$(AM_V_GEN)$(PYTHON) $(srcdir)/$(KEYMAP_GEN) --lang glib2 --varname keymap_xorgevdev2rfb code-map $(srcdir)/$(KEYMAP_CSV) xorgevdev rfb > $@ || rm $@
 
 vncdisplaykeymap_xorgkbd2rfb.c:
-	$(AM_V_GEN)$(PERL) $(KEYMAP_GEN) $(srcdir)/keymaps.csv xorgkbd rfb > $@ || rm $@
+	$(AM_V_GEN)$(PYTHON) $(srcdir)/$(KEYMAP_GEN) --lang glib2 --varname keymap_xorgkbd2rfb code-map $(srcdir)/$(KEYMAP_CSV) xorgkbd rfb > $@ || rm $@
 
 vncdisplaykeymap_xorgxquartz2rfb.c:
-	$(AM_V_GEN)$(PERL) $(KEYMAP_GEN) $(srcdir)/keymaps.csv xorgxquartz rfb > $@ || rm $@
+	$(AM_V_GEN)$(PYTHON) $(srcdir)/$(KEYMAP_GEN) --lang glib2 --varname keymap_xorgxquartz2rfb code-map $(srcdir)/$(KEYMAP_CSV) xorgxquartz rfb > $@ || rm $@
 
 vncdisplaykeymap_xorgxwin2rfb.c:
-	$(AM_V_GEN)$(PERL) $(KEYMAP_GEN) $(srcdir)/keymaps.csv xorgxwin rfb > $@ || rm $@
+	$(AM_V_GEN)$(PYTHON) $(srcdir)/$(KEYMAP_GEN) --lang glib2 --varname keymap_xorgxwin2rfb code-map $(srcdir)/$(KEYMAP_CSV) xorgxwin rfb > $@ || rm $@
 
 vncdisplaykeymap_osx2rfb.c:
-	$(AM_V_GEN)$(PERL) $(KEYMAP_GEN) $(srcdir)/keymaps.csv osx rfb > $@ || rm $@
+	$(AM_V_GEN)$(PYTHON) $(srcdir)/$(KEYMAP_GEN) --lang glib2 --varname keymap_osx2rfb code-map $(srcdir)/$(KEYMAP_CSV) osx rfb > $@ || rm $@
 
 vncdisplaykeymap_win322rfb.c:
-	$(AM_V_GEN)$(PERL) $(KEYMAP_GEN) $(srcdir)/keymaps.csv win32 rfb > $@ || rm $@
+	$(AM_V_GEN)$(PYTHON) $(srcdir)/$(KEYMAP_GEN) --lang glib2 --varname keymap_win322rfb code-map $(srcdir)/$(KEYMAP_CSV) win32 rfb > $@ || rm $@
 
 vncdisplaykeymap_x112rfb.c:
-	$(AM_V_GEN)$(PERL) $(KEYMAP_GEN) $(srcdir)/keymaps.csv x11 rfb > $@ || rm $@
+	$(AM_V_GEN)$(PYTHON) $(srcdir)/$(KEYMAP_GEN) --lang glib2 --varname keymap_x112rfb code-map $(srcdir)/$(KEYMAP_CSV) x11 rfb > $@ || rm $@
 
 vncdisplayenums.c: vncdisplay.h
 	$(AM_V_GEN)glib-mkenums    --fhead "#include <glib-object.h>\n" \
@@ -310,7 +312,11 @@ ENUM_FILES = \
 
 BUILT_SOURCES += $(MARSHAL_FILES) $(ENUM_FILES)
 
-CLEANFILES = $(MARSHAL_FILES) $(ENUM_FILES)
+CLEANFILES += $(MARSHAL_FILES) $(ENUM_FILES)
+
+vncconnectiontest_SOURCES = vncconnectiontest.c
+vncconnectiontest_CFLAGS = $(GOBJECT_CFLAGS) $(GIO_CFLAGS)
+vncconnectiontest_LDADD = libgvnc-1.0.la $(GOBJECT_LIBS) $(GIO_LIBS)
 
 if WITH_PYTHON
 pyexec_LTLIBRARIES = gtkvnc.la
@@ -395,7 +401,7 @@ if HAVE_PULSEAUDIO
 GVncPulse-1.0.gir: libgvncpulse-1.0.la GVnc-1.0.gir
 GVncPulse_1_0_gir_INCLUDES = GObject-2.0
 GVncPulse_1_0_gir_PACKAGES = gobject-2.0 libpulse-simple
-GVncPulse_1_0_gir_EXPORT_PACKAGES = gvnc-1.0
+GVncPulse_1_0_gir_EXPORT_PACKAGES = gvncpulse-1.0
 GVncPulse_1_0_gir_LIBS = libgvnc-1.0.la libgvncpulse-1.0.la
 GVncPulse_1_0_gir_FILES = $(GVNCPULSE_INTROSPECTION_SRCS)
 GVncPulse_1_0_gir_CFLAGS = $(libgvnc_1_0_la_CFLAGS) $(libgvncpulse_1_0_la_CFLAGS) -I$(srcdir)
diff --git a/src/Makefile.in b/src/Makefile.in
index 40d60e6..14c224c 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -16,6 +16,7 @@
 
 
 
+
 VPATH = @srcdir@
 am__is_gnu_make = { \
   if test -z '$(MAKELEVEL)'; then \
@@ -90,6 +91,8 @@ PRE_UNINSTALL = :
 POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
+TESTS = vncconnectiontest$(EXEEXT)
+noinst_PROGRAMS = $(am__EXEEXT_1)
 @USE_VERSION_DEFS_TRUE at am__append_1 = $(GVNC_VERSION_FILE) $(GTK_VNC_VERSION_FILE) $(GVNCPULSE_VERSION_FILE)
 @HAVE_PULSEAUDIO_TRUE at am__append_2 = libgvncpulse-1.0.la
 @WITH_UCONTEXT_TRUE at am__append_3 = continuation.h continuation.c coroutine_ucontext.c
@@ -285,6 +288,17 @@ libgvncpulse_1_0_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
 	$(libgvncpulse_1_0_la_CFLAGS) $(CFLAGS) \
 	$(libgvncpulse_1_0_la_LDFLAGS) $(LDFLAGS) -o $@
 @HAVE_PULSEAUDIO_TRUE at am_libgvncpulse_1_0_la_rpath = -rpath $(libdir)
+am__EXEEXT_1 = vncconnectiontest$(EXEEXT)
+PROGRAMS = $(noinst_PROGRAMS)
+am_vncconnectiontest_OBJECTS =  \
+	vncconnectiontest-vncconnectiontest.$(OBJEXT)
+vncconnectiontest_OBJECTS = $(am_vncconnectiontest_OBJECTS)
+vncconnectiontest_DEPENDENCIES = libgvnc-1.0.la $(am__DEPENDENCIES_1) \
+	$(am__DEPENDENCIES_1)
+vncconnectiontest_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+	$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+	$(vncconnectiontest_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \
+	-o $@
 AM_V_P = $(am__v_P_ at AM_V@)
 am__v_P_ = $(am__v_P_ at AM_DEFAULT_V@)
 am__v_P_0 = false
@@ -325,12 +339,13 @@ SOURCES = $(gtkvnc_la_SOURCES) $(nodist_gtkvnc_la_SOURCES) \
 	$(libgtk_vnc_2_0_la_SOURCES) \
 	$(nodist_libgtk_vnc_2_0_la_SOURCES) $(libgvnc_1_0_la_SOURCES) \
 	$(nodist_libgvnc_1_0_la_SOURCES) \
-	$(libgvncpulse_1_0_la_SOURCES)
+	$(libgvncpulse_1_0_la_SOURCES) $(vncconnectiontest_SOURCES)
 DIST_SOURCES = $(am__gtkvnc_la_SOURCES_DIST) \
 	$(am__libgtk_vnc_1_0_la_SOURCES_DIST) \
 	$(am__libgtk_vnc_2_0_la_SOURCES_DIST) \
 	$(am__libgvnc_1_0_la_SOURCES_DIST) \
-	$(am__libgvncpulse_1_0_la_SOURCES_DIST)
+	$(am__libgvncpulse_1_0_la_SOURCES_DIST) \
+	$(vncconnectiontest_SOURCES)
 am__can_run_installinfo = \
   case $$AM_UPDATE_INFO_DIR in \
     n|no|NO) false;; \
@@ -366,8 +381,186 @@ am__define_uniq_tagged_files = \
   done | $(am__uniquify_input)`
 ETAGS = etags
 CTAGS = ctags
+am__tty_colors_dummy = \
+  mgn= red= grn= lgn= blu= brg= std=; \
+  am__color_tests=no
+am__tty_colors = { \
+  $(am__tty_colors_dummy); \
+  if test "X$(AM_COLOR_TESTS)" = Xno; then \
+    am__color_tests=no; \
+  elif test "X$(AM_COLOR_TESTS)" = Xalways; then \
+    am__color_tests=yes; \
+  elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \
+    am__color_tests=yes; \
+  fi; \
+  if test $$am__color_tests = yes; then \
+    red=''; \
+    grn=''; \
+    lgn=''; \
+    blu=''; \
+    mgn=''; \
+    brg=''; \
+    std=''; \
+  fi; \
+}
+am__recheck_rx = ^[ 	]*:recheck:[ 	]*
+am__global_test_result_rx = ^[ 	]*:global-test-result:[ 	]*
+am__copy_in_global_log_rx = ^[ 	]*:copy-in-global-log:[ 	]*
+# A command that, given a newline-separated list of test names on the
+# standard input, print the name of the tests that are to be re-run
+# upon "make recheck".
+am__list_recheck_tests = $(AWK) '{ \
+  recheck = 1; \
+  while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+    { \
+      if (rc < 0) \
+        { \
+          if ((getline line2 < ($$0 ".log")) < 0) \
+	    recheck = 0; \
+          break; \
+        } \
+      else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \
+        { \
+          recheck = 0; \
+          break; \
+        } \
+      else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \
+        { \
+          break; \
+        } \
+    }; \
+  if (recheck) \
+    print $$0; \
+  close ($$0 ".trs"); \
+  close ($$0 ".log"); \
+}'
+# A command that, given a newline-separated list of test names on the
+# standard input, create the global log from their .trs and .log files.
+am__create_global_log = $(AWK) ' \
+function fatal(msg) \
+{ \
+  print "fatal: making $@: " msg | "cat >&2"; \
+  exit 1; \
+} \
+function rst_section(header) \
+{ \
+  print header; \
+  len = length(header); \
+  for (i = 1; i <= len; i = i + 1) \
+    printf "="; \
+  printf "\n\n"; \
+} \
+{ \
+  copy_in_global_log = 1; \
+  global_test_result = "RUN"; \
+  while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+    { \
+      if (rc < 0) \
+         fatal("failed to read from " $$0 ".trs"); \
+      if (line ~ /$(am__global_test_result_rx)/) \
+        { \
+          sub("$(am__global_test_result_rx)", "", line); \
+          sub("[ 	]*$$", "", line); \
+          global_test_result = line; \
+        } \
+      else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \
+        copy_in_global_log = 0; \
+    }; \
+  if (copy_in_global_log) \
+    { \
+      rst_section(global_test_result ": " $$0); \
+      while ((rc = (getline line < ($$0 ".log"))) != 0) \
+      { \
+        if (rc < 0) \
+          fatal("failed to read from " $$0 ".log"); \
+        print line; \
+      }; \
+      printf "\n"; \
+    }; \
+  close ($$0 ".trs"); \
+  close ($$0 ".log"); \
+}'
+# Restructured Text title.
+am__rst_title = { sed 's/.*/   &   /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; }
+# Solaris 10 'make', and several other traditional 'make' implementations,
+# pass "-e" to $(SHELL), and POSIX 2008 even requires this.  Work around it
+# by disabling -e (using the XSI extension "set +e") if it's set.
+am__sh_e_setup = case $$- in *e*) set +e;; esac
+# Default flags passed to test drivers.
+am__common_driver_flags = \
+  --color-tests "$$am__color_tests" \
+  --enable-hard-errors "$$am__enable_hard_errors" \
+  --expect-failure "$$am__expect_failure"
+# To be inserted before the command running the test.  Creates the
+# directory for the log if needed.  Stores in $dir the directory
+# containing $f, in $tst the test, in $log the log.  Executes the
+# developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and
+# passes TESTS_ENVIRONMENT.  Set up options for the wrapper that
+# will run the test scripts (or their associated LOG_COMPILER, if
+# thy have one).
+am__check_pre = \
+$(am__sh_e_setup);					\
+$(am__vpath_adj_setup) $(am__vpath_adj)			\
+$(am__tty_colors);					\
+srcdir=$(srcdir); export srcdir;			\
+case "$@" in						\
+  */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;;	\
+    *) am__odir=.;; 					\
+esac;							\
+test "x$$am__odir" = x"." || test -d "$$am__odir" 	\
+  || $(MKDIR_P) "$$am__odir" || exit $$?;		\
+if test -f "./$$f"; then dir=./;			\
+elif test -f "$$f"; then dir=;				\
+else dir="$(srcdir)/"; fi;				\
+tst=$$dir$$f; log='$@'; 				\
+if test -n '$(DISABLE_HARD_ERRORS)'; then		\
+  am__enable_hard_errors=no; 				\
+else							\
+  am__enable_hard_errors=yes; 				\
+fi; 							\
+case " $(XFAIL_TESTS) " in				\
+  *[\ \	]$$f[\ \	]* | *[\ \	]$$dir$$f[\ \	]*) \
+    am__expect_failure=yes;;				\
+  *)							\
+    am__expect_failure=no;;				\
+esac; 							\
+$(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT)
+# A shell command to get the names of the tests scripts with any registered
+# extension removed (i.e., equivalently, the names of the test logs, with
+# the '.log' extension removed).  The result is saved in the shell variable
+# '$bases'.  This honors runtime overriding of TESTS and TEST_LOGS.  Sadly,
+# we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)",
+# since that might cause problem with VPATH rewrites for suffix-less tests.
+# See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'.
+am__set_TESTS_bases = \
+  bases='$(TEST_LOGS)'; \
+  bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \
+  bases=`echo $$bases`
+RECHECK_LOGS = $(TEST_LOGS)
+AM_RECURSIVE_TARGETS = check recheck
+TEST_SUITE_LOG = test-suite.log
+TEST_EXTENSIONS = @EXEEXT@ .test
+LOG_DRIVER = $(SHELL) $(top_srcdir)/build-aux/test-driver
+LOG_COMPILE = $(LOG_COMPILER) $(AM_LOG_FLAGS) $(LOG_FLAGS)
+am__set_b = \
+  case '$@' in \
+    */*) \
+      case '$*' in \
+        */*) b='$*';; \
+          *) b=`echo '$@' | sed 's/\.log$$//'`; \
+       esac;; \
+    *) \
+      b='$*';; \
+  esac
+am__test_logs1 = $(TESTS:=.log)
+am__test_logs2 = $(am__test_logs1:@EXEEXT at .log=.log)
+TEST_LOGS = $(am__test_logs2:.test.log=.log)
+TEST_LOG_DRIVER = $(SHELL) $(top_srcdir)/build-aux/test-driver
+TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \
+	$(TEST_LOG_FLAGS)
 am__DIST_COMMON = $(srcdir)/Makefile.in \
-	$(top_srcdir)/build-aux/depcomp
+	$(top_srcdir)/build-aux/depcomp \
+	$(top_srcdir)/build-aux/test-driver
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 ALL_LINGUAS = @ALL_LINGUAS@
@@ -581,12 +774,10 @@ target_alias = @target_alias@
 top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
-
-# Avoid need for perl(Text::CSV) by end users
 EXTRA_DIST = libgvnc_sym.version libgvncpulse_sym.version \
 	libgtk-vnc_sym.version vncmarshal.txt $(am__append_4) \
-	$(am__append_6) $(am__append_8) keymap-gen.pl keymaps.csv \
-	$(KEYMAPS) $(am__append_13) $(am__append_14)
+	$(am__append_6) $(am__append_8) $(KEYMAP_CSV) $(KEYMAP_GEN) \
+	$(am__append_13) $(am__append_14)
 lib_LTLIBRARIES = libgvnc-1.0.la $(am__append_2) $(am__append_9) \
 	$(am__append_10)
 BUILT_SOURCES = $(am__append_1) $(KEYMAPS) $(MARSHAL_FILES) \
@@ -733,7 +924,8 @@ gtk_vnc_LDFLAGS = \
 @HAVE_GTK_2_FALSE at libgtk_vnc_2_0_la_HEADERS = $(gtk_vnc_HDRS)
 @HAVE_GTK_2_FALSE at nodist_libgtk_vnc_2_0_la_SOURCES = $(nodist_gtk_vnc_SOURCES)
 @HAVE_GTK_2_FALSE at nodist_libgtk_vnc_2_0_la_HEADERS = $(nodist_gtk_vnc_HDRS)
-KEYMAP_GEN = $(srcdir)/keymap-gen.pl
+KEYMAP_GEN = keycodemapdb/tools/keymap-gen
+KEYMAP_CSV = keycodemapdb/data/keymaps.csv
 KEYMAPS = \
 	vncdisplaykeymap_xorgevdev2rfb.c \
 	vncdisplaykeymap_xorgkbd2rfb.c \
@@ -743,14 +935,16 @@ KEYMAPS = \
 	vncdisplaykeymap_win322rfb.c \
 	vncdisplaykeymap_x112rfb.c
 
-MAINTAINERCLEANFILES = $(KEYMAPS)
+CLEANFILES = $(KEYMAPS) $(MARSHAL_FILES) $(ENUM_FILES) \
+	$(am__append_12) $(am__append_20)
 MARSHAL_FILES = vncmarshal.c vncmarshal.h
 ENUM_FILES = \
 	vncdisplayenums.h vncdisplayenums.c \
 	vncconnectionenums.h vncconnectionenums.c
 
-CLEANFILES = $(MARSHAL_FILES) $(ENUM_FILES) $(am__append_12) \
-	$(am__append_20)
+vncconnectiontest_SOURCES = vncconnectiontest.c
+vncconnectiontest_CFLAGS = $(GOBJECT_CFLAGS) $(GIO_CFLAGS)
+vncconnectiontest_LDADD = libgvnc-1.0.la $(GOBJECT_LIBS) $(GIO_LIBS)
 @WITH_PYTHON_TRUE at pyexec_LTLIBRARIES = gtkvnc.la
 @WITH_PYTHON_TRUE at gtkvnc_la_LIBADD = libgtk-vnc-$(GTK_VNC_API_VERSION).la $(PYGTK_LIBS)
 @WITH_PYTHON_TRUE at gtkvnc_la_CFLAGS = $(GTK_CFLAGS) $(PYTHON_INCLUDES) \
@@ -808,7 +1002,7 @@ INTROSPECTION_COMPILER_ARGS = --includedir=$(top_srcdir) \
 @HAVE_INTROSPECTION_TRUE at GVnc_1_0_gir_SCANNERFLAGS = --c-include="gvnc.h"
 @HAVE_INTROSPECTION_TRUE@@HAVE_PULSEAUDIO_TRUE at GVncPulse_1_0_gir_INCLUDES = GObject-2.0
 @HAVE_INTROSPECTION_TRUE@@HAVE_PULSEAUDIO_TRUE at GVncPulse_1_0_gir_PACKAGES = gobject-2.0 libpulse-simple
- at HAVE_INTROSPECTION_TRUE@@HAVE_PULSEAUDIO_TRUE at GVncPulse_1_0_gir_EXPORT_PACKAGES = gvnc-1.0
+ at HAVE_INTROSPECTION_TRUE@@HAVE_PULSEAUDIO_TRUE at GVncPulse_1_0_gir_EXPORT_PACKAGES = gvncpulse-1.0
 @HAVE_INTROSPECTION_TRUE@@HAVE_PULSEAUDIO_TRUE at GVncPulse_1_0_gir_LIBS = libgvnc-1.0.la libgvncpulse-1.0.la
 @HAVE_INTROSPECTION_TRUE@@HAVE_PULSEAUDIO_TRUE at GVncPulse_1_0_gir_FILES = $(GVNCPULSE_INTROSPECTION_SRCS)
 @HAVE_INTROSPECTION_TRUE@@HAVE_PULSEAUDIO_TRUE at GVncPulse_1_0_gir_CFLAGS = $(libgvnc_1_0_la_CFLAGS) $(libgvncpulse_1_0_la_CFLAGS) -I$(srcdir)
@@ -841,7 +1035,7 @@ all: $(BUILT_SOURCES)
 	$(MAKE) $(AM_MAKEFLAGS) all-am
 
 .SUFFIXES:
-.SUFFIXES: .c .lo .o .obj
+.SUFFIXES: .c .lo .log .o .obj .test .test$(EXEEXT) .trs
 $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
 	@for dep in $?; do \
 	  case '$(am__configure_deps)' in \
@@ -957,6 +1151,19 @@ libgvnc-1.0.la: $(libgvnc_1_0_la_OBJECTS) $(libgvnc_1_0_la_DEPENDENCIES) $(EXTRA
 libgvncpulse-1.0.la: $(libgvncpulse_1_0_la_OBJECTS) $(libgvncpulse_1_0_la_DEPENDENCIES) $(EXTRA_libgvncpulse_1_0_la_DEPENDENCIES) 
 	$(AM_V_CCLD)$(libgvncpulse_1_0_la_LINK) $(am_libgvncpulse_1_0_la_rpath) $(libgvncpulse_1_0_la_OBJECTS) $(libgvncpulse_1_0_la_LIBADD) $(LIBS)
 
+clean-noinstPROGRAMS:
+	@list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \
+	echo " rm -f" $$list; \
+	rm -f $$list || exit $$?; \
+	test -n "$(EXEEXT)" || exit 0; \
+	list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+	echo " rm -f" $$list; \
+	rm -f $$list
+
+vncconnectiontest$(EXEEXT): $(vncconnectiontest_OBJECTS) $(vncconnectiontest_DEPENDENCIES) $(EXTRA_vncconnectiontest_DEPENDENCIES) 
+	@rm -f vncconnectiontest$(EXEEXT)
+	$(AM_V_CCLD)$(vncconnectiontest_LINK) $(vncconnectiontest_OBJECTS) $(vncconnectiontest_LDADD) $(LIBS)
+
 mostlyclean-compile:
 	-rm -f *.$(OBJEXT)
 
@@ -998,6 +1205,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libgvnc_1_0_la-vncpixelformat.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libgvnc_1_0_la-vncutil.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libgvncpulse_1_0_la-vncaudiopulse.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/vncconnectiontest-vncconnectiontest.Po at am__quote@
 
 .c.o:
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@@ -1265,6 +1473,20 @@ libgvncpulse_1_0_la-vncaudiopulse.lo: vncaudiopulse.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgvncpulse_1_0_la_CFLAGS) $(CFLAGS) -c -o libgvncpulse_1_0_la-vncaudiopulse.lo `test -f 'vncaudiopulse.c' || echo '$(srcdir)/'`vncaudiopulse.c
 
+vncconnectiontest-vncconnectiontest.o: vncconnectiontest.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(vncconnectiontest_CFLAGS) $(CFLAGS) -MT vncconnectiontest-vncconnectiontest.o -MD -MP -MF $(DEPDIR)/vncconnectiontest-vncconnectiontest.Tpo -c -o vncconnectiontest-vncconnectiontest.o `test -f 'vncconnectiontest.c' || echo '$(srcdir)/'`vncconnectiontest.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/vncconnectiontest-vncconnectiontest.Tpo $(DEPDIR)/vncconnectiontest-vncconnectiontest.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vncconnectiontest.c' object='vncconnectiontest-vncconnectiontest.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(vncconnectiontest_CFLAGS) $(CFLAGS) -c -o vncconnectiontest-vncconnectiontest.o `test -f 'vncconnectiontest.c' || echo '$(srcdir)/'`vncconnectiontest.c
+
+vncconnectiontest-vncconnectiontest.obj: vncconnectiontest.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(vncconnectiontest_CFLAGS) $(CFLAGS) -MT vncconnectiontest-vncconnectiontest.obj -MD -MP -MF $(DEPDIR)/vncconnectiontest-vncconnectiontest.Tpo -c -o vncconnectiontest-vncconnectiontest.obj `if test -f 'vncconnectiontest.c'; then $(CYGPATH_W) 'vncconnectiontest.c'; else $(CYGPATH_W) '$(srcdir)/vncconnectiontest.c'; fi`
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/vncconnectiontest-vncconnectiontest.Tpo $(DEPDIR)/vncconnectiontest-vncconnectiontest.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='vncconnectiontest.c' object='vncconnectiontest-vncconnectiontest.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(vncconnectiontest_CFLAGS) $(CFLAGS) -c -o vncconnectiontest-vncconnectiontest.obj `if test -f 'vncconnectiontest.c'; then $(CYGPATH_W) 'vncconnectiontest.c'; else $(CYGPATH_W) '$(srcdir)/vncconnectiontest.c'; fi`
+
 mostlyclean-libtool:
 	-rm -f *.lo
 
@@ -1512,6 +1734,169 @@ cscopelist-am: $(am__tagged_files)
 distclean-tags:
 	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
 
+# Recover from deleted '.trs' file; this should ensure that
+# "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create
+# both 'foo.log' and 'foo.trs'.  Break the recipe in two subshells
+# to avoid problems with "make -n".
+.log.trs:
+	rm -f $< $@
+	$(MAKE) $(AM_MAKEFLAGS) $<
+
+# Leading 'am--fnord' is there to ensure the list of targets does not
+# expand to empty, as could happen e.g. with make check TESTS=''.
+am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck)
+am--force-recheck:
+	@:
+
+$(TEST_SUITE_LOG): $(TEST_LOGS)
+	@$(am__set_TESTS_bases); \
+	am__f_ok () { test -f "$$1" && test -r "$$1"; }; \
+	redo_bases=`for i in $$bases; do \
+	              am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \
+	            done`; \
+	if test -n "$$redo_bases"; then \
+	  redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \
+	  redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \
+	  if $(am__make_dryrun); then :; else \
+	    rm -f $$redo_logs && rm -f $$redo_results || exit 1; \
+	  fi; \
+	fi; \
+	if test -n "$$am__remaking_logs"; then \
+	  echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \
+	       "recursion detected" >&2; \
+	elif test -n "$$redo_logs"; then \
+	  am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \
+	fi; \
+	if $(am__make_dryrun); then :; else \
+	  st=0;  \
+	  errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \
+	  for i in $$redo_bases; do \
+	    test -f $$i.trs && test -r $$i.trs \
+	      || { echo "$$errmsg $$i.trs" >&2; st=1; }; \
+	    test -f $$i.log && test -r $$i.log \
+	      || { echo "$$errmsg $$i.log" >&2; st=1; }; \
+	  done; \
+	  test $$st -eq 0 || exit 1; \
+	fi
+	@$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \
+	ws='[ 	]'; \
+	results=`for b in $$bases; do echo $$b.trs; done`; \
+	test -n "$$results" || results=/dev/null; \
+	all=`  grep "^$$ws*:test-result:"           $$results | wc -l`; \
+	pass=` grep "^$$ws*:test-result:$$ws*PASS"  $$results | wc -l`; \
+	fail=` grep "^$$ws*:test-result:$$ws*FAIL"  $$results | wc -l`; \
+	skip=` grep "^$$ws*:test-result:$$ws*SKIP"  $$results | wc -l`; \
+	xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \
+	xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \
+	error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \
+	if test `expr $$fail + $$xpass + $$error` -eq 0; then \
+	  success=true; \
+	else \
+	  success=false; \
+	fi; \
+	br='==================='; br=$$br$$br$$br$$br; \
+	result_count () \
+	{ \
+	    if test x"$$1" = x"--maybe-color"; then \
+	      maybe_colorize=yes; \
+	    elif test x"$$1" = x"--no-color"; then \
+	      maybe_colorize=no; \
+	    else \
+	      echo "$@: invalid 'result_count' usage" >&2; exit 4; \
+	    fi; \
+	    shift; \
+	    desc=$$1 count=$$2; \
+	    if test $$maybe_colorize = yes && test $$count -gt 0; then \
+	      color_start=$$3 color_end=$$std; \
+	    else \
+	      color_start= color_end=; \
+	    fi; \
+	    echo "$${color_start}# $$desc $$count$${color_end}"; \
+	}; \
+	create_testsuite_report () \
+	{ \
+	  result_count $$1 "TOTAL:" $$all   "$$brg"; \
+	  result_count $$1 "PASS: " $$pass  "$$grn"; \
+	  result_count $$1 "SKIP: " $$skip  "$$blu"; \
+	  result_count $$1 "XFAIL:" $$xfail "$$lgn"; \
+	  result_count $$1 "FAIL: " $$fail  "$$red"; \
+	  result_count $$1 "XPASS:" $$xpass "$$red"; \
+	  result_count $$1 "ERROR:" $$error "$$mgn"; \
+	}; \
+	{								\
+	  echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" |	\
+	    $(am__rst_title);						\
+	  create_testsuite_report --no-color;				\
+	  echo;								\
+	  echo ".. contents:: :depth: 2";				\
+	  echo;								\
+	  for b in $$bases; do echo $$b; done				\
+	    | $(am__create_global_log);					\
+	} >$(TEST_SUITE_LOG).tmp || exit 1;				\
+	mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG);			\
+	if $$success; then						\
+	  col="$$grn";							\
+	 else								\
+	  col="$$red";							\
+	  test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG);		\
+	fi;								\
+	echo "$${col}$$br$${std}"; 					\
+	echo "$${col}Testsuite summary for $(PACKAGE_STRING)$${std}";	\
+	echo "$${col}$$br$${std}"; 					\
+	create_testsuite_report --maybe-color;				\
+	echo "$$col$$br$$std";						\
+	if $$success; then :; else					\
+	  echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}";		\
+	  if test -n "$(PACKAGE_BUGREPORT)"; then			\
+	    echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}";	\
+	  fi;								\
+	  echo "$$col$$br$$std";					\
+	fi;								\
+	$$success || exit 1
+
+check-TESTS:
+	@list='$(RECHECK_LOGS)';           test -z "$$list" || rm -f $$list
+	@list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list
+	@test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+	@set +e; $(am__set_TESTS_bases); \
+	log_list=`for i in $$bases; do echo $$i.log; done`; \
+	trs_list=`for i in $$bases; do echo $$i.trs; done`; \
+	log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \
+	$(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \
+	exit $$?;
+recheck: all 
+	@test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+	@set +e; $(am__set_TESTS_bases); \
+	bases=`for i in $$bases; do echo $$i; done \
+	         | $(am__list_recheck_tests)` || exit 1; \
+	log_list=`for i in $$bases; do echo $$i.log; done`; \
+	log_list=`echo $$log_list`; \
+	$(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \
+	        am__force_recheck=am--force-recheck \
+	        TEST_LOGS="$$log_list"; \
+	exit $$?
+vncconnectiontest.log: vncconnectiontest$(EXEEXT)
+	@p='vncconnectiontest$(EXEEXT)'; \
+	b='vncconnectiontest'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+.test.log:
+	@p='$<'; \
+	$(am__set_b); \
+	$(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+ at am__EXEEXT_TRUE@.test$(EXEEXT).log:
+ at am__EXEEXT_TRUE@	@p='$<'; \
+ at am__EXEEXT_TRUE@	$(am__set_b); \
+ at am__EXEEXT_TRUE@	$(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+ at am__EXEEXT_TRUE@	--log-file $$b.log --trs-file $$b.trs \
+ at am__EXEEXT_TRUE@	$(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+ at am__EXEEXT_TRUE@	"$$tst" $(AM_TESTS_FD_REDIRECT)
+
 distdir: $(DISTFILES)
 	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
 	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
@@ -1543,9 +1928,10 @@ distdir: $(DISTFILES)
 	  fi; \
 	done
 check-am: all-am
+	$(MAKE) $(AM_MAKEFLAGS) check-TESTS
 check: $(BUILT_SOURCES)
 	$(MAKE) $(AM_MAKEFLAGS) check-am
-all-am: Makefile $(LTLIBRARIES) $(DATA) $(HEADERS)
+all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(DATA) $(HEADERS)
 installdirs:
 	for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(pyexecdir)" "$(DESTDIR)$(girdir)" "$(DESTDIR)$(typelibsdir)" "$(DESTDIR)$(gvncpulse_includedir)" "$(DESTDIR)$(libgtk_vnc_1_0_ladir)" "$(DESTDIR)$(libgtk_vnc_2_0_ladir)" "$(DESTDIR)$(libgvnc_1_0_ladir)" "$(DESTDIR)$(libgtk_vnc_1_0_ladir)" "$(DESTDIR)$(libgtk_vnc_2_0_ladir)" "$(DESTDIR)$(libgvnc_1_0_ladir)"; do \
 	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
@@ -1571,6 +1957,9 @@ install-strip:
 	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
 	fi
 mostlyclean-generic:
+	-test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS)
+	-test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs)
+	-test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
 
 clean-generic:
 	-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
@@ -1583,11 +1972,10 @@ maintainer-clean-generic:
 	@echo "This command is intended for maintainers to use"
 	@echo "it deletes files that may require special tools to rebuild."
 	-test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
-	-test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
 clean: clean-am
 
 clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
-	clean-pyexecLTLIBRARIES mostlyclean-am
+	clean-noinstPROGRAMS clean-pyexecLTLIBRARIES mostlyclean-am
 
 distclean: distclean-am
 	-rm -rf ./$(DEPDIR)
@@ -1667,15 +2055,16 @@ uninstall-am: uninstall-girDATA uninstall-gvncpulse_includeHEADERS \
 	uninstall-nodist_libgvnc_1_0_laHEADERS \
 	uninstall-pyexecLTLIBRARIES uninstall-typelibsDATA
 
-.MAKE: all check install install-am install-strip
+.MAKE: all check check-am install install-am install-strip
 
-.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
-	clean-libLTLIBRARIES clean-libtool clean-pyexecLTLIBRARIES \
-	cscopelist-am ctags ctags-am distclean distclean-compile \
-	distclean-generic distclean-libtool distclean-tags distdir dvi \
-	dvi-am html html-am info info-am install install-am \
-	install-data install-data-am install-dvi install-dvi-am \
-	install-exec install-exec-am install-girDATA \
+.PHONY: CTAGS GTAGS TAGS all all-am check check-TESTS check-am clean \
+	clean-generic clean-libLTLIBRARIES clean-libtool \
+	clean-noinstPROGRAMS clean-pyexecLTLIBRARIES cscopelist-am \
+	ctags ctags-am distclean distclean-compile distclean-generic \
+	distclean-libtool distclean-tags distdir dvi dvi-am html \
+	html-am info info-am install install-am install-data \
+	install-data-am install-dvi install-dvi-am install-exec \
+	install-exec-am install-girDATA \
 	install-gvncpulse_includeHEADERS install-html install-html-am \
 	install-info install-info-am install-libLTLIBRARIES \
 	install-libgtk_vnc_1_0_laHEADERS \
@@ -1688,7 +2077,7 @@ uninstall-am: uninstall-girDATA uninstall-gvncpulse_includeHEADERS \
 	installcheck installcheck-am installdirs maintainer-clean \
 	maintainer-clean-generic mostlyclean mostlyclean-compile \
 	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
-	tags tags-am uninstall uninstall-am uninstall-girDATA \
+	recheck tags tags-am uninstall uninstall-am uninstall-girDATA \
 	uninstall-gvncpulse_includeHEADERS uninstall-libLTLIBRARIES \
 	uninstall-libgtk_vnc_1_0_laHEADERS \
 	uninstall-libgtk_vnc_2_0_laHEADERS \
@@ -1714,30 +2103,30 @@ uninstall-am: uninstall-girDATA uninstall-gvncpulse_includeHEADERS \
 @HAVE_GTK_2_FALSE@	mv $@-tmp $@
 			$(NULL)
 
-$(KEYMAPS): $(KEYMAP_GEN) keymaps.csv
+$(KEYMAPS): $(srcdir)/$(KEYMAP_GEN) $(srcdir)/$(KEYMAP_CSV)
 
 vncdisplaykeymap.c: $(KEYMAPS)
 
 vncdisplaykeymap_xorgevdev2rfb.c:
-	$(AM_V_GEN)$(PERL) $(KEYMAP_GEN) $(srcdir)/keymaps.csv xorgevdev rfb > $@ || rm $@
+	$(AM_V_GEN)$(PYTHON) $(srcdir)/$(KEYMAP_GEN) --lang glib2 --varname keymap_xorgevdev2rfb code-map $(srcdir)/$(KEYMAP_CSV) xorgevdev rfb > $@ || rm $@
 
 vncdisplaykeymap_xorgkbd2rfb.c:
-	$(AM_V_GEN)$(PERL) $(KEYMAP_GEN) $(srcdir)/keymaps.csv xorgkbd rfb > $@ || rm $@
+	$(AM_V_GEN)$(PYTHON) $(srcdir)/$(KEYMAP_GEN) --lang glib2 --varname keymap_xorgkbd2rfb code-map $(srcdir)/$(KEYMAP_CSV) xorgkbd rfb > $@ || rm $@
 
 vncdisplaykeymap_xorgxquartz2rfb.c:
-	$(AM_V_GEN)$(PERL) $(KEYMAP_GEN) $(srcdir)/keymaps.csv xorgxquartz rfb > $@ || rm $@
+	$(AM_V_GEN)$(PYTHON) $(srcdir)/$(KEYMAP_GEN) --lang glib2 --varname keymap_xorgxquartz2rfb code-map $(srcdir)/$(KEYMAP_CSV) xorgxquartz rfb > $@ || rm $@
 
 vncdisplaykeymap_xorgxwin2rfb.c:
-	$(AM_V_GEN)$(PERL) $(KEYMAP_GEN) $(srcdir)/keymaps.csv xorgxwin rfb > $@ || rm $@
+	$(AM_V_GEN)$(PYTHON) $(srcdir)/$(KEYMAP_GEN) --lang glib2 --varname keymap_xorgxwin2rfb code-map $(srcdir)/$(KEYMAP_CSV) xorgxwin rfb > $@ || rm $@
 
 vncdisplaykeymap_osx2rfb.c:
-	$(AM_V_GEN)$(PERL) $(KEYMAP_GEN) $(srcdir)/keymaps.csv osx rfb > $@ || rm $@
+	$(AM_V_GEN)$(PYTHON) $(srcdir)/$(KEYMAP_GEN) --lang glib2 --varname keymap_osx2rfb code-map $(srcdir)/$(KEYMAP_CSV) osx rfb > $@ || rm $@
 
 vncdisplaykeymap_win322rfb.c:
-	$(AM_V_GEN)$(PERL) $(KEYMAP_GEN) $(srcdir)/keymaps.csv win32 rfb > $@ || rm $@
+	$(AM_V_GEN)$(PYTHON) $(srcdir)/$(KEYMAP_GEN) --lang glib2 --varname keymap_win322rfb code-map $(srcdir)/$(KEYMAP_CSV) win32 rfb > $@ || rm $@
 
 vncdisplaykeymap_x112rfb.c:
-	$(AM_V_GEN)$(PERL) $(KEYMAP_GEN) $(srcdir)/keymaps.csv x11 rfb > $@ || rm $@
+	$(AM_V_GEN)$(PYTHON) $(srcdir)/$(KEYMAP_GEN) --lang glib2 --varname keymap_x112rfb code-map $(srcdir)/$(KEYMAP_CSV) x11 rfb > $@ || rm $@
 
 vncdisplayenums.c: vncdisplay.h
 	$(AM_V_GEN)glib-mkenums    --fhead "#include <glib-object.h>\n" \
diff --git a/src/keycodemapdb/data/keymaps.csv b/src/keycodemapdb/data/keymaps.csv
new file mode 100644
index 0000000..ef5c33e
--- /dev/null
+++ b/src/keycodemapdb/data/keymaps.csv
@@ -0,0 +1,511 @@
+"Linux Name","Linux Keycode","OS-X Name","OS-X Keycode","AT set1 keycode","AT set2 keycode","AT set3 keycode",XT,"XT KBD","USB Keycodes","Win32 Name","Win32 Keycode","Xwin XT","Xfree86 KBD XT","X11 keysym","X11 keycode"
+KEY_RESERVED,0,,,,,,,,,,,,,,
+KEY_ESC,1,Escape,0x35,1,118,8,1,1,41,VK_ESCAPE,0x1b,1,1,XK_Escape,0xff1b
+KEY_1,2,ANSI_1,0x12,2,22,22,2,2,30,VK_1,0x31,2,2,XK_1,0x0031
+KEY_1,2,ANSI_1,0x12,2,22,22,2,2,30,VK_1,0x31,2,2,XK_exclam,0x0021
+KEY_2,3,ANSI_2,0x13,3,30,30,3,3,31,VK_2,0x32,3,3,XK_2,0x0032
+KEY_2,3,ANSI_2,0x13,3,30,30,3,3,31,VK_2,0x32,3,3,XK_at,0x0040
+KEY_3,4,ANSI_3,0x14,4,38,38,4,4,32,VK_3,0x33,4,4,XK_3,0x0033
+KEY_3,4,ANSI_3,0x14,4,38,38,4,4,32,VK_3,0x33,4,4,XK_numbersign,0x0023
+KEY_4,5,ANSI_4,0x15,5,37,37,5,5,33,VK_4,0x34,5,5,XK_4,0x0034
+KEY_4,5,ANSI_4,0x15,5,37,37,5,5,33,VK_4,0x34,5,5,XK_dollar,0x0024
+KEY_5,6,ANSI_5,0x17,6,46,46,6,6,34,VK_5,0x35,6,6,XK_5,0x0035
+KEY_5,6,ANSI_5,0x17,6,46,46,6,6,34,VK_5,0x35,6,6,XK_percent,0x0025
+KEY_6,7,ANSI_6,0x16,7,54,54,7,7,35,VK_6,0x36,7,7,XK_6,0x0036
+KEY_6,7,ANSI_6,0x16,7,54,54,7,7,35,VK_6,0x36,7,7,XK_asciicircum,0x005e
+KEY_7,8,ANSI_7,0x1a,8,61,61,8,8,36,VK_7,0x37,8,8,XK_7,0x0037
+KEY_7,8,ANSI_7,0x1a,8,61,61,8,8,36,VK_7,0x37,8,8,XK_ampersand,0x0026
+KEY_8,9,ANSI_8,0x1c,9,62,62,9,9,37,VK_8,0x38,9,9,XK_8,0x0038
+KEY_8,9,ANSI_8,0x1c,9,62,62,9,9,37,VK_8,0x38,9,9,XK_asterisk,0x002a
+KEY_9,10,ANSI_9,0x19,10,70,70,10,10,38,VK_9,0x39,10,10,XK_9,0x0039
+KEY_9,10,ANSI_9,0x19,10,70,70,10,10,38,VK_9,0x39,10,10,XK_parenleft,0x0028
+KEY_0,11,ANSI_0,0x1d,11,69,69,11,11,39,VK_0,0x30,11,11,XK_0,0x0030
+KEY_0,11,ANSI_0,0x1d,11,69,69,11,11,39,VK_0,0x30,11,11,XK_parenright,0x0029
+KEY_MINUS,12,ANSI_Minus,0x1b,12,78,78,12,12,45,VK_OEM_MINUS,0xbd,12,12,XK_minus,0x002d
+KEY_MINUS,12,ANSI_Minus,0x1b,12,78,78,12,12,45,VK_OEM_MINUS,0xbd,12,12,XK_underscore,0x005f
+KEY_EQUAL,13,ANSI_Equal,0x18,13,85,85,13,13,46,VK_OEM_PLUS,0xbb,13,13,XK_equal,0x003d
+KEY_EQUAL,13,ANSI_Equal,0x18,13,85,85,13,13,46,VK_OEM_PLUS,0xbb,13,13,XK_plus,0x002b
+KEY_BACKSPACE,14,Delete,0x33,14,102,102,14,14,42,VK_BACK,0x08,14,14,XK_BackSpace,0xff08
+KEY_TAB,15,Tab,0x30,15,13,13,15,15,43,VK_TAB,0x09,15,15,XK_Tab,0xff09
+KEY_Q,16,ANSI_Q,0xc,16,21,21,16,16,20,VK_Q,0x51,16,16,XK_Q,0x0051
+KEY_Q,16,ANSI_Q,0xc,16,21,21,16,16,20,VK_Q,0x51,16,16,XK_q,0x0071
+KEY_W,17,ANSI_W,0xd,17,29,29,17,17,26,VK_W,0x57,17,17,XK_W,0x0057
+KEY_W,17,ANSI_W,0xd,17,29,29,17,17,26,VK_W,0x57,17,17,XK_w,0x0077
+KEY_E,18,ANSI_E,0xe,18,36,36,18,18,8,VK_E,0x45,18,18,XK_E,0x0045
+KEY_E,18,ANSI_E,0xe,18,36,36,18,18,8,VK_E,0x45,18,18,XK_e,0x0065
+KEY_R,19,ANSI_R,0xf,19,45,45,19,19,21,VK_R,0x52,19,19,XK_R,0x0052
+KEY_R,19,ANSI_R,0xf,19,45,45,19,19,21,VK_R,0x52,19,19,XK_r,0x0072
+KEY_T,20,ANSI_T,0x11,20,44,44,20,20,23,VK_T,0x54,20,20,XK_T,0x0054
+KEY_T,20,ANSI_T,0x11,20,44,44,20,20,23,VK_T,0x54,20,20,XK_t,0x0074
+KEY_Y,21,ANSI_Y,0x10,21,53,53,21,21,28,VK_Y,0x59,21,21,XK_Y,0x0059
+KEY_Y,21,ANSI_Y,0x10,21,53,53,21,21,28,VK_Y,0x59,21,21,XK_y,0x0079
+KEY_U,22,ANSI_U,0x20,22,60,60,22,22,24,VK_U,0x55,22,22,XK_U,0x0055
+KEY_U,22,ANSI_U,0x20,22,60,60,22,22,24,VK_U,0x55,22,22,XK_u,0x0075
+KEY_I,23,ANSI_I,0x22,23,67,67,23,23,12,VK_I,0x49,23,23,XK_I,0x0049
+KEY_I,23,ANSI_I,0x22,23,67,67,23,23,12,VK_I,0x49,23,23,XK_i,0x0069
+KEY_O,24,ANSI_O,0x1f,24,68,68,24,24,18,VK_O,0x4f,24,24,XK_O,0x004f
+KEY_O,24,ANSI_O,0x1f,24,68,68,24,24,18,VK_O,0x4f,24,24,XK_o,0x006f
+KEY_P,25,ANSI_P,0x23,25,77,77,25,25,19,VK_P,0x50,25,25,XK_P,0x0050
+KEY_P,25,ANSI_P,0x23,25,77,77,25,25,19,VK_P,0x50,25,25,XK_p,0x0070
+KEY_LEFTBRACE,26,ANSI_LeftBracket,0x21,26,84,84,26,26,47,VK_OEM_4,0xdb,26,26,XK_bracketleft,0x005b
+KEY_LEFTBRACE,26,ANSI_LeftBracket,0x21,26,84,84,26,26,47,VK_OEM_4,0xdb,26,26,XK_braceleft,0x007b
+KEY_RIGHTBRACE,27,ANSI_RightBracket,0x1e,27,91,91,27,27,48,VK_OEM_6,0xdd,27,27,XK_bracketright,0x005d
+KEY_RIGHTBRACE,27,ANSI_RightBracket,0x1e,27,91,91,27,27,48,VK_OEM_6,0xdd,27,27,XK_braceright,0x007d
+KEY_ENTER,28,Return,0x24,28,90,90,28,28,40,VK_RETURN,0x0d,28,28,XK_Return,0xff0d
+KEY_LEFTCTRL,29,Control,0x3b,29,20,17,29,29,224,VK_LCONTROL,0xa2,29,29,XK_Control_L,0xffe3
+KEY_LEFTCTRL,29,Control,0x3b,29,20,17,29,29,224,VK_CONTROL,0x11,29,29,XK_Control_L,0xffe3
+KEY_A,30,ANSI_A,0x0,30,28,28,30,30,4,VK_A,0x41,30,30,XK_A,0x0041
+KEY_A,30,ANSI_A,0x0,30,28,28,30,30,4,VK_A,0x41,30,30,XK_a,0x0061
+KEY_S,31,ANSI_S,0x1,31,27,27,31,31,22,VK_S,0x53,31,31,XK_S,0x0053
+KEY_S,31,ANSI_S,0x1,31,27,27,31,31,22,VK_S,0x53,31,31,XK_s,0x0073
+KEY_D,32,ANSI_D,0x2,32,35,35,32,32,7,VK_D,0x44,32,32,XK_D,0x0044
+KEY_D,32,ANSI_D,0x2,32,35,35,32,32,7,VK_D,0x44,32,32,XK_d,0x0064
+KEY_F,33,ANSI_F,0x3,33,43,43,33,33,9,VK_F,0x46,33,33,XK_F,0x0046
+KEY_F,33,ANSI_F,0x3,33,43,43,33,33,9,VK_F,0x46,33,33,XK_f,0x0066
+KEY_G,34,ANSI_G,0x5,34,52,52,34,34,10,VK_G,0x47,34,34,XK_G,0x0047
+KEY_G,34,ANSI_G,0x5,34,52,52,34,34,10,VK_G,0x47,34,34,XK_g,0x0067
+KEY_H,35,ANSI_H,0x4,35,51,51,35,35,11,VK_H,0x48,35,35,XK_H,0x0048
+KEY_H,35,ANSI_H,0x4,35,51,51,35,35,11,VK_H,0x48,35,35,XK_h,0x0068
+KEY_J,36,ANSI_J,0x26,36,59,59,36,36,13,VK_J,0x4a,36,36,XK_J,0x004a
+KEY_J,36,ANSI_J,0x26,36,59,59,36,36,13,VK_J,0x4a,36,36,XK_j,0x006a
+KEY_K,37,ANSI_K,0x28,37,66,66,37,37,14,VK_K,0x4b,37,37,XK_K,0x004b
+KEY_K,37,ANSI_K,0x28,37,66,66,37,37,14,VK_K,0x4b,37,37,XK_k,0x006b
+KEY_L,38,ANSI_L,0x25,38,75,75,38,38,15,VK_L,0x4c,38,38,XK_L,0x004c
+KEY_L,38,ANSI_L,0x25,38,75,75,38,38,15,VK_L,0x4c,38,38,XK_l,0x006c
+KEY_SEMICOLON,39,ANSI_Semicolon,0x29,39,76,76,39,39,51,VK_OEM_1,0xba,39,39,XK_semicolon,0x003b
+KEY_SEMICOLON,39,ANSI_Semicolon,0x29,39,76,76,39,39,51,VK_OEM_1,0xba,39,39,XK_colon,0x003a
+KEY_APOSTROPHE,40,ANSI_Quote,0x27,40,82,82,40,40,52,VK_OEM_7,0xde,40,40,XK_apostrophe,0x0027
+KEY_APOSTROPHE,40,ANSI_Quote,0x27,40,82,82,40,40,52,VK_OEM_7,0xde,40,40,XK_quotedbl,0x0022
+KEY_GRAVE,41,ANSI_Grave,0x32,41,14,14,41,41,53,VK_OEM_3,0xc0,41,41,XK_grave,0x0060
+KEY_GRAVE,41,ANSI_Grave,0x32,41,14,14,41,41,53,VK_OEM_3,0xc0,41,41,XK_asciitilde,0x007e
+KEY_SHIFT,42,Shift,0x38,42,18,18,42,42,225,VK_SHIFT,0x10,42,42,XK_Shift_L,0xffe1
+KEY_LEFTSHIFT,42,Shift,0x38,42,18,18,42,42,225,VK_LSHIFT,0xa0,42,42,XK_Shift_L,0xffe1
+KEY_BACKSLASH,43,ANSI_Backslash,0x2a,43,93,93,43,43,50,VK_OEM_5,0xdc,43,43,XK_backslash,0x005c
+KEY_BACKSLASH,43,ANSI_Backslash,0x2a,43,93,93,43,43,50,VK_OEM_5,0xdc,43,43,XK_bar,0x007c
+KEY_Z,44,ANSI_Z,0x6,44,26,26,44,44,29,VK_Z,0x5a,44,44,XK_Z,0x005a
+KEY_Z,44,ANSI_Z,0x6,44,26,26,44,44,29,VK_Z,0x5a,44,44,XK_z,0x007a
+KEY_X,45,ANSI_X,0x7,45,34,34,45,45,27,VK_X,0x58,45,45,XK_X,0x0058
+KEY_X,45,ANSI_X,0x7,45,34,34,45,45,27,VK_X,0x58,45,45,XK_x,0x0078
+KEY_C,46,ANSI_C,0x8,46,33,33,46,46,6,VK_C,0x43,46,46,XK_C,0x0043
+KEY_C,46,ANSI_C,0x8,46,33,33,46,46,6,VK_C,0x43,46,46,XK_c,0x0063
+KEY_V,47,ANSI_V,0x9,47,42,42,47,47,25,VK_V,0x56,47,47,XK_V,0x0056
+KEY_V,47,ANSI_V,0x9,47,42,42,47,47,25,VK_V,0x56,47,47,XK_v,0x0076
+KEY_B,48,ANSI_B,0xb,48,50,50,48,48,5,VK_B,0x42,48,48,XK_B,0x0042
+KEY_B,48,ANSI_B,0xb,48,50,50,48,48,5,VK_B,0x42,48,48,XK_b,0x0062
+KEY_N,49,ANSI_N,0x2d,49,49,49,49,49,17,VK_N,0x4e,49,49,XK_N,0x004e
+KEY_N,49,ANSI_N,0x2d,49,49,49,49,49,17,VK_N,0x4e,49,49,XK_n,0x006e
+KEY_M,50,ANSI_M,0x2e,50,58,58,50,50,16,VK_M,0x4d,50,50,XK_M,0x004d
+KEY_M,50,ANSI_M,0x2e,50,58,58,50,50,16,VK_M,0x4d,50,50,XK_m,0x006d
+KEY_COMMA,51,ANSI_Comma,0x2b,51,65,65,51,51,54,VK_OEM_COMMA,0xbc,51,51,XK_comma,0x002c
+KEY_COMMA,51,ANSI_Comma,0x2b,51,65,65,51,51,54,VK_OEM_COMMA,0xbc,51,51,XK_less,0x003c
+KEY_DOT,52,ANSI_Period,0x2f,52,73,73,52,52,55,VK_OEM_PERIOD,0xbe,52,52,XK_period,0x002e
+KEY_DOT,52,ANSI_Period,0x2f,52,73,73,52,52,55,VK_OEM_PERIOD,0xbe,52,52,XK_greater,0x003e
+KEY_SLASH,53,ANSI_Slash,0x2c,53,74,74,53,53,56,VK_OEM_2,0xbf,53,53,XK_slash,0x002f
+KEY_SLASH,53,ANSI_Slash,0x2c,53,74,74,53,53,56,VK_OEM_2,0xbf,53,53,XK_question,0x003f
+KEY_RIGHTSHIFT,54,RightShift,0x3c,54,89,89,54,54,229,VK_RSHIFT,0xa1,54,54,XK_Shift_R,0xffe2
+KEY_KPASTERISK,55,ANSI_KeypadMultiply,0x43,55,124,126,55,55,85,VK_MULTIPLY,0x6a,55,55,XK_multiply,0x00d7
+KEY_LEFTALT,56,Option,0x3a,56,17,25,56,56,226,VK_LMENU,0xa4,56,56,XK_Alt_L,0xffe9
+KEY_LEFTALT,56,Option,0x3a,56,17,25,56,56,226,VK_MENU,0x12,56,56,XK_Alt_L,0xffe9
+KEY_SPACE,57,Space,0x31,57,41,41,57,57,44,VK_SPACE,0x20,57,57,XK_space,0x0020
+KEY_CAPSLOCK,58,CapsLock,0x39,58,88,20,58,58,57,VK_CAPITAL,0x14,58,58,XK_Caps_Lock,0xffe5
+KEY_F1,59,F1,0x7a,59,5,7,59,59,58,VK_F1,0x70,59,59,XK_F1,0xffbe
+KEY_F2,60,F2,0x78,60,6,15,60,60,59,VK_F2,0x71,60,60,XK_F2,0xffbf
+KEY_F3,61,F3,0x63,61,4,23,61,61,60,VK_F3,0x72,61,61,XK_F3,0xffc0
+KEY_F4,62,F4,0x76,62,12,31,62,62,61,VK_F4,0x73,62,62,XK_F4,0xffc1
+KEY_F5,63,F5,0x60,63,3,39,63,63,62,VK_F5,0x74,63,63,XK_F5,0xffc2
+KEY_F6,64,F6,0x61,64,11,47,64,64,63,VK_F6,0x75,64,64,XK_F6,0xffc3
+KEY_F7,65,F7,0x62,65,259,55,65,65,64,VK_F7,0x76,65,65,XK_F7,0xffc4
+KEY_F8,66,F8,0x64,66,10,63,66,66,65,VK_F8,0x77,66,66,XK_F8,0xffc5
+KEY_F9,67,F9,0x65,67,1,71,67,67,66,VK_F9,0x78,67,67,XK_F9,0xffc6
+KEY_F10,68,F10,0x6d,68,9,79,68,68,67,VK_F10,0x79,68,68,XK_F10,0xffc7
+KEY_NUMLOCK,69,,,69,119,118,69,69,83,VK_NUMLOCK,0x90,69,69,XK_Num_Lock,0xff7f
+KEY_SCROLLLOCK,70,,,70,126,95,70,70,71,VK_SCROLL,0x91,70,70,XK_Scroll_Lock,0xff14
+KEY_KP7,71,ANSI_Keypad7,0x59,71,108,108,71,71,95,VK_NUMPAD7,0x67,71,71,XK_KP_7,0xffb7
+KEY_KP8,72,ANSI_Keypad8,0x5b,72,117,117,72,72,96,VK_NUMPAD8,0x68,72,72,XK_KP_8,0xffb8
+KEY_KP9,73,ANSI_Keypad9,0x5c,73,125,125,73,73,97,VK_NUMPAD9,0x69,73,73,XK_KP_9,0xffb9
+KEY_KPMINUS,74,ANSI_KeypadMinus,0x4e,74,123,132,74,74,86,VK_SUBTRACT,0x6d,74,74,XK_KP_Subtract,0xffad
+KEY_KP4,75,ANSI_Keypad4,0x56,75,107,107,75,75,92,VK_NUMPAD4,0x64,75,75,XK_KP_4,0xffb4
+KEY_KP5,76,ANSI_Keypad5,0x57,76,115,115,76,76,93,VK_NUMPAD5,0x65,76,76,XK_KP_5,0xffb5
+KEY_KP6,77,ANSI_Keypad6,0x58,77,116,116,77,77,94,VK_NUMPAD6,0x66,77,77,XK_KP_6,0xffb6
+KEY_KPPLUS,78,ANSI_KeypadPlus,0x45,78,121,124,78,78,87,VK_ADD,0x6b,78,78,XK_KP_Add,0xffab
+KEY_KP1,79,ANSI_Keypad1,0x53,79,105,105,79,79,89,VK_NUMPAD1,0x61,79,79,XK_KP_1,0xffb1
+KEY_KP2,80,ANSI_Keypad2,0x54,80,114,114,80,80,90,VK_NUMPAD2,0x62,80,80,XK_KP_2,0xffb2
+KEY_KP3,81,ANSI_Keypad3,0x55,81,122,122,81,81,91,VK_NUMPAD3,0x63,81,81,XK_KP_3,0xffb3
+KEY_KP0,82,ANSI_Keypad0,0x52,82,112,112,82,82,98,VK_NUMPAD0,0x60,82,82,XK_KP_0,0xffb0
+KEY_KPDOT,83,ANSI_KeypadDecimal,0x41,83,113,113,83,83,99,VK_DECIMAL,0x6e,83,83,XK_KP_Decimal,0xffae
+,84,,,,,,,84,,,,,,,
+KEY_ZENKAKUHANKAKU,85,,,118,95,,,118,148,,,,,,
+KEY_102ND,86,,,86,97,19,,86,100,VK_OEM_102,0xe1,86,86,,
+KEY_F11,87,F11,0x67,87,120,86,101,87,68,VK_F11,0x7a,87,87,XK_F11,0xffc8
+KEY_F12,88,F12,0x6f,88,7,94,102,88,69,VK_F12,0x7b,88,88,XK_F12,0xffc9
+KEY_RO,89,,,115,81,,,115,135,,,,,,
+KEY_KATAKANA,90,JIS_Kana????,0x68,120,99,,,120,146,VK_KANA,0x15,,,,
+KEY_HIRAGANA,91,,,119,98,,,119,147,,,,,,
+KEY_HENKAN,92,,,121,100,134,,121,138,,,,,,
+KEY_KATAKANAHIRAGANA,93,,,112,19,135,,112,136,,,0xc8,0xc8,,
+KEY_MUHENKAN,94,,,123,103,133,,123,139,,,,,,
+KEY_KPJPCOMMA,95,JIS_KeypadComma,0x5f,92,39,,,92,140,,,,,XK_KP_Separator,0xffac
+KEY_KPENTER,96,ANSI_KeypadEnter,0x4c,,158,121,,284,88,,,0x64,0x64,XK_KP_Enter,0xff8d
+KEY_RIGHTCTRL,97,RightControl,0x3e,,,88,,285,228,VK_RCONTROL,0xa3,0x65,0x65,XK_Control_R,0xffe4
+KEY_KPSLASH,98,ANSI_KeypadDivide,0x4b,,181,119,,309,84,VK_DIVIDE,0x6f,0x68,0x68,XK_KP_Divide,0xffaf
+KEY_SYSRQ,99,,,84,260,87,,84,70,"VK_SNAPSHOT ???",0x2c,0x67,0x67,XK_Sys_Req,0xff15
+KEY_RIGHTALT,100,RightOption,0x3d,,,57,,312,230,VK_RMENU,0xa5,0x69,0x69,XK_Alt_R,0xffea
+KEY_LINEFEED,101,,,,,,,91,,,,,,,
+KEY_HOME,102,Home,0x73,,224,110,,327,74,VK_HOME,0x24,0x59,0x59,XK_Home,0xff50
+KEY_UP,103,UpArrow,0x7e,,236,99,109,328,82,VK_UP,0x26,0x5a,0x5a,XK_Up,0xff52
+KEY_PAGEUP,104,PageUp,0x74,,201,111,,329,75,VK_PRIOR,0x21,0x5b,0x5b,XK_Page_Up,0xff55
+KEY_LEFT,105,LeftArrow,0x7b,,203,97,111,331,80,VK_LEFT,0x25,0x5c,0x5c,XK_Left,0xff51
+KEY_RIGHT,106,RightArrow,0x7c,,205,106,112,333,79,VK_RIGHT,0x27,0x5e,0x5e,XK_Right,0xff53
+KEY_END,107,End,0x77,,225,101,,335,77,VK_END,0x23,0x5f,0x5f,XK_End,0xff57
+KEY_DOWN,108,DownArrow,0x7d,,254,96,110,336,81,VK_DOWN,0x28,0x60,0x60,XK_Down,0xff54
+KEY_PAGEDOWN,109,PageDown,0x79,,243,109,,337,78,VK_NEXT,0x22,0x61,0x61,XK_Page_Down,0xff56
+KEY_INSERT,110,,,,210,103,107,338,73,VK_INSERT,0x2d,0x62,0x62,XK_Insert,0xff63
+KEY_DELETE,111,ForwardDelete,0x75,,244,100,108,339,76,VK_DELETE,0x2e,0x63,0x63,XK_Delete,0xffff
+KEY_MACRO,112,,,,239,142,,367,,,,,,,
+KEY_MUTE,113,Mute,0x4a,,251,156,,288,239,VK_VOLUME_MUTE,0xad,,,,
+KEY_VOLUMEDOWN,114,VolumeDown,0x49,,,157,,302,238,VK_VOLUME_DOWN,0xae,,,,
+KEY_VOLUMEUP,115,VolumeUp,0x48,,233,149,,304,237,VK_VOLUME_UP,0xaf,,,,
+KEY_POWER,116,,,,,,,350,102,,,,,,
+KEY_KPEQUAL,117,ANSI_KeypadEquals,0x51,89,15,,,89,103,,,0x76,0x76,XK_KP_Equal,0xffbd
+KEY_KPPLUSMINUS,118,,,,206,,,334,,,,,,,
+KEY_PAUSE,119,,,,198,98,,326,72,VK_PAUSE,0x013,0x66,0x66,XK_Pause,0xff13
+KEY_SCALE,120,,,,,,,267,,,,,,,
+KEY_KPCOMMA,121,ANSI_KeypadClear????,0x47,126,109,,,126,133,VK_SEPARATOR??,0x6c,,,,
+KEY_HANGEUL,122,,,,,,,,144,VK_HANGEUL,0x15,,,,
+KEY_HANJA,123,,,,,,,269,145,VK_HANJA,0x19,,,,
+KEY_YEN,124,JIS_Yen,0x5d,125,106,,,125,137,,,0x7d,0x7d,,
+KEY_LEFTMETA,125,Command,0x37,,,139,,347,227,VK_LWIN,0x5b,0x6b,0x6b,XK_Meta_L,0xffe7
+KEY_RIGHTMETA,126,,,,,140,,348,231,VK_RWIN,0x5c,0x6c,0x6c,XK_Meta_R,0xffe8
+KEY_COMPOSE,127,Function,0x3f,,,141,,349,101,VK_APPS,0x5d,0x6d,0x6d,,
+KEY_STOP,128,,,,,10,,360,243,VK_BROWSER_STOP,0xa9,,,,
+KEY_AGAIN,129,,,,,11,,261,121,,,,,,
+KEY_PROPS,130,,,,,12,,262,118,,,,,,
+KEY_UNDO,131,,,,,16,,263,122,,,,,,
+KEY_FRONT,132,,,,,,,268,119,,,,,,
+KEY_COPY,133,,,,,24,,376,124,,,,,,
+KEY_OPEN,134,,,,,32,,100,116,,,,,,
+KEY_PASTE,135,,,,,40,,101,125,,,,,,
+KEY_FIND,136,,,,,48,,321,244,,,,,,
+KEY_CUT,137,,,,,56,,316,123,,,,,,
+KEY_HELP,138,,,,,9,,373,117,VK_HELP,0x2f,,,XK_Help,0xff6a
+KEY_MENU,139,,,,,145,,286,,,,,,,
+KEY_CALC,140,,,,174,163,,289,251,,,,,,
+KEY_SETUP,141,,,,,,,102,,,,,,,
+KEY_SLEEP,142,,,,,,,351,248,VK_SLEEP,0x5f,,,,
+KEY_WAKEUP,143,,,,,,,355,,,,,,,
+KEY_FILE,144,,,,,,,103,,,,,,,
+KEY_SENDFILE,145,,,,,,,104,,,,,,,
+KEY_DELETEFILE,146,,,,,,,105,,,,,,,
+KEY_XFER,147,,,,,162,,275,,,,,,,
+KEY_PROG1,148,,,,,160,,287,,,,,,,
+KEY_PROG2,149,,,,,161,,279,,,,,,,
+KEY_WWW,150,,,,,,,258,240,,,,,,
+KEY_MSDOS,151,,,,,,,106,,,,,,,
+KEY_SCREENLOCK,152,,,,,150,,274,249,,,,,,
+KEY_DIRECTION,153,,,,,,,107,,,,,,,
+KEY_CYCLEWINDOWS,154,,,,,155,,294,,,,,,,
+KEY_MAIL,155,,,,,,,364,,,,,,,
+KEY_BOOKMARKS,156,,,,,,,358,,,,,,,
+KEY_COMPUTER,157,,,,,,,363,,,,,,,
+KEY_BACK,158,,,,,,,362,241,VK_BROWSER_BACK,0xa6,,,,
+KEY_FORWARD,159,,,,,,,361,242,VK_BROWSER_FORWARD,0xa7,,,,
+KEY_CLOSECD,160,,,,,154,,291,,,,,,,
+KEY_EJECTCD,161,,,,,,,108,236,,,,,,
+KEY_EJECTCLOSECD,162,,,,,,,381,,,,,,,
+KEY_NEXTSONG,163,,,,241,147,,281,235,VK_MEDIA_NEXT_TRACK,0xb0,,,,
+KEY_PLAYPAUSE,164,,,,173,,,290,232,VK_MEDIA_PLAY_PAUSE,0xb3,,,,
+KEY_PREVIOUSSONG,165,,,,250,148,,272,234,VK_MEDIA_PREV_TRACK,0xb1,,,,
+KEY_STOPCD,166,,,,164,152,,292,233,VK_MEDIA_STOP,0xb2,,,,
+KEY_RECORD,167,,,,,158,,305,,,,,,,
+KEY_REWIND,168,,,,,159,,280,,,,,,,
+KEY_PHONE,169,,,,,,,99,,,,,,,
+KEY_ISO,170,ISO_Section,0xa,,,,,112,,,,,,,
+KEY_CONFIG,171,,,,,,,257,,,,,,,
+KEY_HOMEPAGE,172,,,,178,151,,306,,VK_BROWSER_HOME,0xac,,,,
+KEY_REFRESH,173,,,,,,,359,250,VK_BROWSER_REFRESH,0xa8,,,,
+KEY_EXIT,174,,,,,,,113,,,,,,,
+KEY_MOVE,175,,,,,,,114,,,,,,,
+KEY_EDIT,176,,,,,,,264,247,,,,,,
+KEY_SCROLLUP,177,,,,,,,117,245,,,,,,
+KEY_SCROLLDOWN,178,,,,,,,271,246,,,,,,
+KEY_KPLEFTPAREN,179,,,,,,,374,182,,,,,,
+KEY_KPRIGHTPAREN,180,,,,,,,379,183,,,,,,
+KEY_NEW,181,,,,,,,265,,,,,,,
+KEY_REDO,182,,,,,,,266,,,,,,,
+KEY_F13,183,F13,0x69,93,47,127,,93,104,VK_F13,0x7c,0x6e,0x6e,,
+KEY_F14,184,F14,0x6b,94,55,128,,94,105,VK_F14,0x7d,0x6f,0x6f,,
+KEY_F15,185,F15,0x71,95,63,129,,95,106,VK_F15,0x7e,0x70,0x70,,
+KEY_F16,186,F16,0x6a,,,130,,85,107,VK_F16,0x7f,0x71,0x71,,
+KEY_F17,187,F17,0x40,,,131,,259,108,VK_F17,0x80,0x72,0x72,,
+KEY_F18,188,F18,0x4f,,,,,375,109,VK_F18,0x81,,,,
+KEY_F19,189,F19,0x50,,,,,260,110,VK_F19,0x82,,,,
+KEY_F20,190,F20,0x5a,,,,,90,111,VK_F20,0x83,,,,
+KEY_F21,191,,,,,,,116,112,VK_F21,0x84,,,,
+KEY_F22,192,,,,,,,377,113,VK_F22,0x85,,,,
+KEY_F23,193,,,,,,,109,114,VK_F23,0x86,,,,
+KEY_F24,194,,,,,,,111,115,VK_F24,0x87,,,,
+,195,,,,,,,277,,,,,,,
+,196,,,,,,,278,,,,,,,
+,197,,,,,,,282,,,,,,,
+,198,,,,,,,283,,,,,,,
+,199,,,,,,,295,,,,,,,
+KEY_PLAYCD,200,,,,,,,296,,,,,,,
+KEY_PAUSECD,201,,,,,,,297,,,,,,,
+KEY_PROG3,202,,,,,,,299,,,,,,,
+KEY_PROG4,203,,,,,,,300,,,,,,,
+KEY_DASHBOARD,204,,,,,,,301,,,,,,,
+KEY_SUSPEND,205,,,,,,,293,,,,,,,
+KEY_CLOSE,206,,,,,,,303,,,,,,,
+KEY_PLAY,207,,,,,,,307,,VK_PLAY,0xfa,,,,
+KEY_FASTFORWARD,208,,,,,,,308,,,,,,,
+KEY_BASSBOOST,209,,,,,,,310,,,,,,,
+KEY_PRINT,210,,,,,,,313,,VK_PRINT,0x2a,,,,
+KEY_HP,211,,,,,,,314,,,,,,,
+KEY_CAMERA,212,,,,,,,315,,,,,,,
+KEY_SOUND,213,,,,,,,317,,,,,,,
+KEY_QUESTION,214,,,,,,,318,,,,,,,
+KEY_EMAIL,215,,,,,,,319,,VK_LAUNCH_MAIL,0xb4,,,,
+KEY_CHAT,216,,,,,,,320,,,,,,,
+KEY_SEARCH,217,,,,,,,357,,VK_BROWSER_SEARCH,0xaa,,,,
+KEY_CONNECT,218,,,,,,,322,,,,,,,
+KEY_FINANCE,219,,,,,,,323,,,,,,,
+KEY_SPORT,220,,,,,,,324,,,,,,,
+KEY_SHOP,221,,,,,,,325,,,,,,,
+KEY_ALTERASE,222,,,,,,,276,,,,,,,
+KEY_CANCEL,223,,,,,,,330,,,,,,,
+KEY_BRIGHTNESSDOWN,224,,,,,,,332,,,,,,,
+KEY_BRIGHTNESSUP,225,,,,,,,340,,,,,,,
+KEY_MEDIA,226,,,,,,,365,,,,,,,
+KEY_SWITCHVIDEOMODE,227,,,,,,,342,,,,,,,
+KEY_KBDILLUMTOGGLE,228,,,,,,,343,,,,,,,
+KEY_KBDILLUMDOWN,229,,,,,,,344,,,,,,,
+KEY_KBDILLUMUP,230,,,,,,,345,,,,,,,
+KEY_SEND,231,,,,,,,346,,,,,,,
+KEY_REPLY,232,,,,,,,356,,,,,,,
+KEY_FORWARDMAIL,233,,,,,,,270,,,,,,,
+KEY_SAVE,234,,,,,,,341,,,,,,,
+KEY_DOCUMENTS,235,,,,,,,368,,,,,,,
+KEY_BATTERY,236,,,,,,,369,,,,,,,
+KEY_BLUETOOTH,237,,,,,,,370,,,,,,,
+KEY_WLAN,238,,,,,,,371,,,,,,,
+KEY_UWB,239,,,,,,,372,,,,,,,
+KEY_UNKNOWN,240,,,,,,,,,,,,,,
+KEY_VIDEO_NEXT,241,,,,,,,,,,,,,,
+KEY_VIDEO_PREV,242,,,,,,,,,,,,,,
+KEY_BRIGHTNESS_CYCLE,243,,,,,,,,,,,,,,
+KEY_BRIGHTNESS_ZERO,244,,,,,,,,,,,,,,
+KEY_DISPLAY_OFF,245,,,,,,,,,,,,,,
+KEY_WIMAX,246,,,,,,,,,,,,,,
+,247,,,,,,,,,,,,,,
+,248,,,,,,,,,,,,,,
+,249,,,,,,,,,,,,,,
+,250,,,,,,,,,,,,,,
+,251,,,,,,,,,,,,,,
+,252,,,,,,,,,,,,,,
+,253,,,,,,,,,,,,,,
+,254,,,,,,,,,,,,,,
+,255,,,,182,,,,,,,,,,
+BTN_MISC,0x100,,,,,,,,,,,,,,
+BTN_0,0x100,,,,,,,,,VK_LBUTTON,0x01,,,,
+BTN_1,0x101,,,,,,,,,VK_RBUTTON,0x02,,,,
+BTN_2,0x102,,,,,,,,,VK_MBUTTON,0x04,,,,
+BTN_3,0x103,,,,,,,,,VK_XBUTTON1,0x05,,,,
+BTN_4,0x104,,,,,,,,,VK_XBUTTON2,0x06,,,,
+BTN_5,0x105,,,,,,,,,,,,,,
+BTN_6,0x106,,,,,,,,,,,,,,
+BTN_7,0x107,,,,,,,,,,,,,,
+BTN_8,0x108,,,,,,,,,,,,,,
+BTN_9,0x109,,,,,,,,,,,,,,
+BTN_MOUSE,0x110,,,,,,,,,,,,,,
+BTN_LEFT,0x110,,,,,,,,,,,,,,
+BTN_RIGHT,0x111,,,,,,,,,,,,,,
+BTN_MIDDLE,0x112,,,,,,,,,,,,,,
+BTN_SIDE,0x113,,,,,,,,,,,,,,
+BTN_EXTRA,0x114,,,,,,,,,,,,,,
+BTN_FORWARD,0x115,,,,,,,,,,,,,,
+BTN_BACK,0x116,,,,,,,,,,,,,,
+BTN_TASK,0x117,,,,,,,,,,,,,,
+BTN_JOYSTICK,0x120,,,,,,,,,,,,,,
+BTN_TRIGGER,0x120,,,,,,,,,,,,,,
+BTN_THUMB,0x121,,,,,,,,,,,,,,
+BTN_THUMB2,0x122,,,,,,,,,,,,,,
+BTN_TOP,0x123,,,,,,,,,,,,,,
+BTN_TOP2,0x124,,,,,,,,,,,,,,
+BTN_PINKIE,0x125,,,,,,,,,,,,,,
+BTN_BASE,0x126,,,,,,,,,,,,,,
+BTN_BASE2,0x127,,,,,,,,,,,,,,
+BTN_BASE3,0x128,,,,,,,,,,,,,,
+BTN_BASE4,0x129,,,,,,,,,,,,,,
+BTN_BASE5,0x12a,,,,,,,,,,,,,,
+BTN_BASE6,0x12b,,,,,,,,,,,,,,
+BTN_DEAD,0x12f,,,,,,,,,,,,,,
+BTN_GAMEPAD,0x130,,,,,,,,,,,,,,
+BTN_A,0x130,,,,,,,,,,,,,,
+BTN_B,0x131,,,,,,,,,,,,,,
+BTN_C,0x132,,,,,,,,,,,,,,
+BTN_X,0x133,,,,,,,,,,,,,,
+BTN_Y,0x134,,,,,,,,,,,,,,
+BTN_Z,0x135,,,,,,,,,,,,,,
+BTN_TL,0x136,,,,,,,,,,,,,,
+BTN_TR,0x137,,,,,,,,,,,,,,
+BTN_TL2,0x138,,,,,,,,,,,,,,
+BTN_TR2,0x139,,,,,,,,,,,,,,
+BTN_SELECT,0x13a,,,,,,,,,,,,,,
+BTN_START,0x13b,,,,,,,,,,,,,,
+BTN_MODE,0x13c,,,,,,,,,,,,,,
+BTN_THUMBL,0x13d,,,,,,,,,,,,,,
+BTN_THUMBR,0x13e,,,,,,,,,,,,,,
+BTN_DIGI,0x140,,,,,,,,,,,,,,
+BTN_TOOL_PEN,0x140,,,,,,,,,,,,,,
+BTN_TOOL_RUBBER,0x141,,,,,,,,,,,,,,
+BTN_TOOL_BRUSH,0x142,,,,,,,,,,,,,,
+BTN_TOOL_PENCIL,0x143,,,,,,,,,,,,,,
+BTN_TOOL_AIRBRUSH,0x144,,,,,,,,,,,,,,
+BTN_TOOL_FINGER,0x145,,,,,,,,,,,,,,
+BTN_TOOL_MOUSE,0x146,,,,,,,,,,,,,,
+BTN_TOOL_LENS,0x147,,,,,,,,,,,,,,
+BTN_TOUCH,0x14a,,,,,,,,,,,,,,
+BTN_STYLUS,0x14b,,,,,,,,,,,,,,
+BTN_STYLUS2,0x14c,,,,,,,,,,,,,,
+BTN_TOOL_DOUBLETAP,0x14d,,,,,,,,,,,,,,
+BTN_TOOL_TRIPLETAP,0x14e,,,,,,,,,,,,,,
+BTN_TOOL_QUADTAP,0x14f,,,,,,,,,,,,,,
+BTN_WHEEL,0x150,,,,,,,,,,,,,,
+BTN_GEAR_DOWN,0x150,,,,,,,,,,,,,,
+BTN_GEAR_UP,0x151,,,,,,,,,,,,,,
+KEY_OK,0x160,,,,,,,,,,,,,,
+KEY_SELECT,0x161,,,,,,,,,VK_SELECT,0x29,,,XK_Select,0xff60
+KEY_GOTO,0x162,,,,,,,,,,,,,,
+KEY_CLEAR,0x163,,,,,,,,,,,,,,
+KEY_POWER2,0x164,,,,,,,,,,,,,,
+KEY_OPTION,0x165,,,,,,,,,,,,,,
+KEY_INFO,0x166,,,,,,,,,,,,,,
+KEY_TIME,0x167,,,,,,,,,,,,,,
+KEY_VENDOR,0x168,,,,,,,,,,,,,,
+KEY_ARCHIVE,0x169,,,,,,,,,,,,,,
+KEY_PROGRAM,0x16a,,,,,,,,,,,,,,
+KEY_CHANNEL,0x16b,,,,,,,,,,,,,,
+KEY_FAVORITES,0x16c,,,,,,,,,VK_BROWSER_FAVOURITES,0xab,,,,
+KEY_EPG,0x16d,,,,,,,,,,,,,,
+KEY_PVR,0x16e,,,,,,,,,,,,,,
+KEY_MHP,0x16f,,,,,,,,,,,,,,
+KEY_LANGUAGE,0x170,,,,,,,,,,,,,,
+KEY_TITLE,0x171,,,,,,,,,,,,,,
+KEY_SUBTITLE,0x172,,,,,,,,,,,,,,
+KEY_ANGLE,0x173,,,,,,,,,,,,,,
+KEY_ZOOM,0x174,,,,,,,,,VK_ZOOM,0xfb,,,,
+KEY_MODE,0x175,,,,,,,,,,,,,,
+KEY_KEYBOARD,0x176,,,,,,,,,,,,,,
+KEY_SCREEN,0x177,,,,,,,,,,,,,,
+KEY_PC,0x178,,,,,,,,,,,,,,
+KEY_TV,0x179,,,,,,,,,,,,,,
+KEY_TV2,0x17a,,,,,,,,,,,,,,
+KEY_VCR,0x17b,,,,,,,,,,,,,,
+KEY_VCR2,0x17c,,,,,,,,,,,,,,
+KEY_SAT,0x17d,,,,,,,,,,,,,,
+KEY_SAT2,0x17e,,,,,,,,,,,,,,
+KEY_CD,0x17f,,,,,,,,,,,,,,
+KEY_TAPE,0x180,,,,,,,,,,,,,,
+KEY_RADIO,0x181,,,,,,,,,,,,,,
+KEY_TUNER,0x182,,,,,,,,,,,,,,
+KEY_PLAYER,0x183,,,,,,,,,,,,,,
+KEY_TEXT,0x184,,,,,,,,,,,,,,
+KEY_DVD,0x185,,,,,,,,,,,,,,
+KEY_AUX,0x186,,,,,,,,,,,,,,
+KEY_MP3,0x187,,,,,,,,,,,,,,
+KEY_AUDIO,0x188,,,,,,,,,,,,,,
+KEY_VIDEO,0x189,,,,,,,,,,,,,,
+KEY_DIRECTORY,0x18a,,,,,,,,,,,,,,
+KEY_LIST,0x18b,,,,,,,,,,,,,,
+KEY_MEMO,0x18c,,,,,,,,,,,,,,
+KEY_CALENDAR,0x18d,,,,,,,,,,,,,,
+KEY_RED,0x18e,,,,,,,,,,,,,,
+KEY_GREEN,0x18f,,,,,,,,,,,,,,
+KEY_YELLOW,0x190,,,,,,,,,,,,,,
+KEY_BLUE,0x191,,,,,,,,,,,,,,
+KEY_CHANNELUP,0x192,,,,,,,,,,,,,,
+KEY_CHANNELDOWN,0x193,,,,,,,,,,,,,,
+KEY_FIRST,0x194,,,,,,,,,,,,,,
+KEY_LAST,0x195,,,,,,,,,,,,,,
+KEY_AB,0x196,,,,,,,,,,,,,,
+KEY_NEXT,0x197,,,,,,,,,,,,,,
+KEY_RESTART,0x198,,,,,,,,,,,,,,
+KEY_SLOW,0x199,,,,,,,,,,,,,,
+KEY_SHUFFLE,0x19a,,,,,,,,,,,,,,
+KEY_BREAK,0x19b,,,,,,,,,,,,,,
+KEY_PREVIOUS,0x19c,,,,,,,,,,,,,,
+KEY_DIGITS,0x19d,,,,,,,,,,,,,,
+KEY_TEEN,0x19e,,,,,,,,,,,,,,
+KEY_TWEN,0x19f,,,,,,,,,,,,,,
+KEY_VIDEOPHONE,0x1a0,,,,,,,,,,,,,,
+KEY_GAMES,0x1a1,,,,,,,,,,,,,,
+KEY_ZOOMIN,0x1a2,,,,,,,,,,,,,,
+KEY_ZOOMOUT,0x1a3,,,,,,,,,,,,,,
+KEY_ZOOMRESET,0x1a4,,,,,,,,,,,,,,
+KEY_WORDPROCESSOR,0x1a5,,,,,,,,,,,,,,
+KEY_EDITOR,0x1a6,,,,,,,,,,,,,,
+KEY_SPREADSHEET,0x1a7,,,,,,,,,,,,,,
+KEY_GRAPHICSEDITOR,0x1a8,,,,,,,,,,,,,,
+KEY_PRESENTATION,0x1a9,,,,,,,,,,,,,,
+KEY_DATABASE,0x1aa,,,,,,,,,,,,,,
+KEY_NEWS,0x1ab,,,,,,,,,,,,,,
+KEY_VOICEMAIL,0x1ac,,,,,,,,,,,,,,
+KEY_ADDRESSBOOK,0x1ad,,,,,,,,,,,,,,
+KEY_MESSENGER,0x1ae,,,,,,,,,,,,,,
+KEY_DISPLAYTOGGLE,0x1af,,,,,,,,,,,,,,
+KEY_SPELLCHECK,0x1b0,,,,,,,,,,,,,,
+KEY_LOGOFF,0x1b1,,,,,,,,,,,,,,
+KEY_DOLLAR,0x1b2,,,,,,,,,,,,,,
+KEY_EURO,0x1b3,,,,,,,,,,,,,,
+KEY_FRAMEBACK,0x1b4,,,,,,,,,,,,,,
+KEY_FRAMEFORWARD,0x1b5,,,,,,,,,,,,,,
+KEY_CONTEXT_MENU,0x1b6,,,,,,,,,,,,,,
+KEY_MEDIA_REPEAT,0x1b7,,,,,,,,,,,,,,
+KEY_DEL_EOL,0x1c0,,,,,,,,,,,,,,
+KEY_DEL_EOS,0x1c1,,,,,,,,,,,,,,
+KEY_INS_LINE,0x1c2,,,,,,,,,,,,,,
+KEY_DEL_LINE,0x1c3,,,,,,,,,,,,,,
+KEY_FN,0x1d0,,,,,,,,,,,,,,
+KEY_FN_ESC,0x1d1,,,,,,,,,,,,,,
+KEY_FN_F1,0x1d2,,,,,,,,,,,,,,
+KEY_FN_F2,0x1d3,,,,,,,,,,,,,,
+KEY_FN_F3,0x1d4,,,,,,,,,,,,,,
+KEY_FN_F4,0x1d5,,,,,,,,,,,,,,
+KEY_FN_F5,0x1d6,,,,,,,,,,,,,,
+KEY_FN_F6,0x1d7,,,,,,,,,,,,,,
+KEY_FN_F7,0x1d8,,,,,,,,,,,,,,
+KEY_FN_F8,0x1d9,,,,,,,,,,,,,,
+KEY_FN_F9,0x1da,,,,,,,,,,,,,,
+KEY_FN_F10,0x1db,,,,,,,,,,,,,,
+KEY_FN_F11,0x1dc,,,,,,,,,,,,,,
+KEY_FN_F12,0x1dd,,,,,,,,,,,,,,
+KEY_FN_1,0x1de,,,,,,,,,,,,,,
+KEY_FN_2,0x1df,,,,,,,,,,,,,,
+KEY_FN_D,0x1e0,,,,,,,,,,,,,,
+KEY_FN_E,0x1e1,,,,,,,,,,,,,,
+KEY_FN_F,0x1e2,,,,,,,,,,,,,,
+KEY_FN_S,0x1e3,,,,,,,,,,,,,,
+KEY_FN_B,0x1e4,,,,,,,,,,,,,,
+KEY_BRL_DOT1,0x1f1,,,,,,,,,,,,,,
+KEY_BRL_DOT2,0x1f2,,,,,,,,,,,,,,
+KEY_BRL_DOT3,0x1f3,,,,,,,,,,,,,,
+KEY_BRL_DOT4,0x1f4,,,,,,,,,,,,,,
+KEY_BRL_DOT5,0x1f5,,,,,,,,,,,,,,
+KEY_BRL_DOT6,0x1f6,,,,,,,,,,,,,,
+KEY_BRL_DOT7,0x1f7,,,,,,,,,,,,,,
+KEY_BRL_DOT8,0x1f8,,,,,,,,,,,,,,
+KEY_BRL_DOT9,0x1f9,,,,,,,,,,,,,,
+KEY_BRL_DOT10,0x1fa,,,,,,,,,,,,,,
+KEY_NUMERIC_0,0x200,,,,,,,,,,,,,,
+KEY_NUMERIC_1,0x201,,,,,,,,,,,,,,
+KEY_NUMERIC_2,0x202,,,,,,,,,,,,,,
+KEY_NUMERIC_3,0x203,,,,,,,,,,,,,,
+KEY_NUMERIC_4,0x204,,,,,,,,,,,,,,
+KEY_NUMERIC_5,0x205,,,,,,,,,,,,,,
+KEY_NUMERIC_6,0x206,,,,,,,,,,,,,,
+KEY_NUMERIC_7,0x207,,,,,,,,,,,,,,
+KEY_NUMERIC_8,0x208,,,,,,,,,,,,,,
+KEY_NUMERIC_9,0x209,,,,,,,,,,,,,,
+KEY_NUMERIC_STAR,0x20a,,,,,,,,,,,,,,
+KEY_NUMERIC_POUND,0x20b,,,,,,,,,,,,,,
+KEY_RFKILL,0x20c,,,,,,,,,,,,,,
diff --git a/src/keycodemapdb/tools/keymap-gen b/src/keycodemapdb/tools/keymap-gen
new file mode 100755
index 0000000..3ca8762
--- /dev/null
+++ b/src/keycodemapdb/tools/keymap-gen
@@ -0,0 +1,578 @@
+#!/usr/bin/python
+# -*- python -*-
+#
+# Keycode Map Generator
+#
+# Copyright (C) 2009-2017 Red Hat, Inc.
+#
+# This file is dual license under the terms of the GPLv2 or later
+# and 3-clause BSD licenses.
+#
+
+# Requires >= 2.6
+from __future__ import print_function
+
+import csv
+import argparse
+import hashlib
+import time
+
+class Database:
+
+    # Linux: linux/input.h
+    MAP_LINUX = "linux"
+
+    # OS-X: Carbon/HIToolbox/Events.h
+    MAP_OSX = "osx"
+
+    # AT Set 1: linux/drivers/input/keyboard/atkbd.c
+    #           (atkbd_set2_keycode + atkbd_unxlate_table)
+    MAP_ATSET1 = "atset1"
+
+    # AT Set 2: linux/drivers/input/keyboard/atkbd.c
+    #           (atkbd_set2_keycode)
+    MAP_ATSET2 = "atset2"
+
+    # AT Set 3: linux/drivers/input/keyboard/atkbd.c
+    #           (atkbd_set3_keycode)
+    MAP_ATSET3 = "atset3"
+
+    # XT: linux/drivers/input/keyboard/xt.c (xtkbd_keycode)
+    MAP_XT = "xt"
+
+    # Linux RAW: linux/drivers/char/keyboard.c (x86_keycodes)
+    MAP_XTKBD = "xtkbd"
+
+    # USB HID: linux/drivers/hid/usbhid/usbkbd.c (usb_kbd_keycode)
+    MAP_USB = "usb"
+
+    # Win32: mingw32/winuser.h
+    MAP_WIN32 = "win32"
+
+    # XWin XT: xorg-server/hw/xwin/{winkeybd.c,winkeynames.h}
+    #          (xt + manually transcribed)
+    MAP_XWINXT = "xwinxt"
+
+    # X11: http://cgit.freedesktop.org/xorg/proto/x11proto/plain/keysymdef.h
+    MAP_X11 = "x11"
+
+    # XKBD XT: xf86-input-keyboard/src/at_scancode.c
+    #          (xt + manually transcribed)
+    MAP_XKBDXT = "xkbdxt"
+
+    # Xorg with evdev: linux + an offset
+    MAP_XORGEVDEV = "xorgevdev"
+
+    # Xorg with kbd: xkbdxt + an offset
+    MAP_XORGKBD = "xorgkbd"
+
+    # Xorg with OS-X: osx + an offset
+    MAP_XORGXQUARTZ = "xorgxquartz"
+
+    # Xorg + Cygwin: xwinxt + an offset
+    MAP_XORGXWIN = "xorgxwin"
+
+    # XT over RFB: xtkbd + special re-encoding of high bit
+    MAP_RFB = "rfb"
+
+    MAP_LIST = (
+        MAP_LINUX,
+        MAP_OSX,
+        MAP_ATSET1,
+        MAP_ATSET2,
+        MAP_ATSET3,
+        MAP_XT,
+        MAP_XTKBD,
+        MAP_USB,
+        MAP_WIN32,
+        MAP_XWINXT,
+        MAP_XKBDXT,
+        MAP_X11,
+
+        # These are derived from maps above
+        MAP_XORGEVDEV,
+        MAP_XORGKBD,
+        MAP_XORGXQUARTZ,
+        MAP_XORGXWIN,
+        MAP_RFB,
+    )
+
+    CODE_COLUMNS = {
+        MAP_LINUX: 1,
+        MAP_OSX: 3,
+        MAP_ATSET1: 4,
+        MAP_ATSET2: 5,
+        MAP_ATSET3: 6,
+        MAP_XT: 7,
+        MAP_XTKBD: 8,
+        MAP_USB: 9,
+        MAP_WIN32: 11,
+        MAP_XWINXT: 12,
+        MAP_XKBDXT: 13,
+        MAP_X11: 15,
+    }
+
+    NAME_COLUMNS = {
+        MAP_LINUX: 0,
+        MAP_OSX: 2,
+        MAP_WIN32: 10,
+        MAP_X11: 14,
+    }
+
+    def __init__(self):
+
+        self.mapto = {}
+        self.mapfrom = {}
+        self.mapname = {}
+        self.mapchecksum = None
+
+        for name in self.MAP_LIST:
+            # Key is a MAP_LINUX, value is a MAP_XXX
+            self.mapto[name] = {}
+            # key is a MAP_XXX, value is a MAP_LINUX
+            self.mapfrom[name] = {}
+
+        for name in self.NAME_COLUMNS.keys():
+            # key is a MAP_LINUX, value is a string
+            self.mapname[name] = {}
+
+    def _generate_checksum(self, filename):
+        hash = hashlib.sha256()
+        with open(filename, "rb") as f:
+            for chunk in iter(lambda: f.read(4096), b""):
+                hash.update(chunk)
+        self.mapchecksum = hash.hexdigest()
+
+    def load(self, filename):
+        self._generate_checksum(filename)
+
+        with open(filename, 'r') as f:
+            reader = csv.reader(f)
+
+            first = True
+
+            for row in reader:
+                # Discard column headings
+                if first:
+                    first = False
+                    continue
+
+                # We special case MAP_LINUX since that is out
+                # master via which all other mappings are done
+                linux = self.load_linux(row)
+
+                # Now load all the remaining master data values
+                self.load_data(row, linux)
+
+                # Then load all the keycode names
+                self.load_names(row, linux)
+
+                # Finally calculate derived key maps
+                self.derive_data(row, linux)
+
+    def load_linux(self, row):
+        col = self.CODE_COLUMNS[self.MAP_LINUX]
+        linux = row[col]
+
+        if linux.startswith("0x"):
+            linux = int(linux, 16)
+        else:
+            linux = int(linux, 10)
+
+        self.mapto[self.MAP_LINUX][linux] = linux
+        self.mapfrom[self.MAP_LINUX][linux] = linux
+
+        return linux
+
+
+    def load_data(self, row, linux):
+        for mapname in self.CODE_COLUMNS:
+            if mapname == self.MAP_LINUX:
+                continue
+
+            col = self.CODE_COLUMNS[mapname]
+            val = row[col]
+
+            if val == "":
+                continue
+
+            if val.startswith("0x"):
+                val = int(val, 16)
+            else:
+                val = int(val, 10)
+
+            self.mapto[mapname][linux] = val
+            self.mapfrom[mapname][val] = linux
+
+    def load_names(self, row, linux):
+        for mapname in self.NAME_COLUMNS:
+            col = self.NAME_COLUMNS[mapname]
+            val = row[col]
+
+            if val == "":
+                continue
+
+            self.mapname[mapname][linux] = val
+
+
+    def derive_data(self, row, linux):
+        # Xorg KBD is XKBD XT offset by 8
+        if linux in self.mapto[self.MAP_XKBDXT]:
+            xorgkbd = self.mapto[self.MAP_XKBDXT][linux] + 8
+            self.mapto[self.MAP_XORGXQUARTZ][linux] = xorgkbd
+            self.mapfrom[self.MAP_XORGXQUARTZ][xorgkbd] = linux
+
+        # Xorg evdev is Linux offset by 8
+        self.mapto[self.MAP_XORGEVDEV][linux] = linux + 8
+        self.mapfrom[self.MAP_XORGEVDEV][linux + 8] = linux
+
+        # Xorg XQuartx is OS-X offset by 8
+        if linux in self.mapto[self.MAP_OSX]:
+            xorgxquartz = self.mapto[self.MAP_OSX][linux] + 8
+            self.mapto[self.MAP_XORGXQUARTZ][linux] = xorgxquartz
+            self.mapfrom[self.MAP_XORGXQUARTZ][xorgxquartz] = linux
+
+        # Xorg Xwin (aka Cygwin) is XWin XT offset by 8
+        if linux in self.mapto[self.MAP_XWINXT]:
+            xorgxwin = self.mapto[self.MAP_XWINXT][linux] + 8
+            self.mapto[self.MAP_XORGXWIN][linux] = xorgxwin
+            self.mapfrom[self.MAP_XORGXWIN][xorgxwin] = linux
+
+
+        # RFB keycodes are XT kbd keycodes with a slightly
+        # different encoding of 0xe0 scan codes. RFB uses
+        # the high bit of the first byte, instead of the low
+        # bit of the second byte
+        if linux in self.mapto[self.MAP_XTKBD]:
+            xtkbd = self.mapto[self.MAP_XTKBD][linux]
+            if xtkbd != 0:
+                rfb = ((xtkbd & 0x100) >> 1) | (xtkbd & 0x7f)
+            else:
+                rfb = 0
+            self.mapto[self.MAP_RFB][linux] = rfb
+            self.mapfrom[self.MAP_RFB][rfb] = linux
+
+class LanguageGenerator(object):
+
+    def generate_header(self, database, args):
+        today = time.strftime("%Y-%m-%d %H:%M")
+        self._boilerplate([
+            "This file is auto-generated from keymaps.csv on %s" % today,
+            "Database checksum sha256(%s)" % database.mapchecksum,
+            "To re-generate, run:",
+            "  %s" % args,
+        ])
+
+    def generate_code_map(self, varname, database, frommapname, tomapname):
+        if frommapname not in database.mapfrom:
+            raise Exception("Unknown map %s, expected %s",
+                            frommapname, ",".join(database.mapfrom.keys()))
+        if tomapname not in database.mapto:
+            raise Exception("Unknown map %s, expected %s",
+                            tomapname, ",".join(database.mapto.keys()))
+
+        tolinux = database.mapfrom[frommapname]
+        fromlinux = database.mapto[tomapname]
+
+        if varname is None:
+            varname = "code_map_%s_to_%s" % (frommapname, tomapname)
+
+        frommax = 0
+        for key in tolinux.keys():
+            if key > frommax:
+                frommax = key
+
+        self._array_start_code(varname, frommax + 1)
+        for src in range(frommax + 1):
+            linux = tolinux.get(src, None)
+            if linux is None:
+                dst = None
+            else:
+                dst = fromlinux.get(linux, None)
+
+            comment = "%s -> %s -> %s" % (self._label(database, frommapname, src),
+                                          self._label(database, Database.MAP_LINUX, linux),
+                                          self._label(database, tomapname, dst))
+            self._array_entry_code(src, dst, comment)
+        self._array_end()                                        
+
+    def generate_code_table(self, varname, database, mapname):
+        if mapname not in database.mapto:
+            raise Exception("Unknown map %s, expected %s",
+                            mapname, ",".join(database.mapto.keys()))
+
+        keys = database.mapto[Database.MAP_LINUX].keys()
+        keys.sort()
+        names = [database.mapname[Database.MAP_LINUX].get(key, "unnamed") for key in keys]
+
+        if varname is None:
+            varname = "code_table_%s" % mapname
+
+        self._array_start_code(varname, len(keys))
+
+        for i in range(len(keys)):
+            key = keys[i]
+            dst = database.mapto[mapname].get(key, None)
+            self._array_entry_code(i, dst, names[i])
+
+        self._array_end()
+
+    def generate_name_map(self, varname, database, frommapname, tomapname):
+        if frommapname not in database.mapfrom:
+            raise Exception("Unknown map %s, expected %s",
+                            frommapname, ",".join(database.mapfrom.keys()))
+        if tomapname not in database.mapname:
+            raise Exception("Unknown map %s, expected %s",
+                            tomapname, ",".join(database.mapname.keys()))
+
+        tolinux = database.mapfrom[frommapname]
+        fromlinux = database.mapname[tomapname]
+
+        if varname is None:
+            varname = "name_map_%s_to_%s" % (frommapname, tomapname)
+
+        frommax = 0
+        for key in tolinux.keys():
+            if key > frommax:
+                frommax = key
+
+        self._array_start_name(varname, frommax + 1)
+
+        for src in range(frommax + 1):
+            linux = tolinux.get(src, None)
+            if linux is None:
+                dst = None
+            else:
+                dst = fromlinux.get(linux, None)
+
+            comment = "%s -> %s -> %s" % (self._label(database, frommapname, src),
+                                          self._label(database, Database.MAP_LINUX, linux),
+                                          self._label(database, tomapname, dst))
+            self._array_entry_name(src, dst, comment)
+        self._array_end()                                        
+
+    def generate_name_table(self, varname, database, mapname):
+        if mapname not in database.mapname:
+            raise Exception("Unknown map %s, expected %s",
+                            mapname, ",".join(database.mapname.keys()))
+
+        keys = database.mapto[Database.MAP_LINUX].keys()
+        keys.sort()
+        names = [database.mapname[Database.MAP_LINUX].get(key, "unnamed") for key in keys]
+
+        if varname is None:
+            varname = "name_table_%s" % mapname
+
+        self._array_start_name(varname, len(keys))
+
+        for i in range(len(keys)):
+            key = keys[i]
+            dst = database.mapname[mapname].get(key, None)
+            self._array_entry_name(i, dst, names[i])
+
+        self._array_end()
+
+    def _label(self, database, mapname, val):
+        if mapname in database.mapname:
+            return "%s:%s (%s)" % (mapname, val, database.mapname[mapname].get(val, "unnamed"))
+        else:
+            return "%s:%s" % (mapname, val)
+
+
+class CLanguageGenerator(LanguageGenerator):
+
+    def __init__(self, inttypename, strtypename):
+        self.inttypename = inttypename
+        self.strtypename = strtypename
+
+    def _boilerplate(self, lines):
+        print("/*")
+        for line in lines:
+            print(" * %s" % line)
+        print("*/")
+
+    def _array_start_code(self, varname, length):
+        print("const %s %s[%d] = {" % (self.inttypename, varname, length))
+
+    def _array_start_name(self, varname, length):
+        print("const %s %s[%d] = {" % (self.strtypename, varname, length))
+
+    def _array_end(self):
+        print("};")
+
+    def _array_entry_code(self, index, value, comment):
+        if value is not None:
+            print("  [0x%x] = 0x%x, /* %s */" % (index, value, comment))
+
+    def _array_entry_name(self, index, value, comment):
+        if value is not None:
+            print("  [0x%x] = \"%s\", /* %s */" % (index, value, comment))
+
+class StdCLanguageGenerator(CLanguageGenerator):
+
+    def __init__(self):
+        super(StdCLanguageGenerator, self).__init__("unsigned short", "char *")
+
+class GLib2LanguageGenerator(CLanguageGenerator):
+
+    def __init__(self):
+        super(GLib2LanguageGenerator, self).__init__("guint16", "gchar *")
+
+class PythonLanguageGenerator(LanguageGenerator):
+
+    def _boilerplate(self, lines):
+        print("#")
+        for line in lines:
+            print("# %s" % line)
+        print("#")
+
+    def _array_start_code(self, varname, length):
+        print("%s = [" % varname)
+
+    def _array_start_name(self, varname, length):
+        print("%s = [" % varname)
+
+    def _array_end(self):
+        print("]")
+
+    def _array_entry_code(self, index, value, comment):
+        if value is None:
+            print("  None, # %s" % (comment))
+        else:
+            print("  0x%x, # %s" % (value, comment))
+
+    def _array_entry_name(self, index, value, comment):
+        if value is None:
+            print("  None, # %s" % (comment))
+        else:
+            print("  \"%s\", # %s" % (value, comment))
+
+class PerlLanguageGenerator(LanguageGenerator):
+
+    def _boilerplate(self, lines):
+        print("#")
+        for line in lines:
+            print("# %s" % line)
+        print("#")
+
+    def _array_start_code(self, varname, length):
+        print("my @%s = (" % varname)
+
+    def _array_start_name(self, varname, length):
+        print("my @%s = (" % varname)
+
+    def _array_end(self):
+        print(");")
+
+    def _array_entry_code(self, index, value, comment):
+        if value is None:
+            print("  undef, # %s" % (comment))
+        else:
+            print("  0x%x, # %s" % (value, comment))
+
+    def _array_entry_name(self, index, value, comment):
+        if value is None:
+            print("  undef, # %s" % (comment))
+        else:
+            print("  \"%s\", # %s" % (value, comment))
+
+GENERATORS = {
+    "stdc": StdCLanguageGenerator(),
+    "glib2": GLib2LanguageGenerator(),
+    "python2": PythonLanguageGenerator(),
+    "python3": PythonLanguageGenerator(),
+    "perl": PerlLanguageGenerator(),
+}
+
+def code_map(args):
+    database = Database()
+    database.load(args.keymaps)
+
+    cliargs = ["keymap-gen", "--lang=%s" % args.lang]
+    if args.varname is not None:
+        cliargs.append("--varname=%s" % args.varname)
+    cliargs.extend(["code-map", "keymaps.csv", args.frommapname, args.tomapname])
+    GENERATORS[args.lang].generate_header(database, " ".join(cliargs))
+
+    GENERATORS[args.lang].generate_code_map(args.varname, database, args.frommapname, args.tomapname)
+
+def code_table(args):
+    database = Database()
+    database.load(args.keymaps)
+
+    cliargs = ["keymap-gen", "--lang=%s" % args.lang]
+    if args.varname is not None:
+        cliargs.append("--varname=%s" % args.varname)
+    cliargs.extend(["code-table", "keymaps.csv", args.mapname])
+    GENERATORS[args.lang].generate_header(database, " ".join(cliargs))
+
+    GENERATORS[args.lang].generate_code_table(args.varname, database, args.mapname)
+
+def name_map(args):
+    database = Database()
+    database.load(args.keymaps)
+
+    cliargs = ["keymap-gen", "--lang=%s" % args.lang]
+    if args.varname is not None:
+        cliargs.append("--varname=%s" % args.varname)
+    cliargs.extend(["name-map", "keymaps.csv", args.frommapname, args.tomapname])
+    GENERATORS[args.lang].generate_header(database, " ".join(cliargs))
+
+    GENERATORS[args.lang].generate_name_map(args.varname, database, args.frommapname, args.tomapname)
+
+def name_table(args):
+    database = Database()
+    database.load(args.keymaps)
+
+
+    cliargs = ["keymap-gen", "--lang=%s" % args.lang]
+    if args.varname is not None:
+        cliargs.append("--varname=%s" % args.varname)
+    cliargs.extend(["name-table", "keymaps.csv", args.mapname])
+    GENERATORS[args.lang].generate_header(database, " ".join(cliargs))
+
+    GENERATORS[args.lang].generate_name_table(args.varname, database, args.mapname)
+
+def usage(args):
+    print ("Please select a command:")
+    print ("  'code-map', 'code-table', 'name-map', 'name-table'")
+    sys.exit(1)
+
+def main():
+    parser = argparse.ArgumentParser()
+
+    parser.add_argument("--lang", default="stdc",
+                        help="Output language, %s" % ",".join(GENERATORS.keys()))
+    parser.add_argument("--varname", default=None,
+                        help="Data variable name")
+    parser.set_defaults(func=usage)
+
+    subparsers = parser.add_subparsers(help="sub-command help")
+
+    codemapparser = subparsers.add_parser("code-map", help="Generate a mapping between code tables")
+    codemapparser.add_argument("keymaps", help="Path to keymap CSV data file")
+    codemapparser.add_argument("frommapname", help="Source code table name")
+    codemapparser.add_argument("tomapname", help="Target code table name")
+    codemapparser.set_defaults(func=code_map)
+
+    codetableparser = subparsers.add_parser("code-table", help="Generate a flat code table")
+    codetableparser.add_argument("keymaps", help="Path to keymap CSV data file")
+    codetableparser.add_argument("mapname", help="Code table name")
+    codetableparser.set_defaults(func=code_table)
+
+    namemapparser = subparsers.add_parser("name-map", help="Generate a mapping to names")
+    namemapparser.add_argument("keymaps", help="Path to keymap CSV data file")
+    namemapparser.add_argument("frommapname", help="Source code table name")
+    namemapparser.add_argument("tomapname", help="Target name table name")
+    namemapparser.set_defaults(func=name_map)
+
+    nametableparser = subparsers.add_parser("name-table", help="Generate a flat name table")
+    nametableparser.add_argument("keymaps", help="Path to keymap CSV data file")
+    nametableparser.add_argument("mapname", help="Name table name")
+    nametableparser.set_defaults(func=name_table)
+
+    args = parser.parse_args()
+    args.func(args)
+
+
+main()
diff --git a/src/keymap-gen.pl b/src/keymap-gen.pl
deleted file mode 100644
index 56953f8..0000000
--- a/src/keymap-gen.pl
+++ /dev/null
@@ -1,214 +0,0 @@
-#!/usr/bin/perl
-
-use strict;
-use warnings;
-
-use Text::CSV;
-
-my %names = (
-    linux => [],
-    osx => []
-);
-
-my %namecolumns = (
-    linux => 0,
-    osx => 2,
-    win32 => 10,
-    x11 => 14,
-    );
-
-# Base data sources:
-#
-#  linux:     Linux: linux/input.h                                  (master set)
-#    osx:      OS-X: Carbon/HIToolbox/Events.h                      (manually mapped)
-# atset1:  AT Set 1: linux/drivers/input/keyboard/atkbd.c           (atkbd_set2_keycode + atkbd_unxlate_table)
-# atset2:  AT Set 2: linux/drivers/input/keyboard/atkbd.c           (atkbd_set2_keycode)
-# atset3:  AT Set 3: linux/drivers/input/keyboard/atkbd.c           (atkbd_set3_keycode)
-#     xt:        XT: linux/drivers/input/keyboard/xt.c              (xtkbd_keycode)
-#  xtkbd: Linux RAW: linux/drivers/char/keyboard.c                  (x86_keycodes)
-#    usb:   USB HID: linux/drivers/hid/usbhid/usbkbd.c              (usb_kbd_keycode)
-#  win32:     Win32: mingw32/winuser.h                              (manually mapped)
-# xwinxt:   XWin XT: xorg-server/hw/xwin/{winkeybd.c,winkeynames.h} (xt + manually transcribed)
-# xkbdxt:   XKBD XT: xf86-input-keyboard/src/at_scancode.c
-#(xt + manually transcribed)
-#    x11: X11 keysyms: http://cgit.freedesktop.org/xorg/proto/x11proto/plain/keysymdef.h
-#
-# Derived data sources
-#
-#    xorgevdev: Xorg +  evdev: linux + an offset
-#      xorgkbd: Xorg +    kbd: xkbdxt + an offset
-#  xorgxquartz: Xorg +   OS-X: osx + an offset
-#     xorgxwin: Xorg + Cygwin: xwinxt + an offset
-#          rfb:   XT over RFB: xtkbd + special re-encoding of high bit
-
-my @basemaps = qw(linux osx atset1 atset2 atset3 xt xtkbd usb win32 xwinxt xkbdxt x11);
-my @derivedmaps = qw(xorgevdev xorgkbd xorgxquartz xorgxwin rfb);
-my @maps = (@basemaps, @derivedmaps);
-
-my %maps;
-
-foreach my $map (@maps) {
-    $maps{$map} = [ [], [] ];
-}
-my %mapcolumns = (
-    osx => 3,
-    atset1 => 4,
-    atset2 => 5,
-    atset3 => 6,
-    xt => 7,
-    xtkbd => 8,
-    usb => 9,
-    win32 => 11,
-    xwinxt => 12,
-    xkbdxt => 13,
-    x11 => 15
-    );
-
-sub help {
-    my $msg = shift;
-    print $msg;
-    print "\n";
-    print "Valid keymaps are:\n";
-    print "\n";
-    foreach my $name (sort { $a cmp $b } keys %maps) {
-	print "  $name\n";
-    }
-    print "\n";
-    exit (1);
-}
-
-if ($#ARGV != 2) {
-    help("syntax: $0 KEYMAPS SRCMAP DSTMAP\n");
-}
-
-my $keymaps = shift @ARGV;
-my $src = shift @ARGV;
-my $dst = shift @ARGV;
-
-help("$src is not a known keymap\n") unless exists $maps{$src};
-help("$dst is not a known keymap\n") unless exists $maps{$dst};
-
-
-open CSV, $keymaps
-    or die "cannot read $keymaps: $!";
-
-my $csv = Text::CSV->new();
-# Discard column headings
-$csv->getline(\*CSV);
-
-my $row;
-while ($row = $csv->getline(\*CSV)) {
-    my $linux = $row->[1];
-
-    $linux = hex($linux) if $linux =~ /0x/;
-
-    my $to = $maps{linux}->[0];
-    my $from = $maps{linux}->[1];
-    $to->[$linux] = $linux;
-    $from->[$linux] = $linux;
-
-    foreach my $name (keys %namecolumns) {
-	my $col = $namecolumns{$name};
-	my $val = $row->[$col];
-
-	$val = "" unless defined $val;
-
-	$names{$name}->[$linux] = $val;
-    }
-
-    foreach my $name (keys %mapcolumns) {
-	my $col = $mapcolumns{$name};
-	my $val = $row->[$col];
-
-	next unless defined $val && $val ne "";
-	$val = hex($val) if $val =~ /0x/;
-
-	$to = $maps{$name}->[0];
-        $from = $maps{$name}->[1];
-	$to->[$linux] = $val;
-	$from->[$val] = $linux;
-    }
-
-    # XXX there are some special cases in kbd to handle
-    # Xorg KBD driver is the Xorg KBD XT codes offset by +8
-    # The XKBD XT codes are the same as normal XT codes
-    # for values <= 83, and completely made up for extended
-    # scancodes :-(
-    ($to, $from) = @{$maps{xorgkbd}};
-    if (defined $maps{xkbdxt}->[0]->[$linux]) {
-	$to->[$linux] = $maps{xkbdxt}->[0]->[$linux] + 8;
-	$from->[$to->[$linux]] = $linux;
-    }
-
-    # Xorg evdev is simply Linux keycodes offset by +8
-    ($to, $from) = @{$maps{xorgevdev}};
-    $to->[$linux] = $linux + 8;
-    $from->[$to->[$linux]] = $linux;
-
-    # Xorg XQuartz is simply OS-X keycodes offset by +8
-    ($to, $from) = @{$maps{xorgxquartz}};
-    if (defined $maps{osx}->[0]->[$linux]) {
-	$to->[$linux] = $maps{osx}->[0]->[$linux] + 8;
-	$from->[$to->[$linux]] = $linux;
-    }
-
-    # RFB keycodes are XT kbd keycodes with a slightly
-    # different encoding of 0xe0 scan codes. RFB uses
-    # the high bit of the first byte, instead of the low
-    # bit of the second byte.
-    ($to, $from) = @{$maps{rfb}};
-    my $xtkbd = $maps{xtkbd}->[0]->[$linux];
-    if (defined $xtkbd) {
-	$to->[$linux] = $xtkbd ? (($xtkbd & 0x100)>>1) | ($xtkbd & 0x7f) : 0;
-	$from->[$to->[$linux]] = $linux;
-    }
-
-    # Xorg Cygwin is the Xorg Cygwin XT codes offset by +8
-    # The Cygwin XT codes are the same as normal XT codes
-    # for values <= 83, and completely made up for extended
-    # scancodes :-(
-    ($to, $from) = @{$maps{xorgxwin}};
-    if (defined $maps{xwinxt}->[0]->[$linux]) {
-	$to->[$linux] = $maps{xwinxt}->[0]->[$linux] + 8;
-	$from->[$to->[$linux]] = $linux;
-    }
-
-#    print $linux, "\n";
-}
-
-close CSV;
-
-my $srcmap = $maps{$src}->[1];
-my $dstmap = $maps{$dst}->[0];
-
-printf "static const guint16 keymap_%s2%s[] = {\n", $src, $dst;
-
-for (my $i = 0 ; $i <= $#{$srcmap} ; $i++) {
-    my $linux = $srcmap->[$i] || 0;
-    my $j = $dstmap->[$linux];
-    next unless $linux && $j;
-
-    my $srcname = $names{$src}->[$linux] if exists $names{$src};
-    my $dstname = $names{$dst}->[$linux] if exists $names{$dst};
-    my $vianame = $names{linux}->[$linux] unless $src eq "linux" || $dst eq "linux";
-
-    $srcname = "" unless $srcname;
-    $dstname = "" unless $dstname;
-    $vianame = "" unless $vianame;
-    $srcname = " ($srcname)" if $srcname;
-    $dstname = " ($dstname)" if $dstname;
-    $vianame = " ($vianame)" if $vianame;
-
-    my $comment;
-    if ($src ne "linux" && $dst ne "linux") {
-	$comment = sprintf "%d%s => %d%s via %d%s", $i, $srcname, $j, $dstname, $linux, $vianame;
-    } else {
-	$comment = sprintf "%d%s => %d%s", $i, $srcname, $j, $dstname;
-    }
-
-    my $data = sprintf "[0x%x] = 0x%x,", $i, $j;
-
-    printf "  %-20s /* %s */\n", $data, $comment;
-}
-
-print "};\n";
diff --git a/src/keymaps.csv b/src/keymaps.csv
deleted file mode 100644
index 31708ac..0000000
--- a/src/keymaps.csv
+++ /dev/null
@@ -1,490 +0,0 @@
-"Linux Name","Linux Keycode","OS-X Name","OS-X Keycode","AT set1 keycode","AT set2 keycode","AT set3 keycode",XT,"XT KBD","USB Keycodes","Win32 Name","Win32 Keycode","Xwin XT","Xfree86 KBD XT","X11 keysym","X11 keycode"
-KEY_RESERVED,0,,,,,,,,,,,,,,
-KEY_ESC,1,Escape,0x35,1,118,8,1,1,41,VK_ESCAPE,0x1b,1,1,XK_Escape,0xff1b
-KEY_1,2,ANSI_1,0x12,2,22,22,2,2,30,VK_1,0x31,2,2,XK_1,0x0031
-KEY_2,3,ANSI_2,0x13,3,30,30,3,3,31,VK_2,0x32,3,3,XK_2,0x0032
-KEY_3,4,ANSI_3,0x14,4,38,38,4,4,32,VK_3,0x33,4,4,XK_3,0x0033
-KEY_4,5,ANSI_4,0x15,5,37,37,5,5,33,VK_4,0x34,5,5,XK_4,0x0034
-KEY_5,6,ANSI_5,0x17,6,46,46,6,6,34,VK_5,0x35,6,6,XK_5,0x0035
-KEY_6,7,ANSI_6,0x16,7,54,54,7,7,35,VK_6,0x36,7,7,XK_6,0x0036
-KEY_7,8,ANSI_7,0x1a,8,61,61,8,8,36,VK_7,0x37,8,8,XK_7,0x0037
-KEY_8,9,ANSI_8,0x1c,9,62,62,9,9,37,VK_8,0x38,9,9,XK_8,0x0038
-KEY_9,10,ANSI_9,0x19,10,70,70,10,10,38,VK_9,0x39,10,10,XK_9,0x0039
-KEY_0,11,ANSI_0,0x1d,11,69,69,11,11,39,VK_0,0x30,11,11,XK_0,0x0030
-KEY_MINUS,12,ANSI_Minus,0x1b,12,78,78,12,12,45,VK_OEM_MINUS,0xbd,12,12,XK_minus,0x002d
-KEY_EQUAL,13,ANSI_Equal,0x18,13,85,85,13,13,46,VK_OEM_PLUS,0xbb,13,13,XK_equal,0x003d
-KEY_BACKSPACE,14,Delete,0x33,14,102,102,14,14,42,VK_BACK,0x08,14,14,XK_BackSpace,0xff08
-KEY_TAB,15,Tab,0x30,15,13,13,15,15,43,VK_TAB,0x09,15,15,XK_Tab,0xff09
-KEY_Q,16,ANSI_Q,0xc,16,21,21,16,16,20,VK_Q,0x51,16,16,XK_Q,0x0051
-KEY_Q,16,ANSI_Q,0xc,16,21,21,16,16,20,VK_Q,0x51,16,16,XK_q,0x0071
-KEY_W,17,ANSI_W,0xd,17,29,29,17,17,26,VK_W,0x57,17,17,XK_W,0x0057
-KEY_W,17,ANSI_W,0xd,17,29,29,17,17,26,VK_W,0x57,17,17,XK_w,0x0077
-KEY_E,18,ANSI_E,0xe,18,36,36,18,18,8,VK_E,0x45,18,18,XK_E,0x0045
-KEY_E,18,ANSI_E,0xe,18,36,36,18,18,8,VK_E,0x45,18,18,XK_e,0x0065
-KEY_R,19,ANSI_R,0xf,19,45,45,19,19,21,VK_R,0x52,19,19,XK_R,0x0052
-KEY_R,19,ANSI_R,0xf,19,45,45,19,19,21,VK_R,0x52,19,19,XK_r,0x0072
-KEY_T,20,ANSI_T,0x11,20,44,44,20,20,23,VK_T,0x54,20,20,XK_T,0x0054
-KEY_T,20,ANSI_T,0x11,20,44,44,20,20,23,VK_T,0x54,20,20,XK_t,0x0074
-KEY_Y,21,ANSI_Y,0x10,21,53,53,21,21,28,VK_Y,0x59,21,21,XK_Y,0x0059
-KEY_Y,21,ANSI_Y,0x10,21,53,53,21,21,28,VK_Y,0x59,21,21,XK_y,0x0079
-KEY_U,22,ANSI_U,0x20,22,60,60,22,22,24,VK_U,0x55,22,22,XK_U,0x0055
-KEY_U,22,ANSI_U,0x20,22,60,60,22,22,24,VK_U,0x55,22,22,XK_u,0x0075
-KEY_I,23,ANSI_I,0x22,23,67,67,23,23,12,VK_I,0x49,23,23,XK_I,0x0049
-KEY_I,23,ANSI_I,0x22,23,67,67,23,23,12,VK_I,0x49,23,23,XK_i,0x0069
-KEY_O,24,ANSI_O,0x1f,24,68,68,24,24,18,VK_O,0x4f,24,24,XK_O,0x004f
-KEY_O,24,ANSI_O,0x1f,24,68,68,24,24,18,VK_O,0x4f,24,24,XK_o,0x006f
-KEY_P,25,ANSI_P,0x23,25,77,77,25,25,19,VK_P,0x50,25,25,XK_P,0x0050
-KEY_P,25,ANSI_P,0x23,25,77,77,25,25,19,VK_P,0x50,25,25,XK_p,0x0070
-KEY_LEFTBRACE,26,ANSI_LeftBracket,0x21,26,84,84,26,26,47,VK_OEM_4,0xdb,26,26,XK_bracketleft,0x005b
-KEY_RIGHTBRACE,27,ANSI_RightBracket,0x1e,27,91,91,27,27,48,VK_OEM_6,0xdd,27,27,XK_bracketright,0x005d
-KEY_ENTER,28,Return,0x24,28,90,90,28,28,40,VK_RETURN,0x0d,28,28,XK_Return,0xff0d
-KEY_LEFTCTRL,29,Control,0x3b,29,20,17,29,29,224,VK_LCONTROL,0xa2,29,29,XK_Control_L,0xffe3
-KEY_LEFTCTRL,29,Control,0x3b,29,20,17,29,29,224,VK_CONTROL,0x11,29,29,XK_Control_L,0xffe3
-KEY_A,30,ANSI_A,0x0,30,28,28,30,30,4,VK_A,0x41,30,30,XK_A,0x0041
-KEY_A,30,ANSI_A,0x0,30,28,28,30,30,4,VK_A,0x41,30,30,XK_a,0x0061
-KEY_S,31,ANSI_S,0x1,31,27,27,31,31,22,VK_S,0x53,31,31,XK_S,0x0053
-KEY_S,31,ANSI_S,0x1,31,27,27,31,31,22,VK_S,0x53,31,31,XK_s,0x0073
-KEY_D,32,ANSI_D,0x2,32,35,35,32,32,7,VK_D,0x44,32,32,XK_D,0x0044
-KEY_D,32,ANSI_D,0x2,32,35,35,32,32,7,VK_D,0x44,32,32,XK_d,0x0064
-KEY_F,33,ANSI_F,0x3,33,43,43,33,33,9,VK_F,0x46,33,33,XK_F,0x0046
-KEY_F,33,ANSI_F,0x3,33,43,43,33,33,9,VK_F,0x46,33,33,XK_f,0x0066
-KEY_G,34,ANSI_G,0x5,34,52,52,34,34,10,VK_G,0x47,34,34,XK_G,0x0047
-KEY_G,34,ANSI_G,0x5,34,52,52,34,34,10,VK_G,0x47,34,34,XK_g,0x0067
-KEY_H,35,ANSI_H,0x4,35,51,51,35,35,11,VK_H,0x48,35,35,XK_H,0x0048
-KEY_H,35,ANSI_H,0x4,35,51,51,35,35,11,VK_H,0x48,35,35,XK_h,0x0068
-KEY_J,36,ANSI_J,0x26,36,59,59,36,36,13,VK_J,0x4a,36,36,XK_J,0x004a
-KEY_J,36,ANSI_J,0x26,36,59,59,36,36,13,VK_J,0x4a,36,36,XK_j,0x006a
-KEY_K,37,ANSI_K,0x28,37,66,66,37,37,14,VK_K,0x4b,37,37,XK_K,0x004b
-KEY_K,37,ANSI_K,0x28,37,66,66,37,37,14,VK_K,0x4b,37,37,XK_K,0x006b
-KEY_L,38,ANSI_L,0x25,38,75,75,38,38,15,VK_L,0x4c,38,38,XK_L,0x004c
-KEY_L,38,ANSI_L,0x25,38,75,75,38,38,15,VK_L,0x4c,38,38,XK_l,0x006c
-KEY_SEMICOLON,39,ANSI_Semicolon,0x29,39,76,76,39,39,51,VK_OEM_1,0xba,39,39,XK_semicolon,0x003b
-KEY_APOSTROPHE,40,ANSI_Quote,0x27,40,82,82,40,40,52,VK_OEM_7,0xde,40,40,XK_apostrophe,0x0027
-KEY_GRAVE,41,ANSI_Grave,0x32,41,14,14,41,41,53,VK_OEM_3,0xc0,41,41,XK_grave,0x0060
-KEY_SHIFT,42,Shift,0x38,42,18,18,42,42,225,VK_SHIFT,0x10,42,42,XK_Shift_L,0xffe1
-KEY_LEFTSHIFT,42,Shift,0x38,42,18,18,42,42,225,VK_LSHIFT,0xa0,42,42,XK_Shift_L,0xffe1
-KEY_BACKSLASH,43,ANSI_Backslash,0x2a,43,93,93,43,43,50,VK_OEM_5,0xdc,43,43,XK_backslash,0x005c
-KEY_Z,44,ANSI_Z,0x6,44,26,26,44,44,29,VK_Z,0x5a,44,44,XK_Z,0x005a
-KEY_Z,44,ANSI_Z,0x6,44,26,26,44,44,29,VK_Z,0x5a,44,44,XK_z,0x007a
-KEY_X,45,ANSI_X,0x7,45,34,34,45,45,27,VK_X,0x58,45,45,XK_X,0x0058
-KEY_X,45,ANSI_X,0x7,45,34,34,45,45,27,VK_X,0x58,45,45,XK_x,0x0078
-KEY_C,46,ANSI_C,0x8,46,33,33,46,46,6,VK_C,0x43,46,46,XK_C,0x0043
-KEY_C,46,ANSI_C,0x8,46,33,33,46,46,6,VK_C,0x43,46,46,XK_c,0x0063
-KEY_V,47,ANSI_V,0x9,47,42,42,47,47,25,VK_V,0x56,47,47,XK_V,0x0056
-KEY_V,47,ANSI_V,0x9,47,42,42,47,47,25,VK_V,0x56,47,47,XK_v,0x0076
-KEY_B,48,ANSI_B,0xb,48,50,50,48,48,5,VK_B,0x42,48,48,XK_B,0x0042
-KEY_B,48,ANSI_B,0xb,48,50,50,48,48,5,VK_B,0x42,48,48,XK_b,0x0062
-KEY_N,49,ANSI_N,0x2d,49,49,49,49,49,17,VK_N,0x4e,49,49,XK_N,0x004e
-KEY_N,49,ANSI_N,0x2d,49,49,49,49,49,17,VK_N,0x4e,49,49,XK_n,0x006e
-KEY_M,50,ANSI_M,0x2e,50,58,58,50,50,16,VK_M,0x4d,50,50,XK_M,0x004d
-KEY_M,50,ANSI_M,0x2e,50,58,58,50,50,16,VK_M,0x4d,50,50,XK_m,0x006d
-KEY_COMMA,51,ANSI_Comma,0x2b,51,65,65,51,51,54,VK_OEM_COMMA,0xbc,51,51,XK_comma,0x002c
-KEY_DOT,52,ANSI_Period,0x2f,52,73,73,52,52,55,VK_OEM_PERIOD,0xbe,52,52,XK_period,0x002e
-KEY_SLASH,53,ANSI_Slash,0x2c,53,74,74,53,53,56,VK_OEM_2,0xbf,53,53,XK_slash,0x002f
-KEY_RIGHTSHIFT,54,RightShift,0x3c,54,89,89,54,54,229,VK_RSHIFT,0xa1,54,54,XK_Shift_R,0xffe2
-KEY_KPASTERISK,55,ANSI_KeypadMultiply,0x43,55,124,126,55,55,85,VK_MULTIPLY,0x6a,55,55,XK_multiply,0x00d7
-KEY_LEFTALT,56,Option,0x3a,56,17,25,56,56,226,VK_LMENU,0xa4,56,56,XK_Alt_L,0xffe9
-KEY_LEFTALT,56,Option,0x3a,56,17,25,56,56,226,VK_MENU,0x12,56,56,XK_Alt_L,0xffe9
-KEY_SPACE,57,Space,0x31,57,41,41,57,57,44,VK_SPACE,0x20,57,57,XK_space,0x0020
-KEY_CAPSLOCK,58,CapsLock,0x39,58,88,20,58,58,57,VK_CAPITAL,0x14,58,58,XK_Caps_Lock,0xffe5
-KEY_F1,59,F1,0x7a,59,5,7,59,59,58,VK_F1,0x70,59,59,XK_F1,0xffbe
-KEY_F2,60,F2,0x78,60,6,15,60,60,59,VK_F2,0x71,60,60,XK_F2,0xffbf
-KEY_F3,61,F3,0x63,61,4,23,61,61,60,VK_F3,0x72,61,61,XK_F3,0xffc0
-KEY_F4,62,F4,0x76,62,12,31,62,62,61,VK_F4,0x73,62,62,XK_F4,0xffc1
-KEY_F5,63,F5,0x60,63,3,39,63,63,62,VK_F5,0x74,63,63,XK_F5,0xffc2
-KEY_F6,64,F6,0x61,64,11,47,64,64,63,VK_F6,0x75,64,64,XK_F6,0xffc3
-KEY_F7,65,F7,0x62,65,259,55,65,65,64,VK_F7,0x76,65,65,XK_F7,0xffc4
-KEY_F8,66,F8,0x64,66,10,63,66,66,65,VK_F8,0x77,66,66,XK_F8,0xffc5
-KEY_F9,67,F9,0x65,67,1,71,67,67,66,VK_F9,0x78,67,67,XK_F9,0xffc6
-KEY_F10,68,F10,0x6d,68,9,79,68,68,67,VK_F10,0x79,68,68,XK_F10,0xffc7
-KEY_NUMLOCK,69,,,69,119,118,69,69,83,VK_NUMLOCK,0x90,69,69,XK_Num_Lock,0xff7f
-KEY_SCROLLLOCK,70,,,70,126,95,70,70,71,VK_SCROLL,0x91,70,70,XK_Scroll_Lock,0xff14
-KEY_KP7,71,ANSI_Keypad7,0x59,71,108,108,71,71,95,VK_NUMPAD7,0x67,71,71,XK_KP_7,0xffb7
-KEY_KP8,72,ANSI_Keypad8,0x5b,72,117,117,72,72,96,VK_NUMPAD8,0x68,72,72,XK_KP_8,0xffb8
-KEY_KP9,73,ANSI_Keypad9,0x5c,73,125,125,73,73,97,VK_NUMPAD9,0x69,73,73,XK_KP_9,0xffb9
-KEY_KPMINUS,74,ANSI_KeypadMinus,0x4e,74,123,132,74,74,86,VK_SUBTRACT,0x6d,74,74,XK_KP_Subtract,0xffad
-KEY_KP4,75,ANSI_Keypad4,0x56,75,107,107,75,75,92,VK_NUMPAD4,0x64,75,75,XK_KP_4,0xffb4
-KEY_KP5,76,ANSI_Keypad5,0x57,76,115,115,76,76,93,VK_NUMPAD5,0x65,76,76,XK_KP_5,0xffb5
-KEY_KP6,77,ANSI_Keypad6,0x58,77,116,116,77,77,94,VK_NUMPAD6,0x66,77,77,XK_KP_6,0xffb6
-KEY_KPPLUS,78,ANSI_KeypadPlus,0x45,78,121,124,78,78,87,VK_ADD,0x6b,78,78,XK_KP_Add,0xffab
-KEY_KP1,79,ANSI_Keypad1,0x53,79,105,105,79,79,89,VK_NUMPAD1,0x61,79,79,XK_KP_1,0xffb1
-KEY_KP2,80,ANSI_Keypad2,0x54,80,114,114,80,80,90,VK_NUMPAD2,0x62,80,80,XK_KP_2,0xffb2
-KEY_KP3,81,ANSI_Keypad3,0x55,81,122,122,81,81,91,VK_NUMPAD3,0x63,81,81,XK_KP_3,0xffb3
-KEY_KP0,82,ANSI_Keypad0,0x52,82,112,112,82,82,98,VK_NUMPAD0,0x60,82,82,XK_KP_0,0xffb0
-KEY_KPDOT,83,ANSI_KeypadDecimal,0x41,83,113,113,83,83,99,VK_DECIMAL,0x6e,83,83,XK_KP_Decimal,0xffae
-,84,,,,,,,84,,,,,
-KEY_ZENKAKUHANKAKU,85,,,118,95,,,118,148,,,,
-KEY_102ND,86,,,86,97,19,,86,100,VK_OEM_102,0xe1,,
-KEY_F11,87,F11,0x67,87,120,86,101,87,68,VK_F11,0x7a,,
-KEY_F12,88,F12,0x6f,88,7,94,102,88,69,VK_F12,0x7b,,
-KEY_RO,89,,,115,81,,,115,135,,,,
-KEY_KATAKANA,90,JIS_Kana????,0x68,120,99,,,120,146,VK_KANA,0x15,,
-KEY_HIRAGANA,91,,,119,98,,,119,147,,,,
-KEY_HENKAN,92,,,121,100,134,,121,138,,,,
-KEY_KATAKANAHIRAGANA,93,,,112,19,135,,112,136,,,0xc8,0xc8
-KEY_MUHENKAN,94,,,123,103,133,,123,139,,,,
-KEY_KPJPCOMMA,95,JIS_KeypadComma,0x5f,92,39,,,92,140,,,,,XK_KP_Separator,0xffac
-KEY_KPENTER,96,ANSI_KeypadEnter,0x4c,,158,121,,284,88,,,0x64,0x64,XK_KP_Enter,0xff8d
-KEY_RIGHTCTRL,97,RightControl,0x3e,,,88,,285,228,VK_RCONTROL,0xa3,0x65,0x65,XK_Control_R,0xffe4
-KEY_KPSLASH,98,ANSI_KeypadDivide,0x4b,,181,119,,309,84,VK_DIVIDE,0x6f,0x68,0x68,XK_KP_Divide,0xffaf
-KEY_SYSRQ,99,,,84,260,87,,84,70,"VK_SNAPSHOT ???",0x2c,0x67,0x67,XK_Sys_Req,0xff15
-KEY_RIGHTALT,100,RightOption,0x3d,,,57,,312,230,VK_RMENU,0xa5,0x69,0x69,XK_Alt_R,0xffea
-KEY_LINEFEED,101,,,,,,,91,,,,,
-KEY_HOME,102,Home,0x73,,224,110,,327,74,VK_HOME,0x24,0x59,0x59,XK_Home,0xff50
-KEY_UP,103,UpArrow,0x7e,,236,99,109,328,82,VK_UP,0x26,0x5a,0x5a,XK_Up,0xff52
-KEY_PAGEUP,104,PageUp,0x74,,201,111,,329,75,VK_PRIOR,0x21,0x5b,0x5b,XK_Page_Up,0xff55
-KEY_LEFT,105,LeftArrow,0x7b,,203,97,111,331,80,VK_LEFT,0x25,0x5c,0x5c,XK_Left,0xff51
-KEY_RIGHT,106,RightArrow,0x7c,,205,106,112,333,79,VK_RIGHT,0x27,0x5e,0x5e,XK_Right,0xff53
-KEY_END,107,End,0x77,,225,101,,335,77,VK_END,0x23,0x5f,0x5f,XK_End,0xff57
-KEY_DOWN,108,DownArrow,0x7d,,254,96,110,336,81,VK_DOWN,0x28,0x60,0x60,XK_Down,0xff54
-KEY_PAGEDOWN,109,PageDown,0x79,,243,109,,337,78,VK_NEXT,0x22,0x61,0x61,XK_Page_Down,0xff56
-KEY_INSERT,110,,,,210,103,107,338,73,VK_INSERT,0x2d,0x62,0x62,XK_Insert,0xff63
-KEY_DELETE,111,ForwardDelete,0x75,,244,100,108,339,76,VK_DELETE,0x2e,0x63,0x63,XK_Delete,0xffff
-KEY_MACRO,112,,,,239,142,,367,,,,,
-KEY_MUTE,113,Mute,0x4a,,251,156,,288,127,VK_VOLUME_MUTE,0xad,,
-KEY_VOLUMEDOWN,114,VolumeDown,0x49,,,157,,302,129,VK_VOLUME_DOWN,0xae,,
-KEY_VOLUMEUP,115,VolumeUp,0x48,,233,149,,304,128,VK_VOLUME_UP,0xaf,,
-KEY_POWER,116,,,,,,,350,102,,,,
-KEY_KPEQUAL,117,ANSI_KeypadEquals,0x51,89,15,,,89,103,,,0x76,0x76,XK_KP_Equal,0xffbd
-KEY_KPPLUSMINUS,118,,,,206,,,334,,,,,
-KEY_PAUSE,119,,,,198,98,,326,72,VK_PAUSE,0x013,0x66,0x66,XK_Pause,0xff13
-KEY_SCALE,120,,,,,,,267,,,,,
-KEY_KPCOMMA,121,ANSI_KeypadClear????,0x47,126,109,,,126,133,VK_SEPARATOR??,0x6c,,
-KEY_HANGEUL,122,,,,,,,,144,VK_HANGEUL,0x15,,
-KEY_HANJA,123,,,,,,,269,145,VK_HANJA,0x19,,
-KEY_YEN,124,JIS_Yen,0x5d,125,106,,,125,137,,,0x7d,0x7d
-KEY_LEFTMETA,125,Command,0x37,,,139,,347,227,VK_LWIN,0x5b,0x6b,0x6b,XK_Meta_L,0xffe7
-KEY_RIGHTMETA,126,,,,,140,,348,231,VK_RWIN,0x5c,0x6c,0x6c,XK_Meta_R,0xffe8
-KEY_COMPOSE,127,Function,0x3f,,,141,,349,101,VK_APPS,0x5d,0x6d,0x6d
-KEY_STOP,128,,,,,10,,360,120,VK_BROWSER_STOP,0xa9,,
-KEY_AGAIN,129,,,,,11,,261,121,,,,
-KEY_PROPS,130,,,,,12,,262,118,,,,
-KEY_UNDO,131,,,,,16,,263,122,,,,
-KEY_FRONT,132,,,,,,,268,119,,,,
-KEY_COPY,133,,,,,24,,376,124,,,,
-KEY_OPEN,134,,,,,32,,100,116,,,,
-KEY_PASTE,135,,,,,40,,101,125,,,,
-KEY_FIND,136,,,,,48,,321,126,,,,
-KEY_CUT,137,,,,,56,,316,123,,,,
-KEY_HELP,138,,,,,9,,373,117,VK_HELP,0x2f,,,XK_Help,0xff6a
-KEY_MENU,139,,,,,145,,286,,,,,
-KEY_CALC,140,,,,174,163,,289,251,,,,
-KEY_SETUP,141,,,,,,,102,,,,,
-KEY_SLEEP,142,,,,,,,351,248,VK_SLEEP,0x5f,,
-KEY_WAKEUP,143,,,,,,,355,,,,,
-KEY_FILE,144,,,,,,,103,,,,,
-KEY_SENDFILE,145,,,,,,,104,,,,,
-KEY_DELETEFILE,146,,,,,,,105,,,,,
-KEY_XFER,147,,,,,162,,275,,,,,
-KEY_PROG1,148,,,,,160,,287,,,,,
-KEY_PROG2,149,,,,,161,,279,,,,,
-KEY_WWW,150,,,,,,,258,240,,,,
-KEY_MSDOS,151,,,,,,,106,,,,,
-KEY_SCREENLOCK,152,,,,,150,,274,249,,,,
-KEY_DIRECTION,153,,,,,,,107,,,,,
-KEY_CYCLEWINDOWS,154,,,,,155,,294,,,,,
-KEY_MAIL,155,,,,,,,364,,,,,
-KEY_BOOKMARKS,156,,,,,,,358,,,,,
-KEY_COMPUTER,157,,,,,,,363,,,,,
-KEY_BACK,158,,,,,,,362,241,VK_BROWSER_BACK,0xa6,,
-KEY_FORWARD,159,,,,,,,361,242,VK_BROWSER_FORWARD,0xa7,,
-KEY_CLOSECD,160,,,,,154,,291,,,,,
-KEY_EJECTCD,161,,,,,,,108,236,,,,
-KEY_EJECTCLOSECD,162,,,,,,,381,,,,,
-KEY_NEXTSONG,163,,,,241,147,,281,235,VK_MEDIA_NEXT_TRACK,0xb0,,
-KEY_PLAYPAUSE,164,,,,173,,,290,232,VK_MEDIA_PLAY_PAUSE,0xb3,,
-KEY_PREVIOUSSONG,165,,,,250,148,,272,234,VK_MEDIA_PREV_TRACK,0xb1,,
-KEY_STOPCD,166,,,,164,152,,292,233,VK_MEDIA_STOP,0xb2,,
-KEY_RECORD,167,,,,,158,,305,,,,,
-KEY_REWIND,168,,,,,159,,280,,,,,
-KEY_PHONE,169,,,,,,,99,,,,,
-KEY_ISO,170,ISO_Section,0xa,,,,,112,,,,,
-KEY_CONFIG,171,,,,,,,257,,,,,
-KEY_HOMEPAGE,172,,,,178,151,,306,,VK_BROWSER_HOME,0xac,,
-KEY_REFRESH,173,,,,,,,359,250,VK_BROWSER_REFRESH,0xa8,,
-KEY_EXIT,174,,,,,,,113,,,,,
-KEY_MOVE,175,,,,,,,114,,,,,
-KEY_EDIT,176,,,,,,,264,247,,,,
-KEY_SCROLLUP,177,,,,,,,117,245,,,,
-KEY_SCROLLDOWN,178,,,,,,,271,246,,,,
-KEY_KPLEFTPAREN,179,,,,,,,374,182,,,,
-KEY_KPRIGHTPAREN,180,,,,,,,379,183,,,,
-KEY_NEW,181,,,,,,,265,,,,,
-KEY_REDO,182,,,,,,,266,,,,,
-KEY_F13,183,F13,0x69,93,47,127,,93,104,VK_F13,0x7c,0x6e,0x6e
-KEY_F14,184,F14,0x6b,94,55,128,,94,105,VK_F14,0x7d,0x6f,0x6f
-KEY_F15,185,F15,0x71,95,63,129,,95,106,VK_F15,0x7e,0x70,0x70
-KEY_F16,186,F16,0x6a,,,130,,85,107,VK_F16,0x7f,0x71,0x71
-KEY_F17,187,F17,0x40,,,131,,259,108,VK_F17,0x80,0x72,0x72
-KEY_F18,188,F18,0x4f,,,,,375,109,VK_F18,0x81,,
-KEY_F19,189,F19,0x50,,,,,260,110,VK_F19,0x82,,
-KEY_F20,190,F20,0x5a,,,,,90,111,VK_F20,0x83,,
-KEY_F21,191,,,,,,,116,112,VK_F21,0x84,,
-KEY_F22,192,,,,,,,377,113,VK_F22,0x85,,
-KEY_F23,193,,,,,,,109,114,VK_F23,0x86,,
-KEY_F24,194,,,,,,,111,115,VK_F24,0x87,,
-,195,,,,,,,277,,,,,
-,196,,,,,,,278,,,,,
-,197,,,,,,,282,,,,,
-,198,,,,,,,283,,,,,
-,199,,,,,,,295,,,,,
-KEY_PLAYCD,200,,,,,,,296,,,,,
-KEY_PAUSECD,201,,,,,,,297,,,,,
-KEY_PROG3,202,,,,,,,299,,,,,
-KEY_PROG4,203,,,,,,,300,,,,,
-KEY_DASHBOARD,204,,,,,,,301,,,,,
-KEY_SUSPEND,205,,,,,,,293,,,,,
-KEY_CLOSE,206,,,,,,,303,,,,,
-KEY_PLAY,207,,,,,,,307,,VK_PLAY,0xfa,,
-KEY_FASTFORWARD,208,,,,,,,308,,,,,
-KEY_BASSBOOST,209,,,,,,,310,,,,,
-KEY_PRINT,210,,,,,,,313,,VK_PRINT,0x2a,,
-KEY_HP,211,,,,,,,314,,,,,
-KEY_CAMERA,212,,,,,,,315,,,,,
-KEY_SOUND,213,,,,,,,317,,,,,
-KEY_QUESTION,214,,,,,,,318,,,,,
-KEY_EMAIL,215,,,,,,,319,,VK_LAUNCH_MAIL,0xb4,,
-KEY_CHAT,216,,,,,,,320,,,,,
-KEY_SEARCH,217,,,,,,,357,,VK_BROWSER_SEARCH,0xaa,,
-KEY_CONNECT,218,,,,,,,322,,,,,
-KEY_FINANCE,219,,,,,,,323,,,,,
-KEY_SPORT,220,,,,,,,324,,,,,
-KEY_SHOP,221,,,,,,,325,,,,,
-KEY_ALTERASE,222,,,,,,,276,,,,,
-KEY_CANCEL,223,,,,,,,330,,,,,
-KEY_BRIGHTNESSDOWN,224,,,,,,,332,,,,,
-KEY_BRIGHTNESSUP,225,,,,,,,340,,,,,
-KEY_MEDIA,226,,,,,,,365,,,,,
-KEY_SWITCHVIDEOMODE,227,,,,,,,342,,,,,
-KEY_KBDILLUMTOGGLE,228,,,,,,,343,,,,,
-KEY_KBDILLUMDOWN,229,,,,,,,344,,,,,
-KEY_KBDILLUMUP,230,,,,,,,345,,,,,
-KEY_SEND,231,,,,,,,346,,,,,
-KEY_REPLY,232,,,,,,,356,,,,,
-KEY_FORWARDMAIL,233,,,,,,,270,,,,,
-KEY_SAVE,234,,,,,,,341,,,,,
-KEY_DOCUMENTS,235,,,,,,,368,,,,,
-KEY_BATTERY,236,,,,,,,369,,,,,
-KEY_BLUETOOTH,237,,,,,,,370,,,,,
-KEY_WLAN,238,,,,,,,371,,,,,
-KEY_UWB,239,,,,,,,372,,,,,
-KEY_UNKNOWN,240,,,,,,,,,,,,
-KEY_VIDEO_NEXT,241,,,,,,,,,,,,
-KEY_VIDEO_PREV,242,,,,,,,,,,,,
-KEY_BRIGHTNESS_CYCLE,243,,,,,,,,,,,,
-KEY_BRIGHTNESS_ZERO,244,,,,,,,,,,,,
-KEY_DISPLAY_OFF,245,,,,,,,,,,,,
-KEY_WIMAX,246,,,,,,,,,,,,
-,247,,,,,,,,,,,,
-,248,,,,,,,,,,,,
-,249,,,,,,,,,,,,
-,250,,,,,,,,,,,,
-,251,,,,,,,,,,,,
-,252,,,,,,,,,,,,
-,253,,,,,,,,,,,,
-,254,,,,,,,,,,,,
-,255,,,,182,,,,,,,,
-BTN_MISC,0x100,,,,,,,,,,,,
-BTN_0,0x100,,,,,,,,,VK_LBUTTON,0x01,,
-BTN_1,0x101,,,,,,,,,VK_RBUTTON,0x02,,
-BTN_2,0x102,,,,,,,,,VK_MBUTTON,0x04,,
-BTN_3,0x103,,,,,,,,,VK_XBUTTON1,0x05,,
-BTN_4,0x104,,,,,,,,,VK_XBUTTON2,0x06,,
-BTN_5,0x105,,,,,,,,,,,,
-BTN_6,0x106,,,,,,,,,,,,
-BTN_7,0x107,,,,,,,,,,,,
-BTN_8,0x108,,,,,,,,,,,,
-BTN_9,0x109,,,,,,,,,,,,
-BTN_MOUSE,0x110,,,,,,,,,,,,
-BTN_LEFT,0x110,,,,,,,,,,,,
-BTN_RIGHT,0x111,,,,,,,,,,,,
-BTN_MIDDLE,0x112,,,,,,,,,,,,
-BTN_SIDE,0x113,,,,,,,,,,,,
-BTN_EXTRA,0x114,,,,,,,,,,,,
-BTN_FORWARD,0x115,,,,,,,,,,,,
-BTN_BACK,0x116,,,,,,,,,,,,
-BTN_TASK,0x117,,,,,,,,,,,,
-BTN_JOYSTICK,0x120,,,,,,,,,,,,
-BTN_TRIGGER,0x120,,,,,,,,,,,,
-BTN_THUMB,0x121,,,,,,,,,,,,
-BTN_THUMB2,0x122,,,,,,,,,,,,
-BTN_TOP,0x123,,,,,,,,,,,,
-BTN_TOP2,0x124,,,,,,,,,,,,
-BTN_PINKIE,0x125,,,,,,,,,,,,
-BTN_BASE,0x126,,,,,,,,,,,,
-BTN_BASE2,0x127,,,,,,,,,,,,
-BTN_BASE3,0x128,,,,,,,,,,,,
-BTN_BASE4,0x129,,,,,,,,,,,,
-BTN_BASE5,0x12a,,,,,,,,,,,,
-BTN_BASE6,0x12b,,,,,,,,,,,,
-BTN_DEAD,0x12f,,,,,,,,,,,,
-BTN_GAMEPAD,0x130,,,,,,,,,,,,
-BTN_A,0x130,,,,,,,,,,,,
-BTN_B,0x131,,,,,,,,,,,,
-BTN_C,0x132,,,,,,,,,,,,
-BTN_X,0x133,,,,,,,,,,,,
-BTN_Y,0x134,,,,,,,,,,,,
-BTN_Z,0x135,,,,,,,,,,,,
-BTN_TL,0x136,,,,,,,,,,,,
-BTN_TR,0x137,,,,,,,,,,,,
-BTN_TL2,0x138,,,,,,,,,,,,
-BTN_TR2,0x139,,,,,,,,,,,,
-BTN_SELECT,0x13a,,,,,,,,,,,,
-BTN_START,0x13b,,,,,,,,,,,,
-BTN_MODE,0x13c,,,,,,,,,,,,
-BTN_THUMBL,0x13d,,,,,,,,,,,,
-BTN_THUMBR,0x13e,,,,,,,,,,,,
-BTN_DIGI,0x140,,,,,,,,,,,,
-BTN_TOOL_PEN,0x140,,,,,,,,,,,,
-BTN_TOOL_RUBBER,0x141,,,,,,,,,,,,
-BTN_TOOL_BRUSH,0x142,,,,,,,,,,,,
-BTN_TOOL_PENCIL,0x143,,,,,,,,,,,,
-BTN_TOOL_AIRBRUSH,0x144,,,,,,,,,,,,
-BTN_TOOL_FINGER,0x145,,,,,,,,,,,,
-BTN_TOOL_MOUSE,0x146,,,,,,,,,,,,
-BTN_TOOL_LENS,0x147,,,,,,,,,,,,
-BTN_TOUCH,0x14a,,,,,,,,,,,,
-BTN_STYLUS,0x14b,,,,,,,,,,,,
-BTN_STYLUS2,0x14c,,,,,,,,,,,,
-BTN_TOOL_DOUBLETAP,0x14d,,,,,,,,,,,,
-BTN_TOOL_TRIPLETAP,0x14e,,,,,,,,,,,,
-BTN_TOOL_QUADTAP,0x14f,,,,,,,,,,,,
-BTN_WHEEL,0x150,,,,,,,,,,,,
-BTN_GEAR_DOWN,0x150,,,,,,,,,,,,
-BTN_GEAR_UP,0x151,,,,,,,,,,,,
-KEY_OK,0x160,,,,,,,,,,,,
-KEY_SELECT,0x161,,,,,,,,,VK_SELECT,0x29,,,XK_Select,0xff60
-KEY_GOTO,0x162,,,,,,,,,,,,
-KEY_CLEAR,0x163,,,,,,,,,,,,
-KEY_POWER2,0x164,,,,,,,,,,,,
-KEY_OPTION,0x165,,,,,,,,,,,,
-KEY_INFO,0x166,,,,,,,,,,,,
-KEY_TIME,0x167,,,,,,,,,,,,
-KEY_VENDOR,0x168,,,,,,,,,,,,
-KEY_ARCHIVE,0x169,,,,,,,,,,,,
-KEY_PROGRAM,0x16a,,,,,,,,,,,,
-KEY_CHANNEL,0x16b,,,,,,,,,,,,
-KEY_FAVORITES,0x16c,,,,,,,,,VK_BROWSER_FAVOURITES,0xab,,
-KEY_EPG,0x16d,,,,,,,,,,,,
-KEY_PVR,0x16e,,,,,,,,,,,,
-KEY_MHP,0x16f,,,,,,,,,,,,
-KEY_LANGUAGE,0x170,,,,,,,,,,,,
-KEY_TITLE,0x171,,,,,,,,,,,,
-KEY_SUBTITLE,0x172,,,,,,,,,,,,
-KEY_ANGLE,0x173,,,,,,,,,,,,
-KEY_ZOOM,0x174,,,,,,,,,VK_ZOOM,0xfb,,
-KEY_MODE,0x175,,,,,,,,,,,,
-KEY_KEYBOARD,0x176,,,,,,,,,,,,
-KEY_SCREEN,0x177,,,,,,,,,,,,
-KEY_PC,0x178,,,,,,,,,,,,
-KEY_TV,0x179,,,,,,,,,,,,
-KEY_TV2,0x17a,,,,,,,,,,,,
-KEY_VCR,0x17b,,,,,,,,,,,,
-KEY_VCR2,0x17c,,,,,,,,,,,,
-KEY_SAT,0x17d,,,,,,,,,,,,
-KEY_SAT2,0x17e,,,,,,,,,,,,
-KEY_CD,0x17f,,,,,,,,,,,,
-KEY_TAPE,0x180,,,,,,,,,,,,
-KEY_RADIO,0x181,,,,,,,,,,,,
-KEY_TUNER,0x182,,,,,,,,,,,,
-KEY_PLAYER,0x183,,,,,,,,,,,,
-KEY_TEXT,0x184,,,,,,,,,,,,
-KEY_DVD,0x185,,,,,,,,,,,,
-KEY_AUX,0x186,,,,,,,,,,,,
-KEY_MP3,0x187,,,,,,,,,,,,
-KEY_AUDIO,0x188,,,,,,,,,,,,
-KEY_VIDEO,0x189,,,,,,,,,,,,
-KEY_DIRECTORY,0x18a,,,,,,,,,,,,
-KEY_LIST,0x18b,,,,,,,,,,,,
-KEY_MEMO,0x18c,,,,,,,,,,,,
-KEY_CALENDAR,0x18d,,,,,,,,,,,,
-KEY_RED,0x18e,,,,,,,,,,,,
-KEY_GREEN,0x18f,,,,,,,,,,,,
-KEY_YELLOW,0x190,,,,,,,,,,,,
-KEY_BLUE,0x191,,,,,,,,,,,,
-KEY_CHANNELUP,0x192,,,,,,,,,,,,
-KEY_CHANNELDOWN,0x193,,,,,,,,,,,,
-KEY_FIRST,0x194,,,,,,,,,,,,
-KEY_LAST,0x195,,,,,,,,,,,,
-KEY_AB,0x196,,,,,,,,,,,,
-KEY_NEXT,0x197,,,,,,,,,,,,
-KEY_RESTART,0x198,,,,,,,,,,,,
-KEY_SLOW,0x199,,,,,,,,,,,,
-KEY_SHUFFLE,0x19a,,,,,,,,,,,,
-KEY_BREAK,0x19b,,,,,,,,,,,,
-KEY_PREVIOUS,0x19c,,,,,,,,,,,,
-KEY_DIGITS,0x19d,,,,,,,,,,,,
-KEY_TEEN,0x19e,,,,,,,,,,,,
-KEY_TWEN,0x19f,,,,,,,,,,,,
-KEY_VIDEOPHONE,0x1a0,,,,,,,,,,,,
-KEY_GAMES,0x1a1,,,,,,,,,,,,
-KEY_ZOOMIN,0x1a2,,,,,,,,,,,,
-KEY_ZOOMOUT,0x1a3,,,,,,,,,,,,
-KEY_ZOOMRESET,0x1a4,,,,,,,,,,,,
-KEY_WORDPROCESSOR,0x1a5,,,,,,,,,,,,
-KEY_EDITOR,0x1a6,,,,,,,,,,,,
-KEY_SPREADSHEET,0x1a7,,,,,,,,,,,,
-KEY_GRAPHICSEDITOR,0x1a8,,,,,,,,,,,,
-KEY_PRESENTATION,0x1a9,,,,,,,,,,,,
-KEY_DATABASE,0x1aa,,,,,,,,,,,,
-KEY_NEWS,0x1ab,,,,,,,,,,,,
-KEY_VOICEMAIL,0x1ac,,,,,,,,,,,,
-KEY_ADDRESSBOOK,0x1ad,,,,,,,,,,,,
-KEY_MESSENGER,0x1ae,,,,,,,,,,,,
-KEY_DISPLAYTOGGLE,0x1af,,,,,,,,,,,,
-KEY_SPELLCHECK,0x1b0,,,,,,,,,,,,
-KEY_LOGOFF,0x1b1,,,,,,,,,,,,
-KEY_DOLLAR,0x1b2,,,,,,,,,,,,
-KEY_EURO,0x1b3,,,,,,,,,,,,
-KEY_FRAMEBACK,0x1b4,,,,,,,,,,,,
-KEY_FRAMEFORWARD,0x1b5,,,,,,,,,,,,
-KEY_CONTEXT_MENU,0x1b6,,,,,,,,,,,,
-KEY_MEDIA_REPEAT,0x1b7,,,,,,,,,,,,
-KEY_DEL_EOL,0x1c0,,,,,,,,,,,,
-KEY_DEL_EOS,0x1c1,,,,,,,,,,,,
-KEY_INS_LINE,0x1c2,,,,,,,,,,,,
-KEY_DEL_LINE,0x1c3,,,,,,,,,,,,
-KEY_FN,0x1d0,,,,,,,,,,,,
-KEY_FN_ESC,0x1d1,,,,,,,,,,,,
-KEY_FN_F1,0x1d2,,,,,,,,,,,,
-KEY_FN_F2,0x1d3,,,,,,,,,,,,
-KEY_FN_F3,0x1d4,,,,,,,,,,,,
-KEY_FN_F4,0x1d5,,,,,,,,,,,,
-KEY_FN_F5,0x1d6,,,,,,,,,,,,
-KEY_FN_F6,0x1d7,,,,,,,,,,,,
-KEY_FN_F7,0x1d8,,,,,,,,,,,,
-KEY_FN_F8,0x1d9,,,,,,,,,,,,
-KEY_FN_F9,0x1da,,,,,,,,,,,,
-KEY_FN_F10,0x1db,,,,,,,,,,,,
-KEY_FN_F11,0x1dc,,,,,,,,,,,,
-KEY_FN_F12,0x1dd,,,,,,,,,,,,
-KEY_FN_1,0x1de,,,,,,,,,,,,
-KEY_FN_2,0x1df,,,,,,,,,,,,
-KEY_FN_D,0x1e0,,,,,,,,,,,,
-KEY_FN_E,0x1e1,,,,,,,,,,,,
-KEY_FN_F,0x1e2,,,,,,,,,,,,
-KEY_FN_S,0x1e3,,,,,,,,,,,,
-KEY_FN_B,0x1e4,,,,,,,,,,,,
-KEY_BRL_DOT1,0x1f1,,,,,,,,,,,,
-KEY_BRL_DOT2,0x1f2,,,,,,,,,,,,
-KEY_BRL_DOT3,0x1f3,,,,,,,,,,,,
-KEY_BRL_DOT4,0x1f4,,,,,,,,,,,,
-KEY_BRL_DOT5,0x1f5,,,,,,,,,,,,
-KEY_BRL_DOT6,0x1f6,,,,,,,,,,,,
-KEY_BRL_DOT7,0x1f7,,,,,,,,,,,,
-KEY_BRL_DOT8,0x1f8,,,,,,,,,,,,
-KEY_BRL_DOT9,0x1f9,,,,,,,,,,,,
-KEY_BRL_DOT10,0x1fa,,,,,,,,,,,,
-KEY_NUMERIC_0,0x200,,,,,,,,,,,,
-KEY_NUMERIC_1,0x201,,,,,,,,,,,,
-KEY_NUMERIC_2,0x202,,,,,,,,,,,,
-KEY_NUMERIC_3,0x203,,,,,,,,,,,,
-KEY_NUMERIC_4,0x204,,,,,,,,,,,,
-KEY_NUMERIC_5,0x205,,,,,,,,,,,,
-KEY_NUMERIC_6,0x206,,,,,,,,,,,,
-KEY_NUMERIC_7,0x207,,,,,,,,,,,,
-KEY_NUMERIC_8,0x208,,,,,,,,,,,,
-KEY_NUMERIC_9,0x209,,,,,,,,,,,,
-KEY_NUMERIC_STAR,0x20a,,,,,,,,,,,,
-KEY_NUMERIC_POUND,0x20b,,,,,,,,,,,,
-KEY_RFKILL,0x20c,,,,,,,,,,,,
diff --git a/src/libgtk-vnc_sym.version b/src/libgtk-vnc_sym.version
index c6b91af..8fa21b6 100644
--- a/src/libgtk-vnc_sym.version
+++ b/src/libgtk-vnc_sym.version
@@ -57,6 +57,9 @@
     vnc_display_set_force_size;
     vnc_display_get_force_size;
 
+    vnc_display_set_smoothing;
+    vnc_display_get_smoothing;
+
 # introduced with 0.3.8
     vnc_display_get_option_entries;
 
diff --git a/src/vnccolormap.c b/src/vnccolormap.c
index 25cd2fc..f3e153a 100644
--- a/src/vnccolormap.c
+++ b/src/vnccolormap.c
@@ -119,7 +119,7 @@ gboolean vnc_color_map_set(VncColorMap *map,
                            guint16 green,
                            guint16 blue)
 {
-    if (idx >= (map->size + map->offset))
+    if (idx < map->offset || idx >= (map->size + map->offset))
         return FALSE;
 
     map->colors[idx - map->offset].red = red;
@@ -149,7 +149,7 @@ gboolean vnc_color_map_lookup(VncColorMap *map,
                               guint16 *green,
                               guint16 *blue)
 {
-    if (idx >= (map->size + map->offset))
+    if (idx < map->offset || idx >= (map->size + map->offset))
         return FALSE;
 
     *red = map->colors[idx - map->offset].red;
diff --git a/src/vncconnection.c b/src/vncconnection.c
index 89f07d0..1ddf38d 100644
--- a/src/vncconnection.c
+++ b/src/vncconnection.c
@@ -103,6 +103,8 @@
 #endif
 
 
+#define GTK_VNC_ERROR g_quark_from_static_string("gtk-vnc")
+
 struct wait_queue
 {
     gboolean waiting;
@@ -345,6 +347,23 @@ static GIOCondition g_io_wait(GSocket *sock, GIOCondition cond)
 }
 
 
+static void g_io_wakeup(struct wait_queue *wait)
+{
+    if (wait->waiting)
+        coroutine_yieldto(wait->context, NULL);
+}
+
+
+static gboolean vnc_connection_timeout(gpointer data)
+{
+    struct wait_queue *wait = data;
+
+    g_io_wakeup(wait);
+
+    return FALSE;
+}
+
+
 static GIOCondition g_io_wait_interruptable(struct wait_queue *wait,
                                             GSocket *sock,
                                             GIOCondition cond)
@@ -371,13 +390,6 @@ static GIOCondition g_io_wait_interruptable(struct wait_queue *wait,
         return *ret;
 }
 
-static void g_io_wakeup(struct wait_queue *wait)
-{
-    if (wait->waiting)
-        coroutine_yieldto(wait->context, NULL);
-}
-
-
 /*
  * Call immediately before the main loop does an iteration. Returns
  * true if the condition we're checking is ready for dispatch
@@ -919,8 +931,13 @@ static int vnc_connection_read(VncConnection *conn, void *data, size_t len)
         } else if (priv->read_offset == priv->read_size) {
             int ret = vnc_connection_read_buf(conn);
 
-            if (ret < 0)
-                return ret;
+            if (ret < 0) {
+                if (ret == -EAGAIN) {
+                    return offset == 0 ? -EAGAIN : offset;
+                } else {
+                    return ret;
+                }
+            }
             priv->read_offset = 0;
             priv->read_size = ret;
         }
@@ -933,7 +950,7 @@ static int vnc_connection_read(VncConnection *conn, void *data, size_t len)
         offset += tmp;
     }
 
-    return 0;
+    return len;
 }
 
 /*
@@ -2168,6 +2185,21 @@ static vnc_connection_tight_sum_pixel_func *vnc_connection_tight_sum_pixel_table
     (vnc_connection_tight_sum_pixel_func *)vnc_connection_tight_sum_pixel_32x32,
 };
 
+static gboolean vnc_connection_validate_boundary(VncConnection *conn,
+                                                 guint16 x, guint16 y,
+                                                 guint16 width, guint16 height)
+{
+    VncConnectionPrivate *priv = conn->priv;
+
+    if ((x + width) > priv->width || (y + height) > priv->height) {
+        vnc_connection_set_error(conn, "Framebuffer update %dx%d at %d,%d "
+                                 "outside boundary %dx%d",
+                                 width, height, x, y, priv->width, priv->height);
+    }
+
+    return !vnc_connection_has_error(conn);
+}
+
 
 static void vnc_connection_raw_update(VncConnection *conn,
                                       guint16 x, guint16 y,
@@ -2215,6 +2247,9 @@ static void vnc_connection_copyrect_update(VncConnection *conn,
     src_x = vnc_connection_read_u16(conn);
     src_y = vnc_connection_read_u16(conn);
 
+    if (!vnc_connection_validate_boundary(conn, src_x, src_y, width, height))
+        return;
+
     vnc_framebuffer_copyrect(priv->fb,
                              src_x, src_y,
                              dst_x, dst_y,
@@ -2257,6 +2292,10 @@ static void vnc_connection_hextile_rect(VncConnection *conn,
                 xy = vnc_connection_read_u8(conn);
                 wh = vnc_connection_read_u8(conn);
 
+                if (!vnc_connection_validate_boundary(conn, x + nibhi(xy), y + niblo(xy),
+                                                      nibhi(wh) + 1, niblo(wh) + 1))
+                    return;
+
                 vnc_framebuffer_fill(priv->fb, fg,
                                      x + nibhi(xy), y + niblo(xy),
                                      nibhi(wh) + 1, niblo(wh) + 1);
@@ -2313,6 +2352,9 @@ static void vnc_connection_rre_update(VncConnection *conn,
         sub_w = vnc_connection_read_u16(conn);
         sub_h = vnc_connection_read_u16(conn);
 
+        if (!vnc_connection_validate_boundary(conn, x + sub_x, y + sub_y, sub_w, sub_h))
+            break;
+
         vnc_framebuffer_fill(priv->fb, fg,
                              x + sub_x, y + sub_y, sub_w, sub_h);
     }
@@ -2972,7 +3014,7 @@ static void vnc_connection_rich_cursor_blt(VncConnection *conn, guint8 *pixbuf,
     priv->rich_cursor_blt(conn, pixbuf, image, mask, pitch, width, height);
 }
 
-static void vnc_connection_rich_cursor(VncConnection *conn, int x, int y, int width, int height)
+static void vnc_connection_rich_cursor(VncConnection *conn, guint16 x, guint16 y, guint16 width, guint16 height)
 {
     VncConnectionPrivate *priv = conn->priv;
     struct signal_data sigdata;
@@ -3004,6 +3046,16 @@ static void vnc_connection_rich_cursor(VncConnection *conn, int x, int y, int wi
         g_free(image);
         g_free(mask);
 
+        /* Some broken VNC servers send hot-pixel outside
+         * bounds of the cursor. We could disconnect and
+         * report an error, but it is more user friendly
+         * to just clamp the hot pixel coords
+         */
+        if (x >= width)
+            x = width - 1;
+        if (y >= height)
+            y = height - 1;
+
         priv->cursor = vnc_cursor_new(pixbuf, x, y, width, height);
     }
 
@@ -3015,7 +3067,7 @@ static void vnc_connection_rich_cursor(VncConnection *conn, int x, int y, int wi
     vnc_connection_emit_main_context(conn, VNC_CURSOR_CHANGED, &sigdata);
 }
 
-static void vnc_connection_xcursor(VncConnection *conn, int x, int y, int width, int height)
+static void vnc_connection_xcursor(VncConnection *conn, guint16 x, guint16 y, guint16 width, guint16 height)
 {
     VncConnectionPrivate *priv = conn->priv;
     struct signal_data sigdata;
@@ -3029,7 +3081,7 @@ static void vnc_connection_xcursor(VncConnection *conn, int x, int y, int width,
         guint8 *pixbuf = NULL;
         guint8 *data, *mask, *datap, *maskp;
         guint32 *pixp;
-        int rowlen;
+        guint rowlen;
         int x1, y1;
         guint8 fgrgb[3], bgrgb[3];
         guint32 fg, bg;
@@ -3059,6 +3111,16 @@ static void vnc_connection_xcursor(VncConnection *conn, int x, int y, int width,
         g_free(data);
         g_free(mask);
 
+        /* Some broken VNC servers send hot-pixel outside
+         * bounds of the cursor. We could disconnect and
+         * report an error, but it is more user friendly
+         * to just clamp the hot pixel coords
+         */
+        if (x >= width)
+            x = width - 1;
+        if (y >= height)
+            y = height - 1;
+
         priv->cursor = vnc_cursor_new(pixbuf, x, y, width, height);
     }
 
@@ -3079,22 +3141,6 @@ static void vnc_connection_ext_key_event(VncConnection *conn)
 }
 
 
-static gboolean vnc_connection_validate_boundary(VncConnection *conn,
-                                                 guint16 x, guint16 y,
-                                                 guint16 width, guint16 height)
-{
-    VncConnectionPrivate *priv = conn->priv;
-
-    if ((x + width) > priv->width || (y + height) > priv->height) {
-        vnc_connection_set_error(conn, "Framebuffer update %dx%d at %d,%d "
-                                 "outside boundary %dx%d",
-                                 width, height, x, y, priv->width, priv->height);
-    }
-
-    return !vnc_connection_has_error(conn);
-}
-
-
 static gboolean vnc_connection_framebuffer_update(VncConnection *conn, gint32 etype,
                                                   guint16 x, guint16 y,
                                                   guint16 width, guint16 height)
@@ -3324,14 +3370,24 @@ static gboolean vnc_connection_server_message(VncConnection *conn)
         VncColorMap *map;
         int i;
 
+        if (priv->fmt.true_color_flag) {
+            vnc_connection_set_error(conn, "Got color map entries in true-color pix format");
+            break;
+        }
+
         vnc_connection_read(conn, pad, 1);
         first_color = vnc_connection_read_u16(conn);
         n_colors = vnc_connection_read_u16(conn);
 
         VNC_DEBUG("Colour map from %d with %d entries",
                   first_color, n_colors);
-        map = vnc_color_map_new(first_color, n_colors);
 
+        if (first_color > (65536 - n_colors)) {
+            vnc_connection_set_error(conn, "Colormap start %d out of range %d", first_color, 65536 - n_colors);
+            break;
+        }
+
+        map = vnc_color_map_new(first_color, n_colors);
         for (i = 0; i < n_colors; i++) {
             guint16 red, green, blue;
 
@@ -3339,9 +3395,14 @@ static gboolean vnc_connection_server_message(VncConnection *conn)
             green = vnc_connection_read_u16(conn);
             blue = vnc_connection_read_u16(conn);
 
-            vnc_color_map_set(map,
-                              i + first_color,
-                              red, green, blue);
+            if (!vnc_color_map_set(map,
+                                   i + first_color,
+                                   red, green, blue)) {
+                /* Should not be reachable given earlier range check */
+                vnc_connection_set_error(conn, "Colormap index %d out of range %d,%d",
+                                         i + first_color, first_color, 65536 - n_colors);
+                break;
+            }
         }
 
         vnc_framebuffer_set_color_map(priv->fb, map);
@@ -5000,6 +5061,7 @@ static void vnc_connection_close(VncConnection *conn)
 
     if (priv->tls_session) {
         gnutls_bye(priv->tls_session, GNUTLS_SHUT_RDWR);
+        gnutls_deinit(priv->tls_session);
         priv->tls_session = NULL;
     }
 #ifdef HAVE_SASL
@@ -5192,16 +5254,66 @@ static gboolean vnc_connection_after_version (VncConnection *conn, int major, in
 static gboolean vnc_connection_initialize(VncConnection *conn)
 {
     VncConnectionPrivate *priv = conn->priv;
-    int ret, i;
+    int ret, i, want;
     char version[13];
     guint32 n_name;
+    gboolean partialGreeting = FALSE;
+    guint timeout;
 
     priv->absPointer = TRUE;
 
-    vnc_connection_read(conn, version, 12);
-    if (vnc_connection_has_error(conn)) {
-        VNC_DEBUG("Error while reading server version");
-        goto fail;
+    timeout = g_timeout_add_seconds(2, vnc_connection_timeout, &priv->wait);
+    want = 12;
+    while (want > 0) {
+        priv->wait_interruptable = 1;
+        ret = vnc_connection_read(conn, version + (12 - want), want);
+        priv->wait_interruptable = 0;
+        if (vnc_connection_has_error(conn)) {
+            VNC_DEBUG("Error while reading server version");
+            goto fail;
+        }
+        if (ret >= 0) {
+            want -= ret;
+            if (ret != 12)  {
+                timeout = 0;
+            }
+        } else {
+            if (ret == -EAGAIN) {
+                /*
+                 * We didn't see any RFB greeting before our
+                 * timeout. We might have mistakenly connected
+                 * to a SPICE server, in which case we might
+                 * wait forever, since SPICE expects the client
+                 * to send first.
+                 *
+                 * We'll proactively send the 'RFB ' bytes to the
+                 * sever. If we've just got a slow VNC server, it'll
+                 * be harmless, but if we've got a SPICE server, this
+                 * should trigger it to close the connection, avoiding
+                 * us waiting foever.
+                 *
+                 * NB, while we could just send the "RFB " bytes
+                 * immediately, the libvncserver code does something
+                 * really crazy. When it sees a client connection, it
+                 * waits 100ms for an HTTP GET request to indicate
+                 * use of websockets proxy. If it sees the RFB bytes
+                 * it doesn't run a normal VNC connection, it just kills
+                 * the connection :-(
+                 */
+                VNC_DEBUG("No server greeting, sending partial client greeting");
+                vnc_connection_write(conn, "RFB ", 4);
+                vnc_connection_flush(conn);
+                partialGreeting = TRUE;
+                timeout = 0;
+            } else {
+                VNC_DEBUG("Unexpected read error during greeting");
+                goto fail;
+            }
+        }
+    }
+
+    if (timeout != 0) {
+        g_source_remove(timeout);
     }
 
     version[12] = 0;
@@ -5226,8 +5338,16 @@ static gboolean vnc_connection_initialize(VncConnection *conn)
         priv->minor = 8;
     }
 
-    snprintf(version, 13, "RFB %03d.%03d\n", priv->major, priv->minor);
-    vnc_connection_write(conn, version, 12);
+    if (partialGreeting) {
+        VNC_DEBUG("Sending rest of greeting");
+        snprintf(version, 13, "%03d.%03d\n", priv->major, priv->minor);
+        want = 8;
+    } else {
+        VNC_DEBUG("Sending full greeting");
+        snprintf(version, 13, "RFB %03d.%03d\n", priv->major, priv->minor);
+        want = 12;
+    }
+    vnc_connection_write(conn, version, want);
     vnc_connection_flush(conn);
     VNC_DEBUG("Using version: %d.%d", priv->major, priv->minor);
 
@@ -5293,15 +5413,6 @@ static gboolean vnc_connection_open_fd_internal(VncConnection *conn)
     return !vnc_connection_has_error(conn);
 }
 
-static gboolean connect_timeout(gpointer data)
-{
-    struct wait_queue *wait = data;
-
-    g_io_wakeup(wait);
-
-    return FALSE;
-}
-
 static GSocket *vnc_connection_connect_socket(struct wait_queue *wait,
                                               GSocketAddress *sockaddr,
                                               GError **error)
@@ -5314,7 +5425,7 @@ static GSocket *vnc_connection_connect_socket(struct wait_queue *wait,
     if (!sock)
         return NULL;
 
-    guint timeout = g_timeout_add_seconds(10, connect_timeout, wait);
+    guint timeout = g_timeout_add_seconds(10, vnc_connection_timeout, wait);
 
     g_socket_set_blocking(sock, FALSE);
     if (!g_socket_connect(sock, sockaddr, NULL, error)) {
@@ -5323,6 +5434,7 @@ static GSocket *vnc_connection_connect_socket(struct wait_queue *wait,
             *error = NULL;
             VNC_DEBUG("Socket pending");
             if (!g_io_wait_interruptable(wait, sock, G_IO_OUT|G_IO_ERR|G_IO_HUP)) {
+                g_set_error(error, GTK_VNC_ERROR, 0, "%s", "Connection timed out");
                 VNC_DEBUG("connect interrupted");
                 timeout = 0;
                 goto timeout;
@@ -5360,13 +5472,13 @@ static gboolean vnc_connection_open_addr_internal(VncConnection *conn)
     VNC_DEBUG("Connecting with addr %p", priv->addr);
 
     sock = vnc_connection_connect_socket(&priv->wait, priv->addr, &conn_error);
-    vnc_connection_set_error(conn, "Unable to connect: %s",
-                             conn_error->message);
-    g_clear_error(&conn_error);
     if (sock) {
         priv->sock = sock;
         return TRUE;
     }
+    vnc_connection_set_error(conn, "Unable to connect: %s",
+                             conn_error ? conn_error->message : "Unknown problem");
+    g_clear_error(&conn_error);
     return FALSE;
 }
 
@@ -5383,6 +5495,8 @@ static gboolean vnc_connection_open_host_internal(VncConnection *conn)
 
     VNC_DEBUG("Resolving host %s %s", priv->host, priv->port);
 
+    g_return_val_if_fail((priv->host != NULL) && (port != 0), FALSE);
+
     addr = g_network_address_new(priv->host, port);
 
     enumerator = g_socket_connectable_enumerate (addr);
@@ -5401,8 +5515,9 @@ static gboolean vnc_connection_open_host_internal(VncConnection *conn)
     }
     g_object_unref(enumerator);
     if (!sock) {
-        vnc_connection_set_error(conn, "Unable to connect: %s",
-                                 conn_error->message);
+        vnc_connection_set_error(conn, "Unable to connect to %s:%s: %s",
+                                 priv->host, priv->port,
+                                 conn_error ? conn_error->message : "Unknown problem");
     }
     g_clear_error(&conn_error);
     if (sock) {
diff --git a/src/vncconnection.h b/src/vncconnection.h
index 8c1fa28..3477d1b 100644
--- a/src/vncconnection.h
+++ b/src/vncconnection.h
@@ -85,7 +85,7 @@ struct _VncConnectionClass
      * If adding fields to this struct, remove corresponding
      * amount of padding to avoid changing overall struct size
      */
-    gpointer _vnc_reserved[VNC_PADDING_LARGE - 5];
+    gpointer _vnc_reserved[VNC_PADDING_LARGE - 2];
 };
 
 
diff --git a/src/vncconnectiontest.c b/src/vncconnectiontest.c
new file mode 100644
index 0000000..7caaa6e
--- /dev/null
+++ b/src/vncconnectiontest.c
@@ -0,0 +1,628 @@
+/*
+ * GTK VNC Widget
+ *
+ * Copyright (C) 2006  Anthony Liguori <anthony at codemonkey.ws>
+ * Copyright (C) 2009-2010 Daniel P. Berrange <dan at berrange.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.0 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <config.h>
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "vncconnection.h"
+#include "vncbaseframebuffer.h"
+
+static gboolean debug;
+
+#if GLIB_CHECK_VERSION(2, 22, 0)
+
+struct GVncTest {
+    GMutex lock;
+    GMutex clock;
+    GCond cond;
+    int port;
+    VncConnection *conn;
+    GMainLoop *loop;
+    gboolean connected;
+    gboolean quit;
+    char *error;
+
+    guint8 *pixels;
+
+    void (*test_func)(GInputStream *, GOutputStream *);
+};
+
+
+static void test_send_bytes(GOutputStream *os, const guint8 *str, gsize len)
+{
+    g_assert(g_output_stream_write_all(os, str, len, NULL, NULL, NULL));
+}
+
+static void test_send_u8(GOutputStream *os, guint8 v)
+{
+    g_assert(g_output_stream_write_all(os, &v, 1, NULL, NULL, NULL));
+}
+
+static void test_send_u16(GOutputStream *os, guint16 v)
+{
+    v = GUINT16_TO_BE(v);
+    g_assert(g_output_stream_write_all(os, &v, 2, NULL, NULL, NULL));
+}
+
+static void test_send_u32(GOutputStream *os, guint32 v)
+{
+    v = GUINT32_TO_BE(v);
+    g_assert(g_output_stream_write_all(os, &v, 4, NULL, NULL, NULL));
+}
+
+static void test_send_s32(GOutputStream *os, gint32 v)
+{
+    v = GINT32_TO_BE(v);
+    g_assert(g_output_stream_write_all(os, &v, 4, NULL, NULL, NULL));
+}
+
+static void test_recv_bytes(GInputStream *is, guint8 *str, gsize len)
+{
+    g_assert(g_input_stream_read_all(is, str, len, NULL, NULL, NULL));
+}
+
+static void test_recv_u8(GInputStream *is, guint8 v)
+{
+    guint8 e;
+    g_assert(g_input_stream_read_all(is, &e, 1, NULL, NULL, NULL));
+    g_assert(e == v);
+}
+
+static void test_recv_u16(GInputStream *is, guint16 v)
+{
+    guint16 e;
+    g_assert(g_input_stream_read_all(is, &e, 2, NULL, NULL, NULL));
+    e = GINT16_FROM_BE(e);
+    g_assert(e == v);
+}
+
+static void test_recv_s32(GInputStream *is, gint32 v)
+{
+    gint32 e;
+    g_assert(g_input_stream_read_all(is, &e, 4, NULL, NULL, NULL));
+    e = GINT32_FROM_BE(e);
+    g_assert(e == v);
+}
+
+
+static gpointer test_helper_server(gpointer opaque)
+{
+    struct GVncTest *data = opaque;
+    GSocketListener *server;
+    GSocketConnection *client;
+    GIOStream *ios;
+    GInputStream *is;
+    GOutputStream *os;
+
+    server = g_socket_listener_new();
+
+    data->port = g_socket_listener_add_any_inet_port(server, NULL, NULL);
+    g_mutex_unlock(&data->lock);
+
+    client = g_socket_listener_accept(server, NULL, NULL, NULL);
+
+    ios = G_IO_STREAM(client);
+    is = g_io_stream_get_input_stream(ios);
+    os = g_io_stream_get_output_stream(ios);
+
+    guint8 greeting[] = {
+        'R', 'F', 'B', ' ',
+        '0', '0', '3', '.',
+        '0', '0', '8', '\n',
+    };
+
+    /* Greeting */
+    test_send_bytes(os, greeting, G_N_ELEMENTS(greeting));
+    test_recv_bytes(is, greeting, G_N_ELEMENTS(greeting));
+
+    /* N auth */
+    test_send_u8(os, 1);
+    /* auth == none */
+    test_send_u8(os, 1);
+    test_recv_u8(is, 1);
+
+    /* auth result */
+    test_send_u32(os, 0);
+
+    /* shared flag */
+    test_recv_u8(is, 0);
+
+    data->test_func(is, os);
+
+    g_mutex_lock(&data->clock);
+    while (!data->quit) {
+        g_cond_wait(&data->cond, &data->clock);
+    }
+
+    g_object_unref(client);
+
+    return NULL;
+}
+
+static void test_helper_desktop_resize(VncConnection *conn,
+                                       int width, int height,
+                                       gpointer opaque)
+{
+    struct GVncTest *test = opaque;
+    const VncPixelFormat *remoteFormat;
+    VncPixelFormat localFormat = {
+        .bits_per_pixel = 32,
+        .depth = 32,
+        .byte_order = G_BYTE_ORDER,
+        .true_color_flag = TRUE,
+        .red_max = 255,
+        .green_max = 255,
+        .blue_max = 255,
+        .red_shift = 0,
+        .green_shift = 8,
+        .blue_shift = 16,
+    };
+    VncBaseFramebuffer *fb;
+
+
+    VNC_DEBUG("Resize %dx%d", width, height);
+    remoteFormat = vnc_connection_get_pixel_format(conn);
+
+    /* We'll fix our local copy as rgb888 */
+    test->pixels = g_new0(guint8, width * height * 4);
+
+    fb = vnc_base_framebuffer_new(test->pixels, width, height, width * 4,
+                                  &localFormat, remoteFormat);
+
+    vnc_connection_set_framebuffer(conn, VNC_FRAMEBUFFER(fb));
+
+    g_object_unref(fb);
+}
+
+
+static void test_helper_initialized(VncConnection *conn,
+                                    gpointer opaque)
+{
+    struct GVncTest *test = opaque;
+    gint32 encodings[] = {  VNC_CONNECTION_ENCODING_ZRLE,
+                            VNC_CONNECTION_ENCODING_HEXTILE,
+                            VNC_CONNECTION_ENCODING_RRE,
+                            VNC_CONNECTION_ENCODING_COPY_RECT,
+                            VNC_CONNECTION_ENCODING_RAW };
+    gint32 *encodingsp;
+    int n_encodings;
+
+    test_helper_desktop_resize(conn,
+                               vnc_connection_get_width(conn),
+                               vnc_connection_get_height(conn),
+                               test);
+
+    encodingsp = encodings;
+    n_encodings = G_N_ELEMENTS(encodings);
+
+    VNC_DEBUG("Sending %d encodings", n_encodings);
+    if (!vnc_connection_set_encodings(conn, n_encodings, encodingsp))
+        goto error;
+
+    VNC_DEBUG("Requesting first framebuffer update");
+    if (!vnc_connection_framebuffer_update_request(test->conn,
+                                                   0, 0, 0,
+                                                   vnc_connection_get_width(test->conn),
+                                                   vnc_connection_get_height(test->conn)))
+        vnc_connection_shutdown(test->conn);
+
+    test->connected = TRUE;
+    return;
+
+ error:
+    vnc_connection_shutdown(conn);
+}
+
+static void test_helper_auth_choose_type(VncConnection *conn,
+                                         GValueArray *types G_GNUC_UNUSED,
+                                         gpointer opaque G_GNUC_UNUSED)
+{
+    vnc_connection_set_auth_type(conn, VNC_CONNECTION_AUTH_NONE);
+}
+
+
+static void test_helper_disconnected(VncConnection *conn G_GNUC_UNUSED,
+                                     gpointer opaque)
+{
+    struct GVncTest *test = opaque;
+    g_main_quit(test->loop);
+}
+
+static void test_helper_error(VncConnection *conn,
+                              const char *str,
+                              gpointer opaque)
+{
+    struct GVncTest *test = opaque;
+    test->error = g_strdup(str);
+}
+
+static void test_common_bounds_server(GInputStream *is, GOutputStream *os)
+{
+    /* Frame buffer width / height */
+    test_send_u16(os, 100);
+    test_send_u16(os, 100);
+
+    /* BPP, depth, endian, true color */
+    test_send_u8(os, 32);
+    test_send_u8(os, 8);
+    test_send_u8(os, 1);
+    test_send_u8(os, 1);
+
+    /* RGB max + shift*/
+    test_send_u16(os, 255);
+    test_send_u16(os, 255);
+    test_send_u16(os, 255);
+    test_send_u8(os, 0);
+    test_send_u8(os, 8);
+    test_send_u8(os, 16);
+
+    guint8 pad[3] = {0};
+    test_send_bytes(os, pad, G_N_ELEMENTS(pad));
+
+    /* name */
+    guint8 name[] = { 'T', 'e', 's', 't' };
+    test_send_u32(os, G_N_ELEMENTS(name));
+    test_send_bytes(os, name, G_N_ELEMENTS(name));
+}
+
+static void test_rre_bounds_server(GInputStream *is, GOutputStream *os)
+{
+    test_common_bounds_server(is, os);
+
+    /* Message type & pad */
+    test_send_u8(os, 0);
+    test_send_u8(os, 0);
+
+    /* num rect */
+    test_send_u16(os, 1);
+    /* x, y, w, h */
+    test_send_u16(os, 90);
+    test_send_u16(os, 90);
+    test_send_u16(os, 10);
+    test_send_u16(os, 10);
+
+    /* encoding=rre */
+    test_send_s32(os, 2);
+
+    /* num rect */
+    test_send_u32(os, 1);
+
+    /* bg pix, fg pix */
+    test_send_u32(os, 0x41414141);
+    test_send_u32(os, 0x42424242);
+
+    /* x, y, w, h */
+    test_send_u16(os, 10);
+    test_send_u16(os, 10000);
+    test_send_u16(os, 1);
+    test_send_u16(os, 1);
+}
+
+
+static void test_hextile_bounds_server(GInputStream *is, GOutputStream *os)
+{
+    test_common_bounds_server(is, os);
+
+    /* Message type & pad */
+    test_send_u8(os, 0);
+    test_send_u8(os, 0);
+
+    /* num rect */
+    test_send_u16(os, 1);
+    /* x, y, w, h */
+    test_send_u16(os, 90);
+    test_send_u16(os, 90);
+    test_send_u16(os, 10);
+    test_send_u16(os, 10);
+
+    /* encoding=hextile */
+    test_send_s32(os, 5);
+
+    /* tile type */
+    test_send_u8(os, 0x18);
+
+    /* num rect */
+    test_send_u8(os, 1);
+
+    /* fg pix */
+    test_send_u32(os, 0x12345678);
+
+    /* x, y */
+    test_send_u8(os, 0xff);
+    test_send_u8(os, 0xff);
+}
+
+
+static void test_copyrect_bounds_server(GInputStream *is, GOutputStream *os)
+{
+    test_common_bounds_server(is, os);
+
+    /* Message type & pad */
+    test_send_u8(os, 0);
+    test_send_u8(os, 0);
+
+    /* num rect */
+    test_send_u16(os, 1);
+    /* x, y, w, h */
+    test_send_u16(os, 90);
+    test_send_u16(os, 90);
+    test_send_u16(os, 10);
+    test_send_u16(os, 10);
+
+    /* encoding=copyrect */
+    test_send_s32(os, 1);
+
+    /* src x, y */
+    test_send_u16(os, 91);
+    test_send_u16(os, 91);
+}
+
+
+static void test_unexpected_cmap_server(GInputStream *is, GOutputStream *os)
+{
+    /* Frame buffer width / height */
+    test_send_u16(os, 100);
+    test_send_u16(os, 100);
+
+    /* BPP, depth, endian, true color */
+    test_send_u8(os, 32);
+    test_send_u8(os, 8);
+    test_send_u8(os, 1);
+    test_send_u8(os, 1);
+
+    /* RGB max + shift*/
+    test_send_u16(os, 255);
+    test_send_u16(os, 255);
+    test_send_u16(os, 255);
+    test_send_u8(os, 0);
+    test_send_u8(os, 8);
+    test_send_u8(os, 16);
+
+    guint8 pad[3] = {0};
+    test_send_bytes(os, pad, G_N_ELEMENTS(pad));
+
+    /* name */
+    guint8 name[] = { 'T', 'e', 's', 't' };
+    test_send_u32(os, G_N_ELEMENTS(name));
+    test_send_bytes(os, name, G_N_ELEMENTS(name));
+
+    /* n-encodings */
+    test_recv_u8(is, 2);
+    /* pad */
+    test_recv_u8(is, 0);
+    /* num encodings */
+    test_recv_u16(is, 5);
+
+    /* encodings */
+    test_recv_s32(is, 16);
+    test_recv_s32(is, 5);
+    test_recv_s32(is, 2);
+    test_recv_s32(is, 1);
+    test_recv_s32(is, 0);
+
+    /* update request */
+    test_recv_u8(is, 3);
+    /* ! incremental */
+    test_recv_u8(is, 0);
+
+    /* x, y, w, h */
+    test_recv_u16(is, 0);
+    test_recv_u16(is, 0);
+    test_recv_u16(is, 100);
+    test_recv_u16(is, 100);
+
+    /* set color map */
+    test_send_u8(os, 1);
+    /* pad */
+    test_send_u8(os, 0);
+    /* first color, ncolors */
+    test_send_u16(os, 0);
+    test_send_u16(os, 1);
+
+    /* r,g,b */
+    test_send_u16(os, 128);
+    test_send_u16(os, 128);
+    test_send_u16(os, 128);
+}
+
+
+static void test_overflow_cmap_server(GInputStream *is, GOutputStream *os)
+{
+    /* Frame buffer width / height */
+    test_send_u16(os, 100);
+    test_send_u16(os, 100);
+
+    /* BPP, depth, endian, true color */
+    test_send_u8(os, 32);
+    test_send_u8(os, 8);
+    test_send_u8(os, 1);
+    test_send_u8(os, 0);
+
+    /* RGB max + shift*/
+    test_send_u16(os, 255);
+    test_send_u16(os, 255);
+    test_send_u16(os, 255);
+    test_send_u8(os, 0);
+    test_send_u8(os, 8);
+    test_send_u8(os, 16);
+
+    guint8 pad[3] = {0};
+    test_send_bytes(os, pad, G_N_ELEMENTS(pad));
+
+    /* name */
+    guint8 name[] = { 'T', 'e', 's', 't' };
+    test_send_u32(os, G_N_ELEMENTS(name));
+    test_send_bytes(os, name, G_N_ELEMENTS(name));
+
+    /* n-encodings */
+    test_recv_u8(is, 2);
+    /* pad */
+    test_recv_u8(is, 0);
+    /* num encodings */
+    test_recv_u16(is, 5);
+
+    /* encodings */
+    test_recv_s32(is, 16);
+    test_recv_s32(is, 5);
+    test_recv_s32(is, 2);
+    test_recv_s32(is, 1);
+    test_recv_s32(is, 0);
+
+    /* update request */
+    test_recv_u8(is, 3);
+    /* ! incremental */
+    test_recv_u8(is, 0);
+
+    /* x, y, w, h */
+    test_recv_u16(is, 0);
+    test_recv_u16(is, 0);
+    test_recv_u16(is, 100);
+    test_recv_u16(is, 100);
+
+    /* set color map */
+    test_send_u8(os, 1);
+    /* pad */
+    test_send_u8(os, 0);
+    /* first color, ncolors */
+    test_send_u16(os, 65535);
+    test_send_u16(os, 2);
+
+    /* r,g,b */
+    for (int i = 0 ; i < 2; i++) {
+        test_send_u16(os, i);
+        test_send_u16(os, i);
+        test_send_u16(os, i);
+    }
+}
+
+
+static void test_validation(void (*test_func)(GInputStream *, GOutputStream *))
+{
+    struct GVncTest *test;
+    char *port;
+    GThread *th;
+
+    test = g_new0(struct GVncTest, 1);
+    test->test_func = test_func;
+
+    g_mutex_init(&test->lock);
+    g_mutex_init(&test->clock);
+    g_cond_init(&test->cond);
+    g_mutex_lock(&test->lock);
+
+    th = g_thread_new("rre-server", test_helper_server, test);
+
+    g_mutex_lock(&test->lock);
+    port = g_strdup_printf("%d", test->port);
+
+    test->conn = vnc_connection_new();
+
+    g_signal_connect(test->conn, "vnc-initialized",
+                     G_CALLBACK(test_helper_initialized), test);
+    g_signal_connect(test->conn, "vnc-disconnected",
+                     G_CALLBACK(test_helper_disconnected), test);
+    g_signal_connect(test->conn, "vnc-auth-choose-type",
+                     G_CALLBACK(test_helper_auth_choose_type), test);
+    g_signal_connect(test->conn, "vnc-desktop-resize",
+                     G_CALLBACK(test_helper_desktop_resize), test);
+    g_signal_connect(test->conn, "vnc-error",
+                     G_CALLBACK(test_helper_error), test);
+
+    vnc_connection_open_host(test->conn, "127.0.0.1", port);
+
+    test->loop = g_main_loop_new(g_main_context_default(), FALSE);
+
+    g_main_loop_run(test->loop);
+
+    g_mutex_lock(&test->clock);
+    test->quit = TRUE;
+    g_mutex_unlock(&test->clock);
+    g_cond_signal(&test->cond);
+
+    g_thread_join(th);
+
+    vnc_connection_shutdown(test->conn);
+    g_object_unref(test->conn);
+    g_free(test->pixels);
+    g_main_loop_unref(test->loop);
+
+    g_assert(test->error);
+    if (debug)
+        g_printerr("Got err %s\n", test->error);
+    g_free(test->error);
+
+    g_free(port);
+    g_free(test);
+}
+
+static void test_validation_rre(void)
+{
+    test_validation(test_rre_bounds_server);
+}
+
+static void test_validation_hextile(void)
+{
+    test_validation(test_hextile_bounds_server);
+}
+
+static void test_validation_copyrect(void)
+{
+    test_validation(test_copyrect_bounds_server);
+}
+
+static void test_validation_unexpected_cmap(void)
+{
+    test_validation(test_unexpected_cmap_server);
+}
+
+static void test_validation_overflow_cmap(void)
+{
+    test_validation(test_overflow_cmap_server);
+}
+#endif
+
+int main(int argc, char **argv) {
+    g_test_init(&argc, &argv, NULL);
+
+    if (getenv("GTK_VNC_DEBUG")) {
+        debug = TRUE;
+        vnc_util_set_debug(TRUE);
+    }
+
+#if GLIB_CHECK_VERSION(2, 22, 0)
+    g_test_add_func("/conn/validation/rre", test_validation_rre);
+    g_test_add_func("/conn/validation/copyrect", test_validation_copyrect);
+    g_test_add_func("/conn/validation/hextile", test_validation_hextile);
+    g_test_add_func("/conn/validation/unexpectedcmap", test_validation_unexpected_cmap);
+    g_test_add_func("/conn/validation/overflowcmap", test_validation_overflow_cmap);
+#endif
+
+    return g_test_run();
+}
+/*
+ * Local variables:
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  indent-tabs-mode: nil
+ * End:
+ */
diff --git a/src/vncdisplay.c b/src/vncdisplay.c
index 458d8ab..5039694 100644
--- a/src/vncdisplay.c
+++ b/src/vncdisplay.c
@@ -82,6 +82,7 @@ struct _VncDisplayPrivate
     gboolean allow_scaling;
     gboolean shared_flag;
     gboolean force_size;
+    gboolean smoothing;
 
     GSList *preferable_auths;
     GSList *preferable_vencrypt_subauths;
@@ -114,6 +115,7 @@ enum
     PROP_SCALING,
     PROP_SHARED_FLAG,
     PROP_FORCE_SIZE,
+    PROP_SMOOTHING,
     PROP_DEPTH,
     PROP_GRAB_KEYS,
     PROP_CONNECTION,
@@ -225,6 +227,9 @@ vnc_display_get_property (GObject    *object,
         case PROP_FORCE_SIZE:
             g_value_set_boolean (value, vnc->priv->force_size);
             break;
+        case PROP_SMOOTHING:
+            g_value_set_boolean (value, vnc->priv->smoothing);
+            break;
         case PROP_DEPTH:
             g_value_set_enum (value, vnc->priv->depth);
             break;
@@ -274,6 +279,9 @@ vnc_display_set_property (GObject      *object,
         case PROP_FORCE_SIZE:
             vnc_display_set_force_size (vnc, g_value_get_boolean (value));
             break;
+        case PROP_SMOOTHING:
+            vnc_display_set_smoothing (vnc, g_value_get_boolean (value));
+            break;
         case PROP_DEPTH:
             vnc_display_set_depth (vnc, g_value_get_enum (value));
             break;
@@ -423,6 +431,10 @@ static gboolean draw_event(GtkWidget *widget, cairo_t *cr)
                                      priv->fbCache,
                                      0,
                                      0);
+            if (!priv->smoothing) {
+                cairo_pattern_set_filter(cairo_get_source(cr),
+                                         CAIRO_FILTER_NEAREST);
+            }
         } else {
             cairo_set_source_surface(cr,
                                      priv->fbCache,
@@ -1766,8 +1778,11 @@ static void on_disconnected(VncConnection *conn G_GNUC_UNUSED,
  */
 gboolean vnc_display_open_fd(VncDisplay *obj, int fd)
 {
-    VncDisplayPrivate *priv = obj->priv;
+    VncDisplayPrivate *priv;
 
+    g_return_val_if_fail(VNC_IS_DISPLAY(obj), FALSE);
+
+    priv = obj->priv;
     if (vnc_connection_is_open(priv->conn))
         return FALSE;
 
@@ -1799,8 +1814,11 @@ gboolean vnc_display_open_fd(VncDisplay *obj, int fd)
  */
 gboolean vnc_display_open_fd_with_hostname(VncDisplay *obj, int fd, const char *hostname)
 {
-    VncDisplayPrivate *priv = obj->priv;
+    VncDisplayPrivate *priv;
+
+    g_return_val_if_fail(VNC_IS_DISPLAY(obj), FALSE);
 
+    priv = obj->priv;
     if (vnc_connection_is_open(priv->conn))
         return FALSE;
 
@@ -1837,8 +1855,12 @@ gboolean vnc_display_open_fd_with_hostname(VncDisplay *obj, int fd, const char *
  */
 gboolean vnc_display_open_addr(VncDisplay *obj, GSocketAddress *addr, const char *hostname)
 {
-    VncDisplayPrivate *priv = obj->priv;
+    VncDisplayPrivate *priv;
 
+    g_return_val_if_fail(VNC_IS_DISPLAY(obj), FALSE);
+    g_return_val_if_fail(addr != NULL, FALSE);
+
+    priv = obj->priv;
     if (vnc_connection_is_open(priv->conn))
         return FALSE;
 
@@ -1867,8 +1889,13 @@ gboolean vnc_display_open_addr(VncDisplay *obj, GSocketAddress *addr, const char
  */
 gboolean vnc_display_open_host(VncDisplay *obj, const char *host, const char *port)
 {
-    VncDisplayPrivate *priv = obj->priv;
+    VncDisplayPrivate *priv;
+
+    g_return_val_if_fail(VNC_IS_DISPLAY(obj), FALSE);
+    g_return_val_if_fail(host != NULL, FALSE);
+    g_return_val_if_fail(port != NULL, FALSE);
 
+    priv = obj->priv;
     if (vnc_connection_is_open(priv->conn))
         return FALSE;
 
@@ -1894,9 +1921,9 @@ gboolean vnc_display_open_host(VncDisplay *obj, const char *host, const char *po
  */
 gboolean vnc_display_is_open(VncDisplay *obj)
 {
-    VncDisplayPrivate *priv = obj->priv;
+    g_return_val_if_fail(VNC_IS_DISPLAY(obj), FALSE);
 
-    return vnc_connection_is_open(priv->conn);
+    return vnc_connection_is_open(obj->priv->conn);
 }
 
 
@@ -1911,9 +1938,12 @@ gboolean vnc_display_is_open(VncDisplay *obj)
  */
 void vnc_display_close(VncDisplay *obj)
 {
-    VncDisplayPrivate *priv = obj->priv;
+    VncDisplayPrivate *priv;
     GtkWidget *widget = GTK_WIDGET(obj);
 
+    g_return_if_fail(VNC_IS_DISPLAY(obj));
+
+    priv = obj->priv;
     if (vnc_connection_is_open(priv->conn)) {
         VNC_DEBUG("Requesting graceful shutdown of connection");
         vnc_connection_shutdown(priv->conn);
@@ -1939,8 +1969,9 @@ void vnc_display_close(VncDisplay *obj)
  */
 VncConnection * vnc_display_get_connection(VncDisplay *obj)
 {
-    VncDisplayPrivate *priv = obj->priv;
-    return priv->conn;
+    g_return_val_if_fail(VNC_IS_DISPLAY(obj), NULL);
+
+    return obj->priv->conn;
 }
 
 
@@ -1958,6 +1989,8 @@ VncConnection * vnc_display_get_connection(VncDisplay *obj)
  */
 void vnc_display_send_keys(VncDisplay *obj, const guint *keyvals, int nkeyvals)
 {
+    g_return_if_fail(VNC_IS_DISPLAY(obj));
+
     vnc_display_send_keys_ex(obj, keyvals,
                              nkeyvals, VNC_DISPLAY_KEY_EVENT_CLICK);
 }
@@ -2001,6 +2034,8 @@ void vnc_display_send_keys_ex(VncDisplay *obj, const guint *keyvals,
 {
     int i;
 
+    g_return_if_fail(VNC_IS_DISPLAY(obj));
+
     if (obj->priv->conn == NULL || !vnc_connection_is_open(obj->priv->conn) || obj->priv->read_only)
         return;
 
@@ -2034,6 +2069,8 @@ void vnc_display_send_pointer(VncDisplay *obj, gint x, gint y, int button_mask)
 {
     VncDisplayPrivate *priv = obj->priv;
 
+    g_return_if_fail(VNC_IS_DISPLAY(obj));
+
     if (priv->conn == NULL || !vnc_connection_is_open(obj->priv->conn))
         return;
 
@@ -2090,6 +2127,11 @@ static void vnc_display_finalize (GObject *obj)
         priv->vncgrabseq = NULL;
     }
 
+    if (priv->vncactiveseq) {
+        g_free(priv->vncactiveseq);
+        priv->vncactiveseq = NULL;
+    }
+
     g_slist_free (priv->preferable_auths);
     g_slist_free (priv->preferable_vencrypt_subauths);
 
@@ -2252,6 +2294,18 @@ static void vnc_display_class_init(VncDisplayClass *klass)
                                                             G_PARAM_STATIC_BLURB));
 
     g_object_class_install_property (object_class,
+                                     PROP_SMOOTHING,
+                                     g_param_spec_boolean ( "smoothing",
+                                                            "Smooth scaling",
+                                                            "Whether we should smoothly interpolate when scaling",
+                                                            TRUE,
+                                                            G_PARAM_READWRITE |
+                                                            G_PARAM_CONSTRUCT |
+                                                            G_PARAM_STATIC_NAME |
+                                                            G_PARAM_STATIC_NICK |
+                                                            G_PARAM_STATIC_BLURB));
+
+    g_object_class_install_property (object_class,
                                      PROP_DEPTH,
                                      g_param_spec_enum    ( "depth",
                                                             "Depth",
@@ -2490,6 +2544,7 @@ static void vnc_display_init(VncDisplay *display)
     priv->local_pointer = FALSE;
     priv->shared_flag = FALSE;
     priv->force_size = TRUE;
+    priv->smoothing = TRUE;
     priv->vncgrabseq = vnc_grab_sequence_new_from_string("Control_L+Alt_L");
     priv->vncactiveseq = g_new0(gboolean, priv->vncgrabseq->nkeysyms);
 
@@ -2934,6 +2989,33 @@ void vnc_display_set_force_size(VncDisplay *obj, gboolean enabled)
 
 
 /**
+ * vnc_display_smoothing:
+ * @obj: (transfer none): the VNC display widget
+ * @enabled: TRUE to enable smooth scaling, FALSE otherwise
+ *
+ * Set whether pixels are smoothly interpolated when scaling,
+ * to avoid aliasing.
+ */
+void vnc_display_set_smoothing(VncDisplay *obj, gboolean enabled)
+{
+    int ww, wh;
+
+    g_return_if_fail (VNC_IS_DISPLAY (obj));
+    obj->priv->smoothing = enabled;
+
+    if (obj->priv->fb != NULL) {
+        GdkWindow *window = gtk_widget_get_window(GTK_WIDGET(obj));
+
+        if (window != NULL) {
+            gdk_drawable_get_size(gtk_widget_get_window(GTK_WIDGET(obj)),
+                                  &ww, &wh);
+            gtk_widget_queue_draw_area(GTK_WIDGET(obj), 0, 0, ww, wh);
+        }
+    }
+}
+
+
+/**
  * vnc_display_set_depth:
  * @obj: (transfer none): the VNC display widget
  * @depth: the desired colour depth
@@ -2992,6 +3074,23 @@ gboolean vnc_display_get_force_size(VncDisplay *obj)
 
 
 /**
+ * vnc_display_get_smoothing:
+ * @obj: (transfer none): the VNC display widget
+ *
+ * Determine whether pixels are smoothly interpolated when
+ * scaling.
+ *
+ * Returns: TRUE if smoothing is enabled, FALSE otherwise
+ */
+gboolean vnc_display_get_smoothing(VncDisplay *obj)
+{
+    g_return_val_if_fail (VNC_IS_DISPLAY (obj), FALSE);
+
+    return obj->priv->smoothing;
+}
+
+
+/**
  * vnc_display_get_scaling:
  * @obj: (transfer none): the VNC display widget
  *
diff --git a/src/vncdisplay.h b/src/vncdisplay.h
index b53eee3..57a3f8f 100644
--- a/src/vncdisplay.h
+++ b/src/vncdisplay.h
@@ -134,6 +134,9 @@ gboolean vnc_display_get_scaling(VncDisplay *obj);
 void vnc_display_set_force_size(VncDisplay *obj, gboolean enable);
 gboolean vnc_display_get_force_size(VncDisplay *obj);
 
+void vnc_display_set_smoothing(VncDisplay *obj, gboolean enable);
+gboolean vnc_display_get_smoothing(VncDisplay *obj);
+
 void vnc_display_set_shared_flag(VncDisplay *obj, gboolean shared);
 gboolean vnc_display_get_shared_flag(VncDisplay *obj);
 
diff --git a/src/vncdisplaykeymap_osx2rfb.c b/src/vncdisplaykeymap_osx2rfb.c
deleted file mode 100644
index 62cd692..0000000
--- a/src/vncdisplaykeymap_osx2rfb.c
+++ /dev/null
@@ -1,117 +0,0 @@
-static const guint16 keymap_osx2rfb[] = {
-  [0x0] = 0x1e,        /* 0 (ANSI_A) => 30 via 30 (KEY_A) */
-  [0x1] = 0x1f,        /* 1 (ANSI_S) => 31 via 31 (KEY_S) */
-  [0x2] = 0x20,        /* 2 (ANSI_D) => 32 via 32 (KEY_D) */
-  [0x3] = 0x21,        /* 3 (ANSI_F) => 33 via 33 (KEY_F) */
-  [0x4] = 0x23,        /* 4 (ANSI_H) => 35 via 35 (KEY_H) */
-  [0x5] = 0x22,        /* 5 (ANSI_G) => 34 via 34 (KEY_G) */
-  [0x6] = 0x2c,        /* 6 (ANSI_Z) => 44 via 44 (KEY_Z) */
-  [0x7] = 0x2d,        /* 7 (ANSI_X) => 45 via 45 (KEY_X) */
-  [0x8] = 0x2e,        /* 8 (ANSI_C) => 46 via 46 (KEY_C) */
-  [0x9] = 0x2f,        /* 9 (ANSI_V) => 47 via 47 (KEY_V) */
-  [0xa] = 0x70,        /* 10 (ISO_Section) => 112 via 170 (KEY_ISO) */
-  [0xb] = 0x30,        /* 11 (ANSI_B) => 48 via 48 (KEY_B) */
-  [0xc] = 0x10,        /* 12 (ANSI_Q) => 16 via 16 (KEY_Q) */
-  [0xd] = 0x11,        /* 13 (ANSI_W) => 17 via 17 (KEY_W) */
-  [0xe] = 0x12,        /* 14 (ANSI_E) => 18 via 18 (KEY_E) */
-  [0xf] = 0x13,        /* 15 (ANSI_R) => 19 via 19 (KEY_R) */
-  [0x10] = 0x15,       /* 16 (ANSI_Y) => 21 via 21 (KEY_Y) */
-  [0x11] = 0x14,       /* 17 (ANSI_T) => 20 via 20 (KEY_T) */
-  [0x12] = 0x2,        /* 18 (ANSI_1) => 2 via 2 (KEY_1) */
-  [0x13] = 0x3,        /* 19 (ANSI_2) => 3 via 3 (KEY_2) */
-  [0x14] = 0x4,        /* 20 (ANSI_3) => 4 via 4 (KEY_3) */
-  [0x15] = 0x5,        /* 21 (ANSI_4) => 5 via 5 (KEY_4) */
-  [0x16] = 0x7,        /* 22 (ANSI_6) => 7 via 7 (KEY_6) */
-  [0x17] = 0x6,        /* 23 (ANSI_5) => 6 via 6 (KEY_5) */
-  [0x18] = 0xd,        /* 24 (ANSI_Equal) => 13 via 13 (KEY_EQUAL) */
-  [0x19] = 0xa,        /* 25 (ANSI_9) => 10 via 10 (KEY_9) */
-  [0x1a] = 0x8,        /* 26 (ANSI_7) => 8 via 8 (KEY_7) */
-  [0x1b] = 0xc,        /* 27 (ANSI_Minus) => 12 via 12 (KEY_MINUS) */
-  [0x1c] = 0x9,        /* 28 (ANSI_8) => 9 via 9 (KEY_8) */
-  [0x1d] = 0xb,        /* 29 (ANSI_0) => 11 via 11 (KEY_0) */
-  [0x1e] = 0x1b,       /* 30 (ANSI_RightBracket) => 27 via 27 (KEY_RIGHTBRACE) */
-  [0x1f] = 0x18,       /* 31 (ANSI_O) => 24 via 24 (KEY_O) */
-  [0x20] = 0x16,       /* 32 (ANSI_U) => 22 via 22 (KEY_U) */
-  [0x21] = 0x1a,       /* 33 (ANSI_LeftBracket) => 26 via 26 (KEY_LEFTBRACE) */
-  [0x22] = 0x17,       /* 34 (ANSI_I) => 23 via 23 (KEY_I) */
-  [0x23] = 0x19,       /* 35 (ANSI_P) => 25 via 25 (KEY_P) */
-  [0x24] = 0x1c,       /* 36 (Return) => 28 via 28 (KEY_ENTER) */
-  [0x25] = 0x26,       /* 37 (ANSI_L) => 38 via 38 (KEY_L) */
-  [0x26] = 0x24,       /* 38 (ANSI_J) => 36 via 36 (KEY_J) */
-  [0x27] = 0x28,       /* 39 (ANSI_Quote) => 40 via 40 (KEY_APOSTROPHE) */
-  [0x28] = 0x25,       /* 40 (ANSI_K) => 37 via 37 (KEY_K) */
-  [0x29] = 0x27,       /* 41 (ANSI_Semicolon) => 39 via 39 (KEY_SEMICOLON) */
-  [0x2a] = 0x2b,       /* 42 (ANSI_Backslash) => 43 via 43 (KEY_BACKSLASH) */
-  [0x2b] = 0x33,       /* 43 (ANSI_Comma) => 51 via 51 (KEY_COMMA) */
-  [0x2c] = 0x35,       /* 44 (ANSI_Slash) => 53 via 53 (KEY_SLASH) */
-  [0x2d] = 0x31,       /* 45 (ANSI_N) => 49 via 49 (KEY_N) */
-  [0x2e] = 0x32,       /* 46 (ANSI_M) => 50 via 50 (KEY_M) */
-  [0x2f] = 0x34,       /* 47 (ANSI_Period) => 52 via 52 (KEY_DOT) */
-  [0x30] = 0xf,        /* 48 (Tab) => 15 via 15 (KEY_TAB) */
-  [0x31] = 0x39,       /* 49 (Space) => 57 via 57 (KEY_SPACE) */
-  [0x32] = 0x29,       /* 50 (ANSI_Grave) => 41 via 41 (KEY_GRAVE) */
-  [0x33] = 0xe,        /* 51 (Delete) => 14 via 14 (KEY_BACKSPACE) */
-  [0x35] = 0x1,        /* 53 (Escape) => 1 via 1 (KEY_ESC) */
-  [0x37] = 0xdb,       /* 55 (Command) => 219 via 125 (KEY_LEFTMETA) */
-  [0x38] = 0x2a,       /* 56 (Shift) => 42 via 42 (KEY_LEFTSHIFT) */
-  [0x39] = 0x3a,       /* 57 (CapsLock) => 58 via 58 (KEY_CAPSLOCK) */
-  [0x3a] = 0x38,       /* 58 (Option) => 56 via 56 (KEY_LEFTALT) */
-  [0x3b] = 0x1d,       /* 59 (Control) => 29 via 29 (KEY_LEFTCTRL) */
-  [0x3c] = 0x36,       /* 60 (RightShift) => 54 via 54 (KEY_RIGHTSHIFT) */
-  [0x3d] = 0xb8,       /* 61 (RightOption) => 184 via 100 (KEY_RIGHTALT) */
-  [0x3e] = 0x9d,       /* 62 (RightControl) => 157 via 97 (KEY_RIGHTCTRL) */
-  [0x3f] = 0xdd,       /* 63 (Function) => 221 via 127 (KEY_COMPOSE) */
-  [0x40] = 0x83,       /* 64 (F17) => 131 via 187 (KEY_F17) */
-  [0x41] = 0x53,       /* 65 (ANSI_KeypadDecimal) => 83 via 83 (KEY_KPDOT) */
-  [0x43] = 0x37,       /* 67 (ANSI_KeypadMultiply) => 55 via 55 (KEY_KPASTERISK) */
-  [0x45] = 0x4e,       /* 69 (ANSI_KeypadPlus) => 78 via 78 (KEY_KPPLUS) */
-  [0x47] = 0x7e,       /* 71 (ANSI_KeypadClear????) => 126 via 121 (KEY_KPCOMMA) */
-  [0x48] = 0xb0,       /* 72 (VolumeUp) => 176 via 115 (KEY_VOLUMEUP) */
-  [0x49] = 0xae,       /* 73 (VolumeDown) => 174 via 114 (KEY_VOLUMEDOWN) */
-  [0x4a] = 0xa0,       /* 74 (Mute) => 160 via 113 (KEY_MUTE) */
-  [0x4b] = 0xb5,       /* 75 (ANSI_KeypadDivide) => 181 via 98 (KEY_KPSLASH) */
-  [0x4c] = 0x9c,       /* 76 (ANSI_KeypadEnter) => 156 via 96 (KEY_KPENTER) */
-  [0x4e] = 0x4a,       /* 78 (ANSI_KeypadMinus) => 74 via 74 (KEY_KPMINUS) */
-  [0x4f] = 0xf7,       /* 79 (F18) => 247 via 188 (KEY_F18) */
-  [0x50] = 0x84,       /* 80 (F19) => 132 via 189 (KEY_F19) */
-  [0x51] = 0x59,       /* 81 (ANSI_KeypadEquals) => 89 via 117 (KEY_KPEQUAL) */
-  [0x52] = 0x52,       /* 82 (ANSI_Keypad0) => 82 via 82 (KEY_KP0) */
-  [0x53] = 0x4f,       /* 83 (ANSI_Keypad1) => 79 via 79 (KEY_KP1) */
-  [0x54] = 0x50,       /* 84 (ANSI_Keypad2) => 80 via 80 (KEY_KP2) */
-  [0x55] = 0x51,       /* 85 (ANSI_Keypad3) => 81 via 81 (KEY_KP3) */
-  [0x56] = 0x4b,       /* 86 (ANSI_Keypad4) => 75 via 75 (KEY_KP4) */
-  [0x57] = 0x4c,       /* 87 (ANSI_Keypad5) => 76 via 76 (KEY_KP5) */
-  [0x58] = 0x4d,       /* 88 (ANSI_Keypad6) => 77 via 77 (KEY_KP6) */
-  [0x59] = 0x47,       /* 89 (ANSI_Keypad7) => 71 via 71 (KEY_KP7) */
-  [0x5a] = 0x5a,       /* 90 (F20) => 90 via 190 (KEY_F20) */
-  [0x5b] = 0x48,       /* 91 (ANSI_Keypad8) => 72 via 72 (KEY_KP8) */
-  [0x5c] = 0x49,       /* 92 (ANSI_Keypad9) => 73 via 73 (KEY_KP9) */
-  [0x5d] = 0x7d,       /* 93 (JIS_Yen) => 125 via 124 (KEY_YEN) */
-  [0x5f] = 0x5c,       /* 95 (JIS_KeypadComma) => 92 via 95 (KEY_KPJPCOMMA) */
-  [0x60] = 0x3f,       /* 96 (F5) => 63 via 63 (KEY_F5) */
-  [0x61] = 0x40,       /* 97 (F6) => 64 via 64 (KEY_F6) */
-  [0x62] = 0x41,       /* 98 (F7) => 65 via 65 (KEY_F7) */
-  [0x63] = 0x3d,       /* 99 (F3) => 61 via 61 (KEY_F3) */
-  [0x64] = 0x42,       /* 100 (F8) => 66 via 66 (KEY_F8) */
-  [0x65] = 0x43,       /* 101 (F9) => 67 via 67 (KEY_F9) */
-  [0x67] = 0x57,       /* 103 (F11) => 87 via 87 (KEY_F11) */
-  [0x68] = 0x78,       /* 104 (JIS_Kana????) => 120 via 90 (KEY_KATAKANA) */
-  [0x69] = 0x5d,       /* 105 (F13) => 93 via 183 (KEY_F13) */
-  [0x6a] = 0x55,       /* 106 (F16) => 85 via 186 (KEY_F16) */
-  [0x6b] = 0x5e,       /* 107 (F14) => 94 via 184 (KEY_F14) */
-  [0x6d] = 0x44,       /* 109 (F10) => 68 via 68 (KEY_F10) */
-  [0x6f] = 0x58,       /* 111 (F12) => 88 via 88 (KEY_F12) */
-  [0x71] = 0x5f,       /* 113 (F15) => 95 via 185 (KEY_F15) */
-  [0x73] = 0xc7,       /* 115 (Home) => 199 via 102 (KEY_HOME) */
-  [0x74] = 0xc9,       /* 116 (PageUp) => 201 via 104 (KEY_PAGEUP) */
-  [0x75] = 0xd3,       /* 117 (ForwardDelete) => 211 via 111 (KEY_DELETE) */
-  [0x76] = 0x3e,       /* 118 (F4) => 62 via 62 (KEY_F4) */
-  [0x77] = 0xcf,       /* 119 (End) => 207 via 107 (KEY_END) */
-  [0x78] = 0x3c,       /* 120 (F2) => 60 via 60 (KEY_F2) */
-  [0x79] = 0xd1,       /* 121 (PageDown) => 209 via 109 (KEY_PAGEDOWN) */
-  [0x7a] = 0x3b,       /* 122 (F1) => 59 via 59 (KEY_F1) */
-  [0x7b] = 0xcb,       /* 123 (LeftArrow) => 203 via 105 (KEY_LEFT) */
-  [0x7c] = 0xcd,       /* 124 (RightArrow) => 205 via 106 (KEY_RIGHT) */
-  [0x7d] = 0xd0,       /* 125 (DownArrow) => 208 via 108 (KEY_DOWN) */
-  [0x7e] = 0xc8,       /* 126 (UpArrow) => 200 via 103 (KEY_UP) */
-};
diff --git a/src/vncdisplaykeymap_win322rfb.c b/src/vncdisplaykeymap_win322rfb.c
deleted file mode 100644
index 54a84f0..0000000
--- a/src/vncdisplaykeymap_win322rfb.c
+++ /dev/null
@@ -1,141 +0,0 @@
-static const guint16 keymap_win322rfb[] = {
-  [0x8] = 0xe,         /* 8 (VK_BACK) => 14 via 14 (KEY_BACKSPACE) */
-  [0x9] = 0xf,         /* 9 (VK_TAB) => 15 via 15 (KEY_TAB) */
-  [0xd] = 0x1c,        /* 13 (VK_RETURN) => 28 via 28 (KEY_ENTER) */
-  [0x10] = 0x2a,       /* 16 (VK_LSHIFT) => 42 via 42 (KEY_LEFTSHIFT) */
-  [0x11] = 0x1d,       /* 17 (VK_CONTROL) => 29 via 29 (KEY_LEFTCTRL) */
-  [0x12] = 0x38,       /* 18 (VK_MENU) => 56 via 56 (KEY_LEFTALT) */
-  [0x13] = 0xc6,       /* 19 (VK_PAUSE) => 198 via 119 (KEY_PAUSE) */
-  [0x14] = 0x3a,       /* 20 (VK_CAPITAL) => 58 via 58 (KEY_CAPSLOCK) */
-  [0x19] = 0x8d,       /* 25 (VK_HANJA) => 141 via 123 (KEY_HANJA) */
-  [0x1b] = 0x1,        /* 27 (VK_ESCAPE) => 1 via 1 (KEY_ESC) */
-  [0x20] = 0x39,       /* 32 (VK_SPACE) => 57 via 57 (KEY_SPACE) */
-  [0x21] = 0xc9,       /* 33 (VK_PRIOR) => 201 via 104 (KEY_PAGEUP) */
-  [0x22] = 0xd1,       /* 34 (VK_NEXT) => 209 via 109 (KEY_PAGEDOWN) */
-  [0x23] = 0xcf,       /* 35 (VK_END) => 207 via 107 (KEY_END) */
-  [0x24] = 0xc7,       /* 36 (VK_HOME) => 199 via 102 (KEY_HOME) */
-  [0x25] = 0xcb,       /* 37 (VK_LEFT) => 203 via 105 (KEY_LEFT) */
-  [0x26] = 0xc8,       /* 38 (VK_UP) => 200 via 103 (KEY_UP) */
-  [0x27] = 0xcd,       /* 39 (VK_RIGHT) => 205 via 106 (KEY_RIGHT) */
-  [0x28] = 0xd0,       /* 40 (VK_DOWN) => 208 via 108 (KEY_DOWN) */
-  [0x2a] = 0xb9,       /* 42 (VK_PRINT) => 185 via 210 (KEY_PRINT) */
-  [0x2c] = 0x54,       /* 44 (VK_SNAPSHOT ???) => 84 via 99 (KEY_SYSRQ) */
-  [0x2d] = 0xd2,       /* 45 (VK_INSERT) => 210 via 110 (KEY_INSERT) */
-  [0x2e] = 0xd3,       /* 46 (VK_DELETE) => 211 via 111 (KEY_DELETE) */
-  [0x2f] = 0xf5,       /* 47 (VK_HELP) => 245 via 138 (KEY_HELP) */
-  [0x30] = 0xb,        /* 48 (VK_0) => 11 via 11 (KEY_0) */
-  [0x31] = 0x2,        /* 49 (VK_1) => 2 via 2 (KEY_1) */
-  [0x32] = 0x3,        /* 50 (VK_2) => 3 via 3 (KEY_2) */
-  [0x33] = 0x4,        /* 51 (VK_3) => 4 via 4 (KEY_3) */
-  [0x34] = 0x5,        /* 52 (VK_4) => 5 via 5 (KEY_4) */
-  [0x35] = 0x6,        /* 53 (VK_5) => 6 via 6 (KEY_5) */
-  [0x36] = 0x7,        /* 54 (VK_6) => 7 via 7 (KEY_6) */
-  [0x37] = 0x8,        /* 55 (VK_7) => 8 via 8 (KEY_7) */
-  [0x38] = 0x9,        /* 56 (VK_8) => 9 via 9 (KEY_8) */
-  [0x39] = 0xa,        /* 57 (VK_9) => 10 via 10 (KEY_9) */
-  [0x41] = 0x1e,       /* 65 (VK_A) => 30 via 30 (KEY_A) */
-  [0x42] = 0x30,       /* 66 (VK_B) => 48 via 48 (KEY_B) */
-  [0x43] = 0x2e,       /* 67 (VK_C) => 46 via 46 (KEY_C) */
-  [0x44] = 0x20,       /* 68 (VK_D) => 32 via 32 (KEY_D) */
-  [0x45] = 0x12,       /* 69 (VK_E) => 18 via 18 (KEY_E) */
-  [0x46] = 0x21,       /* 70 (VK_F) => 33 via 33 (KEY_F) */
-  [0x47] = 0x22,       /* 71 (VK_G) => 34 via 34 (KEY_G) */
-  [0x48] = 0x23,       /* 72 (VK_H) => 35 via 35 (KEY_H) */
-  [0x49] = 0x17,       /* 73 (VK_I) => 23 via 23 (KEY_I) */
-  [0x4a] = 0x24,       /* 74 (VK_J) => 36 via 36 (KEY_J) */
-  [0x4b] = 0x25,       /* 75 (VK_K) => 37 via 37 (KEY_K) */
-  [0x4c] = 0x26,       /* 76 (VK_L) => 38 via 38 (KEY_L) */
-  [0x4d] = 0x32,       /* 77 (VK_M) => 50 via 50 (KEY_M) */
-  [0x4e] = 0x31,       /* 78 (VK_N) => 49 via 49 (KEY_N) */
-  [0x4f] = 0x18,       /* 79 (VK_O) => 24 via 24 (KEY_O) */
-  [0x50] = 0x19,       /* 80 (VK_P) => 25 via 25 (KEY_P) */
-  [0x51] = 0x10,       /* 81 (VK_Q) => 16 via 16 (KEY_Q) */
-  [0x52] = 0x13,       /* 82 (VK_R) => 19 via 19 (KEY_R) */
-  [0x53] = 0x1f,       /* 83 (VK_S) => 31 via 31 (KEY_S) */
-  [0x54] = 0x14,       /* 84 (VK_T) => 20 via 20 (KEY_T) */
-  [0x55] = 0x16,       /* 85 (VK_U) => 22 via 22 (KEY_U) */
-  [0x56] = 0x2f,       /* 86 (VK_V) => 47 via 47 (KEY_V) */
-  [0x57] = 0x11,       /* 87 (VK_W) => 17 via 17 (KEY_W) */
-  [0x58] = 0x2d,       /* 88 (VK_X) => 45 via 45 (KEY_X) */
-  [0x59] = 0x15,       /* 89 (VK_Y) => 21 via 21 (KEY_Y) */
-  [0x5a] = 0x2c,       /* 90 (VK_Z) => 44 via 44 (KEY_Z) */
-  [0x5b] = 0xdb,       /* 91 (VK_LWIN) => 219 via 125 (KEY_LEFTMETA) */
-  [0x5c] = 0xdc,       /* 92 (VK_RWIN) => 220 via 126 (KEY_RIGHTMETA) */
-  [0x5d] = 0xdd,       /* 93 (VK_APPS) => 221 via 127 (KEY_COMPOSE) */
-  [0x5f] = 0xdf,       /* 95 (VK_SLEEP) => 223 via 142 (KEY_SLEEP) */
-  [0x60] = 0x52,       /* 96 (VK_NUMPAD0) => 82 via 82 (KEY_KP0) */
-  [0x61] = 0x4f,       /* 97 (VK_NUMPAD1) => 79 via 79 (KEY_KP1) */
-  [0x62] = 0x50,       /* 98 (VK_NUMPAD2) => 80 via 80 (KEY_KP2) */
-  [0x63] = 0x51,       /* 99 (VK_NUMPAD3) => 81 via 81 (KEY_KP3) */
-  [0x64] = 0x4b,       /* 100 (VK_NUMPAD4) => 75 via 75 (KEY_KP4) */
-  [0x65] = 0x4c,       /* 101 (VK_NUMPAD5) => 76 via 76 (KEY_KP5) */
-  [0x66] = 0x4d,       /* 102 (VK_NUMPAD6) => 77 via 77 (KEY_KP6) */
-  [0x67] = 0x47,       /* 103 (VK_NUMPAD7) => 71 via 71 (KEY_KP7) */
-  [0x68] = 0x48,       /* 104 (VK_NUMPAD8) => 72 via 72 (KEY_KP8) */
-  [0x69] = 0x49,       /* 105 (VK_NUMPAD9) => 73 via 73 (KEY_KP9) */
-  [0x6a] = 0x37,       /* 106 (VK_MULTIPLY) => 55 via 55 (KEY_KPASTERISK) */
-  [0x6b] = 0x4e,       /* 107 (VK_ADD) => 78 via 78 (KEY_KPPLUS) */
-  [0x6c] = 0x7e,       /* 108 (VK_SEPARATOR??) => 126 via 121 (KEY_KPCOMMA) */
-  [0x6d] = 0x4a,       /* 109 (VK_SUBTRACT) => 74 via 74 (KEY_KPMINUS) */
-  [0x6e] = 0x53,       /* 110 (VK_DECIMAL) => 83 via 83 (KEY_KPDOT) */
-  [0x6f] = 0xb5,       /* 111 (VK_DIVIDE) => 181 via 98 (KEY_KPSLASH) */
-  [0x70] = 0x3b,       /* 112 (VK_F1) => 59 via 59 (KEY_F1) */
-  [0x71] = 0x3c,       /* 113 (VK_F2) => 60 via 60 (KEY_F2) */
-  [0x72] = 0x3d,       /* 114 (VK_F3) => 61 via 61 (KEY_F3) */
-  [0x73] = 0x3e,       /* 115 (VK_F4) => 62 via 62 (KEY_F4) */
-  [0x74] = 0x3f,       /* 116 (VK_F5) => 63 via 63 (KEY_F5) */
-  [0x75] = 0x40,       /* 117 (VK_F6) => 64 via 64 (KEY_F6) */
-  [0x76] = 0x41,       /* 118 (VK_F7) => 65 via 65 (KEY_F7) */
-  [0x77] = 0x42,       /* 119 (VK_F8) => 66 via 66 (KEY_F8) */
-  [0x78] = 0x43,       /* 120 (VK_F9) => 67 via 67 (KEY_F9) */
-  [0x79] = 0x44,       /* 121 (VK_F10) => 68 via 68 (KEY_F10) */
-  [0x7a] = 0x57,       /* 122 (VK_F11) => 87 via 87 (KEY_F11) */
-  [0x7b] = 0x58,       /* 123 (VK_F12) => 88 via 88 (KEY_F12) */
-  [0x7c] = 0x5d,       /* 124 (VK_F13) => 93 via 183 (KEY_F13) */
-  [0x7d] = 0x5e,       /* 125 (VK_F14) => 94 via 184 (KEY_F14) */
-  [0x7e] = 0x5f,       /* 126 (VK_F15) => 95 via 185 (KEY_F15) */
-  [0x7f] = 0x55,       /* 127 (VK_F16) => 85 via 186 (KEY_F16) */
-  [0x80] = 0x83,       /* 128 (VK_F17) => 131 via 187 (KEY_F17) */
-  [0x81] = 0xf7,       /* 129 (VK_F18) => 247 via 188 (KEY_F18) */
-  [0x82] = 0x84,       /* 130 (VK_F19) => 132 via 189 (KEY_F19) */
-  [0x83] = 0x5a,       /* 131 (VK_F20) => 90 via 190 (KEY_F20) */
-  [0x84] = 0x74,       /* 132 (VK_F21) => 116 via 191 (KEY_F21) */
-  [0x85] = 0xf9,       /* 133 (VK_F22) => 249 via 192 (KEY_F22) */
-  [0x86] = 0x6d,       /* 134 (VK_F23) => 109 via 193 (KEY_F23) */
-  [0x87] = 0x6f,       /* 135 (VK_F24) => 111 via 194 (KEY_F24) */
-  [0x90] = 0x45,       /* 144 (VK_NUMLOCK) => 69 via 69 (KEY_NUMLOCK) */
-  [0x91] = 0x46,       /* 145 (VK_SCROLL) => 70 via 70 (KEY_SCROLLLOCK) */
-  [0xa0] = 0x2a,       /* 160 (VK_LSHIFT) => 42 via 42 (KEY_LEFTSHIFT) */
-  [0xa1] = 0x36,       /* 161 (VK_RSHIFT) => 54 via 54 (KEY_RIGHTSHIFT) */
-  [0xa2] = 0x1d,       /* 162 (VK_CONTROL) => 29 via 29 (KEY_LEFTCTRL) */
-  [0xa3] = 0x9d,       /* 163 (VK_RCONTROL) => 157 via 97 (KEY_RIGHTCTRL) */
-  [0xa4] = 0x38,       /* 164 (VK_MENU) => 56 via 56 (KEY_LEFTALT) */
-  [0xa5] = 0xb8,       /* 165 (VK_RMENU) => 184 via 100 (KEY_RIGHTALT) */
-  [0xa6] = 0xea,       /* 166 (VK_BROWSER_BACK) => 234 via 158 (KEY_BACK) */
-  [0xa7] = 0xe9,       /* 167 (VK_BROWSER_FORWARD) => 233 via 159 (KEY_FORWARD) */
-  [0xa8] = 0xe7,       /* 168 (VK_BROWSER_REFRESH) => 231 via 173 (KEY_REFRESH) */
-  [0xa9] = 0xe8,       /* 169 (VK_BROWSER_STOP) => 232 via 128 (KEY_STOP) */
-  [0xaa] = 0xe5,       /* 170 (VK_BROWSER_SEARCH) => 229 via 217 (KEY_SEARCH) */
-  [0xac] = 0xb2,       /* 172 (VK_BROWSER_HOME) => 178 via 172 (KEY_HOMEPAGE) */
-  [0xad] = 0xa0,       /* 173 (VK_VOLUME_MUTE) => 160 via 113 (KEY_MUTE) */
-  [0xae] = 0xae,       /* 174 (VK_VOLUME_DOWN) => 174 via 114 (KEY_VOLUMEDOWN) */
-  [0xaf] = 0xb0,       /* 175 (VK_VOLUME_UP) => 176 via 115 (KEY_VOLUMEUP) */
-  [0xb0] = 0x99,       /* 176 (VK_MEDIA_NEXT_TRACK) => 153 via 163 (KEY_NEXTSONG) */
-  [0xb1] = 0x90,       /* 177 (VK_MEDIA_PREV_TRACK) => 144 via 165 (KEY_PREVIOUSSONG) */
-  [0xb2] = 0xa4,       /* 178 (VK_MEDIA_STOP) => 164 via 166 (KEY_STOPCD) */
-  [0xb3] = 0xa2,       /* 179 (VK_MEDIA_PLAY_PAUSE) => 162 via 164 (KEY_PLAYPAUSE) */
-  [0xb4] = 0xbf,       /* 180 (VK_LAUNCH_MAIL) => 191 via 215 (KEY_EMAIL) */
-  [0xba] = 0x27,       /* 186 (VK_OEM_1) => 39 via 39 (KEY_SEMICOLON) */
-  [0xbb] = 0xd,        /* 187 (VK_OEM_PLUS) => 13 via 13 (KEY_EQUAL) */
-  [0xbc] = 0x33,       /* 188 (VK_OEM_COMMA) => 51 via 51 (KEY_COMMA) */
-  [0xbd] = 0xc,        /* 189 (VK_OEM_MINUS) => 12 via 12 (KEY_MINUS) */
-  [0xbe] = 0x34,       /* 190 (VK_OEM_PERIOD) => 52 via 52 (KEY_DOT) */
-  [0xbf] = 0x35,       /* 191 (VK_OEM_2) => 53 via 53 (KEY_SLASH) */
-  [0xc0] = 0x29,       /* 192 (VK_OEM_3) => 41 via 41 (KEY_GRAVE) */
-  [0xdb] = 0x1a,       /* 219 (VK_OEM_4) => 26 via 26 (KEY_LEFTBRACE) */
-  [0xdc] = 0x2b,       /* 220 (VK_OEM_5) => 43 via 43 (KEY_BACKSLASH) */
-  [0xdd] = 0x1b,       /* 221 (VK_OEM_6) => 27 via 27 (KEY_RIGHTBRACE) */
-  [0xde] = 0x28,       /* 222 (VK_OEM_7) => 40 via 40 (KEY_APOSTROPHE) */
-  [0xe1] = 0x56,       /* 225 (VK_OEM_102) => 86 via 86 (KEY_102ND) */
-  [0xfa] = 0xb3,       /* 250 (VK_PLAY) => 179 via 207 (KEY_PLAY) */
-};
diff --git a/src/vncdisplaykeymap_x112rfb.c b/src/vncdisplaykeymap_x112rfb.c
deleted file mode 100644
index 14dbdcb..0000000
--- a/src/vncdisplaykeymap_x112rfb.c
+++ /dev/null
@@ -1,132 +0,0 @@
-static const guint16 keymap_x112rfb[] = {
-  [0x20] = 0x39,       /* 32 (XK_space) => 57 via 57 (KEY_SPACE) */
-  [0x27] = 0x28,       /* 39 (XK_apostrophe) => 40 via 40 (KEY_APOSTROPHE) */
-  [0x2c] = 0x33,       /* 44 (XK_comma) => 51 via 51 (KEY_COMMA) */
-  [0x2d] = 0xc,        /* 45 (XK_minus) => 12 via 12 (KEY_MINUS) */
-  [0x2e] = 0x34,       /* 46 (XK_period) => 52 via 52 (KEY_DOT) */
-  [0x2f] = 0x35,       /* 47 (XK_slash) => 53 via 53 (KEY_SLASH) */
-  [0x30] = 0xb,        /* 48 (XK_0) => 11 via 11 (KEY_0) */
-  [0x31] = 0x2,        /* 49 (XK_1) => 2 via 2 (KEY_1) */
-  [0x32] = 0x3,        /* 50 (XK_2) => 3 via 3 (KEY_2) */
-  [0x33] = 0x4,        /* 51 (XK_3) => 4 via 4 (KEY_3) */
-  [0x34] = 0x5,        /* 52 (XK_4) => 5 via 5 (KEY_4) */
-  [0x35] = 0x6,        /* 53 (XK_5) => 6 via 6 (KEY_5) */
-  [0x36] = 0x7,        /* 54 (XK_6) => 7 via 7 (KEY_6) */
-  [0x37] = 0x8,        /* 55 (XK_7) => 8 via 8 (KEY_7) */
-  [0x38] = 0x9,        /* 56 (XK_8) => 9 via 9 (KEY_8) */
-  [0x39] = 0xa,        /* 57 (XK_9) => 10 via 10 (KEY_9) */
-  [0x3b] = 0x27,       /* 59 (XK_semicolon) => 39 via 39 (KEY_SEMICOLON) */
-  [0x3d] = 0xd,        /* 61 (XK_equal) => 13 via 13 (KEY_EQUAL) */
-  [0x41] = 0x1e,       /* 65 (XK_a) => 30 via 30 (KEY_A) */
-  [0x42] = 0x30,       /* 66 (XK_b) => 48 via 48 (KEY_B) */
-  [0x43] = 0x2e,       /* 67 (XK_c) => 46 via 46 (KEY_C) */
-  [0x44] = 0x20,       /* 68 (XK_d) => 32 via 32 (KEY_D) */
-  [0x45] = 0x12,       /* 69 (XK_e) => 18 via 18 (KEY_E) */
-  [0x46] = 0x21,       /* 70 (XK_f) => 33 via 33 (KEY_F) */
-  [0x47] = 0x22,       /* 71 (XK_g) => 34 via 34 (KEY_G) */
-  [0x48] = 0x23,       /* 72 (XK_h) => 35 via 35 (KEY_H) */
-  [0x49] = 0x17,       /* 73 (XK_i) => 23 via 23 (KEY_I) */
-  [0x4a] = 0x24,       /* 74 (XK_j) => 36 via 36 (KEY_J) */
-  [0x4b] = 0x25,       /* 75 (XK_K) => 37 via 37 (KEY_K) */
-  [0x4c] = 0x26,       /* 76 (XK_l) => 38 via 38 (KEY_L) */
-  [0x4d] = 0x32,       /* 77 (XK_m) => 50 via 50 (KEY_M) */
-  [0x4e] = 0x31,       /* 78 (XK_n) => 49 via 49 (KEY_N) */
-  [0x4f] = 0x18,       /* 79 (XK_o) => 24 via 24 (KEY_O) */
-  [0x50] = 0x19,       /* 80 (XK_p) => 25 via 25 (KEY_P) */
-  [0x51] = 0x10,       /* 81 (XK_q) => 16 via 16 (KEY_Q) */
-  [0x52] = 0x13,       /* 82 (XK_r) => 19 via 19 (KEY_R) */
-  [0x53] = 0x1f,       /* 83 (XK_s) => 31 via 31 (KEY_S) */
-  [0x54] = 0x14,       /* 84 (XK_t) => 20 via 20 (KEY_T) */
-  [0x55] = 0x16,       /* 85 (XK_u) => 22 via 22 (KEY_U) */
-  [0x56] = 0x2f,       /* 86 (XK_v) => 47 via 47 (KEY_V) */
-  [0x57] = 0x11,       /* 87 (XK_w) => 17 via 17 (KEY_W) */
-  [0x58] = 0x2d,       /* 88 (XK_x) => 45 via 45 (KEY_X) */
-  [0x59] = 0x15,       /* 89 (XK_y) => 21 via 21 (KEY_Y) */
-  [0x5a] = 0x2c,       /* 90 (XK_z) => 44 via 44 (KEY_Z) */
-  [0x5b] = 0x1a,       /* 91 (XK_bracketleft) => 26 via 26 (KEY_LEFTBRACE) */
-  [0x5c] = 0x2b,       /* 92 (XK_backslash) => 43 via 43 (KEY_BACKSLASH) */
-  [0x5d] = 0x1b,       /* 93 (XK_bracketright) => 27 via 27 (KEY_RIGHTBRACE) */
-  [0x60] = 0x29,       /* 96 (XK_grave) => 41 via 41 (KEY_GRAVE) */
-  [0x61] = 0x1e,       /* 97 (XK_a) => 30 via 30 (KEY_A) */
-  [0x62] = 0x30,       /* 98 (XK_b) => 48 via 48 (KEY_B) */
-  [0x63] = 0x2e,       /* 99 (XK_c) => 46 via 46 (KEY_C) */
-  [0x64] = 0x20,       /* 100 (XK_d) => 32 via 32 (KEY_D) */
-  [0x65] = 0x12,       /* 101 (XK_e) => 18 via 18 (KEY_E) */
-  [0x66] = 0x21,       /* 102 (XK_f) => 33 via 33 (KEY_F) */
-  [0x67] = 0x22,       /* 103 (XK_g) => 34 via 34 (KEY_G) */
-  [0x68] = 0x23,       /* 104 (XK_h) => 35 via 35 (KEY_H) */
-  [0x69] = 0x17,       /* 105 (XK_i) => 23 via 23 (KEY_I) */
-  [0x6a] = 0x24,       /* 106 (XK_j) => 36 via 36 (KEY_J) */
-  [0x6b] = 0x25,       /* 107 (XK_K) => 37 via 37 (KEY_K) */
-  [0x6c] = 0x26,       /* 108 (XK_l) => 38 via 38 (KEY_L) */
-  [0x6d] = 0x32,       /* 109 (XK_m) => 50 via 50 (KEY_M) */
-  [0x6e] = 0x31,       /* 110 (XK_n) => 49 via 49 (KEY_N) */
-  [0x6f] = 0x18,       /* 111 (XK_o) => 24 via 24 (KEY_O) */
-  [0x70] = 0x19,       /* 112 (XK_p) => 25 via 25 (KEY_P) */
-  [0x71] = 0x10,       /* 113 (XK_q) => 16 via 16 (KEY_Q) */
-  [0x72] = 0x13,       /* 114 (XK_r) => 19 via 19 (KEY_R) */
-  [0x73] = 0x1f,       /* 115 (XK_s) => 31 via 31 (KEY_S) */
-  [0x74] = 0x14,       /* 116 (XK_t) => 20 via 20 (KEY_T) */
-  [0x75] = 0x16,       /* 117 (XK_u) => 22 via 22 (KEY_U) */
-  [0x76] = 0x2f,       /* 118 (XK_v) => 47 via 47 (KEY_V) */
-  [0x77] = 0x11,       /* 119 (XK_w) => 17 via 17 (KEY_W) */
-  [0x78] = 0x2d,       /* 120 (XK_x) => 45 via 45 (KEY_X) */
-  [0x79] = 0x15,       /* 121 (XK_y) => 21 via 21 (KEY_Y) */
-  [0x7a] = 0x2c,       /* 122 (XK_z) => 44 via 44 (KEY_Z) */
-  [0xd7] = 0x37,       /* 215 (XK_multiply) => 55 via 55 (KEY_KPASTERISK) */
-  [0xff08] = 0xe,      /* 65288 (XK_BackSpace) => 14 via 14 (KEY_BACKSPACE) */
-  [0xff09] = 0xf,      /* 65289 (XK_Tab) => 15 via 15 (KEY_TAB) */
-  [0xff0d] = 0x1c,     /* 65293 (XK_Return) => 28 via 28 (KEY_ENTER) */
-  [0xff13] = 0xc6,     /* 65299 (XK_Pause) => 198 via 119 (KEY_PAUSE) */
-  [0xff14] = 0x46,     /* 65300 (XK_Scroll_Lock) => 70 via 70 (KEY_SCROLLLOCK) */
-  [0xff15] = 0x54,     /* 65301 (XK_Sys_Req) => 84 via 99 (KEY_SYSRQ) */
-  [0xff1b] = 0x1,      /* 65307 (XK_Escape) => 1 via 1 (KEY_ESC) */
-  [0xff50] = 0xc7,     /* 65360 (XK_Home) => 199 via 102 (KEY_HOME) */
-  [0xff51] = 0xcb,     /* 65361 (XK_Left) => 203 via 105 (KEY_LEFT) */
-  [0xff52] = 0xc8,     /* 65362 (XK_Up) => 200 via 103 (KEY_UP) */
-  [0xff53] = 0xcd,     /* 65363 (XK_Right) => 205 via 106 (KEY_RIGHT) */
-  [0xff54] = 0xd0,     /* 65364 (XK_Down) => 208 via 108 (KEY_DOWN) */
-  [0xff55] = 0xc9,     /* 65365 (XK_Page_Up) => 201 via 104 (KEY_PAGEUP) */
-  [0xff56] = 0xd1,     /* 65366 (XK_Page_Down) => 209 via 109 (KEY_PAGEDOWN) */
-  [0xff57] = 0xcf,     /* 65367 (XK_End) => 207 via 107 (KEY_END) */
-  [0xff63] = 0xd2,     /* 65379 (XK_Insert) => 210 via 110 (KEY_INSERT) */
-  [0xff6a] = 0xf5,     /* 65386 (XK_Help) => 245 via 138 (KEY_HELP) */
-  [0xff7f] = 0x45,     /* 65407 (XK_Num_Lock) => 69 via 69 (KEY_NUMLOCK) */
-  [0xff8d] = 0x9c,     /* 65421 (XK_KP_Enter) => 156 via 96 (KEY_KPENTER) */
-  [0xffab] = 0x4e,     /* 65451 (XK_KP_Add) => 78 via 78 (KEY_KPPLUS) */
-  [0xffac] = 0x5c,     /* 65452 (XK_KP_Separator) => 92 via 95 (KEY_KPJPCOMMA) */
-  [0xffad] = 0x4a,     /* 65453 (XK_KP_Subtract) => 74 via 74 (KEY_KPMINUS) */
-  [0xffae] = 0x53,     /* 65454 (XK_KP_Decimal) => 83 via 83 (KEY_KPDOT) */
-  [0xffaf] = 0xb5,     /* 65455 (XK_KP_Divide) => 181 via 98 (KEY_KPSLASH) */
-  [0xffb0] = 0x52,     /* 65456 (XK_KP_0) => 82 via 82 (KEY_KP0) */
-  [0xffb1] = 0x4f,     /* 65457 (XK_KP_1) => 79 via 79 (KEY_KP1) */
-  [0xffb2] = 0x50,     /* 65458 (XK_KP_2) => 80 via 80 (KEY_KP2) */
-  [0xffb3] = 0x51,     /* 65459 (XK_KP_3) => 81 via 81 (KEY_KP3) */
-  [0xffb4] = 0x4b,     /* 65460 (XK_KP_4) => 75 via 75 (KEY_KP4) */
-  [0xffb5] = 0x4c,     /* 65461 (XK_KP_5) => 76 via 76 (KEY_KP5) */
-  [0xffb6] = 0x4d,     /* 65462 (XK_KP_6) => 77 via 77 (KEY_KP6) */
-  [0xffb7] = 0x47,     /* 65463 (XK_KP_7) => 71 via 71 (KEY_KP7) */
-  [0xffb8] = 0x48,     /* 65464 (XK_KP_8) => 72 via 72 (KEY_KP8) */
-  [0xffb9] = 0x49,     /* 65465 (XK_KP_9) => 73 via 73 (KEY_KP9) */
-  [0xffbd] = 0x59,     /* 65469 (XK_KP_Equal) => 89 via 117 (KEY_KPEQUAL) */
-  [0xffbe] = 0x3b,     /* 65470 (XK_F1) => 59 via 59 (KEY_F1) */
-  [0xffbf] = 0x3c,     /* 65471 (XK_F2) => 60 via 60 (KEY_F2) */
-  [0xffc0] = 0x3d,     /* 65472 (XK_F3) => 61 via 61 (KEY_F3) */
-  [0xffc1] = 0x3e,     /* 65473 (XK_F4) => 62 via 62 (KEY_F4) */
-  [0xffc2] = 0x3f,     /* 65474 (XK_F5) => 63 via 63 (KEY_F5) */
-  [0xffc3] = 0x40,     /* 65475 (XK_F6) => 64 via 64 (KEY_F6) */
-  [0xffc4] = 0x41,     /* 65476 (XK_F7) => 65 via 65 (KEY_F7) */
-  [0xffc5] = 0x42,     /* 65477 (XK_F8) => 66 via 66 (KEY_F8) */
-  [0xffc6] = 0x43,     /* 65478 (XK_F9) => 67 via 67 (KEY_F9) */
-  [0xffc7] = 0x44,     /* 65479 (XK_F10) => 68 via 68 (KEY_F10) */
-  [0xffe1] = 0x2a,     /* 65505 (XK_Shift_L) => 42 via 42 (KEY_LEFTSHIFT) */
-  [0xffe2] = 0x36,     /* 65506 (XK_Shift_R) => 54 via 54 (KEY_RIGHTSHIFT) */
-  [0xffe3] = 0x1d,     /* 65507 (XK_Control_L) => 29 via 29 (KEY_LEFTCTRL) */
-  [0xffe4] = 0x9d,     /* 65508 (XK_Control_R) => 157 via 97 (KEY_RIGHTCTRL) */
-  [0xffe5] = 0x3a,     /* 65509 (XK_Caps_Lock) => 58 via 58 (KEY_CAPSLOCK) */
-  [0xffe7] = 0xdb,     /* 65511 (XK_Meta_L) => 219 via 125 (KEY_LEFTMETA) */
-  [0xffe8] = 0xdc,     /* 65512 (XK_Meta_R) => 220 via 126 (KEY_RIGHTMETA) */
-  [0xffe9] = 0x38,     /* 65513 (XK_Alt_L) => 56 via 56 (KEY_LEFTALT) */
-  [0xffea] = 0xb8,     /* 65514 (XK_Alt_R) => 184 via 100 (KEY_RIGHTALT) */
-  [0xffff] = 0xd3,     /* 65535 (XK_Delete) => 211 via 111 (KEY_DELETE) */
-};
diff --git a/src/vncdisplaykeymap_xorgevdev2rfb.c b/src/vncdisplaykeymap_xorgevdev2rfb.c
deleted file mode 100644
index 6f12b32..0000000
--- a/src/vncdisplaykeymap_xorgevdev2rfb.c
+++ /dev/null
@@ -1,240 +0,0 @@
-static const guint16 keymap_xorgevdev2rfb[] = {
-  [0x9] = 0x1,         /* 9 => 1 via 1 (KEY_ESC) */
-  [0xa] = 0x2,         /* 10 => 2 via 2 (KEY_1) */
-  [0xb] = 0x3,         /* 11 => 3 via 3 (KEY_2) */
-  [0xc] = 0x4,         /* 12 => 4 via 4 (KEY_3) */
-  [0xd] = 0x5,         /* 13 => 5 via 5 (KEY_4) */
-  [0xe] = 0x6,         /* 14 => 6 via 6 (KEY_5) */
-  [0xf] = 0x7,         /* 15 => 7 via 7 (KEY_6) */
-  [0x10] = 0x8,        /* 16 => 8 via 8 (KEY_7) */
-  [0x11] = 0x9,        /* 17 => 9 via 9 (KEY_8) */
-  [0x12] = 0xa,        /* 18 => 10 via 10 (KEY_9) */
-  [0x13] = 0xb,        /* 19 => 11 via 11 (KEY_0) */
-  [0x14] = 0xc,        /* 20 => 12 via 12 (KEY_MINUS) */
-  [0x15] = 0xd,        /* 21 => 13 via 13 (KEY_EQUAL) */
-  [0x16] = 0xe,        /* 22 => 14 via 14 (KEY_BACKSPACE) */
-  [0x17] = 0xf,        /* 23 => 15 via 15 (KEY_TAB) */
-  [0x18] = 0x10,       /* 24 => 16 via 16 (KEY_Q) */
-  [0x19] = 0x11,       /* 25 => 17 via 17 (KEY_W) */
-  [0x1a] = 0x12,       /* 26 => 18 via 18 (KEY_E) */
-  [0x1b] = 0x13,       /* 27 => 19 via 19 (KEY_R) */
-  [0x1c] = 0x14,       /* 28 => 20 via 20 (KEY_T) */
-  [0x1d] = 0x15,       /* 29 => 21 via 21 (KEY_Y) */
-  [0x1e] = 0x16,       /* 30 => 22 via 22 (KEY_U) */
-  [0x1f] = 0x17,       /* 31 => 23 via 23 (KEY_I) */
-  [0x20] = 0x18,       /* 32 => 24 via 24 (KEY_O) */
-  [0x21] = 0x19,       /* 33 => 25 via 25 (KEY_P) */
-  [0x22] = 0x1a,       /* 34 => 26 via 26 (KEY_LEFTBRACE) */
-  [0x23] = 0x1b,       /* 35 => 27 via 27 (KEY_RIGHTBRACE) */
-  [0x24] = 0x1c,       /* 36 => 28 via 28 (KEY_ENTER) */
-  [0x25] = 0x1d,       /* 37 => 29 via 29 (KEY_LEFTCTRL) */
-  [0x26] = 0x1e,       /* 38 => 30 via 30 (KEY_A) */
-  [0x27] = 0x1f,       /* 39 => 31 via 31 (KEY_S) */
-  [0x28] = 0x20,       /* 40 => 32 via 32 (KEY_D) */
-  [0x29] = 0x21,       /* 41 => 33 via 33 (KEY_F) */
-  [0x2a] = 0x22,       /* 42 => 34 via 34 (KEY_G) */
-  [0x2b] = 0x23,       /* 43 => 35 via 35 (KEY_H) */
-  [0x2c] = 0x24,       /* 44 => 36 via 36 (KEY_J) */
-  [0x2d] = 0x25,       /* 45 => 37 via 37 (KEY_K) */
-  [0x2e] = 0x26,       /* 46 => 38 via 38 (KEY_L) */
-  [0x2f] = 0x27,       /* 47 => 39 via 39 (KEY_SEMICOLON) */
-  [0x30] = 0x28,       /* 48 => 40 via 40 (KEY_APOSTROPHE) */
-  [0x31] = 0x29,       /* 49 => 41 via 41 (KEY_GRAVE) */
-  [0x32] = 0x2a,       /* 50 => 42 via 42 (KEY_LEFTSHIFT) */
-  [0x33] = 0x2b,       /* 51 => 43 via 43 (KEY_BACKSLASH) */
-  [0x34] = 0x2c,       /* 52 => 44 via 44 (KEY_Z) */
-  [0x35] = 0x2d,       /* 53 => 45 via 45 (KEY_X) */
-  [0x36] = 0x2e,       /* 54 => 46 via 46 (KEY_C) */
-  [0x37] = 0x2f,       /* 55 => 47 via 47 (KEY_V) */
-  [0x38] = 0x30,       /* 56 => 48 via 48 (KEY_B) */
-  [0x39] = 0x31,       /* 57 => 49 via 49 (KEY_N) */
-  [0x3a] = 0x32,       /* 58 => 50 via 50 (KEY_M) */
-  [0x3b] = 0x33,       /* 59 => 51 via 51 (KEY_COMMA) */
-  [0x3c] = 0x34,       /* 60 => 52 via 52 (KEY_DOT) */
-  [0x3d] = 0x35,       /* 61 => 53 via 53 (KEY_SLASH) */
-  [0x3e] = 0x36,       /* 62 => 54 via 54 (KEY_RIGHTSHIFT) */
-  [0x3f] = 0x37,       /* 63 => 55 via 55 (KEY_KPASTERISK) */
-  [0x40] = 0x38,       /* 64 => 56 via 56 (KEY_LEFTALT) */
-  [0x41] = 0x39,       /* 65 => 57 via 57 (KEY_SPACE) */
-  [0x42] = 0x3a,       /* 66 => 58 via 58 (KEY_CAPSLOCK) */
-  [0x43] = 0x3b,       /* 67 => 59 via 59 (KEY_F1) */
-  [0x44] = 0x3c,       /* 68 => 60 via 60 (KEY_F2) */
-  [0x45] = 0x3d,       /* 69 => 61 via 61 (KEY_F3) */
-  [0x46] = 0x3e,       /* 70 => 62 via 62 (KEY_F4) */
-  [0x47] = 0x3f,       /* 71 => 63 via 63 (KEY_F5) */
-  [0x48] = 0x40,       /* 72 => 64 via 64 (KEY_F6) */
-  [0x49] = 0x41,       /* 73 => 65 via 65 (KEY_F7) */
-  [0x4a] = 0x42,       /* 74 => 66 via 66 (KEY_F8) */
-  [0x4b] = 0x43,       /* 75 => 67 via 67 (KEY_F9) */
-  [0x4c] = 0x44,       /* 76 => 68 via 68 (KEY_F10) */
-  [0x4d] = 0x45,       /* 77 => 69 via 69 (KEY_NUMLOCK) */
-  [0x4e] = 0x46,       /* 78 => 70 via 70 (KEY_SCROLLLOCK) */
-  [0x4f] = 0x47,       /* 79 => 71 via 71 (KEY_KP7) */
-  [0x50] = 0x48,       /* 80 => 72 via 72 (KEY_KP8) */
-  [0x51] = 0x49,       /* 81 => 73 via 73 (KEY_KP9) */
-  [0x52] = 0x4a,       /* 82 => 74 via 74 (KEY_KPMINUS) */
-  [0x53] = 0x4b,       /* 83 => 75 via 75 (KEY_KP4) */
-  [0x54] = 0x4c,       /* 84 => 76 via 76 (KEY_KP5) */
-  [0x55] = 0x4d,       /* 85 => 77 via 77 (KEY_KP6) */
-  [0x56] = 0x4e,       /* 86 => 78 via 78 (KEY_KPPLUS) */
-  [0x57] = 0x4f,       /* 87 => 79 via 79 (KEY_KP1) */
-  [0x58] = 0x50,       /* 88 => 80 via 80 (KEY_KP2) */
-  [0x59] = 0x51,       /* 89 => 81 via 81 (KEY_KP3) */
-  [0x5a] = 0x52,       /* 90 => 82 via 82 (KEY_KP0) */
-  [0x5b] = 0x53,       /* 91 => 83 via 83 (KEY_KPDOT) */
-  [0x5c] = 0x54,       /* 92 => 84 via 84 */
-  [0x5d] = 0x76,       /* 93 => 118 via 85 (KEY_ZENKAKUHANKAKU) */
-  [0x5e] = 0x56,       /* 94 => 86 via 86 (KEY_102ND) */
-  [0x5f] = 0x57,       /* 95 => 87 via 87 (KEY_F11) */
-  [0x60] = 0x58,       /* 96 => 88 via 88 (KEY_F12) */
-  [0x61] = 0x73,       /* 97 => 115 via 89 (KEY_RO) */
-  [0x62] = 0x78,       /* 98 => 120 via 90 (KEY_KATAKANA) */
-  [0x63] = 0x77,       /* 99 => 119 via 91 (KEY_HIRAGANA) */
-  [0x64] = 0x79,       /* 100 => 121 via 92 (KEY_HENKAN) */
-  [0x65] = 0x70,       /* 101 => 112 via 93 (KEY_KATAKANAHIRAGANA) */
-  [0x66] = 0x7b,       /* 102 => 123 via 94 (KEY_MUHENKAN) */
-  [0x67] = 0x5c,       /* 103 => 92 via 95 (KEY_KPJPCOMMA) */
-  [0x68] = 0x9c,       /* 104 => 156 via 96 (KEY_KPENTER) */
-  [0x69] = 0x9d,       /* 105 => 157 via 97 (KEY_RIGHTCTRL) */
-  [0x6a] = 0xb5,       /* 106 => 181 via 98 (KEY_KPSLASH) */
-  [0x6b] = 0x54,       /* 107 => 84 via 99 (KEY_SYSRQ) */
-  [0x6c] = 0xb8,       /* 108 => 184 via 100 (KEY_RIGHTALT) */
-  [0x6d] = 0x5b,       /* 109 => 91 via 101 (KEY_LINEFEED) */
-  [0x6e] = 0xc7,       /* 110 => 199 via 102 (KEY_HOME) */
-  [0x6f] = 0xc8,       /* 111 => 200 via 103 (KEY_UP) */
-  [0x70] = 0xc9,       /* 112 => 201 via 104 (KEY_PAGEUP) */
-  [0x71] = 0xcb,       /* 113 => 203 via 105 (KEY_LEFT) */
-  [0x72] = 0xcd,       /* 114 => 205 via 106 (KEY_RIGHT) */
-  [0x73] = 0xcf,       /* 115 => 207 via 107 (KEY_END) */
-  [0x74] = 0xd0,       /* 116 => 208 via 108 (KEY_DOWN) */
-  [0x75] = 0xd1,       /* 117 => 209 via 109 (KEY_PAGEDOWN) */
-  [0x76] = 0xd2,       /* 118 => 210 via 110 (KEY_INSERT) */
-  [0x77] = 0xd3,       /* 119 => 211 via 111 (KEY_DELETE) */
-  [0x78] = 0xef,       /* 120 => 239 via 112 (KEY_MACRO) */
-  [0x79] = 0xa0,       /* 121 => 160 via 113 (KEY_MUTE) */
-  [0x7a] = 0xae,       /* 122 => 174 via 114 (KEY_VOLUMEDOWN) */
-  [0x7b] = 0xb0,       /* 123 => 176 via 115 (KEY_VOLUMEUP) */
-  [0x7c] = 0xde,       /* 124 => 222 via 116 (KEY_POWER) */
-  [0x7d] = 0x59,       /* 125 => 89 via 117 (KEY_KPEQUAL) */
-  [0x7e] = 0xce,       /* 126 => 206 via 118 (KEY_KPPLUSMINUS) */
-  [0x7f] = 0xc6,       /* 127 => 198 via 119 (KEY_PAUSE) */
-  [0x80] = 0x8b,       /* 128 => 139 via 120 (KEY_SCALE) */
-  [0x81] = 0x7e,       /* 129 => 126 via 121 (KEY_KPCOMMA) */
-  [0x83] = 0x8d,       /* 131 => 141 via 123 (KEY_HANJA) */
-  [0x84] = 0x7d,       /* 132 => 125 via 124 (KEY_YEN) */
-  [0x85] = 0xdb,       /* 133 => 219 via 125 (KEY_LEFTMETA) */
-  [0x86] = 0xdc,       /* 134 => 220 via 126 (KEY_RIGHTMETA) */
-  [0x87] = 0xdd,       /* 135 => 221 via 127 (KEY_COMPOSE) */
-  [0x88] = 0xe8,       /* 136 => 232 via 128 (KEY_STOP) */
-  [0x89] = 0x85,       /* 137 => 133 via 129 (KEY_AGAIN) */
-  [0x8a] = 0x86,       /* 138 => 134 via 130 (KEY_PROPS) */
-  [0x8b] = 0x87,       /* 139 => 135 via 131 (KEY_UNDO) */
-  [0x8c] = 0x8c,       /* 140 => 140 via 132 (KEY_FRONT) */
-  [0x8d] = 0xf8,       /* 141 => 248 via 133 (KEY_COPY) */
-  [0x8e] = 0x64,       /* 142 => 100 via 134 (KEY_OPEN) */
-  [0x8f] = 0x65,       /* 143 => 101 via 135 (KEY_PASTE) */
-  [0x90] = 0xc1,       /* 144 => 193 via 136 (KEY_FIND) */
-  [0x91] = 0xbc,       /* 145 => 188 via 137 (KEY_CUT) */
-  [0x92] = 0xf5,       /* 146 => 245 via 138 (KEY_HELP) */
-  [0x93] = 0x9e,       /* 147 => 158 via 139 (KEY_MENU) */
-  [0x94] = 0xa1,       /* 148 => 161 via 140 (KEY_CALC) */
-  [0x95] = 0x66,       /* 149 => 102 via 141 (KEY_SETUP) */
-  [0x96] = 0xdf,       /* 150 => 223 via 142 (KEY_SLEEP) */
-  [0x97] = 0xe3,       /* 151 => 227 via 143 (KEY_WAKEUP) */
-  [0x98] = 0x67,       /* 152 => 103 via 144 (KEY_FILE) */
-  [0x99] = 0x68,       /* 153 => 104 via 145 (KEY_SENDFILE) */
-  [0x9a] = 0x69,       /* 154 => 105 via 146 (KEY_DELETEFILE) */
-  [0x9b] = 0x93,       /* 155 => 147 via 147 (KEY_XFER) */
-  [0x9c] = 0x9f,       /* 156 => 159 via 148 (KEY_PROG1) */
-  [0x9d] = 0x97,       /* 157 => 151 via 149 (KEY_PROG2) */
-  [0x9e] = 0x82,       /* 158 => 130 via 150 (KEY_WWW) */
-  [0x9f] = 0x6a,       /* 159 => 106 via 151 (KEY_MSDOS) */
-  [0xa0] = 0x92,       /* 160 => 146 via 152 (KEY_SCREENLOCK) */
-  [0xa1] = 0x6b,       /* 161 => 107 via 153 (KEY_DIRECTION) */
-  [0xa2] = 0xa6,       /* 162 => 166 via 154 (KEY_CYCLEWINDOWS) */
-  [0xa3] = 0xec,       /* 163 => 236 via 155 (KEY_MAIL) */
-  [0xa4] = 0xe6,       /* 164 => 230 via 156 (KEY_BOOKMARKS) */
-  [0xa5] = 0xeb,       /* 165 => 235 via 157 (KEY_COMPUTER) */
-  [0xa6] = 0xea,       /* 166 => 234 via 158 (KEY_BACK) */
-  [0xa7] = 0xe9,       /* 167 => 233 via 159 (KEY_FORWARD) */
-  [0xa8] = 0xa3,       /* 168 => 163 via 160 (KEY_CLOSECD) */
-  [0xa9] = 0x6c,       /* 169 => 108 via 161 (KEY_EJECTCD) */
-  [0xaa] = 0xfd,       /* 170 => 253 via 162 (KEY_EJECTCLOSECD) */
-  [0xab] = 0x99,       /* 171 => 153 via 163 (KEY_NEXTSONG) */
-  [0xac] = 0xa2,       /* 172 => 162 via 164 (KEY_PLAYPAUSE) */
-  [0xad] = 0x90,       /* 173 => 144 via 165 (KEY_PREVIOUSSONG) */
-  [0xae] = 0xa4,       /* 174 => 164 via 166 (KEY_STOPCD) */
-  [0xaf] = 0xb1,       /* 175 => 177 via 167 (KEY_RECORD) */
-  [0xb0] = 0x98,       /* 176 => 152 via 168 (KEY_REWIND) */
-  [0xb1] = 0x63,       /* 177 => 99 via 169 (KEY_PHONE) */
-  [0xb2] = 0x70,       /* 178 => 112 via 170 (KEY_ISO) */
-  [0xb3] = 0x81,       /* 179 => 129 via 171 (KEY_CONFIG) */
-  [0xb4] = 0xb2,       /* 180 => 178 via 172 (KEY_HOMEPAGE) */
-  [0xb5] = 0xe7,       /* 181 => 231 via 173 (KEY_REFRESH) */
-  [0xb6] = 0x71,       /* 182 => 113 via 174 (KEY_EXIT) */
-  [0xb7] = 0x72,       /* 183 => 114 via 175 (KEY_MOVE) */
-  [0xb8] = 0x88,       /* 184 => 136 via 176 (KEY_EDIT) */
-  [0xb9] = 0x75,       /* 185 => 117 via 177 (KEY_SCROLLUP) */
-  [0xba] = 0x8f,       /* 186 => 143 via 178 (KEY_SCROLLDOWN) */
-  [0xbb] = 0xf6,       /* 187 => 246 via 179 (KEY_KPLEFTPAREN) */
-  [0xbc] = 0xfb,       /* 188 => 251 via 180 (KEY_KPRIGHTPAREN) */
-  [0xbd] = 0x89,       /* 189 => 137 via 181 (KEY_NEW) */
-  [0xbe] = 0x8a,       /* 190 => 138 via 182 (KEY_REDO) */
-  [0xbf] = 0x5d,       /* 191 => 93 via 183 (KEY_F13) */
-  [0xc0] = 0x5e,       /* 192 => 94 via 184 (KEY_F14) */
-  [0xc1] = 0x5f,       /* 193 => 95 via 185 (KEY_F15) */
-  [0xc2] = 0x55,       /* 194 => 85 via 186 (KEY_F16) */
-  [0xc3] = 0x83,       /* 195 => 131 via 187 (KEY_F17) */
-  [0xc4] = 0xf7,       /* 196 => 247 via 188 (KEY_F18) */
-  [0xc5] = 0x84,       /* 197 => 132 via 189 (KEY_F19) */
-  [0xc6] = 0x5a,       /* 198 => 90 via 190 (KEY_F20) */
-  [0xc7] = 0x74,       /* 199 => 116 via 191 (KEY_F21) */
-  [0xc8] = 0xf9,       /* 200 => 249 via 192 (KEY_F22) */
-  [0xc9] = 0x6d,       /* 201 => 109 via 193 (KEY_F23) */
-  [0xca] = 0x6f,       /* 202 => 111 via 194 (KEY_F24) */
-  [0xcb] = 0x95,       /* 203 => 149 via 195 */
-  [0xcc] = 0x96,       /* 204 => 150 via 196 */
-  [0xcd] = 0x9a,       /* 205 => 154 via 197 */
-  [0xce] = 0x9b,       /* 206 => 155 via 198 */
-  [0xcf] = 0xa7,       /* 207 => 167 via 199 */
-  [0xd0] = 0xa8,       /* 208 => 168 via 200 (KEY_PLAYCD) */
-  [0xd1] = 0xa9,       /* 209 => 169 via 201 (KEY_PAUSECD) */
-  [0xd2] = 0xab,       /* 210 => 171 via 202 (KEY_PROG3) */
-  [0xd3] = 0xac,       /* 211 => 172 via 203 (KEY_PROG4) */
-  [0xd4] = 0xad,       /* 212 => 173 via 204 (KEY_DASHBOARD) */
-  [0xd5] = 0xa5,       /* 213 => 165 via 205 (KEY_SUSPEND) */
-  [0xd6] = 0xaf,       /* 214 => 175 via 206 (KEY_CLOSE) */
-  [0xd7] = 0xb3,       /* 215 => 179 via 207 (KEY_PLAY) */
-  [0xd8] = 0xb4,       /* 216 => 180 via 208 (KEY_FASTFORWARD) */
-  [0xd9] = 0xb6,       /* 217 => 182 via 209 (KEY_BASSBOOST) */
-  [0xda] = 0xb9,       /* 218 => 185 via 210 (KEY_PRINT) */
-  [0xdb] = 0xba,       /* 219 => 186 via 211 (KEY_HP) */
-  [0xdc] = 0xbb,       /* 220 => 187 via 212 (KEY_CAMERA) */
-  [0xdd] = 0xbd,       /* 221 => 189 via 213 (KEY_SOUND) */
-  [0xde] = 0xbe,       /* 222 => 190 via 214 (KEY_QUESTION) */
-  [0xdf] = 0xbf,       /* 223 => 191 via 215 (KEY_EMAIL) */
-  [0xe0] = 0xc0,       /* 224 => 192 via 216 (KEY_CHAT) */
-  [0xe1] = 0xe5,       /* 225 => 229 via 217 (KEY_SEARCH) */
-  [0xe2] = 0xc2,       /* 226 => 194 via 218 (KEY_CONNECT) */
-  [0xe3] = 0xc3,       /* 227 => 195 via 219 (KEY_FINANCE) */
-  [0xe4] = 0xc4,       /* 228 => 196 via 220 (KEY_SPORT) */
-  [0xe5] = 0xc5,       /* 229 => 197 via 221 (KEY_SHOP) */
-  [0xe6] = 0x94,       /* 230 => 148 via 222 (KEY_ALTERASE) */
-  [0xe7] = 0xca,       /* 231 => 202 via 223 (KEY_CANCEL) */
-  [0xe8] = 0xcc,       /* 232 => 204 via 224 (KEY_BRIGHTNESSDOWN) */
-  [0xe9] = 0xd4,       /* 233 => 212 via 225 (KEY_BRIGHTNESSUP) */
-  [0xea] = 0xed,       /* 234 => 237 via 226 (KEY_MEDIA) */
-  [0xeb] = 0xd6,       /* 235 => 214 via 227 (KEY_SWITCHVIDEOMODE) */
-  [0xec] = 0xd7,       /* 236 => 215 via 228 (KEY_KBDILLUMTOGGLE) */
-  [0xed] = 0xd8,       /* 237 => 216 via 229 (KEY_KBDILLUMDOWN) */
-  [0xee] = 0xd9,       /* 238 => 217 via 230 (KEY_KBDILLUMUP) */
-  [0xef] = 0xda,       /* 239 => 218 via 231 (KEY_SEND) */
-  [0xf0] = 0xe4,       /* 240 => 228 via 232 (KEY_REPLY) */
-  [0xf1] = 0x8e,       /* 241 => 142 via 233 (KEY_FORWARDMAIL) */
-  [0xf2] = 0xd5,       /* 242 => 213 via 234 (KEY_SAVE) */
-  [0xf3] = 0xf0,       /* 243 => 240 via 235 (KEY_DOCUMENTS) */
-  [0xf4] = 0xf1,       /* 244 => 241 via 236 (KEY_BATTERY) */
-  [0xf5] = 0xf2,       /* 245 => 242 via 237 (KEY_BLUETOOTH) */
-  [0xf6] = 0xf3,       /* 246 => 243 via 238 (KEY_WLAN) */
-  [0xf7] = 0xf4,       /* 247 => 244 via 239 (KEY_UWB) */
-};
diff --git a/src/vncdisplaykeymap_xorgkbd2rfb.c b/src/vncdisplaykeymap_xorgkbd2rfb.c
deleted file mode 100644
index 4a741ae..0000000
--- a/src/vncdisplaykeymap_xorgkbd2rfb.c
+++ /dev/null
@@ -1,112 +0,0 @@
-static const guint16 keymap_xorgkbd2rfb[] = {
-  [0x9] = 0x1,         /* 9 => 1 via 1 (KEY_ESC) */
-  [0xa] = 0x2,         /* 10 => 2 via 2 (KEY_1) */
-  [0xb] = 0x3,         /* 11 => 3 via 3 (KEY_2) */
-  [0xc] = 0x4,         /* 12 => 4 via 4 (KEY_3) */
-  [0xd] = 0x5,         /* 13 => 5 via 5 (KEY_4) */
-  [0xe] = 0x6,         /* 14 => 6 via 6 (KEY_5) */
-  [0xf] = 0x7,         /* 15 => 7 via 7 (KEY_6) */
-  [0x10] = 0x8,        /* 16 => 8 via 8 (KEY_7) */
-  [0x11] = 0x9,        /* 17 => 9 via 9 (KEY_8) */
-  [0x12] = 0xa,        /* 18 => 10 via 10 (KEY_9) */
-  [0x13] = 0xb,        /* 19 => 11 via 11 (KEY_0) */
-  [0x14] = 0xc,        /* 20 => 12 via 12 (KEY_MINUS) */
-  [0x15] = 0xd,        /* 21 => 13 via 13 (KEY_EQUAL) */
-  [0x16] = 0xe,        /* 22 => 14 via 14 (KEY_BACKSPACE) */
-  [0x17] = 0xf,        /* 23 => 15 via 15 (KEY_TAB) */
-  [0x18] = 0x10,       /* 24 => 16 via 16 (KEY_Q) */
-  [0x19] = 0x11,       /* 25 => 17 via 17 (KEY_W) */
-  [0x1a] = 0x12,       /* 26 => 18 via 18 (KEY_E) */
-  [0x1b] = 0x13,       /* 27 => 19 via 19 (KEY_R) */
-  [0x1c] = 0x14,       /* 28 => 20 via 20 (KEY_T) */
-  [0x1d] = 0x15,       /* 29 => 21 via 21 (KEY_Y) */
-  [0x1e] = 0x16,       /* 30 => 22 via 22 (KEY_U) */
-  [0x1f] = 0x17,       /* 31 => 23 via 23 (KEY_I) */
-  [0x20] = 0x18,       /* 32 => 24 via 24 (KEY_O) */
-  [0x21] = 0x19,       /* 33 => 25 via 25 (KEY_P) */
-  [0x22] = 0x1a,       /* 34 => 26 via 26 (KEY_LEFTBRACE) */
-  [0x23] = 0x1b,       /* 35 => 27 via 27 (KEY_RIGHTBRACE) */
-  [0x24] = 0x1c,       /* 36 => 28 via 28 (KEY_ENTER) */
-  [0x25] = 0x1d,       /* 37 => 29 via 29 (KEY_LEFTCTRL) */
-  [0x26] = 0x1e,       /* 38 => 30 via 30 (KEY_A) */
-  [0x27] = 0x1f,       /* 39 => 31 via 31 (KEY_S) */
-  [0x28] = 0x20,       /* 40 => 32 via 32 (KEY_D) */
-  [0x29] = 0x21,       /* 41 => 33 via 33 (KEY_F) */
-  [0x2a] = 0x22,       /* 42 => 34 via 34 (KEY_G) */
-  [0x2b] = 0x23,       /* 43 => 35 via 35 (KEY_H) */
-  [0x2c] = 0x24,       /* 44 => 36 via 36 (KEY_J) */
-  [0x2d] = 0x25,       /* 45 => 37 via 37 (KEY_K) */
-  [0x2e] = 0x26,       /* 46 => 38 via 38 (KEY_L) */
-  [0x2f] = 0x27,       /* 47 => 39 via 39 (KEY_SEMICOLON) */
-  [0x30] = 0x28,       /* 48 => 40 via 40 (KEY_APOSTROPHE) */
-  [0x31] = 0x29,       /* 49 => 41 via 41 (KEY_GRAVE) */
-  [0x32] = 0x2a,       /* 50 => 42 via 42 (KEY_LEFTSHIFT) */
-  [0x33] = 0x2b,       /* 51 => 43 via 43 (KEY_BACKSLASH) */
-  [0x34] = 0x2c,       /* 52 => 44 via 44 (KEY_Z) */
-  [0x35] = 0x2d,       /* 53 => 45 via 45 (KEY_X) */
-  [0x36] = 0x2e,       /* 54 => 46 via 46 (KEY_C) */
-  [0x37] = 0x2f,       /* 55 => 47 via 47 (KEY_V) */
-  [0x38] = 0x30,       /* 56 => 48 via 48 (KEY_B) */
-  [0x39] = 0x31,       /* 57 => 49 via 49 (KEY_N) */
-  [0x3a] = 0x32,       /* 58 => 50 via 50 (KEY_M) */
-  [0x3b] = 0x33,       /* 59 => 51 via 51 (KEY_COMMA) */
-  [0x3c] = 0x34,       /* 60 => 52 via 52 (KEY_DOT) */
-  [0x3d] = 0x35,       /* 61 => 53 via 53 (KEY_SLASH) */
-  [0x3e] = 0x36,       /* 62 => 54 via 54 (KEY_RIGHTSHIFT) */
-  [0x3f] = 0x37,       /* 63 => 55 via 55 (KEY_KPASTERISK) */
-  [0x40] = 0x38,       /* 64 => 56 via 56 (KEY_LEFTALT) */
-  [0x41] = 0x39,       /* 65 => 57 via 57 (KEY_SPACE) */
-  [0x42] = 0x3a,       /* 66 => 58 via 58 (KEY_CAPSLOCK) */
-  [0x43] = 0x3b,       /* 67 => 59 via 59 (KEY_F1) */
-  [0x44] = 0x3c,       /* 68 => 60 via 60 (KEY_F2) */
-  [0x45] = 0x3d,       /* 69 => 61 via 61 (KEY_F3) */
-  [0x46] = 0x3e,       /* 70 => 62 via 62 (KEY_F4) */
-  [0x47] = 0x3f,       /* 71 => 63 via 63 (KEY_F5) */
-  [0x48] = 0x40,       /* 72 => 64 via 64 (KEY_F6) */
-  [0x49] = 0x41,       /* 73 => 65 via 65 (KEY_F7) */
-  [0x4a] = 0x42,       /* 74 => 66 via 66 (KEY_F8) */
-  [0x4b] = 0x43,       /* 75 => 67 via 67 (KEY_F9) */
-  [0x4c] = 0x44,       /* 76 => 68 via 68 (KEY_F10) */
-  [0x4d] = 0x45,       /* 77 => 69 via 69 (KEY_NUMLOCK) */
-  [0x4e] = 0x46,       /* 78 => 70 via 70 (KEY_SCROLLLOCK) */
-  [0x4f] = 0x47,       /* 79 => 71 via 71 (KEY_KP7) */
-  [0x50] = 0x48,       /* 80 => 72 via 72 (KEY_KP8) */
-  [0x51] = 0x49,       /* 81 => 73 via 73 (KEY_KP9) */
-  [0x52] = 0x4a,       /* 82 => 74 via 74 (KEY_KPMINUS) */
-  [0x53] = 0x4b,       /* 83 => 75 via 75 (KEY_KP4) */
-  [0x54] = 0x4c,       /* 84 => 76 via 76 (KEY_KP5) */
-  [0x55] = 0x4d,       /* 85 => 77 via 77 (KEY_KP6) */
-  [0x56] = 0x4e,       /* 86 => 78 via 78 (KEY_KPPLUS) */
-  [0x57] = 0x4f,       /* 87 => 79 via 79 (KEY_KP1) */
-  [0x58] = 0x50,       /* 88 => 80 via 80 (KEY_KP2) */
-  [0x59] = 0x51,       /* 89 => 81 via 81 (KEY_KP3) */
-  [0x5a] = 0x52,       /* 90 => 82 via 82 (KEY_KP0) */
-  [0x5b] = 0x53,       /* 91 => 83 via 83 (KEY_KPDOT) */
-  [0x61] = 0xc7,       /* 97 => 199 via 102 (KEY_HOME) */
-  [0x62] = 0xc8,       /* 98 => 200 via 103 (KEY_UP) */
-  [0x63] = 0xc9,       /* 99 => 201 via 104 (KEY_PAGEUP) */
-  [0x64] = 0xcb,       /* 100 => 203 via 105 (KEY_LEFT) */
-  [0x66] = 0xcd,       /* 102 => 205 via 106 (KEY_RIGHT) */
-  [0x67] = 0xcf,       /* 103 => 207 via 107 (KEY_END) */
-  [0x68] = 0xd0,       /* 104 => 208 via 108 (KEY_DOWN) */
-  [0x69] = 0xd1,       /* 105 => 209 via 109 (KEY_PAGEDOWN) */
-  [0x6a] = 0xd2,       /* 106 => 210 via 110 (KEY_INSERT) */
-  [0x6b] = 0xd3,       /* 107 => 211 via 111 (KEY_DELETE) */
-  [0x6c] = 0x9c,       /* 108 => 156 via 96 (KEY_KPENTER) */
-  [0x6d] = 0x9d,       /* 109 => 157 via 97 (KEY_RIGHTCTRL) */
-  [0x6e] = 0xc6,       /* 110 => 198 via 119 (KEY_PAUSE) */
-  [0x6f] = 0x54,       /* 111 => 84 via 99 (KEY_SYSRQ) */
-  [0x70] = 0xb5,       /* 112 => 181 via 98 (KEY_KPSLASH) */
-  [0x71] = 0xb8,       /* 113 => 184 via 100 (KEY_RIGHTALT) */
-  [0x73] = 0xdb,       /* 115 => 219 via 125 (KEY_LEFTMETA) */
-  [0x74] = 0xdc,       /* 116 => 220 via 126 (KEY_RIGHTMETA) */
-  [0x75] = 0xdd,       /* 117 => 221 via 127 (KEY_COMPOSE) */
-  [0x76] = 0x5d,       /* 118 => 93 via 183 (KEY_F13) */
-  [0x77] = 0x5e,       /* 119 => 94 via 184 (KEY_F14) */
-  [0x78] = 0x5f,       /* 120 => 95 via 185 (KEY_F15) */
-  [0x79] = 0x55,       /* 121 => 85 via 186 (KEY_F16) */
-  [0x7a] = 0x83,       /* 122 => 131 via 187 (KEY_F17) */
-  [0x7e] = 0x59,       /* 126 => 89 via 117 (KEY_KPEQUAL) */
-  [0x85] = 0x7d,       /* 133 => 125 via 124 (KEY_YEN) */
-  [0xd0] = 0x70,       /* 208 => 112 via 93 (KEY_KATAKANAHIRAGANA) */
-};
diff --git a/src/vncdisplaykeymap_xorgxquartz2rfb.c b/src/vncdisplaykeymap_xorgxquartz2rfb.c
deleted file mode 100644
index 992ff6b..0000000
--- a/src/vncdisplaykeymap_xorgxquartz2rfb.c
+++ /dev/null
@@ -1,117 +0,0 @@
-static const guint16 keymap_xorgxquartz2rfb[] = {
-  [0x8] = 0x1e,        /* 8 => 30 via 30 (KEY_A) */
-  [0x9] = 0x1f,        /* 9 => 31 via 31 (KEY_S) */
-  [0xa] = 0x20,        /* 10 => 32 via 32 (KEY_D) */
-  [0xb] = 0x21,        /* 11 => 33 via 33 (KEY_F) */
-  [0xc] = 0x23,        /* 12 => 35 via 35 (KEY_H) */
-  [0xd] = 0x22,        /* 13 => 34 via 34 (KEY_G) */
-  [0xe] = 0x2c,        /* 14 => 44 via 44 (KEY_Z) */
-  [0xf] = 0x2d,        /* 15 => 45 via 45 (KEY_X) */
-  [0x10] = 0x2e,       /* 16 => 46 via 46 (KEY_C) */
-  [0x11] = 0x2f,       /* 17 => 47 via 47 (KEY_V) */
-  [0x12] = 0x70,       /* 18 => 112 via 170 (KEY_ISO) */
-  [0x13] = 0x30,       /* 19 => 48 via 48 (KEY_B) */
-  [0x14] = 0x10,       /* 20 => 16 via 16 (KEY_Q) */
-  [0x15] = 0x11,       /* 21 => 17 via 17 (KEY_W) */
-  [0x16] = 0x12,       /* 22 => 18 via 18 (KEY_E) */
-  [0x17] = 0x13,       /* 23 => 19 via 19 (KEY_R) */
-  [0x18] = 0x15,       /* 24 => 21 via 21 (KEY_Y) */
-  [0x19] = 0x14,       /* 25 => 20 via 20 (KEY_T) */
-  [0x1a] = 0x2,        /* 26 => 2 via 2 (KEY_1) */
-  [0x1b] = 0x3,        /* 27 => 3 via 3 (KEY_2) */
-  [0x1c] = 0x4,        /* 28 => 4 via 4 (KEY_3) */
-  [0x1d] = 0x5,        /* 29 => 5 via 5 (KEY_4) */
-  [0x1e] = 0x7,        /* 30 => 7 via 7 (KEY_6) */
-  [0x1f] = 0x6,        /* 31 => 6 via 6 (KEY_5) */
-  [0x20] = 0xd,        /* 32 => 13 via 13 (KEY_EQUAL) */
-  [0x21] = 0xa,        /* 33 => 10 via 10 (KEY_9) */
-  [0x22] = 0x8,        /* 34 => 8 via 8 (KEY_7) */
-  [0x23] = 0xc,        /* 35 => 12 via 12 (KEY_MINUS) */
-  [0x24] = 0x9,        /* 36 => 9 via 9 (KEY_8) */
-  [0x25] = 0xb,        /* 37 => 11 via 11 (KEY_0) */
-  [0x26] = 0x1b,       /* 38 => 27 via 27 (KEY_RIGHTBRACE) */
-  [0x27] = 0x18,       /* 39 => 24 via 24 (KEY_O) */
-  [0x28] = 0x16,       /* 40 => 22 via 22 (KEY_U) */
-  [0x29] = 0x1a,       /* 41 => 26 via 26 (KEY_LEFTBRACE) */
-  [0x2a] = 0x17,       /* 42 => 23 via 23 (KEY_I) */
-  [0x2b] = 0x19,       /* 43 => 25 via 25 (KEY_P) */
-  [0x2c] = 0x1c,       /* 44 => 28 via 28 (KEY_ENTER) */
-  [0x2d] = 0x26,       /* 45 => 38 via 38 (KEY_L) */
-  [0x2e] = 0x24,       /* 46 => 36 via 36 (KEY_J) */
-  [0x2f] = 0x28,       /* 47 => 40 via 40 (KEY_APOSTROPHE) */
-  [0x30] = 0x25,       /* 48 => 37 via 37 (KEY_K) */
-  [0x31] = 0x27,       /* 49 => 39 via 39 (KEY_SEMICOLON) */
-  [0x32] = 0x2b,       /* 50 => 43 via 43 (KEY_BACKSLASH) */
-  [0x33] = 0x33,       /* 51 => 51 via 51 (KEY_COMMA) */
-  [0x34] = 0x35,       /* 52 => 53 via 53 (KEY_SLASH) */
-  [0x35] = 0x31,       /* 53 => 49 via 49 (KEY_N) */
-  [0x36] = 0x32,       /* 54 => 50 via 50 (KEY_M) */
-  [0x37] = 0x34,       /* 55 => 52 via 52 (KEY_DOT) */
-  [0x38] = 0xf,        /* 56 => 15 via 15 (KEY_TAB) */
-  [0x39] = 0x39,       /* 57 => 57 via 57 (KEY_SPACE) */
-  [0x3a] = 0x29,       /* 58 => 41 via 41 (KEY_GRAVE) */
-  [0x3b] = 0xe,        /* 59 => 14 via 14 (KEY_BACKSPACE) */
-  [0x3d] = 0x1,        /* 61 => 1 via 1 (KEY_ESC) */
-  [0x3f] = 0xdb,       /* 63 => 219 via 125 (KEY_LEFTMETA) */
-  [0x40] = 0x2a,       /* 64 => 42 via 42 (KEY_LEFTSHIFT) */
-  [0x41] = 0x3a,       /* 65 => 58 via 58 (KEY_CAPSLOCK) */
-  [0x42] = 0x38,       /* 66 => 56 via 56 (KEY_LEFTALT) */
-  [0x43] = 0x1d,       /* 67 => 29 via 29 (KEY_LEFTCTRL) */
-  [0x44] = 0x36,       /* 68 => 54 via 54 (KEY_RIGHTSHIFT) */
-  [0x45] = 0xb8,       /* 69 => 184 via 100 (KEY_RIGHTALT) */
-  [0x46] = 0x9d,       /* 70 => 157 via 97 (KEY_RIGHTCTRL) */
-  [0x47] = 0xdd,       /* 71 => 221 via 127 (KEY_COMPOSE) */
-  [0x48] = 0x83,       /* 72 => 131 via 187 (KEY_F17) */
-  [0x49] = 0x53,       /* 73 => 83 via 83 (KEY_KPDOT) */
-  [0x4b] = 0x37,       /* 75 => 55 via 55 (KEY_KPASTERISK) */
-  [0x4d] = 0x4e,       /* 77 => 78 via 78 (KEY_KPPLUS) */
-  [0x4f] = 0x7e,       /* 79 => 126 via 121 (KEY_KPCOMMA) */
-  [0x50] = 0xb0,       /* 80 => 176 via 115 (KEY_VOLUMEUP) */
-  [0x51] = 0xae,       /* 81 => 174 via 114 (KEY_VOLUMEDOWN) */
-  [0x52] = 0xa0,       /* 82 => 160 via 113 (KEY_MUTE) */
-  [0x53] = 0xb5,       /* 83 => 181 via 98 (KEY_KPSLASH) */
-  [0x54] = 0x9c,       /* 84 => 156 via 96 (KEY_KPENTER) */
-  [0x56] = 0x4a,       /* 86 => 74 via 74 (KEY_KPMINUS) */
-  [0x57] = 0xf7,       /* 87 => 247 via 188 (KEY_F18) */
-  [0x58] = 0x84,       /* 88 => 132 via 189 (KEY_F19) */
-  [0x59] = 0x59,       /* 89 => 89 via 117 (KEY_KPEQUAL) */
-  [0x5a] = 0x52,       /* 90 => 82 via 82 (KEY_KP0) */
-  [0x5b] = 0x4f,       /* 91 => 79 via 79 (KEY_KP1) */
-  [0x5c] = 0x50,       /* 92 => 80 via 80 (KEY_KP2) */
-  [0x5d] = 0x51,       /* 93 => 81 via 81 (KEY_KP3) */
-  [0x5e] = 0x4b,       /* 94 => 75 via 75 (KEY_KP4) */
-  [0x5f] = 0x4c,       /* 95 => 76 via 76 (KEY_KP5) */
-  [0x60] = 0x4d,       /* 96 => 77 via 77 (KEY_KP6) */
-  [0x61] = 0x47,       /* 97 => 71 via 71 (KEY_KP7) */
-  [0x62] = 0x5a,       /* 98 => 90 via 190 (KEY_F20) */
-  [0x63] = 0x48,       /* 99 => 72 via 72 (KEY_KP8) */
-  [0x64] = 0x49,       /* 100 => 73 via 73 (KEY_KP9) */
-  [0x65] = 0x7d,       /* 101 => 125 via 124 (KEY_YEN) */
-  [0x67] = 0x5c,       /* 103 => 92 via 95 (KEY_KPJPCOMMA) */
-  [0x68] = 0x3f,       /* 104 => 63 via 63 (KEY_F5) */
-  [0x69] = 0x40,       /* 105 => 64 via 64 (KEY_F6) */
-  [0x6a] = 0x41,       /* 106 => 65 via 65 (KEY_F7) */
-  [0x6b] = 0x3d,       /* 107 => 61 via 61 (KEY_F3) */
-  [0x6c] = 0x42,       /* 108 => 66 via 66 (KEY_F8) */
-  [0x6d] = 0x43,       /* 109 => 67 via 67 (KEY_F9) */
-  [0x6f] = 0x57,       /* 111 => 87 via 87 (KEY_F11) */
-  [0x70] = 0x78,       /* 112 => 120 via 90 (KEY_KATAKANA) */
-  [0x71] = 0x5d,       /* 113 => 93 via 183 (KEY_F13) */
-  [0x72] = 0x55,       /* 114 => 85 via 186 (KEY_F16) */
-  [0x73] = 0x5e,       /* 115 => 94 via 184 (KEY_F14) */
-  [0x75] = 0x44,       /* 117 => 68 via 68 (KEY_F10) */
-  [0x77] = 0x58,       /* 119 => 88 via 88 (KEY_F12) */
-  [0x79] = 0x5f,       /* 121 => 95 via 185 (KEY_F15) */
-  [0x7b] = 0xc7,       /* 123 => 199 via 102 (KEY_HOME) */
-  [0x7c] = 0xc9,       /* 124 => 201 via 104 (KEY_PAGEUP) */
-  [0x7d] = 0xd3,       /* 125 => 211 via 111 (KEY_DELETE) */
-  [0x7e] = 0x3e,       /* 126 => 62 via 62 (KEY_F4) */
-  [0x7f] = 0xcf,       /* 127 => 207 via 107 (KEY_END) */
-  [0x80] = 0x3c,       /* 128 => 60 via 60 (KEY_F2) */
-  [0x81] = 0xd1,       /* 129 => 209 via 109 (KEY_PAGEDOWN) */
-  [0x82] = 0x3b,       /* 130 => 59 via 59 (KEY_F1) */
-  [0x83] = 0xcb,       /* 131 => 203 via 105 (KEY_LEFT) */
-  [0x84] = 0xcd,       /* 132 => 205 via 106 (KEY_RIGHT) */
-  [0x85] = 0xd0,       /* 133 => 208 via 108 (KEY_DOWN) */
-  [0x86] = 0xc8,       /* 134 => 200 via 103 (KEY_UP) */
-};
diff --git a/src/vncdisplaykeymap_xorgxwin2rfb.c b/src/vncdisplaykeymap_xorgxwin2rfb.c
deleted file mode 100644
index f1c1762..0000000
--- a/src/vncdisplaykeymap_xorgxwin2rfb.c
+++ /dev/null
@@ -1,112 +0,0 @@
-static const guint16 keymap_xorgxwin2rfb[] = {
-  [0x9] = 0x1,         /* 9 => 1 via 1 (KEY_ESC) */
-  [0xa] = 0x2,         /* 10 => 2 via 2 (KEY_1) */
-  [0xb] = 0x3,         /* 11 => 3 via 3 (KEY_2) */
-  [0xc] = 0x4,         /* 12 => 4 via 4 (KEY_3) */
-  [0xd] = 0x5,         /* 13 => 5 via 5 (KEY_4) */
-  [0xe] = 0x6,         /* 14 => 6 via 6 (KEY_5) */
-  [0xf] = 0x7,         /* 15 => 7 via 7 (KEY_6) */
-  [0x10] = 0x8,        /* 16 => 8 via 8 (KEY_7) */
-  [0x11] = 0x9,        /* 17 => 9 via 9 (KEY_8) */
-  [0x12] = 0xa,        /* 18 => 10 via 10 (KEY_9) */
-  [0x13] = 0xb,        /* 19 => 11 via 11 (KEY_0) */
-  [0x14] = 0xc,        /* 20 => 12 via 12 (KEY_MINUS) */
-  [0x15] = 0xd,        /* 21 => 13 via 13 (KEY_EQUAL) */
-  [0x16] = 0xe,        /* 22 => 14 via 14 (KEY_BACKSPACE) */
-  [0x17] = 0xf,        /* 23 => 15 via 15 (KEY_TAB) */
-  [0x18] = 0x10,       /* 24 => 16 via 16 (KEY_Q) */
-  [0x19] = 0x11,       /* 25 => 17 via 17 (KEY_W) */
-  [0x1a] = 0x12,       /* 26 => 18 via 18 (KEY_E) */
-  [0x1b] = 0x13,       /* 27 => 19 via 19 (KEY_R) */
-  [0x1c] = 0x14,       /* 28 => 20 via 20 (KEY_T) */
-  [0x1d] = 0x15,       /* 29 => 21 via 21 (KEY_Y) */
-  [0x1e] = 0x16,       /* 30 => 22 via 22 (KEY_U) */
-  [0x1f] = 0x17,       /* 31 => 23 via 23 (KEY_I) */
-  [0x20] = 0x18,       /* 32 => 24 via 24 (KEY_O) */
-  [0x21] = 0x19,       /* 33 => 25 via 25 (KEY_P) */
-  [0x22] = 0x1a,       /* 34 => 26 via 26 (KEY_LEFTBRACE) */
-  [0x23] = 0x1b,       /* 35 => 27 via 27 (KEY_RIGHTBRACE) */
-  [0x24] = 0x1c,       /* 36 => 28 via 28 (KEY_ENTER) */
-  [0x25] = 0x1d,       /* 37 => 29 via 29 (KEY_LEFTCTRL) */
-  [0x26] = 0x1e,       /* 38 => 30 via 30 (KEY_A) */
-  [0x27] = 0x1f,       /* 39 => 31 via 31 (KEY_S) */
-  [0x28] = 0x20,       /* 40 => 32 via 32 (KEY_D) */
-  [0x29] = 0x21,       /* 41 => 33 via 33 (KEY_F) */
-  [0x2a] = 0x22,       /* 42 => 34 via 34 (KEY_G) */
-  [0x2b] = 0x23,       /* 43 => 35 via 35 (KEY_H) */
-  [0x2c] = 0x24,       /* 44 => 36 via 36 (KEY_J) */
-  [0x2d] = 0x25,       /* 45 => 37 via 37 (KEY_K) */
-  [0x2e] = 0x26,       /* 46 => 38 via 38 (KEY_L) */
-  [0x2f] = 0x27,       /* 47 => 39 via 39 (KEY_SEMICOLON) */
-  [0x30] = 0x28,       /* 48 => 40 via 40 (KEY_APOSTROPHE) */
-  [0x31] = 0x29,       /* 49 => 41 via 41 (KEY_GRAVE) */
-  [0x32] = 0x2a,       /* 50 => 42 via 42 (KEY_LEFTSHIFT) */
-  [0x33] = 0x2b,       /* 51 => 43 via 43 (KEY_BACKSLASH) */
-  [0x34] = 0x2c,       /* 52 => 44 via 44 (KEY_Z) */
-  [0x35] = 0x2d,       /* 53 => 45 via 45 (KEY_X) */
-  [0x36] = 0x2e,       /* 54 => 46 via 46 (KEY_C) */
-  [0x37] = 0x2f,       /* 55 => 47 via 47 (KEY_V) */
-  [0x38] = 0x30,       /* 56 => 48 via 48 (KEY_B) */
-  [0x39] = 0x31,       /* 57 => 49 via 49 (KEY_N) */
-  [0x3a] = 0x32,       /* 58 => 50 via 50 (KEY_M) */
-  [0x3b] = 0x33,       /* 59 => 51 via 51 (KEY_COMMA) */
-  [0x3c] = 0x34,       /* 60 => 52 via 52 (KEY_DOT) */
-  [0x3d] = 0x35,       /* 61 => 53 via 53 (KEY_SLASH) */
-  [0x3e] = 0x36,       /* 62 => 54 via 54 (KEY_RIGHTSHIFT) */
-  [0x3f] = 0x37,       /* 63 => 55 via 55 (KEY_KPASTERISK) */
-  [0x40] = 0x38,       /* 64 => 56 via 56 (KEY_LEFTALT) */
-  [0x41] = 0x39,       /* 65 => 57 via 57 (KEY_SPACE) */
-  [0x42] = 0x3a,       /* 66 => 58 via 58 (KEY_CAPSLOCK) */
-  [0x43] = 0x3b,       /* 67 => 59 via 59 (KEY_F1) */
-  [0x44] = 0x3c,       /* 68 => 60 via 60 (KEY_F2) */
-  [0x45] = 0x3d,       /* 69 => 61 via 61 (KEY_F3) */
-  [0x46] = 0x3e,       /* 70 => 62 via 62 (KEY_F4) */
-  [0x47] = 0x3f,       /* 71 => 63 via 63 (KEY_F5) */
-  [0x48] = 0x40,       /* 72 => 64 via 64 (KEY_F6) */
-  [0x49] = 0x41,       /* 73 => 65 via 65 (KEY_F7) */
-  [0x4a] = 0x42,       /* 74 => 66 via 66 (KEY_F8) */
-  [0x4b] = 0x43,       /* 75 => 67 via 67 (KEY_F9) */
-  [0x4c] = 0x44,       /* 76 => 68 via 68 (KEY_F10) */
-  [0x4d] = 0x45,       /* 77 => 69 via 69 (KEY_NUMLOCK) */
-  [0x4e] = 0x46,       /* 78 => 70 via 70 (KEY_SCROLLLOCK) */
-  [0x4f] = 0x47,       /* 79 => 71 via 71 (KEY_KP7) */
-  [0x50] = 0x48,       /* 80 => 72 via 72 (KEY_KP8) */
-  [0x51] = 0x49,       /* 81 => 73 via 73 (KEY_KP9) */
-  [0x52] = 0x4a,       /* 82 => 74 via 74 (KEY_KPMINUS) */
-  [0x53] = 0x4b,       /* 83 => 75 via 75 (KEY_KP4) */
-  [0x54] = 0x4c,       /* 84 => 76 via 76 (KEY_KP5) */
-  [0x55] = 0x4d,       /* 85 => 77 via 77 (KEY_KP6) */
-  [0x56] = 0x4e,       /* 86 => 78 via 78 (KEY_KPPLUS) */
-  [0x57] = 0x4f,       /* 87 => 79 via 79 (KEY_KP1) */
-  [0x58] = 0x50,       /* 88 => 80 via 80 (KEY_KP2) */
-  [0x59] = 0x51,       /* 89 => 81 via 81 (KEY_KP3) */
-  [0x5a] = 0x52,       /* 90 => 82 via 82 (KEY_KP0) */
-  [0x5b] = 0x53,       /* 91 => 83 via 83 (KEY_KPDOT) */
-  [0x61] = 0xc7,       /* 97 => 199 via 102 (KEY_HOME) */
-  [0x62] = 0xc8,       /* 98 => 200 via 103 (KEY_UP) */
-  [0x63] = 0xc9,       /* 99 => 201 via 104 (KEY_PAGEUP) */
-  [0x64] = 0xcb,       /* 100 => 203 via 105 (KEY_LEFT) */
-  [0x66] = 0xcd,       /* 102 => 205 via 106 (KEY_RIGHT) */
-  [0x67] = 0xcf,       /* 103 => 207 via 107 (KEY_END) */
-  [0x68] = 0xd0,       /* 104 => 208 via 108 (KEY_DOWN) */
-  [0x69] = 0xd1,       /* 105 => 209 via 109 (KEY_PAGEDOWN) */
-  [0x6a] = 0xd2,       /* 106 => 210 via 110 (KEY_INSERT) */
-  [0x6b] = 0xd3,       /* 107 => 211 via 111 (KEY_DELETE) */
-  [0x6c] = 0x9c,       /* 108 => 156 via 96 (KEY_KPENTER) */
-  [0x6d] = 0x9d,       /* 109 => 157 via 97 (KEY_RIGHTCTRL) */
-  [0x6e] = 0xc6,       /* 110 => 198 via 119 (KEY_PAUSE) */
-  [0x6f] = 0x54,       /* 111 => 84 via 99 (KEY_SYSRQ) */
-  [0x70] = 0xb5,       /* 112 => 181 via 98 (KEY_KPSLASH) */
-  [0x71] = 0xb8,       /* 113 => 184 via 100 (KEY_RIGHTALT) */
-  [0x73] = 0xdb,       /* 115 => 219 via 125 (KEY_LEFTMETA) */
-  [0x74] = 0xdc,       /* 116 => 220 via 126 (KEY_RIGHTMETA) */
-  [0x75] = 0xdd,       /* 117 => 221 via 127 (KEY_COMPOSE) */
-  [0x76] = 0x5d,       /* 118 => 93 via 183 (KEY_F13) */
-  [0x77] = 0x5e,       /* 119 => 94 via 184 (KEY_F14) */
-  [0x78] = 0x5f,       /* 120 => 95 via 185 (KEY_F15) */
-  [0x79] = 0x55,       /* 121 => 85 via 186 (KEY_F16) */
-  [0x7a] = 0x83,       /* 122 => 131 via 187 (KEY_F17) */
-  [0x7e] = 0x59,       /* 126 => 89 via 117 (KEY_KPEQUAL) */
-  [0x85] = 0x7d,       /* 133 => 125 via 124 (KEY_YEN) */
-  [0xd0] = 0x70,       /* 208 => 112 via 93 (KEY_KATAKANAHIRAGANA) */
-};
diff --git a/src/vncgrabsequence.c b/src/vncgrabsequence.c
index 072e2d9..fc06011 100644
--- a/src/vncgrabsequence.c
+++ b/src/vncgrabsequence.c
@@ -134,6 +134,7 @@ VncGrabSequence *vnc_grab_sequence_copy(VncGrabSequence *sequence)
  */
 void vnc_grab_sequence_free(VncGrabSequence *sequence)
 {
+    g_free(sequence->keysyms);
     g_slice_free(VncGrabSequence, sequence);
 }
 
diff --git a/vapi/Makefile.am b/vapi/Makefile.am
index 40e070d..c306217 100644
--- a/vapi/Makefile.am
+++ b/vapi/Makefile.am
@@ -5,12 +5,15 @@ vapidir = $(datadir)/vala/vapi
 vapi_DATA =					\
 	gtk-vnc-$(GTK_VNC_API_VERSION).deps	\
 	gtk-vnc-$(GTK_VNC_API_VERSION).vapi	\
+	gvnc-1.0.deps				\
 	gvnc-1.0.vapi				\
 	$(NULL)
 
 if HAVE_PULSEAUDIO
 vapi_DATA += \
-	gvncpulse-1.0.vapi
+	gvncpulse-1.0.deps			\
+	gvncpulse-1.0.vapi			\
+	$(NULL)
 endif
 
 gvnc-1.0.vapi: $(top_builddir)/src/GVnc-1.0.gir
@@ -20,6 +23,9 @@ gvnc-1.0.vapi: $(top_builddir)/src/GVnc-1.0.gir
 		--library gvnc-1.0		\
 		$<
 
+gvnc-1.0.deps: gvnc-1.0.vapi
+	@echo "gio-2.0" > $@
+
 if HAVE_PULSEAUDIO
 gvncpulse-1.0.vapi: $(top_builddir)/src/GVncPulse-1.0.gir gvnc-1.0.vapi
 	$(AM_V_GEN)$(VAPIGEN)			\
@@ -30,6 +36,10 @@ gvncpulse-1.0.vapi: $(top_builddir)/src/GVncPulse-1.0.gir gvnc-1.0.vapi
 		--library gvncpulse-1.0		\
 		--girdir=$(top_builddir)/src	\
 		$<
+
+gvncpulse-1.0.deps: gvnc-1.0.vapi
+	@echo "gio-2.0" > $@
+	@echo "gvnc-1.0" >> $@
 endif
 
 gtk-vnc-$(GTK_VNC_API_VERSION).vapi: $(top_builddir)/src/GtkVnc-$(GTK_VNC_API_VERSION).gir gvnc-1.0.vapi
diff --git a/vapi/Makefile.in b/vapi/Makefile.in
index 3c4b7bf..bfb80bb 100644
--- a/vapi/Makefile.in
+++ b/vapi/Makefile.in
@@ -89,7 +89,9 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 @HAVE_PULSEAUDIO_TRUE@@WITH_VALA_TRUE at am__append_1 = \
- at HAVE_PULSEAUDIO_TRUE@@WITH_VALA_TRUE@	gvncpulse-1.0.vapi
+ at HAVE_PULSEAUDIO_TRUE@@WITH_VALA_TRUE@	gvncpulse-1.0.deps			\
+ at HAVE_PULSEAUDIO_TRUE@@WITH_VALA_TRUE@	gvncpulse-1.0.vapi			\
+ at HAVE_PULSEAUDIO_TRUE@@WITH_VALA_TRUE@	$(NULL)
 
 subdir = vapi
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
@@ -373,7 +375,8 @@ NULL =
 @WITH_VALA_TRUE at vapidir = $(datadir)/vala/vapi
 @WITH_VALA_TRUE at vapi_DATA = gtk-vnc-$(GTK_VNC_API_VERSION).deps \
 @WITH_VALA_TRUE@	gtk-vnc-$(GTK_VNC_API_VERSION).vapi \
- at WITH_VALA_TRUE@	gvnc-1.0.vapi $(NULL) $(am__append_1)
+ at WITH_VALA_TRUE@	gvnc-1.0.deps gvnc-1.0.vapi $(NULL) \
+ at WITH_VALA_TRUE@	$(am__append_1)
 CLEANFILES = $(vapi_DATA)
 all: all-am
 
@@ -599,6 +602,9 @@ uninstall-am: uninstall-vapiDATA
 @WITH_VALA_TRUE@		--library gvnc-1.0		\
 @WITH_VALA_TRUE@		$<
 
+ at WITH_VALA_TRUE@gvnc-1.0.deps: gvnc-1.0.vapi
+ at WITH_VALA_TRUE@	@echo "gio-2.0" > $@
+
 @HAVE_PULSEAUDIO_TRUE@@WITH_VALA_TRUE at gvncpulse-1.0.vapi: $(top_builddir)/src/GVncPulse-1.0.gir gvnc-1.0.vapi
 @HAVE_PULSEAUDIO_TRUE@@WITH_VALA_TRUE@	$(AM_V_GEN)$(VAPIGEN)			\
 @HAVE_PULSEAUDIO_TRUE@@WITH_VALA_TRUE@		--vapidir=$(builddir)		\
@@ -609,6 +615,10 @@ uninstall-am: uninstall-vapiDATA
 @HAVE_PULSEAUDIO_TRUE@@WITH_VALA_TRUE@		--girdir=$(top_builddir)/src	\
 @HAVE_PULSEAUDIO_TRUE@@WITH_VALA_TRUE@		$<
 
+ at HAVE_PULSEAUDIO_TRUE@@WITH_VALA_TRUE at gvncpulse-1.0.deps: gvnc-1.0.vapi
+ at HAVE_PULSEAUDIO_TRUE@@WITH_VALA_TRUE@	@echo "gio-2.0" > $@
+ at HAVE_PULSEAUDIO_TRUE@@WITH_VALA_TRUE@	@echo "gvnc-1.0" >> $@
+
 @WITH_VALA_TRUE at gtk-vnc-$(GTK_VNC_API_VERSION).vapi: $(top_builddir)/src/GtkVnc-$(GTK_VNC_API_VERSION).gir gvnc-1.0.vapi
 @WITH_VALA_TRUE@	$(AM_V_GEN)$(VAPIGEN)			\
 @WITH_VALA_TRUE@		--vapidir=$(builddir)		\

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-libvirt/gtk-vnc.git



More information about the Pkg-libvirt-commits mailing list