Skip to content

Commit

Permalink
TEMP: more hot key handling
Browse files Browse the repository at this point in the history
  • Loading branch information
CendioOssman committed Apr 9, 2021
1 parent 2806cf8 commit 69a11e6
Show file tree
Hide file tree
Showing 2 changed files with 178 additions and 53 deletions.
221 changes: 171 additions & 50 deletions vncviewer/Viewport.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
#include <config.h>
#endif

#include <algorithm>

#include <assert.h>
#include <stdio.h>
#include <string.h>
Expand Down Expand Up @@ -113,7 +115,7 @@ static const WORD SCAN_FAKE = 0xaa;

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),
lastPointerPos(0, 0), lastButtonMask(0), hotKeyWedged(false),
#ifdef WIN32
altGrArmed(false),
#endif
Expand Down Expand Up @@ -823,59 +825,27 @@ void Viewport::handlePointerTimeout(void *data)

void Viewport::handleKeyPress(int keyCode, rdr::U32 keySym)
{
std::set<HotKey> hotkeys;

hotkeys = parseHotKeyCombo(hotKeyCombo);

if ((hotkeys.count(hotkeyCtrl) > 0) &&
((keySym == XK_Control_L) || (keySym == XK_Control_R)))
downHotkeys.insert(hotkeyCtrl);
else if ((hotkeys.count(hotkeyShift) > 0) &&
((keySym == XK_Shift_L) || (keySym == XK_Shift_R)))
downHotkeys.insert(hotkeyShift);
else if ((hotkeys.count(hotkeyAlt) > 0) &&
((keySym == XK_Alt_L) || (keySym == XK_Alt_R)))
downHotkeys.insert(hotkeyAlt);
else if ((hotkeys.count(hotkeySuper) > 0) &&
((keySym == XK_Super_L) || (keySym == XK_Super_R)))
downHotkeys.insert(hotkeySuper);

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
// remote VNC server. However that means we lose the ability to use
// Alt as a shortcut modifier. Do what RealVNC does and hijack the
// left command key as an Alt replacement.
switch (keySym) {
case XK_Super_L:
keySym = XK_Alt_L;
break;
case XK_Super_R:
keySym = XK_Super_L;
break;
case XK_Alt_L:
keySym = XK_Mode_switch;
break;
case XK_Alt_R:
keySym = XK_ISO_Level3_Shift;
break;
}
#endif
// Possible hot key combo?
if (handleHotKeyPress(keyCode, keySym))
return;

// Because of the way keyboards work, we cannot expect to have the same
// symbol on release as when pressed. This breaks the VNC protocol however,
// so we need to keep track of what keysym a key _code_ generated on press
// and send the same on release.
downKeySym[keyCode] = keySym;

if (viewOnly)
return;

// Platform specific adjustments
keySym = adjustKeySym(keyCode, keySym);

#if defined(WIN32) || defined(__APPLE__)
vlog.debug("Key pressed: 0x%04x => 0x%04x", keyCode, keySym);
#else
Expand All @@ -900,9 +870,7 @@ void Viewport::handleKeyPress(int keyCode, rdr::U32 keySym)
void Viewport::handleKeyRelease(int keyCode)
{
DownMap::iterator iter;

if (viewOnly)
return;
rdr::U32 keySym;

iter = downKeySym.find(keyCode);
if (iter == downKeySym.end()) {
Expand All @@ -912,25 +880,178 @@ void Viewport::handleKeyRelease(int keyCode)
return;
}

keySym = iter->second;
downKeySym.erase(iter);

if (downKeySym.empty())
hotKeyWedged = false;

if (viewOnly)
return;

// Platform specific adjustments
keySym = adjustKeySym(keyCode, keySym);

#if defined(WIN32) || defined(__APPLE__)
vlog.debug("Key released: 0x%04x => 0x%04x", keyCode, iter->second);
vlog.debug("Key released: 0x%04x => 0x%04x", keyCode, keySym);
#else
vlog.debug("Key released: 0x%04x => XK_%s (0x%04x)",
keyCode, XKeysymToString(iter->second), iter->second);
keyCode, XKeysymToString(keySym), keySym);
#endif

try {
if (keyCode > 0xff)
cc->writer()->writeKeyEvent(iter->second, 0, false);
cc->writer()->writeKeyEvent(keySym, 0, false);
else
cc->writer()->writeKeyEvent(iter->second, keyCode, false);
cc->writer()->writeKeyEvent(keySym, keyCode, false);
} catch (rdr::Exception& e) {
vlog.error("%s", e.str());
exit_vncviewer(_("An unexpected error occurred when communicating "
"with the server:\n\n%s"), e.str());
}
}

