aboutsummaryrefslogtreecommitdiffstats
path: root/vncviewer
diff options
context:
space:
mode:
authorPierre Ossman <ossman@cendio.se>2017-09-15 11:03:48 +0200
committerPierre Ossman <ossman@cendio.se>2017-09-15 11:03:48 +0200
commit24e83052d28d464e7f3f12aa800736bcdd16874a (patch)
treea09f3373566e759131255ac5f8648f90c37d6544 /vncviewer
parent71ca8d546baaf13cca282c840b6521a98078fb42 (diff)
parent0c15866f0c86402016e55eeb7c044eb2e6cd95f5 (diff)
downloadtigervnc-24e83052d28d464e7f3f12aa800736bcdd16874a.tar.gz
tigervnc-24e83052d28d464e7f3f12aa800736bcdd16874a.zip
Merge branch 'qemukbd-merge' of https://github.com/CendioOssman/tigervnc
Diffstat (limited to 'vncviewer')
-rw-r--r--vncviewer/CConn.cxx9
-rw-r--r--vncviewer/CConn.h2
-rw-r--r--vncviewer/CMakeLists.txt8
-rw-r--r--vncviewer/DesktopWindow.cxx38
-rw-r--r--vncviewer/DesktopWindow.h3
-rw-r--r--vncviewer/Viewport.cxx413
-rw-r--r--vncviewer/Viewport.h9
-rw-r--r--vncviewer/cocoa.h6
-rw-r--r--vncviewer/cocoa.mm77
-rw-r--r--vncviewer/menukey.cxx44
-rw-r--r--vncviewer/menukey.h3
-rw-r--r--vncviewer/osx_to_qnum.c126
-rw-r--r--vncviewer/xkb_to_qnum.c257
13 files changed, 913 insertions, 82 deletions
diff --git a/vncviewer/CConn.cxx b/vncviewer/CConn.cxx
index 2e97ec28..07e7841c 100644
--- a/vncviewer/CConn.cxx
+++ b/vncviewer/CConn.cxx
@@ -92,6 +92,8 @@ CConn::CConn(const char* vncServerName, network::Socket* socket=NULL)
cp.supportsExtendedDesktopSize = true;
cp.supportsDesktopRename = true;
+ cp.supportsLEDState = true;
+
if (customCompressLevel)
cp.compressLevel = compressLevel;
else
@@ -503,6 +505,13 @@ void CConn::fence(rdr::U32 flags, unsigned len, const char data[])
}
}
+void CConn::setLEDState(unsigned int state)
+{
+ CConnection::setLEDState(state);
+
+ desktop->setLEDState(state);
+}
+
////////////////////// Internal methods //////////////////////
diff --git a/vncviewer/CConn.h b/vncviewer/CConn.h
index 93cc278f..426bd1e2 100644
--- a/vncviewer/CConn.h
+++ b/vncviewer/CConn.h
@@ -74,6 +74,8 @@ public:
void fence(rdr::U32 flags, unsigned len, const char data[]);
+ void setLEDState(unsigned int state);
+
private:
void resizeFramebuffer();
diff --git a/vncviewer/CMakeLists.txt b/vncviewer/CMakeLists.txt
index 2aecda23..3c186463 100644
--- a/vncviewer/CMakeLists.txt
+++ b/vncviewer/CMakeLists.txt
@@ -29,7 +29,9 @@ endif()
if(WIN32)
set(VNCVIEWER_SOURCES ${VNCVIEWER_SOURCES} win32.c)
elseif(APPLE)
- set(VNCVIEWER_SOURCES ${VNCVIEWER_SOURCES} cocoa.mm)
+ set(VNCVIEWER_SOURCES ${VNCVIEWER_SOURCES} cocoa.mm osx_to_qnum.c)
+else()
+ set(VNCVIEWER_SOURCES ${VNCVIEWER_SOURCES} xkb_to_qnum.c)
endif()
if(WIN32)
@@ -53,7 +55,9 @@ if(WIN32)
endif()
if(APPLE)
- target_link_libraries(vncviewer "-framework Cocoa" "-framework Carbon")
+ target_link_libraries(vncviewer "-framework Cocoa")
+ target_link_libraries(vncviewer "-framework Carbon")
+ target_link_libraries(vncviewer "-framework IOKit")
endif()
install(TARGETS vncviewer DESTINATION ${BIN_DIR})
diff --git a/vncviewer/DesktopWindow.cxx b/vncviewer/DesktopWindow.cxx
index 408efd19..897f9557 100644
--- a/vncviewer/DesktopWindow.cxx
+++ b/vncviewer/DesktopWindow.cxx
@@ -395,6 +395,12 @@ void DesktopWindow::draw()
}
+void DesktopWindow::setLEDState(unsigned int state)
+{
+ viewport->setLEDState(state);
+}
+
+
void DesktopWindow::resize(int x, int y, int w, int h)
{
bool resizing;
@@ -660,23 +666,31 @@ int DesktopWindow::fltkHandle(int event, Fl_Window *win)
DesktopWindow *dw = dynamic_cast<DesktopWindow*>(win);
- if (dw && fullscreenSystemKeys) {
+ if (dw) {
switch (event) {
case FL_FOCUS:
- // FIXME: We reassert the keyboard grabbing on focus as FLTK there are
- // some issues we need to work around:
- // a) Fl::grab(0) on X11 will release the keyboard grab for us.
- // b) Gaining focus on the system level causes FLTK to switch
- // window level on OS X.
- if (dw->fullscreen_active())
- dw->grabKeyboard();
+ if (fullscreenSystemKeys) {
+ // FIXME: We reassert the keyboard grabbing on focus as FLTK there are
+ // some issues we need to work around:
+ // a) Fl::grab(0) on X11 will release the keyboard grab for us.
+ // b) Gaining focus on the system level causes FLTK to switch
+ // window level on OS X.
+ if (dw->fullscreen_active())
+ dw->grabKeyboard();
+ }
+
+ // We may have gotten our lock keys out of sync with the server
+ // whilst we didn't have focus. Try to sort this out.
+ dw->viewport->pushLEDState();
break;
case FL_UNFOCUS:
- // FIXME: We need to relinquish control when the entire window loses
- // focus as it is very tied to this specific window on some
- // platforms and we want to be able to open subwindows.
- dw->ungrabKeyboard();
+ if (fullscreenSystemKeys) {
+ // FIXME: We need to relinquish control when the entire window loses
+ // focus as it is very tied to this specific window on some
+ // platforms and we want to be able to open subwindows.
+ dw->ungrabKeyboard();
+ }
break;
}
}
diff --git a/vncviewer/DesktopWindow.h b/vncviewer/DesktopWindow.h
index 4224699c..f1bf312f 100644
--- a/vncviewer/DesktopWindow.h
+++ b/vncviewer/DesktopWindow.h
@@ -66,6 +66,9 @@ public:
void setCursor(int width, int height, const rfb::Point& hotspot,
const rdr::U8* data);
+ // Change client LED state
+ void setLEDState(unsigned int state);
+
// Fl_Window callback methods
void draw();
void resize(int x, int y, int w, int h);
diff --git a/vncviewer/Viewport.cxx b/vncviewer/Viewport.cxx
index 6a23526a..331efbc7 100644
--- a/vncviewer/Viewport.cxx
+++ b/vncviewer/Viewport.cxx
@@ -28,6 +28,7 @@
#include <rfb/CMsgWriter.h>
#include <rfb/LogWriter.h>
#include <rfb/Exception.h>
+#include <rfb/ledStates.h>
// FLTK can pull in the X11 headers on some systems
#ifndef XK_VoidSymbol
@@ -41,6 +42,10 @@
#include <rfb/XF86keysym.h>
#endif
+#if ! (defined(WIN32) || defined(__APPLE__))
+#include <X11/XKBlib.h>
+#endif
+
#ifndef NoSymbol
#define NoSymbol 0
#endif
@@ -69,8 +74,21 @@
#include <FL/Fl_Menu.H>
#include <FL/Fl_Menu_Button.H>
+#if !defined(WIN32) && !defined(__APPLE__)
+#include <X11/XKBlib.h>
+extern const struct _code_map_xkb_to_qnum {
+ const char * from;
+ const unsigned short to;
+} code_map_xkb_to_qnum[];
+extern const unsigned int code_map_xkb_to_qnum_len;
+
+static int code_map_keycode_to_qnum[256];
+#endif
+
#ifdef __APPLE__
#include "cocoa.h"
+extern const unsigned short code_map_osx_to_qnum[];
+extern const unsigned int code_map_osx_to_qnum_len;
#endif
#ifdef WIN32
@@ -89,14 +107,55 @@ enum { ID_EXIT, ID_FULLSCREEN, ID_MINIMIZE, ID_RESIZE,
ID_CTRL, ID_ALT, ID_MENUKEY, ID_CTRLALTDEL,
ID_REFRESH, ID_OPTIONS, ID_INFO, ID_ABOUT, ID_DISMISS };
-// Fake key presses use this value and above
-static const int fakeKeyBase = 0x200;
+// Used to detect fake input (0xaa is not a real key)
+#ifdef WIN32
+static const WORD SCAN_FAKE = 0xaa;
+#endif
Viewport::Viewport(int w, int h, const rfb::PixelFormat& serverPF, CConn* cc_)
: Fl_Widget(0, 0, w, h), cc(cc_), frameBuffer(NULL),
lastPointerPos(0, 0), lastButtonMask(0),
menuCtrlKey(false), menuAltKey(false), cursor(NULL)
{
+#if !defined(WIN32) && !defined(__APPLE__)
+ XkbDescPtr xkb;
+ Status status;
+
+ xkb = XkbGetMap(fl_display, 0, XkbUseCoreKbd);
+ if (!xkb)
+ throw Exception("XkbGetMap");
+
+ status = XkbGetNames(fl_display, XkbKeyNamesMask, xkb);
+ if (status != Success)
+ throw Exception("XkbGetNames");
+
+ memset(code_map_keycode_to_qnum, 0, sizeof(code_map_keycode_to_qnum));
+ for (KeyCode keycode = xkb->min_key_code;
+ keycode < xkb->max_key_code;
+ keycode++) {
+ const char *keyname = xkb->names->keys[keycode].name;
+ unsigned short rfbcode;
+
+ if (keyname[0] == '\0')
+ continue;
+
+ rfbcode = 0;
+ for (unsigned i = 0;i < code_map_xkb_to_qnum_len;i++) {
+ if (strncmp(code_map_xkb_to_qnum[i].from,
+ keyname, XkbKeyNameLength) == 0) {
+ rfbcode = code_map_xkb_to_qnum[i].to;
+ break;
+ }
+ }
+ if (rfbcode != 0)
+ code_map_keycode_to_qnum[keycode] = rfbcode;
+ else
+ vlog.debug("No key mapping for key %.4s", keyname);
+ }
+
+ XkbFreeKeyboard(xkb, 0, True);
+#endif
+
Fl::add_clipboard_notify(handleClipboardChange, this);
// We need to intercept keyboard events early
@@ -218,6 +277,189 @@ void Viewport::setCursor(int width, int height, const Point& hotspot,
}
+void Viewport::setLEDState(unsigned int state)
+{
+ Fl_Widget *focus;
+
+ vlog.debug("Got server LED state: 0x%08x", state);
+
+ focus = Fl::grab();
+ if (!focus)
+ focus = Fl::focus();
+ if (!focus)
+ return;
+
+ if (focus != this)
+ return;
+
+#if defined(WIN32)
+ INPUT input[6];
+ UINT count;
+ UINT ret;
+
+ memset(input, 0, sizeof(input));
+ count = 0;
+
+ if (!!(state & ledCapsLock) != !!(GetKeyState(VK_CAPITAL) & 0x1)) {
+ input[count].type = input[count+1].type = INPUT_KEYBOARD;
+ input[count].ki.wVk = input[count+1].ki.wVk = VK_CAPITAL;
+ input[count].ki.wScan = input[count+1].ki.wScan = SCAN_FAKE;
+ input[count].ki.dwFlags = 0;
+ input[count+1].ki.dwFlags = KEYEVENTF_KEYUP;
+ count += 2;
+ }
+
+ if (!!(state & ledNumLock) != !!(GetKeyState(VK_NUMLOCK) & 0x1)) {
+ input[count].type = input[count+1].type = INPUT_KEYBOARD;
+ input[count].ki.wVk = input[count+1].ki.wVk = VK_NUMLOCK;
+ input[count].ki.wScan = input[count+1].ki.wScan = SCAN_FAKE;
+ input[count].ki.dwFlags = KEYEVENTF_EXTENDEDKEY;
+ input[count+1].ki.dwFlags = KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY;
+ count += 2;
+ }
+
+ if (!!(state & ledScrollLock) != !!(GetKeyState(VK_SCROLL) & 0x1)) {
+ input[count].type = input[count+1].type = INPUT_KEYBOARD;
+ input[count].ki.wVk = input[count+1].ki.wVk = VK_SCROLL;
+ input[count].ki.wScan = input[count+1].ki.wScan = SCAN_FAKE;
+ input[count].ki.dwFlags = 0;
+ input[count+1].ki.dwFlags = KEYEVENTF_KEYUP;
+ count += 2;
+ }
+
+ if (count == 0)
+ return;
+
+ ret = SendInput(count, input, sizeof(*input));
+ if (ret < count)
+ vlog.error(_("Failed to update keyboard LED state: %lu"), GetLastError());
+#elif defined(__APPLE__)
+ int ret;
+
+ ret = cocoa_set_caps_lock_state(state & ledCapsLock);
+ if (ret != 0) {
+ vlog.error(_("Failed to update keyboard LED state: %d"), ret);
+ return;
+ }
+
+ ret = cocoa_set_num_lock_state(state & ledNumLock);
+ if (ret != 0) {
+ vlog.error(_("Failed to update keyboard LED state: %d"), ret);
+ return;
+ }
+
+ // No support for Scroll Lock //
+
+#else
+ unsigned int affect, values;
+ unsigned int mask;
+
+ Bool ret;
+
+ affect = values = 0;
+
+ affect |= LockMask;
+ if (state & ledCapsLock)
+ values |= LockMask;
+
+ mask = getModifierMask(XK_Num_Lock);
+ affect |= mask;
+ if (state & ledNumLock)
+ values |= mask;
+
+ mask = getModifierMask(XK_Scroll_Lock);
+ affect |= mask;
+ if (state & ledScrollLock)
+ values |= mask;
+
+ ret = XkbLockModifiers(fl_display, XkbUseCoreKbd, affect, values);
+ if (!ret)
+ vlog.error(_("Failed to update keyboard LED state"));
+#endif
+}
+
+void Viewport::pushLEDState()
+{
+ unsigned int state;
+
+ // Server support?
+ if (cc->cp.ledState() == ledUnknown)
+ return;
+
+ state = 0;
+
+#if defined(WIN32)
+ if (GetKeyState(VK_CAPITAL) & 0x1)
+ state |= ledCapsLock;
+ if (GetKeyState(VK_NUMLOCK) & 0x1)
+ state |= ledNumLock;
+ if (GetKeyState(VK_SCROLL) & 0x1)
+ state |= ledScrollLock;
+#elif defined(__APPLE__)
+ int ret;
+ bool on;
+
+ ret = cocoa_get_caps_lock_state(&on);
+ if (ret != 0) {
+ vlog.error(_("Failed to get keyboard LED state: %d"), ret);
+ return;
+ }
+ if (on)
+ state |= ledCapsLock;
+
+ ret = cocoa_get_num_lock_state(&on);
+ if (ret != 0) {
+ vlog.error(_("Failed to get keyboard LED state: %d"), ret);
+ return;
+ }
+ if (on)
+ state |= ledNumLock;
+
+ // No support for Scroll Lock //
+ state |= (cc->cp.ledState() & ledScrollLock);
+
+#else
+ unsigned int mask;
+
+ Status status;
+ XkbStateRec xkbState;
+
+ status = XkbGetState(fl_display, XkbUseCoreKbd, &xkbState);
+ if (status != Success) {
+ vlog.error(_("Failed to get keyboard LED state: %d"), status);
+ return;
+ }
+
+ if (xkbState.locked_mods & LockMask)
+ state |= ledCapsLock;
+
+ mask = getModifierMask(XK_Num_Lock);
+ if (xkbState.locked_mods & mask)
+ state |= ledNumLock;
+
+ mask = getModifierMask(XK_Scroll_Lock);
+ if (xkbState.locked_mods & mask)
+ state |= ledScrollLock;
+#endif
+
+ if ((state & ledCapsLock) != (cc->cp.ledState() & ledCapsLock)) {
+ vlog.debug("Inserting fake CapsLock to get in sync with server");
+ handleKeyPress(0x3a, XK_Caps_Lock);
+ handleKeyRelease(0x3a);
+ }
+ if ((state & ledNumLock) != (cc->cp.ledState() & ledNumLock)) {
+ vlog.debug("Inserting fake NumLock to get in sync with server");
+ handleKeyPress(0x45, XK_Num_Lock);
+ handleKeyRelease(0x45);
+ }
+ if ((state & ledScrollLock) != (cc->cp.ledState() & ledScrollLock)) {
+ vlog.debug("Inserting fake ScrollLock to get in sync with server");
+ handleKeyPress(0x46, XK_Scroll_Lock);
+ handleKeyRelease(0x46);
+ }
+}
+
+
void Viewport::draw(Surface* dst)
{
int X, Y, W, H;
@@ -352,6 +594,55 @@ int Viewport::handle(int event)
return Fl_Widget::handle(event);
}
+
+#if ! (defined(WIN32) || defined(__APPLE__))
+unsigned int Viewport::getModifierMask(unsigned int keysym)
+{
+ XkbDescPtr xkb;
+ unsigned int mask, keycode;
+ XkbAction *act;
+
+ mask = 0;
+
+ xkb = XkbGetMap(fl_display, XkbAllComponentsMask, XkbUseCoreKbd);
+ if (xkb == NULL)
+ return 0;
+
+ for (keycode = xkb->min_key_code; keycode <= xkb->max_key_code; keycode++) {
+ unsigned int state_out;
+ KeySym ks;
+
+ XkbTranslateKeyCode(xkb, keycode, 0, &state_out, &ks);
+ if (ks == NoSymbol)
+ continue;
+
+ if (ks == keysym)
+ break;
+ }
+
+ // KeySym not mapped?
+ if (keycode > xkb->max_key_code)
+ goto out;
+
+ act = XkbKeyAction(xkb, keycode, 0);
+ if (act == NULL)
+ goto out;
+ if (act->type != XkbSA_LockMods)
+ goto out;
+
+ if (act->mods.flags & XkbSA_UseModMapMods)
+ mask = xkb->map->modmap[keycode];
+ else
+ mask = act->mods.mask;
+
+out:
+ XkbFreeKeyboard(xkb, XkbAllComponentsMask, True);
+
+ return mask;
+}
+#endif
+
+
void Viewport::handleClipboardChange(int source, void *data)
{
Viewport *self = (Viewport *)data;
@@ -422,6 +713,11 @@ void Viewport::handleKeyPress(int keyCode, rdr::U32 keySym)
if (viewOnly)
return;
+ if (keyCode == 0) {
+ vlog.error(_("No key code specified on key press"));
+ return;
+ }
+
#ifdef __APPLE__
// Alt on OS X behaves more like AltGr on other systems, and to get
// sane behaviour we should translate things in that manner for the
@@ -452,23 +748,11 @@ void Viewport::handleKeyPress(int keyCode, rdr::U32 keySym)
// Ctrl+Alt+AltGr, which we usually end up with when Xvnc tries to
// get everything in the correct state. Cheat and temporarily release
// Ctrl and Alt when we send some other symbol.
- bool ctrlPressed, altPressed;
- DownMap::iterator iter;
-
- ctrlPressed = false;
- altPressed = false;
- for (iter = downKeySym.begin();iter != downKeySym.end();++iter) {
- if (iter->second == XK_Control_L)
- ctrlPressed = true;
- else if (iter->second == XK_Alt_R)
- altPressed = true;
- }
-
- if (ctrlPressed && altPressed) {
+ if (downKeySym.count(0x1d) && downKeySym.count(0xb8)) {
vlog.debug("Faking release of AltGr (Ctrl_L+Alt_R)");
try {
- cc->writer()->keyEvent(XK_Control_L, false);
- cc->writer()->keyEvent(XK_Alt_R, false);
+ cc->writer()->keyEvent(downKeySym[0x1d], 0x1d, false);
+ cc->writer()->keyEvent(downKeySym[0xb8], 0xb8, false);
} catch (rdr::Exception& e) {
vlog.error("%s", e.str());
exit_vncviewer(e.str());
@@ -490,7 +774,11 @@ void Viewport::handleKeyPress(int keyCode, rdr::U32 keySym)
#endif
try {
- cc->writer()->keyEvent(keySym, true);
+ // Fake keycode?
+ if (keyCode > 0xff)
+ cc->writer()->keyEvent(keySym, 0, true);
+ else
+ cc->writer()->keyEvent(keySym, keyCode, true);
} catch (rdr::Exception& e) {
vlog.error("%s", e.str());
exit_vncviewer(e.str());
@@ -498,11 +786,11 @@ void Viewport::handleKeyPress(int keyCode, rdr::U32 keySym)
#ifdef WIN32
// Ugly hack continued...
- if (ctrlPressed && altPressed) {
+ if (downKeySym.count(0x1d) && downKeySym.count(0xb8)) {
vlog.debug("Restoring AltGr state");
try {
- cc->writer()->keyEvent(XK_Control_L, true);
- cc->writer()->keyEvent(XK_Alt_R, true);
+ cc->writer()->keyEvent(downKeySym[0x1d], 0x1d, true);
+ cc->writer()->keyEvent(downKeySym[0xb8], 0xb8, true);
} catch (rdr::Exception& e) {
vlog.error("%s", e.str());
exit_vncviewer(e.str());
@@ -535,7 +823,10 @@ void Viewport::handleKeyRelease(int keyCode)
#endif
try {
- cc->writer()->keyEvent(iter->second, false);
+ if (keyCode > 0xff)
+ cc->writer()->keyEvent(iter->second, 0, false);
+ else
+ cc->writer()->keyEvent(iter->second, keyCode, false);
} catch (rdr::Exception& e) {
vlog.error("%s", e.str());
exit_vncviewer(e.str());
@@ -577,6 +868,11 @@ int Viewport::handleSystemEvent(void *event, void *data)
keyCode = ((msg->lParam >> 16) & 0xff);
+ if (keyCode == SCAN_FAKE) {
+ vlog.debug("Ignoring fake key press (virtual key 0x%02x)", vKey);
+ return 1;
+ }
+
// Windows sets the scan code to 0x00 for multimedia keys, so we
// have to do a reverse lookup based on the vKey.
if (keyCode == 0x00) {
@@ -590,14 +886,19 @@ int Viewport::handleSystemEvent(void *event, void *data)
}
}
+ if (keyCode & ~0x7f) {
+ vlog.error(_("Invalid scan code 0x%02x"), (int)keyCode);
+ return 1;
+ }
+
if (isExtended)
- keyCode |= 0x100;
+ keyCode |= 0x80;
// VK_SNAPSHOT sends different scan codes depending on the state of
// Alt. This means that we can get different scan codes on press and
// release. Force it to be something standard.
if (vKey == VK_SNAPSHOT)
- keyCode = 0x137;
+ keyCode = 0x54;
keySym = win32_vkey_to_keysym(vKey, isExtended);
if (keySym == NoSymbol) {
@@ -605,9 +906,12 @@ int Viewport::handleSystemEvent(void *event, void *data)
vlog.error(_("No symbol for extended virtual key 0x%02x"), (int)vKey);
else
vlog.error(_("No symbol for virtual key 0x%02x"), (int)vKey);
- return 1;
}
+ // Fortunately RFB and Windows use the same scan code set,
+ // so there is no conversion needed
+ // (as long as we encode the extended keys with the high bit)
+
self->handleKeyPress(keyCode, keySym);
return 1;
@@ -620,12 +924,18 @@ int Viewport::handleSystemEvent(void *event, void *data)
isExtended = (msg->lParam & (1 << 24)) != 0;
keyCode = ((msg->lParam >> 16) & 0xff);
+
+ if (keyCode == SCAN_FAKE) {
+ vlog.debug("Ignoring fake key release (virtual key 0x%02x)", vKey);
+ return 1;
+ }
+
if (keyCode == 0x00)
keyCode = MapVirtualKey(vKey, MAPVK_VK_TO_VSC);
if (isExtended)
- keyCode |= 0x100;
+ keyCode |= 0x80;
if (vKey == VK_SNAPSHOT)
- keyCode = 0x137;
+ keyCode = 0x54;
self->handleKeyRelease(keyCode);
@@ -636,6 +946,10 @@ int Viewport::handleSystemEvent(void *event, void *data)
int keyCode;
keyCode = cocoa_event_keycode(event);
+ if ((unsigned)keyCode >= code_map_osx_to_qnum_len)
+ keyCode = 0;
+ else
+ keyCode = code_map_osx_to_qnum[keyCode];
if (cocoa_is_key_press(event)) {
rdr::U32 keySym;
@@ -644,7 +958,6 @@ int Viewport::handleSystemEvent(void *event, void *data)
if (keySym == NoSymbol) {
vlog.error(_("No symbol for key code 0x%02x (in the current state)"),
(int)keyCode);
- return 1;
}
self->handleKeyPress(keyCode, keySym);
@@ -663,14 +976,21 @@ int Viewport::handleSystemEvent(void *event, void *data)
XEvent *xevent = (XEvent*)event;
if (xevent->type == KeyPress) {
+ int keycode;
char str;
KeySym keysym;
+ keycode = code_map_keycode_to_qnum[xevent->xkey.keycode];
+
+ // Generate a fake keycode just for tracking if we can't figure
+ // out the proper one
+ if (keycode == 0)
+ keycode = 0x100 | xevent->xkey.keycode;
+
XLookupString(&xevent->xkey, &str, 1, &keysym, NULL);
if (keysym == NoSymbol) {
vlog.error(_("No symbol for key code %d (in the current state)"),
(int)xevent->xkey.keycode);
- return 1;
}
switch (keysym) {
@@ -690,10 +1010,13 @@ int Viewport::handleSystemEvent(void *event, void *data)
break;
}
- self->handleKeyPress(xevent->xkey.keycode, keysym);
+ self->handleKeyPress(keycode, keysym);
return 1;
} else if (xevent->type == KeyRelease) {
- self->handleKeyRelease(xevent->xkey.keycode);
+ int keycode = code_map_keycode_to_qnum[xevent->xkey.keycode];
+ if (keycode == 0)
+ keycode = 0x100 | xevent->xkey.keycode;
+ self->handleKeyRelease(keycode);
return 1;
}
#endif
@@ -729,7 +1052,7 @@ void Viewport::initContextMenu()
char sendMenuKey[64];
snprintf(sendMenuKey, 64, p_("ContextMenu|", "Send %s"), (const char *)menuKey);
fltk_menu_add(contextMenu, sendMenuKey, 0, NULL, (void*)ID_MENUKEY, 0);
- fltk_menu_add(contextMenu, "Secret shortcut menu key", menuKeyCode, NULL,
+ fltk_menu_add(contextMenu, "Secret shortcut menu key", menuKeyFLTK, NULL,
(void*)ID_MENUKEY, FL_MENU_INVISIBLE);
}
@@ -797,30 +1120,30 @@ void Viewport::popupContextMenu()
break;
case ID_CTRL:
if (m->value())
- handleKeyPress(fakeKeyBase + 0, XK_Control_L);
+ handleKeyPress(0x1d, XK_Control_L);
else
- handleKeyRelease(fakeKeyBase + 0);
+ handleKeyRelease(0x1d);
menuCtrlKey = !menuCtrlKey;
break;
case ID_ALT:
if (m->value())
- handleKeyPress(fakeKeyBase + 1, XK_Alt_L);
+ handleKeyPress(0x38, XK_Alt_L);
else
- handleKeyRelease(fakeKeyBase + 1);
+ handleKeyRelease(0x38);
menuAltKey = !menuAltKey;
break;
case ID_MENUKEY:
- handleKeyPress(fakeKeyBase + 2, menuKeySym);
- handleKeyRelease(fakeKeyBase + 2);
+ handleKeyPress(menuKeyCode, menuKeySym);
+ handleKeyRelease(menuKeyCode);
break;
case ID_CTRLALTDEL:
- handleKeyPress(fakeKeyBase + 3, XK_Control_L);
- handleKeyPress(fakeKeyBase + 4, XK_Alt_L);
- handleKeyPress(fakeKeyBase + 5, XK_Delete);
+ handleKeyPress(0x1d, XK_Control_L);
+ handleKeyPress(0x38, XK_Alt_L);
+ handleKeyPress(0xd3, XK_Delete);
- handleKeyRelease(fakeKeyBase + 5);
- handleKeyRelease(fakeKeyBase + 4);
- handleKeyRelease(fakeKeyBase + 3);
+ handleKeyRelease(0xd3);
+ handleKeyRelease(0x38);
+ handleKeyRelease(0x1d);
break;
case ID_REFRESH:
cc->refreshFramebuffer();
@@ -846,7 +1169,7 @@ void Viewport::popupContextMenu()
void Viewport::setMenuKey()
{
- getMenuKey(&menuKeyCode, &menuKeySym);
+ getMenuKey(&menuKeyFLTK, &menuKeyCode, &menuKeySym);
}
diff --git a/vncviewer/Viewport.h b/vncviewer/Viewport.h
index 6f0710d3..a4b7d8b7 100644
--- a/vncviewer/Viewport.h
+++ b/vncviewer/Viewport.h
@@ -47,6 +47,11 @@ public:
void setCursor(int width, int height, const rfb::Point& hotspot,
const rdr::U8* data);
+ // Change client LED state
+ void setLEDState(unsigned int state);
+ // Change server LED state
+ void pushLEDState();
+
void draw(Surface* dst);
// Fl_Widget callback methods
@@ -59,6 +64,8 @@ public:
private:
+ unsigned int getModifierMask(unsigned int keysym);
+
static void handleClipboardChange(int source, void *data);
void handlePointerEvent(const rfb::Point& pos, int buttonMask);
@@ -88,7 +95,7 @@ private:
DownMap downKeySym;
rdr::U32 menuKeySym;
- int menuKeyCode;
+ int menuKeyCode, menuKeyFLTK;
Fl_Menu_Button *contextMenu;
bool menuCtrlKey;
diff --git a/vncviewer/cocoa.h b/vncviewer/cocoa.h
index 0c3ac82f..a7138026 100644
--- a/vncviewer/cocoa.h
+++ b/vncviewer/cocoa.h
@@ -33,4 +33,10 @@ int cocoa_is_key_press(const void *event);
int cocoa_event_keycode(const void *event);
int cocoa_event_keysym(const void *event);
+int cocoa_set_caps_lock_state(bool on);
+int cocoa_set_num_lock_state(bool on);
+
+int cocoa_get_caps_lock_state(bool *on);
+int cocoa_get_num_lock_state(bool *on);
+
#endif
diff --git a/vncviewer/cocoa.mm b/vncviewer/cocoa.mm
index 6e464fa4..e26851d6 100644
--- a/vncviewer/cocoa.mm
+++ b/vncviewer/cocoa.mm
@@ -27,6 +27,9 @@
#import <Cocoa/Cocoa.h>
#import <Carbon/Carbon.h>
+#include <IOKit/hidsystem/IOHIDLib.h>
+#include <IOKit/hidsystem/IOHIDParameter.h>
+
#define XK_LATIN1
#define XK_MISCELLANY
#define XK_XKB_KEYS
@@ -406,3 +409,77 @@ int cocoa_event_keysym(const void *event)
return ucs2keysym([chars characterAtIndex:0]);
}
+
+static int cocoa_open_hid(io_connect_t *ioc)
+{
+ kern_return_t ret;
+ io_service_t ios;
+ CFMutableDictionaryRef mdict;
+
+ mdict = IOServiceMatching(kIOHIDSystemClass);
+ ios = IOServiceGetMatchingService(kIOMasterPortDefault,
+ (CFDictionaryRef) mdict);
+ if (!ios)
+ return KERN_FAILURE;
+
+ ret = IOServiceOpen(ios, mach_task_self(), kIOHIDParamConnectType, ioc);
+ IOObjectRelease(ios);
+ if (ret != KERN_SUCCESS)
+ return ret;
+
+ return KERN_SUCCESS;
+}
+
+static int cocoa_set_modifier_lock_state(int modifier, bool on)
+{
+ kern_return_t ret;
+ io_connect_t ioc;
+
+ ret = cocoa_open_hid(&ioc);
+ if (ret != KERN_SUCCESS)
+ return ret;
+
+ ret = IOHIDSetModifierLockState(ioc, modifier, on);
+ IOServiceClose(ioc);
+ if (ret != KERN_SUCCESS)
+ return ret;
+
+ return KERN_SUCCESS;
+}
+
+static int cocoa_get_modifier_lock_state(int modifier, bool *on)
+{
+ kern_return_t ret;
+ io_connect_t ioc;
+
+ ret = cocoa_open_hid(&ioc);
+ if (ret != KERN_SUCCESS)
+ return ret;
+
+ ret = IOHIDGetModifierLockState(ioc, modifier, on);
+ IOServiceClose(ioc);
+ if (ret != KERN_SUCCESS)
+ return ret;
+
+ return KERN_SUCCESS;
+}
+
+int cocoa_set_caps_lock_state(bool on)
+{
+ return cocoa_set_modifier_lock_state(kIOHIDCapsLockState, on);
+}
+
+int cocoa_set_num_lock_state(bool on)
+{
+ return cocoa_set_modifier_lock_state(kIOHIDNumLockState, on);
+}
+
+int cocoa_get_caps_lock_state(bool *on)
+{
+ return cocoa_get_modifier_lock_state(kIOHIDCapsLockState, on);
+}
+
+int cocoa_get_num_lock_state(bool *on)
+{
+ return cocoa_get_modifier_lock_state(kIOHIDNumLockState, on);
+}
diff --git a/vncviewer/menukey.cxx b/vncviewer/menukey.cxx
index 04e52d00..25f9f56e 100644
--- a/vncviewer/menukey.cxx
+++ b/vncviewer/menukey.cxx
@@ -30,26 +30,26 @@
#include "parameters.h"
static const MenuKeySymbol menuSymbols[] = {
- {"F1", FL_F + 1, XK_F1},
- {"F2", FL_F + 2, XK_F2},
- {"F3", FL_F + 3, XK_F3},
- {"F4", FL_F + 4, XK_F4},
- {"F5", FL_F + 5, XK_F5},
- {"F6", FL_F + 6, XK_F6},
- {"F7", FL_F + 7, XK_F7},
- {"F8", FL_F + 8, XK_F8},
- {"F9", FL_F + 9, XK_F9},
- {"F10", FL_F + 10, XK_F10},
- {"F11", FL_F + 11, XK_F11},
- {"F12", FL_F + 12, XK_F12},
- {"Pause", FL_Pause, XK_Pause},
- {"Scroll_Lock", FL_Scroll_Lock, XK_Scroll_Lock},
- {"Escape", FL_Escape, XK_Escape},
- {"Insert", FL_Insert, XK_Insert},
- {"Delete", FL_Delete, XK_Delete},
- {"Home", FL_Home, XK_Home},
- {"Page_Up", FL_Page_Up, XK_Page_Up},
- {"Page_Down", FL_Page_Down, XK_Page_Down},
+ {"F1", FL_F + 1, 0x3b, XK_F1},
+ {"F2", FL_F + 2, 0x3c, XK_F2},
+ {"F3", FL_F + 3, 0x3d, XK_F3},
+ {"F4", FL_F + 4, 0x3e, XK_F4},
+ {"F5", FL_F + 5, 0x3f, XK_F5},
+ {"F6", FL_F + 6, 0x40, XK_F6},
+ {"F7", FL_F + 7, 0x41, XK_F7},
+ {"F8", FL_F + 8, 0x42, XK_F8},
+ {"F9", FL_F + 9, 0x43, XK_F9},
+ {"F10", FL_F + 10, 0x44, XK_F10},
+ {"F11", FL_F + 11, 0x57, XK_F11},
+ {"F12", FL_F + 12, 0x58, XK_F12},
+ {"Pause", FL_Pause, 0xc6, XK_Pause},
+ {"Scroll_Lock", FL_Scroll_Lock, 0x46, XK_Scroll_Lock},
+ {"Escape", FL_Escape, 0x01, XK_Escape},
+ {"Insert", FL_Insert, 0xd2, XK_Insert},
+ {"Delete", FL_Delete, 0xd3, XK_Delete},
+ {"Home", FL_Home, 0xc7, XK_Home},
+ {"Page_Up", FL_Page_Up, 0xc9, XK_Page_Up},
+ {"Page_Down", FL_Page_Down, 0xd1, XK_Page_Down},
};
int getMenuKeySymbolCount()
@@ -62,19 +62,21 @@ const MenuKeySymbol* getMenuKeySymbols()
return menuSymbols;
}
-void getMenuKey(int *keycode, rdr::U32 *keysym)
+void getMenuKey(int *fltkcode, int *keycode, rdr::U32 *keysym)
{
const char *menuKeyStr;
menuKeyStr = menuKey;
for(int i = 0; i < getMenuKeySymbolCount(); i++) {
if (!strcmp(menuSymbols[i].name, menuKeyStr)) {
+ *fltkcode = menuSymbols[i].fltkcode;
*keycode = menuSymbols[i].keycode;
*keysym = menuSymbols[i].keysym;
return;
}
}
+ *fltkcode = 0;
*keycode = 0;
*keysym = 0;
}
diff --git a/vncviewer/menukey.h b/vncviewer/menukey.h
index fcc51353..79354288 100644
--- a/vncviewer/menukey.h
+++ b/vncviewer/menukey.h
@@ -22,11 +22,12 @@
typedef struct {
const char* name;
+ int fltkcode;
int keycode;
rdr::U32 keysym;
} MenuKeySymbol;
-void getMenuKey(int *keycode, rdr::U32 *keysym);
+void getMenuKey(int *fltkcode, int *keycode, rdr::U32 *keysym);
int getMenuKeySymbolCount();
const MenuKeySymbol* getMenuKeySymbols();
diff --git a/vncviewer/osx_to_qnum.c b/vncviewer/osx_to_qnum.c
new file mode 100644
index 00000000..511b7d54
--- /dev/null
+++ b/vncviewer/osx_to_qnum.c
@@ -0,0 +1,126 @@
+/*
+ * This file is auto-generated from keymaps.csv on 2017-08-28 13:04
+ * Database checksum sha256(f8aeff0c3430077a350e3d7ba2b335b381bd929ac4b193413730a402ff3f0097)
+ * To re-generate, run:
+ * keymap-gen --lang=stdc code-map keymaps.csv osx qnum
+*/
+const unsigned short code_map_osx_to_qnum[256] = {
+ [0x0] = 0x1e, /* osx:0 (ANSI_A) -> linux:30 (KEY_A) -> qnum:30 */
+ [0x1] = 0x1f, /* osx:1 (ANSI_S) -> linux:31 (KEY_S) -> qnum:31 */
+ [0x2] = 0x20, /* osx:2 (ANSI_D) -> linux:32 (KEY_D) -> qnum:32 */
+ [0x3] = 0x21, /* osx:3 (ANSI_F) -> linux:33 (KEY_F) -> qnum:33 */
+ [0x4] = 0x23, /* osx:4 (ANSI_H) -> linux:35 (KEY_H) -> qnum:35 */
+ [0x5] = 0x22, /* osx:5 (ANSI_G) -> linux:34 (KEY_G) -> qnum:34 */
+ [0x6] = 0x2c, /* osx:6 (ANSI_Z) -> linux:44 (KEY_Z) -> qnum:44 */
+ [0x7] = 0x2d, /* osx:7 (ANSI_X) -> linux:45 (KEY_X) -> qnum:45 */
+ [0x8] = 0x2e, /* osx:8 (ANSI_C) -> linux:46 (KEY_C) -> qnum:46 */
+ [0x9] = 0x2f, /* osx:9 (ANSI_V) -> linux:47 (KEY_V) -> qnum:47 */
+ [0xa] = 0x70, /* osx:10 (ISO_Section) -> linux:170 (KEY_ISO) -> qnum:112 */
+ [0xb] = 0x30, /* osx:11 (ANSI_B) -> linux:48 (KEY_B) -> qnum:48 */
+ [0xc] = 0x10, /* osx:12 (ANSI_Q) -> linux:16 (KEY_Q) -> qnum:16 */
+ [0xd] = 0x11, /* osx:13 (ANSI_W) -> linux:17 (KEY_W) -> qnum:17 */
+ [0xe] = 0x12, /* osx:14 (ANSI_E) -> linux:18 (KEY_E) -> qnum:18 */
+ [0xf] = 0x13, /* osx:15 (ANSI_R) -> linux:19 (KEY_R) -> qnum:19 */
+ [0x10] = 0x15, /* osx:16 (ANSI_Y) -> linux:21 (KEY_Y) -> qnum:21 */
+ [0x11] = 0x14, /* osx:17 (ANSI_T) -> linux:20 (KEY_T) -> qnum:20 */
+ [0x12] = 0x2, /* osx:18 (ANSI_1) -> linux:2 (KEY_1) -> qnum:2 */
+ [0x13] = 0x3, /* osx:19 (ANSI_2) -> linux:3 (KEY_2) -> qnum:3 */
+ [0x14] = 0x4, /* osx:20 (ANSI_3) -> linux:4 (KEY_3) -> qnum:4 */
+ [0x15] = 0x5, /* osx:21 (ANSI_4) -> linux:5 (KEY_4) -> qnum:5 */
+ [0x16] = 0x7, /* osx:22 (ANSI_6) -> linux:7 (KEY_6) -> qnum:7 */
+ [0x17] = 0x6, /* osx:23 (ANSI_5) -> linux:6 (KEY_5) -> qnum:6 */
+ [0x18] = 0xd, /* osx:24 (ANSI_Equal) -> linux:13 (KEY_EQUAL) -> qnum:13 */
+ [0x19] = 0xa, /* osx:25 (ANSI_9) -> linux:10 (KEY_9) -> qnum:10 */
+ [0x1a] = 0x8, /* osx:26 (ANSI_7) -> linux:8 (KEY_7) -> qnum:8 */
+ [0x1b] = 0xc, /* osx:27 (ANSI_Minus) -> linux:12 (KEY_MINUS) -> qnum:12 */
+ [0x1c] = 0x9, /* osx:28 (ANSI_8) -> linux:9 (KEY_8) -> qnum:9 */
+ [0x1d] = 0xb, /* osx:29 (ANSI_0) -> linux:11 (KEY_0) -> qnum:11 */
+ [0x1e] = 0x1b, /* osx:30 (ANSI_RightBracket) -> linux:27 (KEY_RIGHTBRACE) -> qnum:27 */
+ [0x1f] = 0x18, /* osx:31 (ANSI_O) -> linux:24 (KEY_O) -> qnum:24 */
+ [0x20] = 0x16, /* osx:32 (ANSI_U) -> linux:22 (KEY_U) -> qnum:22 */
+ [0x21] = 0x1a, /* osx:33 (ANSI_LeftBracket) -> linux:26 (KEY_LEFTBRACE) -> qnum:26 */
+ [0x22] = 0x17, /* osx:34 (ANSI_I) -> linux:23 (KEY_I) -> qnum:23 */
+ [0x23] = 0x19, /* osx:35 (ANSI_P) -> linux:25 (KEY_P) -> qnum:25 */
+ [0x24] = 0x1c, /* osx:36 (Return) -> linux:28 (KEY_ENTER) -> qnum:28 */
+ [0x25] = 0x26, /* osx:37 (ANSI_L) -> linux:38 (KEY_L) -> qnum:38 */
+ [0x26] = 0x24, /* osx:38 (ANSI_J) -> linux:36 (KEY_J) -> qnum:36 */
+ [0x27] = 0x28, /* osx:39 (ANSI_Quote) -> linux:40 (KEY_APOSTROPHE) -> qnum:40 */
+ [0x28] = 0x25, /* osx:40 (ANSI_K) -> linux:37 (KEY_K) -> qnum:37 */
+ [0x29] = 0x27, /* osx:41 (ANSI_Semicolon) -> linux:39 (KEY_SEMICOLON) -> qnum:39 */
+ [0x2a] = 0x2b, /* osx:42 (ANSI_Backslash) -> linux:43 (KEY_BACKSLASH) -> qnum:43 */
+ [0x2b] = 0x33, /* osx:43 (ANSI_Comma) -> linux:51 (KEY_COMMA) -> qnum:51 */
+ [0x2c] = 0x35, /* osx:44 (ANSI_Slash) -> linux:53 (KEY_SLASH) -> qnum:53 */
+ [0x2d] = 0x31, /* osx:45 (ANSI_N) -> linux:49 (KEY_N) -> qnum:49 */
+ [0x2e] = 0x32, /* osx:46 (ANSI_M) -> linux:50 (KEY_M) -> qnum:50 */
+ [0x2f] = 0x34, /* osx:47 (ANSI_Period) -> linux:52 (KEY_DOT) -> qnum:52 */
+ [0x30] = 0xf, /* osx:48 (Tab) -> linux:15 (KEY_TAB) -> qnum:15 */
+ [0x31] = 0x39, /* osx:49 (Space) -> linux:57 (KEY_SPACE) -> qnum:57 */
+ [0x32] = 0x29, /* osx:50 (ANSI_Grave) -> linux:41 (KEY_GRAVE) -> qnum:41 */
+ [0x33] = 0xe, /* osx:51 (Delete) -> linux:14 (KEY_BACKSPACE) -> qnum:14 */
+ [0x35] = 0x1, /* osx:53 (Escape) -> linux:1 (KEY_ESC) -> qnum:1 */
+ [0x36] = 0xdc, /* osx:54 (RightCommand) -> linux:126 (KEY_RIGHTMETA) -> qnum:220 */
+ [0x37] = 0xdb, /* osx:55 (Command) -> linux:125 (KEY_LEFTMETA) -> qnum:219 */
+ [0x38] = 0x2a, /* osx:56 (Shift) -> linux:42 (KEY_LEFTSHIFT) -> qnum:42 */
+ [0x39] = 0x3a, /* osx:57 (CapsLock) -> linux:58 (KEY_CAPSLOCK) -> qnum:58 */
+ [0x3a] = 0x38, /* osx:58 (Option) -> linux:56 (KEY_LEFTALT) -> qnum:56 */
+ [0x3b] = 0x1d, /* osx:59 (Control) -> linux:29 (KEY_LEFTCTRL) -> qnum:29 */
+ [0x3c] = 0x36, /* osx:60 (RightShift) -> linux:54 (KEY_RIGHTSHIFT) -> qnum:54 */
+ [0x3d] = 0xb8, /* osx:61 (RightOption) -> linux:100 (KEY_RIGHTALT) -> qnum:184 */
+ [0x3e] = 0x9d, /* osx:62 (RightControl) -> linux:97 (KEY_RIGHTCTRL) -> qnum:157 */
+ [0x40] = 0x83, /* osx:64 (F17) -> linux:187 (KEY_F17) -> qnum:131 */
+ [0x41] = 0x53, /* osx:65 (ANSI_KeypadDecimal) -> linux:83 (KEY_KPDOT) -> qnum:83 */
+ [0x43] = 0x37, /* osx:67 (ANSI_KeypadMultiply) -> linux:55 (KEY_KPASTERISK) -> qnum:55 */
+ [0x45] = 0x4e, /* osx:69 (ANSI_KeypadPlus) -> linux:78 (KEY_KPPLUS) -> qnum:78 */
+ [0x47] = 0x45, /* osx:71 (ANSI_KeypadClear) -> linux:69 (KEY_NUMLOCK) -> qnum:69 */
+ [0x48] = 0xb0, /* osx:72 (VolumeUp) -> linux:115 (KEY_VOLUMEUP) -> qnum:176 */
+ [0x49] = 0xae, /* osx:73 (VolumeDown) -> linux:114 (KEY_VOLUMEDOWN) -> qnum:174 */
+ [0x4a] = 0xa0, /* osx:74 (Mute) -> linux:113 (KEY_MUTE) -> qnum:160 */
+ [0x4b] = 0xb5, /* osx:75 (ANSI_KeypadDivide) -> linux:98 (KEY_KPSLASH) -> qnum:181 */
+ [0x4c] = 0x9c, /* osx:76 (ANSI_KeypadEnter) -> linux:96 (KEY_KPENTER) -> qnum:156 */
+ [0x4e] = 0x4a, /* osx:78 (ANSI_KeypadMinus) -> linux:74 (KEY_KPMINUS) -> qnum:74 */
+ [0x4f] = 0xf7, /* osx:79 (F18) -> linux:188 (KEY_F18) -> qnum:247 */
+ [0x50] = 0x84, /* osx:80 (F19) -> linux:189 (KEY_F19) -> qnum:132 */
+ [0x51] = 0x59, /* osx:81 (ANSI_KeypadEquals) -> linux:117 (KEY_KPEQUAL) -> qnum:89 */
+ [0x52] = 0x52, /* osx:82 (ANSI_Keypad0) -> linux:82 (KEY_KP0) -> qnum:82 */
+ [0x53] = 0x4f, /* osx:83 (ANSI_Keypad1) -> linux:79 (KEY_KP1) -> qnum:79 */
+ [0x54] = 0x50, /* osx:84 (ANSI_Keypad2) -> linux:80 (KEY_KP2) -> qnum:80 */
+ [0x55] = 0x51, /* osx:85 (ANSI_Keypad3) -> linux:81 (KEY_KP3) -> qnum:81 */
+ [0x56] = 0x4b, /* osx:86 (ANSI_Keypad4) -> linux:75 (KEY_KP4) -> qnum:75 */
+ [0x57] = 0x4c, /* osx:87 (ANSI_Keypad5) -> linux:76 (KEY_KP5) -> qnum:76 */
+ [0x58] = 0x4d, /* osx:88 (ANSI_Keypad6) -> linux:77 (KEY_KP6) -> qnum:77 */
+ [0x59] = 0x47, /* osx:89 (ANSI_Keypad7) -> linux:71 (KEY_KP7) -> qnum:71 */
+ [0x5a] = 0x5a, /* osx:90 (F20) -> linux:190 (KEY_F20) -> qnum:90 */
+ [0x5b] = 0x48, /* osx:91 (ANSI_Keypad8) -> linux:72 (KEY_KP8) -> qnum:72 */
+ [0x5c] = 0x49, /* osx:92 (ANSI_Keypad9) -> linux:73 (KEY_KP9) -> qnum:73 */
+ [0x5d] = 0x7d, /* osx:93 (JIS_Yen) -> linux:124 (KEY_YEN) -> qnum:125 */
+ [0x5f] = 0x5c, /* osx:95 (JIS_KeypadComma) -> linux:95 (KEY_KPJPCOMMA) -> qnum:92 */
+ [0x60] = 0x3f, /* osx:96 (F5) -> linux:63 (KEY_F5) -> qnum:63 */
+ [0x61] = 0x40, /* osx:97 (F6) -> linux:64 (KEY_F6) -> qnum:64 */
+ [0x62] = 0x41, /* osx:98 (F7) -> linux:65 (KEY_F7) -> qnum:65 */
+ [0x63] = 0x3d, /* osx:99 (F3) -> linux:61 (KEY_F3) -> qnum:61 */
+ [0x64] = 0x42, /* osx:100 (F8) -> linux:66 (KEY_F8) -> qnum:66 */
+ [0x65] = 0x43, /* osx:101 (F9) -> linux:67 (KEY_F9) -> qnum:67 */
+ [0x67] = 0x57, /* osx:103 (F11) -> linux:87 (KEY_F11) -> qnum:87 */
+ [0x68] = 0x78, /* osx:104 (JIS_Kana) -> linux:90 (KEY_KATAKANA) -> qnum:120 */
+ [0x69] = 0x5d, /* osx:105 (F13) -> linux:183 (KEY_F13) -> qnum:93 */
+ [0x6a] = 0x55, /* osx:106 (F16) -> linux:186 (KEY_F16) -> qnum:85 */
+ [0x6b] = 0x5e, /* osx:107 (F14) -> linux:184 (KEY_F14) -> qnum:94 */
+ [0x6d] = 0x44, /* osx:109 (F10) -> linux:68 (KEY_F10) -> qnum:68 */
+ [0x6e] = 0xdd, /* osx:110 (unnamed) -> linux:127 (KEY_COMPOSE) -> qnum:221 */
+ [0x6f] = 0x58, /* osx:111 (F12) -> linux:88 (KEY_F12) -> qnum:88 */
+ [0x71] = 0x5f, /* osx:113 (F15) -> linux:185 (KEY_F15) -> qnum:95 */
+ [0x72] = 0xf5, /* osx:114 (Help) -> linux:138 (KEY_HELP) -> qnum:245 */
+ [0x73] = 0xc7, /* osx:115 (Home) -> linux:102 (KEY_HOME) -> qnum:199 */
+ [0x74] = 0xc9, /* osx:116 (PageUp) -> linux:104 (KEY_PAGEUP) -> qnum:201 */
+ [0x75] = 0xd3, /* osx:117 (ForwardDelete) -> linux:111 (KEY_DELETE) -> qnum:211 */
+ [0x76] = 0x3e, /* osx:118 (F4) -> linux:62 (KEY_F4) -> qnum:62 */
+ [0x77] = 0xcf, /* osx:119 (End) -> linux:107 (KEY_END) -> qnum:207 */
+ [0x78] = 0x3c, /* osx:120 (F2) -> linux:60 (KEY_F2) -> qnum:60 */
+ [0x79] = 0xd1, /* osx:121 (PageDown) -> linux:109 (KEY_PAGEDOWN) -> qnum:209 */
+ [0x7a] = 0x3b, /* osx:122 (F1) -> linux:59 (KEY_F1) -> qnum:59 */
+ [0x7b] = 0xcb, /* osx:123 (LeftArrow) -> linux:105 (KEY_LEFT) -> qnum:203 */
+ [0x7c] = 0xcd, /* osx:124 (RightArrow) -> linux:106 (KEY_RIGHT) -> qnum:205 */
+ [0x7d] = 0xd0, /* osx:125 (DownArrow) -> linux:108 (KEY_DOWN) -> qnum:208 */
+ [0x7e] = 0xc8, /* osx:126 (UpArrow) -> linux:103 (KEY_UP) -> qnum:200 */
+};
+const unsigned int code_map_osx_to_qnum_len = sizeof(code_map_osx_to_qnum)/sizeof(code_map_osx_to_qnum[0]);
diff --git a/vncviewer/xkb_to_qnum.c b/vncviewer/xkb_to_qnum.c
new file mode 100644
index 00000000..759c3d44
--- /dev/null
+++ b/vncviewer/xkb_to_qnum.c
@@ -0,0 +1,257 @@
+/*
+ * This file is auto-generated from keymaps.csv on 2017-08-28 13:04
+ * Database checksum sha256(f8aeff0c3430077a350e3d7ba2b335b381bd929ac4b193413730a402ff3f0097)
+ * To re-generate, run:
+ * keymap-gen --lang=stdc code-map keymaps.csv xkb qnum
+*/
+const struct _code_map_xkb_to_qnum {
+ const char * from;
+ const unsigned short to;
+} code_map_xkb_to_qnum[] = {
+ {"AB00", 0x29}, /* xkb:AB00 (AB00) -> linux:41 (KEY_GRAVE) -> qnum:41 */
+ {"AB01", 0x2c}, /* xkb:AB01 (AB01) -> linux:44 (KEY_Z) -> qnum:44 */
+ {"AB02", 0x2d}, /* xkb:AB02 (AB02) -> linux:45 (KEY_X) -> qnum:45 */
+ {"AB03", 0x2e}, /* xkb:AB03 (AB03) -> linux:46 (KEY_C) -> qnum:46 */
+ {"AB04", 0x2f}, /* xkb:AB04 (AB04) -> linux:47 (KEY_V) -> qnum:47 */
+ {"AB05", 0x30}, /* xkb:AB05 (AB05) -> linux:48 (KEY_B) -> qnum:48 */
+ {"AB06", 0x31}, /* xkb:AB06 (AB06) -> linux:49 (KEY_N) -> qnum:49 */
+ {"AB07", 0x32}, /* xkb:AB07 (AB07) -> linux:50 (KEY_M) -> qnum:50 */
+ {"AB08", 0x33}, /* xkb:AB08 (AB08) -> linux:51 (KEY_COMMA) -> qnum:51 */
+ {"AB09", 0x34}, /* xkb:AB09 (AB09) -> linux:52 (KEY_DOT) -> qnum:52 */
+ {"AB10", 0x35}, /* xkb:AB10 (AB10) -> linux:53 (KEY_SLASH) -> qnum:53 */
+ {"AB11", 0x73}, /* xkb:AB11 (AB11) -> linux:89 (KEY_RO) -> qnum:115 */
+ {"AC01", 0x1e}, /* xkb:AC01 (AC01) -> linux:30 (KEY_A) -> qnum:30 */
+ {"AC02", 0x1f}, /* xkb:AC02 (AC02) -> linux:31 (KEY_S) -> qnum:31 */
+ {"AC03", 0x20}, /* xkb:AC03 (AC03) -> linux:32 (KEY_D) -> qnum:32 */
+ {"AC04", 0x21}, /* xkb:AC04 (AC04) -> linux:33 (KEY_F) -> qnum:33 */
+ {"AC05", 0x22}, /* xkb:AC05 (AC05) -> linux:34 (KEY_G) -> qnum:34 */
+ {"AC06", 0x23}, /* xkb:AC06 (AC06) -> linux:35 (KEY_H) -> qnum:35 */
+ {"AC07", 0x24}, /* xkb:AC07 (AC07) -> linux:36 (KEY_J) -> qnum:36 */
+ {"AC08", 0x25}, /* xkb:AC08 (AC08) -> linux:37 (KEY_K) -> qnum:37 */
+ {"AC09", 0x26}, /* xkb:AC09 (AC09) -> linux:38 (KEY_L) -> qnum:38 */
+ {"AC10", 0x27}, /* xkb:AC10 (AC10) -> linux:39 (KEY_SEMICOLON) -> qnum:39 */
+ {"AC11", 0x28}, /* xkb:AC11 (AC11) -> linux:40 (KEY_APOSTROPHE) -> qnum:40 */
+ {"AC12", 0x2b}, /* xkb:AC12 (AC12) -> linux:43 (KEY_BACKSLASH) -> qnum:43 */
+ {"AD01", 0x10}, /* xkb:AD01 (AD01) -> linux:16 (KEY_Q) -> qnum:16 */
+ {"AD02", 0x11}, /* xkb:AD02 (AD02) -> linux:17 (KEY_W) -> qnum:17 */
+ {"AD03", 0x12}, /* xkb:AD03 (AD03) -> linux:18 (KEY_E) -> qnum:18 */
+ {"AD04", 0x13}, /* xkb:AD04 (AD04) -> linux:19 (KEY_R) -> qnum:19 */
+ {"AD05", 0x14}, /* xkb:AD05 (AD05) -> linux:20 (KEY_T) -> qnum:20 */
+ {"AD06", 0x15}, /* xkb:AD06 (AD06) -> linux:21 (KEY_Y) -> qnum:21 */
+ {"AD07", 0x16}, /* xkb:AD07 (AD07) -> linux:22 (KEY_U) -> qnum:22 */
+ {"AD08", 0x17}, /* xkb:AD08 (AD08) -> linux:23 (KEY_I) -> qnum:23 */
+ {"AD09", 0x18}, /* xkb:AD09 (AD09) -> linux:24 (KEY_O) -> qnum:24 */
+ {"AD10", 0x19}, /* xkb:AD10 (AD10) -> linux:25 (KEY_P) -> qnum:25 */
+ {"AD11", 0x1a}, /* xkb:AD11 (AD11) -> linux:26 (KEY_LEFTBRACE) -> qnum:26 */
+ {"AD12", 0x1b}, /* xkb:AD12 (AD12) -> linux:27 (KEY_RIGHTBRACE) -> qnum:27 */
+ {"AE01", 0x2}, /* xkb:AE01 (AE01) -> linux:2 (KEY_1) -> qnum:2 */
+ {"AE02", 0x3}, /* xkb:AE02 (AE02) -> linux:3 (KEY_2) -> qnum:3 */
+ {"AE03", 0x4}, /* xkb:AE03 (AE03) -> linux:4 (KEY_3) -> qnum:4 */
+ {"AE04", 0x5}, /* xkb:AE04 (AE04) -> linux:5 (KEY_4) -> qnum:5 */
+ {"AE05", 0x6}, /* xkb:AE05 (AE05) -> linux:6 (KEY_5) -> qnum:6 */
+ {"AE06", 0x7}, /* xkb:AE06 (AE06) -> linux:7 (KEY_6) -> qnum:7 */
+ {"AE07", 0x8}, /* xkb:AE07 (AE07) -> linux:8 (KEY_7) -> qnum:8 */
+ {"AE08", 0x9}, /* xkb:AE08 (AE08) -> linux:9 (KEY_8) -> qnum:9 */
+ {"AE09", 0xa}, /* xkb:AE09 (AE09) -> linux:10 (KEY_9) -> qnum:10 */
+ {"AE10", 0xb}, /* xkb:AE10 (AE10) -> linux:11 (KEY_0) -> qnum:11 */
+ {"AE11", 0xc}, /* xkb:AE11 (AE11) -> linux:12 (KEY_MINUS) -> qnum:12 */
+ {"AE12", 0xd}, /* xkb:AE12 (AE12) -> linux:13 (KEY_EQUAL) -> qnum:13 */
+ {"AE13", 0x7d}, /* xkb:AE13 (AE13) -> linux:124 (KEY_YEN) -> qnum:125 */
+ {"AGAI", 0x85}, /* xkb:AGAI (AGAI) -> linux:129 (KEY_AGAIN) -> qnum:133 */
+ {"ALGR", 0xb8}, /* xkb:ALGR (RALT) -> linux:100 (KEY_RIGHTALT) -> qnum:184 */
+ {"BKSL", 0x2b}, /* xkb:BKSL (AC12) -> linux:43 (KEY_BACKSLASH) -> qnum:43 */
+ {"BKSP", 0xe}, /* xkb:BKSP (BKSP) -> linux:14 (KEY_BACKSPACE) -> qnum:14 */
+ {"CAPS", 0x3a}, /* xkb:CAPS (CAPS) -> linux:58 (KEY_CAPSLOCK) -> qnum:58 */
+ {"COMP", 0xdd}, /* xkb:COMP (COMP) -> linux:127 (KEY_COMPOSE) -> qnum:221 */
+ {"COPY", 0xf8}, /* xkb:COPY (COPY) -> linux:133 (KEY_COPY) -> qnum:248 */
+ {"CUT", 0xbc}, /* xkb:CUT (CUT) -> linux:137 (KEY_CUT) -> qnum:188 */
+ {"DEL", 0xd3}, /* xkb:DEL (DELE) -> linux:111 (KEY_DELETE) -> qnum:211 */
+ {"DELE", 0xd3}, /* xkb:DELE (DELE) -> linux:111 (KEY_DELETE) -> qnum:211 */
+ {"DOWN", 0xd0}, /* xkb:DOWN (DOWN) -> linux:108 (KEY_DOWN) -> qnum:208 */
+ {"END", 0xcf}, /* xkb:END (END) -> linux:107 (KEY_END) -> qnum:207 */
+ {"ESC", 0x1}, /* xkb:ESC (ESC) -> linux:1 (KEY_ESC) -> qnum:1 */
+ {"FIND", 0xc1}, /* xkb:FIND (FIND) -> linux:136 (KEY_FIND) -> qnum:193 */
+ {"FK01", 0x3b}, /* xkb:FK01 (FK01) -> linux:59 (KEY_F1) -> qnum:59 */
+ {"FK02", 0x3c}, /* xkb:FK02 (FK02) -> linux:60 (KEY_F2) -> qnum:60 */
+ {"FK03", 0x3d}, /* xkb:FK03 (FK03) -> linux:61 (KEY_F3) -> qnum:61 */
+ {"FK04", 0x3e}, /* xkb:FK04 (FK04) -> linux:62 (KEY_F4) -> qnum:62 */
+ {"FK05", 0x3f}, /* xkb:FK05 (FK05) -> linux:63 (KEY_F5) -> qnum:63 */
+ {"FK06", 0x40}, /* xkb:FK06 (FK06) -> linux:64 (KEY_F6) -> qnum:64 */
+ {"FK07", 0x41}, /* xkb:FK07 (FK07) -> linux:65 (KEY_F7) -> qnum:65 */
+ {"FK08", 0x42}, /* xkb:FK08 (FK08) -> linux:66 (KEY_F8) -> qnum:66 */
+ {"FK09", 0x43}, /* xkb:FK09 (FK09) -> linux:67 (KEY_F9) -> qnum:67 */
+ {"FK10", 0x44}, /* xkb:FK10 (FK10) -> linux:68 (KEY_F10) -> qnum:68 */
+ {"FK11", 0x57}, /* xkb:FK11 (FK11) -> linux:87 (KEY_F11) -> qnum:87 */
+ {"FK12", 0x58}, /* xkb:FK12 (FK12) -> linux:88 (KEY_F12) -> qnum:88 */
+ {"FK13", 0x5d}, /* xkb:FK13 (FK13) -> linux:183 (KEY_F13) -> qnum:93 */
+ {"FK14", 0x5e}, /* xkb:FK14 (FK14) -> linux:184 (KEY_F14) -> qnum:94 */
+ {"FK15", 0x5f}, /* xkb:FK15 (FK15) -> linux:185 (KEY_F15) -> qnum:95 */
+ {"FK16", 0x55}, /* xkb:FK16 (FK16) -> linux:186 (KEY_F16) -> qnum:85 */
+ {"FK17", 0x83}, /* xkb:FK17 (FK17) -> linux:187 (KEY_F17) -> qnum:131 */
+ {"FK18", 0xf7}, /* xkb:FK18 (FK18) -> linux:188 (KEY_F18) -> qnum:247 */
+ {"FK19", 0x84}, /* xkb:FK19 (FK19) -> linux:189 (KEY_F19) -> qnum:132 */
+ {"FK20", 0x5a}, /* xkb:FK20 (FK20) -> linux:190 (KEY_F20) -> qnum:90 */
+ {"FK21", 0x74}, /* xkb:FK21 (FK21) -> linux:191 (KEY_F21) -> qnum:116 */
+ {"FK22", 0xf9}, /* xkb:FK22 (FK22) -> linux:192 (KEY_F22) -> qnum:249 */
+ {"FK23", 0x6d}, /* xkb:FK23 (FK23) -> linux:193 (KEY_F23) -> qnum:109 */
+ {"FK24", 0x6f}, /* xkb:FK24 (FK24) -> linux:194 (KEY_F24) -> qnum:111 */
+ {"FRNT", 0x8c}, /* xkb:FRNT (FRNT) -> linux:132 (KEY_FRONT) -> qnum:140 */
+ {"HELP", 0xf5}, /* xkb:HELP (HELP) -> linux:138 (KEY_HELP) -> qnum:245 */
+ {"HENK", 0x79}, /* xkb:HENK (HENK) -> linux:92 (KEY_HENKAN) -> qnum:121 */
+ {"HIRA", 0x77}, /* xkb:HIRA (HIRA) -> linux:91 (KEY_HIRAGANA) -> qnum:119 */
+ {"HJCV", 0x8d}, /* xkb:HJCV (HJCV) -> linux:123 (KEY_HANJA) -> qnum:141 */
+ {"HKTG", 0x70}, /* xkb:HKTG (HKTG) -> linux:93 (KEY_KATAKANAHIRAGANA) -> qnum:112 */
+ {"HOME", 0xc7}, /* xkb:HOME (HOME) -> linux:102 (KEY_HOME) -> qnum:199 */
+ {"HZTG", 0x76}, /* xkb:HZTG (HZTG) -> linux:85 (KEY_ZENKAKUHANKAKU) -> qnum:118 */
+ {"I120", 0xef}, /* xkb:I120 (I120) -> linux:112 (KEY_MACRO) -> qnum:239 */
+ {"I126", 0xce}, /* xkb:I126 (I126) -> linux:118 (KEY_KPPLUSMINUS) -> qnum:206 */
+ {"I128", 0x8b}, /* xkb:I128 (I128) -> linux:120 (KEY_SCALE) -> qnum:139 */
+ {"I129", 0x7e}, /* xkb:I129 (I129) -> linux:121 (KEY_KPCOMMA) -> qnum:126 */
+ {"I147", 0x9e}, /* xkb:I147 (I147) -> linux:139 (KEY_MENU) -> qnum:158 */
+ {"I148", 0xa1}, /* xkb:I148 (I148) -> linux:140 (KEY_CALC) -> qnum:161 */
+ {"I149", 0x66}, /* xkb:I149 (I149) -> linux:141 (KEY_SETUP) -> qnum:102 */
+ {"I150", 0xdf}, /* xkb:I150 (I150) -> linux:142 (KEY_SLEEP) -> qnum:223 */
+ {"I151", 0xe3}, /* xkb:I151 (I151) -> linux:143 (KEY_WAKEUP) -> qnum:227 */
+ {"I152", 0x67}, /* xkb:I152 (I152) -> linux:144 (KEY_FILE) -> qnum:103 */
+ {"I153", 0x68}, /* xkb:I153 (I153) -> linux:145 (KEY_SENDFILE) -> qnum:104 */
+ {"I154", 0x69}, /* xkb:I154 (I154) -> linux:146 (KEY_DELETEFILE) -> qnum:105 */
+ {"I155", 0x93}, /* xkb:I155 (I155) -> linux:147 (KEY_XFER) -> qnum:147 */
+ {"I156", 0x9f}, /* xkb:I156 (I156) -> linux:148 (KEY_PROG1) -> qnum:159 */
+ {"I157", 0x97}, /* xkb:I157 (I157) -> linux:149 (KEY_PROG2) -> qnum:151 */
+ {"I158", 0x82}, /* xkb:I158 (I158) -> linux:150 (KEY_WWW) -> qnum:130 */
+ {"I159", 0x6a}, /* xkb:I159 (I159) -> linux:151 (KEY_MSDOS) -> qnum:106 */
+ {"I160", 0x92}, /* xkb:I160 (I160) -> linux:152 (KEY_SCREENLOCK) -> qnum:146 */
+ {"I161", 0x6b}, /* xkb:I161 (I161) -> linux:153 (KEY_DIRECTION) -> qnum:107 */
+ {"I162", 0xa6}, /* xkb:I162 (I162) -> linux:154 (KEY_CYCLEWINDOWS) -> qnum:166 */
+ {"I163", 0xec}, /* xkb:I163 (I163) -> linux:155 (KEY_MAIL) -> qnum:236 */
+ {"I164", 0xe6}, /* xkb:I164 (I164) -> linux:156 (KEY_BOOKMARKS) -> qnum:230 */
+ {"I165", 0xeb}, /* xkb:I165 (I165) -> linux:157 (KEY_COMPUTER) -> qnum:235 */
+ {"I166", 0xea}, /* xkb:I166 (I166) -> linux:158 (KEY_BACK) -> qnum:234 */
+ {"I167", 0xe9}, /* xkb:I167 (I167) -> linux:159 (KEY_FORWARD) -> qnum:233 */
+ {"I168", 0xa3}, /* xkb:I168 (I168) -> linux:160 (KEY_CLOSECD) -> qnum:163 */
+ {"I169", 0x6c}, /* xkb:I169 (I169) -> linux:161 (KEY_EJECTCD) -> qnum:108 */
+ {"I170", 0xfd}, /* xkb:I170 (I170) -> linux:162 (KEY_EJECTCLOSECD) -> qnum:253 */
+ {"I171", 0x99}, /* xkb:I171 (I171) -> linux:163 (KEY_NEXTSONG) -> qnum:153 */
+ {"I172", 0xa2}, /* xkb:I172 (I172) -> linux:164 (KEY_PLAYPAUSE) -> qnum:162 */
+ {"I173", 0x90}, /* xkb:I173 (I173) -> linux:165 (KEY_PREVIOUSSONG) -> qnum:144 */
+ {"I174", 0xa4}, /* xkb:I174 (I174) -> linux:166 (KEY_STOPCD) -> qnum:164 */
+ {"I175", 0xb1}, /* xkb:I175 (I175) -> linux:167 (KEY_RECORD) -> qnum:177 */
+ {"I176", 0x98}, /* xkb:I176 (I176) -> linux:168 (KEY_REWIND) -> qnum:152 */
+ {"I177", 0x63}, /* xkb:I177 (I177) -> linux:169 (KEY_PHONE) -> qnum:99 */
+ {"I178", 0x70}, /* xkb:I178 (I178) -> linux:170 (KEY_ISO) -> qnum:112 */
+ {"I179", 0x81}, /* xkb:I179 (I179) -> linux:171 (KEY_CONFIG) -> qnum:129 */
+ {"I180", 0xb2}, /* xkb:I180 (I180) -> linux:172 (KEY_HOMEPAGE) -> qnum:178 */
+ {"I181", 0xe7}, /* xkb:I181 (I181) -> linux:173 (KEY_REFRESH) -> qnum:231 */
+ {"I182", 0x71}, /* xkb:I182 (I182) -> linux:174 (KEY_EXIT) -> qnum:113 */
+ {"I183", 0x72}, /* xkb:I183 (I183) -> linux:175 (KEY_MOVE) -> qnum:114 */
+ {"I184", 0x88}, /* xkb:I184 (I184) -> linux:176 (KEY_EDIT) -> qnum:136 */
+ {"I185", 0x75}, /* xkb:I185 (I185) -> linux:177 (KEY_SCROLLUP) -> qnum:117 */
+ {"I186", 0x8f}, /* xkb:I186 (I186) -> linux:178 (KEY_SCROLLDOWN) -> qnum:143 */
+ {"I187", 0xf6}, /* xkb:I187 (I187) -> linux:179 (KEY_KPLEFTPAREN) -> qnum:246 */
+ {"I188", 0xfb}, /* xkb:I188 (I188) -> linux:180 (KEY_KPRIGHTPAREN) -> qnum:251 */
+ {"I189", 0x89}, /* xkb:I189 (I189) -> linux:181 (KEY_NEW) -> qnum:137 */
+ {"I190", 0x8a}, /* xkb:I190 (I190) -> linux:182 (KEY_REDO) -> qnum:138 */
+ {"I208", 0xa8}, /* xkb:I208 (I208) -> linux:200 (KEY_PLAYCD) -> qnum:168 */
+ {"I209", 0xa9}, /* xkb:I209 (I209) -> linux:201 (KEY_PAUSECD) -> qnum:169 */
+ {"I210", 0xab}, /* xkb:I210 (I210) -> linux:202 (KEY_PROG3) -> qnum:171 */
+ {"I211", 0xac}, /* xkb:I211 (I211) -> linux:203 (KEY_PROG4) -> qnum:172 */
+ {"I212", 0xad}, /* xkb:I212 (I212) -> linux:204 (KEY_DASHBOARD) -> qnum:173 */
+ {"I213", 0xa5}, /* xkb:I213 (I213) -> linux:205 (KEY_SUSPEND) -> qnum:165 */
+ {"I214", 0xaf}, /* xkb:I214 (I214) -> linux:206 (KEY_CLOSE) -> qnum:175 */
+ {"I215", 0xb3}, /* xkb:I215 (I215) -> linux:207 (KEY_PLAY) -> qnum:179 */
+ {"I216", 0xb4}, /* xkb:I216 (I216) -> linux:208 (KEY_FASTFORWARD) -> qnum:180 */
+ {"I217", 0xb6}, /* xkb:I217 (I217) -> linux:209 (KEY_BASSBOOST) -> qnum:182 */
+ {"I218", 0xb9}, /* xkb:I218 (I218) -> linux:210 (KEY_PRINT) -> qnum:185 */
+ {"I219", 0xba}, /* xkb:I219 (I219) -> linux:211 (KEY_HP) -> qnum:186 */
+ {"I220", 0xbb}, /* xkb:I220 (I220) -> linux:212 (KEY_CAMERA) -> qnum:187 */
+ {"I221", 0xbd}, /* xkb:I221 (I221) -> linux:213 (KEY_SOUND) -> qnum:189 */
+ {"I222", 0xbe}, /* xkb:I222 (I222) -> linux:214 (KEY_QUESTION) -> qnum:190 */
+ {"I223", 0xbf}, /* xkb:I223 (I223) -> linux:215 (KEY_EMAIL) -> qnum:191 */
+ {"I224", 0xc0}, /* xkb:I224 (I224) -> linux:216 (KEY_CHAT) -> qnum:192 */
+ {"I225", 0xe5}, /* xkb:I225 (I225) -> linux:217 (KEY_SEARCH) -> qnum:229 */
+ {"I226", 0xc2}, /* xkb:I226 (I226) -> linux:218 (KEY_CONNECT) -> qnum:194 */
+ {"I227", 0xc3}, /* xkb:I227 (I227) -> linux:219 (KEY_FINANCE) -> qnum:195 */
+ {"I228", 0xc4}, /* xkb:I228 (I228) -> linux:220 (KEY_SPORT) -> qnum:196 */
+ {"I229", 0xc5}, /* xkb:I229 (I229) -> linux:221 (KEY_SHOP) -> qnum:197 */
+ {"I230", 0x94}, /* xkb:I230 (I230) -> linux:222 (KEY_ALTERASE) -> qnum:148 */
+ {"I231", 0xca}, /* xkb:I231 (I231) -> linux:223 (KEY_CANCEL) -> qnum:202 */
+ {"I232", 0xcc}, /* xkb:I232 (I232) -> linux:224 (KEY_BRIGHTNESSDOWN) -> qnum:204 */
+ {"I233", 0xd4}, /* xkb:I233 (I233) -> linux:225 (KEY_BRIGHTNESSUP) -> qnum:212 */
+ {"I234", 0xed}, /* xkb:I234 (I234) -> linux:226 (KEY_MEDIA) -> qnum:237 */
+ {"I235", 0xd6}, /* xkb:I235 (I235) -> linux:227 (KEY_SWITCHVIDEOMODE) -> qnum:214 */
+ {"I236", 0xd7}, /* xkb:I236 (I236) -> linux:228 (KEY_KBDILLUMTOGGLE) -> qnum:215 */
+ {"I237", 0xd8}, /* xkb:I237 (I237) -> linux:229 (KEY_KBDILLUMDOWN) -> qnum:216 */
+ {"I238", 0xd9}, /* xkb:I238 (I238) -> linux:230 (KEY_KBDILLUMUP) -> qnum:217 */
+ {"I239", 0xda}, /* xkb:I239 (I239) -> linux:231 (KEY_SEND) -> qnum:218 */
+ {"I240", 0xe4}, /* xkb:I240 (I240) -> linux:232 (KEY_REPLY) -> qnum:228 */
+ {"I241", 0x8e}, /* xkb:I241 (I241) -> linux:233 (KEY_FORWARDMAIL) -> qnum:142 */
+ {"I242", 0xd5}, /* xkb:I242 (I242) -> linux:234 (KEY_SAVE) -> qnum:213 */
+ {"I243", 0xf0}, /* xkb:I243 (I243) -> linux:235 (KEY_DOCUMENTS) -> qnum:240 */
+ {"I244", 0xf1}, /* xkb:I244 (I244) -> linux:236 (KEY_BATTERY) -> qnum:241 */
+ {"I245", 0xf2}, /* xkb:I245 (I245) -> linux:237 (KEY_BLUETOOTH) -> qnum:242 */
+ {"I246", 0xf3}, /* xkb:I246 (I246) -> linux:238 (KEY_WLAN) -> qnum:243 */
+ {"I247", 0xf4}, /* xkb:I247 (I247) -> linux:239 (KEY_UWB) -> qnum:244 */
+ {"INS", 0xd2}, /* xkb:INS (INS) -> linux:110 (KEY_INSERT) -> qnum:210 */
+ {"JPCM", 0x5c}, /* xkb:JPCM (JPCM) -> linux:95 (KEY_KPJPCOMMA) -> qnum:92 */
+ {"KATA", 0x78}, /* xkb:KATA (KATA) -> linux:90 (KEY_KATAKANA) -> qnum:120 */
+ {"KP0", 0x52}, /* xkb:KP0 (KP0) -> linux:82 (KEY_KP0) -> qnum:82 */
+ {"KP1", 0x4f}, /* xkb:KP1 (KP1) -> linux:79 (KEY_KP1) -> qnum:79 */
+ {"KP2", 0x50}, /* xkb:KP2 (KP2) -> linux:80 (KEY_KP2) -> qnum:80 */
+ {"KP3", 0x51}, /* xkb:KP3 (KP3) -> linux:81 (KEY_KP3) -> qnum:81 */
+ {"KP4", 0x4b}, /* xkb:KP4 (KP4) -> linux:75 (KEY_KP4) -> qnum:75 */
+ {"KP5", 0x4c}, /* xkb:KP5 (KP5) -> linux:76 (KEY_KP5) -> qnum:76 */
+ {"KP6", 0x4d}, /* xkb:KP6 (KP6) -> linux:77 (KEY_KP6) -> qnum:77 */
+ {"KP7", 0x47}, /* xkb:KP7 (KP7) -> linux:71 (KEY_KP7) -> qnum:71 */
+ {"KP8", 0x48}, /* xkb:KP8 (KP8) -> linux:72 (KEY_KP8) -> qnum:72 */
+ {"KP9", 0x49}, /* xkb:KP9 (KP9) -> linux:73 (KEY_KP9) -> qnum:73 */
+ {"KPAD", 0x4e}, /* xkb:KPAD (KPAD) -> linux:78 (KEY_KPPLUS) -> qnum:78 */
+ {"KPCO", 0x7e}, /* xkb:KPCO (I129) -> linux:121 (KEY_KPCOMMA) -> qnum:126 */
+ {"KPDC", 0x53}, /* xkb:KPDC (KPDC) -> linux:83 (KEY_KPDOT) -> qnum:83 */
+ {"KPDL", 0x53}, /* xkb:KPDL (KPDC) -> linux:83 (KEY_KPDOT) -> qnum:83 */
+ {"KPDV", 0xb5}, /* xkb:KPDV (KPDV) -> linux:98 (KEY_KPSLASH) -> qnum:181 */
+ {"KPEN", 0x9c}, /* xkb:KPEN (KPEN) -> linux:96 (KEY_KPENTER) -> qnum:156 */
+ {"KPEQ", 0x59}, /* xkb:KPEQ (KPEQ) -> linux:117 (KEY_KPEQUAL) -> qnum:89 */
+ {"KPMU", 0x37}, /* xkb:KPMU (KPMU) -> linux:55 (KEY_KPASTERISK) -> qnum:55 */
+ {"KPSP", 0x5c}, /* xkb:KPSP (JPCM) -> linux:95 (KEY_KPJPCOMMA) -> qnum:92 */
+ {"KPSU", 0x4a}, /* xkb:KPSU (KPSU) -> linux:74 (KEY_KPMINUS) -> qnum:74 */
+ {"LALT", 0x38}, /* xkb:LALT (LALT) -> linux:56 (KEY_LEFTALT) -> qnum:56 */
+ {"LCTL", 0x1d}, /* xkb:LCTL (LCTL) -> linux:29 (KEY_LEFTCTRL) -> qnum:29 */
+ {"LEFT", 0xcb}, /* xkb:LEFT (LEFT) -> linux:105 (KEY_LEFT) -> qnum:203 */
+ {"LFSH", 0x2a}, /* xkb:LFSH (LFSH) -> linux:42 (KEY_LEFTSHIFT) -> qnum:42 */
+ {"LMTA", 0xdb}, /* xkb:LMTA (LWIN) -> linux:125 (KEY_LEFTMETA) -> qnum:219 */
+ {"LNFD", 0x5b}, /* xkb:LNFD (LNFD) -> linux:101 (KEY_LINEFEED) -> qnum:91 */
+ {"LSGT", 0x56}, /* xkb:LSGT (LSGT) -> linux:86 (KEY_102ND) -> qnum:86 */
+ {"LWIN", 0xdb}, /* xkb:LWIN (LWIN) -> linux:125 (KEY_LEFTMETA) -> qnum:219 */
+ {"MENU", 0xdd}, /* xkb:MENU (COMP) -> linux:127 (KEY_COMPOSE) -> qnum:221 */
+ {"MUHE", 0x7b}, /* xkb:MUHE (MUHE) -> linux:94 (KEY_MUHENKAN) -> qnum:123 */
+ {"MUTE", 0xa0}, /* xkb:MUTE (MUTE) -> linux:113 (KEY_MUTE) -> qnum:160 */
+ {"NFER", 0x7b}, /* xkb:NFER (MUHE) -> linux:94 (KEY_MUHENKAN) -> qnum:123 */
+ {"NMLK", 0x45}, /* xkb:NMLK (NMLK) -> linux:69 (KEY_NUMLOCK) -> qnum:69 */
+ {"OPEN", 0x64}, /* xkb:OPEN (OPEN) -> linux:134 (KEY_OPEN) -> qnum:100 */
+ {"PAST", 0x65}, /* xkb:PAST (PAST) -> linux:135 (KEY_PASTE) -> qnum:101 */
+ {"PAUS", 0xc6}, /* xkb:PAUS (PAUS) -> linux:119 (KEY_PAUSE) -> qnum:198 */
+ {"PGDN", 0xd1}, /* xkb:PGDN (PGDN) -> linux:109 (KEY_PAGEDOWN) -> qnum:209 */
+ {"PGUP", 0xc9}, /* xkb:PGUP (PGUP) -> linux:104 (KEY_PAGEUP) -> qnum:201 */
+ {"POWR", 0xde}, /* xkb:POWR (POWR) -> linux:116 (KEY_POWER) -> qnum:222 */
+ {"PROP", 0x86}, /* xkb:PROP (PROP) -> linux:130 (KEY_PROPS) -> qnum:134 */
+ {"PRSC", 0x54}, /* xkb:PRSC (SYRQ) -> linux:99 (KEY_SYSRQ) -> qnum:84 */
+ {"RALT", 0xb8}, /* xkb:RALT (RALT) -> linux:100 (KEY_RIGHTALT) -> qnum:184 */
+ {"RCTL", 0x9d}, /* xkb:RCTL (RCTL) -> linux:97 (KEY_RIGHTCTRL) -> qnum:157 */
+ {"RGHT", 0xcd}, /* xkb:RGHT (RGHT) -> linux:106 (KEY_RIGHT) -> qnum:205 */
+ {"RMTA", 0xdc}, /* xkb:RMTA (RWIN) -> linux:126 (KEY_RIGHTMETA) -> qnum:220 */
+ {"RTRN", 0x1c}, /* xkb:RTRN (RTRN) -> linux:28 (KEY_ENTER) -> qnum:28 */
+ {"RTSH", 0x36}, /* xkb:RTSH (RTSH) -> linux:54 (KEY_RIGHTSHIFT) -> qnum:54 */
+ {"RWIN", 0xdc}, /* xkb:RWIN (RWIN) -> linux:126 (KEY_RIGHTMETA) -> qnum:220 */
+ {"SCLK", 0x46}, /* xkb:SCLK (SCLK) -> linux:70 (KEY_SCROLLLOCK) -> qnum:70 */
+ {"SPCE", 0x39}, /* xkb:SPCE (SPCE) -> linux:57 (KEY_SPACE) -> qnum:57 */
+ {"STOP", 0xe8}, /* xkb:STOP (STOP) -> linux:128 (KEY_STOP) -> qnum:232 */
+ {"SYRQ", 0x54}, /* xkb:SYRQ (SYRQ) -> linux:99 (KEY_SYSRQ) -> qnum:84 */
+ {"TAB", 0xf}, /* xkb:TAB (TAB) -> linux:15 (KEY_TAB) -> qnum:15 */
+ {"TLDE", 0x29}, /* xkb:TLDE (AB00) -> linux:41 (KEY_GRAVE) -> qnum:41 */
+ {"UNDO", 0x87}, /* xkb:UNDO (UNDO) -> linux:131 (KEY_UNDO) -> qnum:135 */
+ {"UP", 0xc8}, /* xkb:UP (UP) -> linux:103 (KEY_UP) -> qnum:200 */
+ {"VOL+", 0xb0}, /* xkb:VOL+ (VOL+) -> linux:115 (KEY_VOLUMEUP) -> qnum:176 */
+ {"VOL-", 0xae}, /* xkb:VOL- (VOL-) -> linux:114 (KEY_VOLUMEDOWN) -> qnum:174 */
+ {"XFER", 0x93}, /* xkb:XFER (I155) -> linux:147 (KEY_XFER) -> qnum:147 */
+};
+const unsigned int code_map_xkb_to_qnum_len = sizeof(code_map_xkb_to_qnum)/sizeof(code_map_xkb_to_qnum[0]);