aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--vncviewer/DesktopWindow.cxx32
-rw-r--r--vncviewer/Viewport.cxx81
-rw-r--r--vncviewer/Viewport.h2
-rw-r--r--vncviewer/cocoa.h3
-rw-r--r--vncviewer/cocoa.mm27
5 files changed, 133 insertions, 12 deletions
diff --git a/vncviewer/DesktopWindow.cxx b/vncviewer/DesktopWindow.cxx
index 3973cd66..897f9557 100644
--- a/vncviewer/DesktopWindow.cxx
+++ b/vncviewer/DesktopWindow.cxx
@@ -666,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/Viewport.cxx b/vncviewer/Viewport.cxx
index c0bbd0dd..bfadd4c0 100644
--- a/vncviewer/Viewport.cxx
+++ b/vncviewer/Viewport.cxx
@@ -329,6 +329,87 @@ void Viewport::setLEDState(unsigned int 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(fakeKeyBase + 100, XK_Caps_Lock);
+ handleKeyRelease(fakeKeyBase + 100);
+ }
+ if ((state & ledNumLock) != (cc->cp.ledState() & ledNumLock)) {
+ vlog.debug("Inserting fake NumLock to get in sync with server");
+ handleKeyPress(fakeKeyBase + 101, XK_Num_Lock);
+ handleKeyRelease(fakeKeyBase + 101);
+ }
+ if ((state & ledScrollLock) != (cc->cp.ledState() & ledScrollLock)) {
+ vlog.debug("Inserting fake ScrollLock to get in sync with server");
+ handleKeyPress(fakeKeyBase + 102, XK_Scroll_Lock);
+ handleKeyRelease(fakeKeyBase + 102);
+ }
+}
+
void Viewport::draw(Surface* dst)
{
diff --git a/vncviewer/Viewport.h b/vncviewer/Viewport.h
index 652feb45..31158c2d 100644
--- a/vncviewer/Viewport.h
+++ b/vncviewer/Viewport.h
@@ -49,6 +49,8 @@ public:
// Change client LED state
void setLEDState(unsigned int state);
+ // Change server LED state
+ void pushLEDState();
void draw(Surface* dst);
diff --git a/vncviewer/cocoa.h b/vncviewer/cocoa.h
index b5d5f763..a7138026 100644
--- a/vncviewer/cocoa.h
+++ b/vncviewer/cocoa.h
@@ -36,4 +36,7 @@ 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 6483291c..e26851d6 100644
--- a/vncviewer/cocoa.mm
+++ b/vncviewer/cocoa.mm
@@ -447,6 +447,23 @@ static int cocoa_set_modifier_lock_state(int modifier, bool on)
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);
@@ -456,3 +473,13 @@ 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);
+}