downKeySym.erase(iter);
rdr::U32 Viewport::adjustKeySym(int keyCode, rdr::U32 keySym)
{
#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
// remote VNC server. However that means we lose the ability to use
// Alt as a shortcut modifier. Do what RealVNC does and hijack the
// left command key as an Alt replacement.
switch (keySym) {
case XK_Super_L:
keySym = XK_Alt_L;
break;
case XK_Super_R:
keySym = XK_Super_L;
break;
case XK_Alt_L:
keySym = XK_Mode_switch;
break;
case XK_Alt_R:
keySym = XK_ISO_Level3_Shift;
break;
}
#endif

return keySym;
}

bool Viewport::handleHotKeyPress(int keyCode, rdr::U32 keySym)
{
// Already determined this isn't a hot key combo?
if (hotKeyWedged)
return false;

// Are we still collecting modifiers?
if (!hotKeyReady) {
std::set<HotKey> hotkeys;
std::set<HotKey> downHotkeys;
DownMap::iterator iter;

hotkeys = parseHotKeyCombo(hotKeyCombo);

// No hot key combo configured?
if (hotkeys.empty()) {
hotKeyWedged = true;
return false;
}

// Which modifiers are pressed?
for (iter = downKeySym.begin(); iter != downKeySym.end(); ++iter) {
switch (iter->second) {
case XK_Super_L:
case XK_Super_R:
downHotkeys.insert(hotkeySuper);
break;
case XK_Alt_L:
case XK_Alt_R:
downHotkeys.insert(hotkeyAlt);
break;
case XK_Shift_L:
case XK_Shift_R:
downHotkeys.insert(hotkeyShift);
break;
case XK_Control_L:
case XK_Control_R:
downHotkeys.insert(hotkeyCtrl);
break;
default:
// Something else snuck in
hotKeyWedged = true;
return false;
}
}

// Not enough?
if (hotkeys != downHotkeys) {
// Extra modifiers?
if (!std::includes(hotkeys.begin(), hotkeys.end(),
downHotkeys.begin(), downHotkeys.end())) {
// Yes, so this is likely some other key combo we should ignore
hotKeyWedged = true;
}

return false;
}

// Is this new key also a modifier?
switch (keySym) {
case XK_Super_L:
case XK_Super_R:
case XK_Alt_L:
case XK_Alt_R:
case XK_Shift_L:
case XK_Shift_R:
case XK_Control_L:
case XK_Control_R:
// Yes, so this is likely some other key combo we should ignore
hotKeyWedged = true;
return false;
}

if (keySym == XK_space) {
vlog.debug("Detected hot key escape sequence");
// We're not really wedged, but we want the same effect,
// i.e. that all following keys are passed through
hotKeyWedged = true;
// This space is consumed though
return true;
}

vlog.debug("Detected hot key 0x%04x", keySym);

// The remote session won't see any more keys, so release the ones
// currently down
while (!downKeySym.empty())
handleKeyRelease(downKeySym.begin()->first);

hotKeyReady = true;
}

assert(hotKeyReady);

switch (keySym) {
case XK_m:
popupContextMenu();
break;
case XK_KP_Enter:
case XK_Return:
if (window()->fullscreen_active())
window()->fullscreen_off();
else
((DesktopWindow*)window())->fullscreen_on();
break;
default:
// Unknown/Unused hot key combo
break;
}

// FIXME: Should be able to press multiple hot keys
hotKeyReady = false;

return true;
}


Expand Down
10 changes: 7 additions & 3 deletions vncviewer/Viewport.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,11 @@
#define __VIEWPORT_H__

#include <map>
#include <set>

#include <rfb/Rect.h>

#include <FL/Fl_Widget.H>

#include "parameters.h"
#include "EmulateMB.h"

class Fl_Menu_Button;
Expand Down Expand Up @@ -89,6 +87,11 @@ class Viewport : public Fl_Widget, public EmulateMB {
void handleKeyPress(int keyCode, rdr::U32 keySym);
void handleKeyRelease(int keyCode);

rdr::U32 adjustKeySym(int keyCode, rdr::U32 keySym);

bool handleHotKeyPress(int keyCode, rdr::U32 keySym);
bool handleHotKeyRelease(int keyCode, rdr::U32 keySym);

static int handleSystemEvent(void *event, void *data);

#ifdef WIN32
Expand All @@ -112,7 +115,8 @@ class Viewport : public Fl_Widget, public EmulateMB {
typedef std::map<int, rdr::U32> DownMap;
DownMap downKeySym;

std::set<HotKey> downHotkeys;
bool hotKeyReady;
bool hotKeyWedged;

#ifdef WIN32
bool altGrArmed;
Expand Down

0 comments on commit 69a11e6

Please sign in to comment.