aboutsummaryrefslogtreecommitdiffstats
path: root/vncviewer/Viewport.cxx
diff options
context:
space:
mode:
authorPierre Ossman <ossman@cendio.se>2016-12-05 15:26:21 +0100
committerPierre Ossman <ossman@cendio.se>2017-08-24 12:33:03 +0200
commit2fa63f8576e5d1c632efeeb2c185f11e943899d8 (patch)
tree9a4e68d8be1ff669c2c07b95380ba4a0a71a3e6d /vncviewer/Viewport.cxx
parent82e753d4e1928342c82cc7b82e854aa2666d1145 (diff)
downloadtigervnc-2fa63f8576e5d1c632efeeb2c185f11e943899d8.tar.gz
tigervnc-2fa63f8576e5d1c632efeeb2c185f11e943899d8.zip
Add client support for LED state sync
Diffstat (limited to 'vncviewer/Viewport.cxx')
-rw-r--r--vncviewer/Viewport.cxx172
1 files changed, 172 insertions, 0 deletions
diff --git a/vncviewer/Viewport.cxx b/vncviewer/Viewport.cxx
index 6a23526a..c0bbd0dd 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
@@ -92,6 +97,11 @@ enum { ID_EXIT, ID_FULLSCREEN, ID_MINIMIZE, ID_RESIZE,
// 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),
@@ -218,6 +228,108 @@ 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::draw(Surface* dst)
{
int X, Y, W, H;
@@ -352,6 +464,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;
@@ -577,6 +738,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) {
@@ -620,6 +786,12 @@ 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)