Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use generic hot key combo for client control #1375

Draft
wants to merge 24 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
ad89bad
Log invalid screen layout
CendioOssman Dec 27, 2021
2c2ee11
Move keyboard tracking to CConnection
CendioOssman May 14, 2021
13d4e97
Move keyboard handling to separate classes
CendioOssman Dec 14, 2021
c19831d
Update keysym header files
CendioOssman Dec 7, 2021
6e97a3b
Add own keysym to name function
CendioOssman Dec 7, 2021
93da303
Better fix for fake focus grab events
CendioOssman Nov 22, 2021
32f0263
Use generic hot key combo for client control
CendioOssman Oct 31, 2017
ba830df
Add hot key for full screen
CendioOssman Dec 14, 2021
15a0d61
Add a bypass for hot key combinations
CendioOssman Sep 30, 2021
a672958
Add hot key to release keyboard grab
CendioOssman Nov 16, 2021
511694b
Add hot key to grab keyboard
CendioOssman Nov 13, 2021
9d8937f
Add support for more overlays
CendioOssman Nov 19, 2021
9b7bcf6
Add overlays for grab and full screen
CendioOssman Nov 19, 2021
31e83e6
Avoid repeating overlay tips
CendioOssman Dec 22, 2021
815aafe
More dynamic window title cropping
CendioOssman Oct 14, 2022
e5021fe
Update window caption on grab
CendioOssman Dec 27, 2021
4c8993b
Synchronously retry X11 keyboard grab
CendioOssman Dec 30, 2021
9304d4f
Show error grabbing keyboard
CendioOssman Dec 30, 2021
a05b2e0
Handle macOS keyboard stealing
CendioOssman Dec 14, 2021
20ba98a
TEMP remove unused actions
CendioOssman Nov 13, 2021
d990c54
TEMP: low level keyboard events debug output
CendioOssman Dec 9, 2021
af825d3
Use event taps for keyboard grab on macOS
CendioOssman Dec 23, 2021
d3487aa
TEMP: remove level workaround?
CendioOssman Dec 27, 2021
ce81726
TEMP: experiment giving focus to auth dialog
CendioOssman Jan 4, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 88 additions & 0 deletions common/rfb/CConnection.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,16 @@
#include <rfb/CMsgWriter.h>
#include <rfb/CSecurity.h>
#include <rfb/Decoder.h>
#include <rfb/KeysymStr.h>
#include <rfb/Security.h>
#include <rfb/SecurityClient.h>
#include <rfb/CConnection.h>
#include <rfb/util.h>

#define XK_MISCELLANY
#define XK_XKB_KEYS
#include <rfb/keysymdef.h>

#include <rfb/LogWriter.h>

#include <rdr/InStream.h>
Expand Down Expand Up @@ -693,6 +698,89 @@ void CConnection::sendClipboardData(const char* data)
}
}

void CConnection::sendKeyPress(int systemKeyCode,
rdr::U32 keyCode, rdr::U32 keySym)
{
// For the first few years, there wasn't a good consensus on what the
// Windows keys should be mapped to for X11. So we need to help out a
// bit and map all variants to the same key...
switch (keySym) {
case XK_Hyper_L:
keySym = XK_Super_L;
break;
case XK_Hyper_R:
keySym = XK_Super_R;
break;
// There has been several variants for Shift-Tab over the years.
// RFB states that we should always send a normal tab.
case XK_ISO_Left_Tab:
keySym = XK_Tab;
break;
}

#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

// 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.
downKeys[systemKeyCode].keyCode = keyCode;
downKeys[systemKeyCode].keySym = keySym;

vlog.debug("Key pressed: %d => 0x%04x / %s (0x%04x)",
systemKeyCode, keyCode, KeySymName(keySym), keySym);

writer()->writeKeyEvent(keySym, keyCode, true);
}

void CConnection::sendKeyRelease(int systemKeyCode)
{
DownMap::iterator iter;

iter = downKeys.find(systemKeyCode);
if (iter == downKeys.end()) {
// These occur somewhat frequently so let's not spam them unless
// logging is turned up.
vlog.debug("Unexpected release of key code %d", systemKeyCode);
return;
}

vlog.debug("Key released: %d => 0x%04x / %s (0x%04x)",
systemKeyCode, iter->second.keyCode,
KeySymName(iter->second.keySym), iter->second.keySym);

writer()->writeKeyEvent(iter->second.keySym,
iter->second.keyCode, false);

downKeys.erase(iter);
}

