Index: src/client/c/hu/varadiistvan/xplra/XPlane.cc
===================================================================
--- src/client/c/hu/varadiistvan/xplra/XPlane.cc	(revision 40)
+++ src/client/c/hu/varadiistvan/xplra/XPlane.cc	(revision 54)
@@ -59,4 +59,5 @@
 using std::auto_ptr;
 using std::string;
+using std::min;
 
 //------------------------------------------------------------------------------
@@ -500,4 +501,47 @@
 //------------------------------------------------------------------------------
 
+void XPlane::registerHotkeys(const uint16_t* codes, size_t length)
+    throw(Exception)
+{
+    stream->writeU8(Protocol::COMMAND_REGISTER_HOTKEYS);
+    stream->writeU32(length);
+    stream->write(codes, sizeof(uint16_t)*length);
+    stream->flush();
+    checkResult();
+}
+
+//------------------------------------------------------------------------------
+
+void XPlane::queryHotkeys(uint8_t* states, size_t length) throw(Exception)
+{
+    stream->writeU8(Protocol::COMMAND_QUERY_HOTKEYS);
+    stream->flush();
+    checkResult();
+
+    size_t count = stream->readU32();
+    checkStream();
+    stream->read(states, min(length, count));
+    if (length<count) {
+        while(length<count) {
+            stream->readU8();
+            ++length;
+        }
+    } else if (length>count) {
+        memset(states + count, 0, length - count);
+    }
+    checkStream();
+}
+
+//------------------------------------------------------------------------------
+
+void XPlane::unregisterHotkeys()
+{
+    stream->writeU8(Protocol::COMMAND_UNREGISTER_HOTKEYS);
+    stream->flush();
+    checkResult();
+}
+
+//------------------------------------------------------------------------------
+
 // Local Variables:
 // mode: C++
Index: src/client/c/hu/varadiistvan/xplra/XPlane.h
===================================================================
--- src/client/c/hu/varadiistvan/xplra/XPlane.h	(revision 40)
+++ src/client/c/hu/varadiistvan/xplra/XPlane.h	(revision 54)
@@ -282,4 +282,20 @@
     void showMessage(const char* message, float duration) throw(Exception);
 
+    /**
+     * Register the given hotkey codes for listening. If there is an
+     * existing set of hotkeys registered, those will be overwritten.
+     */
+    void registerHotkeys(const uint16_t* codes, size_t length) throw(Exception);
+
+    /**
+     * Query the registered hotkeys whether they were pressed.
+     */
+    void queryHotkeys(uint8_t* states, size_t length) throw(Exception);
+
+    /**
+     * Unregister the hotkeys.
+     */
+    void unregisterHotkeys();
+
 private:
     /**
Index: test/Makefile.am
===================================================================
--- test/Makefile.am	(revision 31)
+++ test/Makefile.am	(revision 54)
@@ -6,5 +6,5 @@
 endif
 
-noinst_PROGRAMS=ctest basictest basicctest multigettest multigetctest multisettest multisetctest
+noinst_PROGRAMS=ctest basictest basicctest multigettest multigetctest multisettest multisetctest hotkeytest
 
 ctest_SOURCES=ctest.c
@@ -34,5 +34,10 @@
 endif
 
+hotkeytest_SOURCES=hotkeytest.cc
+
 EXTRA_DIST=\
         runpy.sh                \
-        basictest.py
+        basictest.py            \
+        multigettest.py         \
+        multisettest.py         \
+        hotkeytest.py
Index: test/hotkeytest.cc
===================================================================
--- test/hotkeytest.cc	(revision 54)
+++ test/hotkeytest.cc	(revision 54)
@@ -0,0 +1,111 @@
+// Copyright (c) 2013 by István Váradi
+
+// This file is part of XPLRA, a remote-access plugin for X-Plane
+
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+
+// 1. Redistributions of source code must retain the above copyright notice, this
+//    list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+//    this list of conditions and the following disclaimer in the documentation
+//    and/or other materials provided with the distribution.
+
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// The views and conclusions contained in the software and documentation are those
+// of the authors and should not be interpreted as representing official policies,
+// either expressed or implied, of the FreeBSD Project.
+
+//------------------------------------------------------------------------------
+
+#include <hu/varadiistvan/xplra/XPlane.h>
+
+#include <hu/varadiistvan/scpl/Thread.h>
+
+#include <cstdio>
+#include <cstring>
+
+//------------------------------------------------------------------------------
+
+using hu::varadiistvan::xplra::XPlane;
+using hu::varadiistvan::xplra::Exception;
+using hu::varadiistvan::xplra::ProtocolException;
+
+using hu::varadiistvan::scpl::Thread;
+
+using std::string;
+
+//------------------------------------------------------------------------------
+
+int main()
+{
+    try {
+        XPlane xplane;
+
+        printf("Connecting to X-Plane...\n");
+        xplane.connect();
+        printf("Connected to X-Plane.\n\n");
+
+        printf("Registering hotkeys: Ctrl+A, Shift+B, Ctrl+Shift+C, Ctrl+Q...\n");
+        uint16_t codes[] = { 0x0241, 0x0142, 0x0343, 0x0251 };
+        xplane.registerHotkeys(codes, sizeof(codes)/sizeof(uint16_t));
+        printf("Registered hotkeys...\n\n");
+
+        printf("Listening to hotkeys...\n");
+        while(true) {
+            uint8_t states[4];
+            xplane.queryHotkeys(states, sizeof(states));
+            if (states[3]!=0) {
+                xplane.unregisterHotkeys();
+                break;
+            }
+
+            char message[256];
+            message[0] = '\0';
+
+            if (states[0]!=0) {
+                if (message[0]!='\0') strcat(message, ", ");
+                strcat(message, "Ctrl+A");
+            }
+            if (states[1]!=0) {
+                if (message[0]!='\0') strcat(message, ", ");
+                strcat(message, "Shift+B");
+            }
+            if (states[2]!=0) {
+                if (message[0]!='\0') strcat(message, ", ");
+                strcat(message, "Ctrl+Shift+C");
+            }
+
+            if (message[0]!='\0') {
+                strcat(message, " pressed");
+                xplane.showMessage(message, 3.0);
+            }
+
+            Thread::sleep(500);
+        }
+
+
+    } catch(const Exception& exception) {
+        printf("\n>>>>>>>>>>>>>>>>> Exception caugth: %s\n", exception.what());
+
+        return 1;
+    }
+}
+
+//------------------------------------------------------------------------------
+
+// Local Variables:
+// mode: C++
+// c-basic-offset: 4
+// indent-tabs-mode: nil
+// End:
Index: test/hotkeytest.py
===================================================================
--- test/hotkeytest.py	(revision 53)
+++ test/hotkeytest.py	(revision 54)
@@ -21,4 +21,5 @@
         xplane.registerHotkeys([0x0241, 0x0142, 0x0343, 0x0251])
         print "Registered hotkeys..."
+        print
 
         print "Listening to hotkeys..."
@@ -45,3 +46,4 @@
         print ">>>>>>>>>>>>>>>>>>>>>> Exception caught:", str(e)
     finally:
+        xplane.unregisterHotkeys()
         xplane.disconnect()