void CConnection::releaseAllKeys()
{
while (!downKeys.empty())
sendKeyRelease(downKeys.begin()->first);
}

void CConnection::refreshFramebuffer()
{
forceNonincremental = true;
Expand Down
21 changes: 21 additions & 0 deletions common/rfb/CConnection.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
#ifndef __RFB_CCONNECTION_H__
#define __RFB_CCONNECTION_H__

#include <map>

#include <rfb/CMsgHandler.h>
#include <rfb/DecodeManager.h>
#include <rfb/SecurityClient.h>
Expand Down Expand Up @@ -180,6 +182,18 @@ namespace rfb {
// clipboard via handleClipboardRequest().
virtual void sendClipboardData(const char* data);

// sendKeyPress()/sendKeyRelease() send keyboard events to the
// server
void sendKeyPress(int systemKeyCode, rdr::U32 keyCode, rdr::U32 keySym);
void sendKeyRelease(int systemKeyCode);

// releaseAllKeys() sends keyboard release events to the server for
// all keys that are currently pressed down by this client,
// avoiding keys getting stuck. This can be useful if the client
// loses keyboard focus or otherwise no longer gets keyboard events
// from the system.
void releaseAllKeys();

// refreshFramebuffer() forces a complete refresh of the entire
// framebuffer
void refreshFramebuffer();
Expand Down Expand Up @@ -296,6 +310,13 @@ namespace rfb {
char* serverClipboard;
bool hasLocalClipboard;
bool unsolicitedClipboardAttempt;

struct DownKey {
rdr::U32 keyCode;
rdr::U32 keySym;
};
typedef std::map<int, DownKey> DownMap;
DownMap downKeys;
};
}
#endif
1 change: 1 addition & 0 deletions common/rfb/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ add_library(rfb STATIC
JpegCompressor.cxx
JpegDecompressor.cxx
KeyRemapper.cxx
KeysymStr.c
LogWriter.cxx
Logger.cxx
Logger_file.cxx
Expand Down
11 changes: 10 additions & 1 deletion common/rfb/ClientParams.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,16 @@
#endif

#include <rfb/Exception.h>
#include <rfb/LogWriter.h>
#include <rfb/encodings.h>
#include <rfb/ledStates.h>
#include <rfb/clipboardTypes.h>
#include <rfb/ClientParams.h>

using namespace rfb;

static LogWriter vlog("ClientParams");

ClientParams::ClientParams()
: majorVersion(0), minorVersion(0),
compressLevel(2), qualityLevel(-1), fineQualityLevel(-1),
Expand Down Expand Up @@ -62,8 +65,14 @@ void ClientParams::setDimensions(int width, int height)

void ClientParams::setDimensions(int width, int height, const ScreenSet& layout)
{
if (!layout.validate(width, height))
if (!layout.validate(width, height)) {
char buffer[2048];
vlog.debug("Invalid screen layout for %dx%d:", width, height);
layout.print(buffer, sizeof(buffer));
vlog.debug("%s", buffer);

throw Exception("Attempted to configure an invalid screen layout");
}

width_ = width;
height_ = height;
Expand Down
108 changes: 108 additions & 0 deletions common/rfb/KeysymStr.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@

/*

Copyright 1990, 1998 The Open Group

Permission to use, copy, modify, distribute, and sell this software and its
documentation for any purpose is hereby granted without fee, provided that
the above copyright notice appear in all copies and that both that
copyright notice and this permission notice appear in supporting
documentation.

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Except as contained in this notice, the name of The Open Group shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from The Open Group.

*/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdlib.h>

#include "keysymdef.h"
#include "KeysymStr.h"

#define NEEDKTABLE
#define NEEDVTABLE
#include "ks_tables.h"

static const char *_XKeysymToString(unsigned ks)
{
if (!ks || (ks & ((unsigned long) ~0x1fffffff)) != 0)
return ((char *)NULL);
if (ks == XK_VoidSymbol)
ks = 0;
if (ks <= 0x1fffffff)
{
unsigned char val1 = ks >> 24;
unsigned char val2 = (ks >> 16) & 0xff;
unsigned char val3 = (ks >> 8) & 0xff;
unsigned char val4 = ks & 0xff;
int i = ks % VTABLESIZE;
int h = i + 1;
int n = VMAXHASH;
int idx;
while ((idx = hashKeysym[i]))
{
const unsigned char *entry = &_XkeyTable[idx];
if ((entry[0] == val1) && (entry[1] == val2) &&
(entry[2] == val3) && (entry[3] == val4))
return ((char *)entry + 4);
if (!--n)
break;
i += h;
if (i >= VTABLESIZE)
i -= VTABLESIZE;
}
}

if (ks >= 0x01000100 && ks <= 0x0110ffff) {
unsigned val = ks & 0xffffff;
char *s;
int i;
if (val & 0xff0000)
i = 10;
else
i = 6;
s = malloc(i);
if (s == NULL)
return s;
i--;
s[i--] = '\0';
for (; i; i--){
unsigned char val1 = val & 0xf;
val >>= 4;
if (val1 < 10)
s[i] = '0'+ val1;
else
s[i] = 'A'+ val1 - 10;
}
s[i] = 'U';
return s;
}
return ((char *) NULL);
}

const char* KeySymName(unsigned keysym)
{
const char* name;

name = _XKeysymToString(keysym);
if (name == NULL)
return "[unknown keysym]";

return name;
}

24 changes: 11 additions & 13 deletions vncviewer/menukey.h → common/rfb/KeysymStr.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* Copyright 2011 Martin Koegler <[email protected]>
/* Copyright 2021 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand All @@ -15,20 +15,18 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#ifndef __KEYSYM_H__
#define __KEYSYM_H__

#include <rdr/types.h>
#ifndef __RFB_KEYSYMSTR_H__
#define __RFB_KEYSYMSTR_H__

typedef struct {
const char* name;
int fltkcode;
int keycode;
rdr::U32 keysym;
} MenuKeySymbol;
#ifdef __cplusplus
extern "C" {
#endif

const char* KeySymName(unsigned keysym);

void getMenuKey(int *fltkcode, int *keycode, rdr::U32 *keysym);
int getMenuKeySymbolCount();
const MenuKeySymbol* getMenuKeySymbols();
#ifdef __cplusplus
}
#endif

#endif
11 changes: 10 additions & 1 deletion common/rfb/ServerParams.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,14 @@
#endif

#include <rfb/Exception.h>
#include <rfb/LogWriter.h>
#include <rfb/ledStates.h>
#include <rfb/ServerParams.h>

using namespace rfb;

static LogWriter vlog("ServerParams");

ServerParams::ServerParams()
: majorVersion(0), minorVersion(0),
supportsQEMUKeyEvent(false),
Expand Down Expand Up @@ -59,8 +62,14 @@ void ServerParams::setDimensions(int width, int height)

void ServerParams::setDimensions(int width, int height, const ScreenSet& layout)
{
if (!layout.validate(width, height))
if (!layout.validate(width, height)) {
char buffer[2048];
vlog.debug("Invalid screen layout for %dx%d:", width, height);
layout.print(buffer, sizeof(buffer));
vlog.debug("%s", buffer);

throw Exception("Attempted to configure an invalid screen layout");
}

width_ = width;
height_ = height;
Expand Down
11 changes: 7 additions & 4 deletions common/rfb/VNCSConnectionST.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include <rfb/ComparingUpdateTracker.h>
#include <rfb/Encoder.h>
#include <rfb/KeyRemapper.h>
#include <rfb/KeysymStr.h>
#include <rfb/LogWriter.h>
#include <rfb/Security.h>
#include <rfb/ServerCore.h>
Expand Down Expand Up @@ -86,8 +87,8 @@ VNCSConnectionST::~VNCSConnectionST()
keycode = pressedKeys.begin()->first;
pressedKeys.erase(pressedKeys.begin());

vlog.debug("Releasing key 0x%x / 0x%x on client disconnect",
keysym, keycode);
vlog.debug("Releasing key 0x%04x / %s (0x%04x) on client disconnect",
keycode, KeySymName(keysym), keysym);
server->keyEvent(keysym, keycode, false);
}

Expand Down Expand Up @@ -511,9 +512,11 @@ void VNCSConnectionST::keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down) {
if (!rfb::Server::acceptKeyEvents) return;

if (down)
vlog.debug("Key pressed: 0x%x / 0x%x", keysym, keycode);
vlog.debug("Key pressed: 0x%04x / %s (0x%04x)",
keycode, KeySymName(keysym), keysym);
else
vlog.debug("Key released: 0x%x / 0x%x", keysym, keycode);
vlog.debug("Key released: 0x%04x / %s (0x%04x)",
keycode, KeySymName(keysym), keysym);

// Avoid lock keys if we don't know the server state
if ((server->getLEDState() == ledUnknown) &&
Expand Down
Loading