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

Force grab/ungrab keyboard+mouse with Right Ctrl key #1906

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
114 changes: 72 additions & 42 deletions vncviewer/DesktopWindow.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -78,14 +78,14 @@ static rfb::LogWriter vlog("DesktopWindow");
// issue for Fl::event_dispatch.
static std::set<DesktopWindow *> instances;

DesktopWindow::DesktopWindow(int w, int h, const char *name,
DesktopWindow::DesktopWindow(int w, int h, const char *name_,
const rfb::PixelFormat& serverPF,
CConn* cc_)
: Fl_Window(w, h), cc(cc_), offscreen(nullptr), overlay(nullptr),
firstUpdate(true),
name(nullptr), firstUpdate(true),
delayedFullscreen(false), sentDesktopSize(false),
pendingRemoteResize(false), lastResize({0, 0}),
keyboardGrabbed(false), mouseGrabbed(false),
keyboardGrabbed(false), mouseGrabbed(false), forceGrabbed(false),
statsLastUpdates(0), statsLastPixels(0), statsLastPosition(0),
statsGraph(nullptr)
{
Expand All @@ -109,7 +109,7 @@ DesktopWindow::DesktopWindow(int w, int h, const char *name,

callback(handleClose, this);

setName(name);
setName(name_);

OptionsDialog::addCallback(handleOptions, this);

Expand Down Expand Up @@ -272,6 +272,8 @@ DesktopWindow::~DesktopWindow()

Fl::event_dispatch(Fl::handle_);

free(name);

// FLTK automatically deletes all child widgets, so we shouldn't touch
// them ourselves here
}
Expand All @@ -282,53 +284,48 @@ const rfb::PixelFormat &DesktopWindow::getPreferredPF()
return viewport->getPreferredPF();
}


void DesktopWindow::setName(const char *name)
void DesktopWindow::setName(const char *new_name)
{
char windowNameStr[100];
const char *labelFormat;
size_t maxNameSize;
char truncatedName[sizeof(windowNameStr)];

labelFormat = "%s - TigerVNC";

// Ignore the length of '%s' since it is
// a format marker which won't take up space
maxNameSize = sizeof(windowNameStr) - 1 - strlen(labelFormat) + 2;

if (maxNameSize > strlen(name)) {
// Guaranteed to fit, no need to truncate
strcpy(truncatedName, name);
} else if (maxNameSize <= strlen("...")) {
// Even an ellipsis won't fit
truncatedName[0] = '\0';
} else {
int offset;

// We need to truncate, add an ellipsis
offset = maxNameSize - strlen("...");
strncpy(truncatedName, name, sizeof(truncatedName));
strcpy(truncatedName + offset, "...");
free(name);
name = nullptr;
if (new_name) {
name = strdup(new_name);
}
updateLabel();
}

void DesktopWindow::updateLabel() {
const char *strTitle = " - TigerVNC";
const char *strGrabbed = " [GRAB]";
const size_t maxNameLen = 100;

char *label = (char*)malloc(maxNameLen + strlen(strGrabbed) + strlen(strTitle) + 1);
strcpy(label, "");

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
if (name) {
if (strlen(name) <= maxNameLen) {
strcat(label, name);
} else {
strncat(label, name, maxNameLen - 3);
strcat(label, "...");
}
} else {
strcat(label, "unknown");
}

if (snprintf(windowNameStr, sizeof(windowNameStr), labelFormat,
truncatedName) >= (int)sizeof(windowNameStr)) {
// This is just to shut up the compiler, as we've already made sure
// we won't truncate anything
if (keyboardGrabbed || mouseGrabbed) {
strcat(label, strGrabbed);
}

#pragma GCC diagnostic pop
strcat(label, strTitle);

copy_label(windowNameStr);
}
copy_label(label);

free(label);
}

// Copy the areas of the framebuffer that have been changed (damaged)
// to the displayed window.

void DesktopWindow::updateWindow()
{
if (firstUpdate) {
Expand Down Expand Up @@ -841,6 +838,29 @@ void DesktopWindow::updateOverlay(void *data)
self->damage(FL_DAMAGE_USER1);
}

void DesktopWindow::toggleForceGrab() {
if (keyboardGrabbed && mouseGrabbed) {
ungrabPointer();
ungrabKeyboard();
forceGrabbed = false;
} else {
grabPointer();
grabKeyboard();
forceGrabbed = true;
}
}

bool DesktopWindow::isKeyboardGrabbed() const {
return keyboardGrabbed;
}

bool DesktopWindow::isMouseGrabbed() const {
return mouseGrabbed;
}

bool DesktopWindow::isForceGrabbed() const {
return forceGrabbed;
}

int DesktopWindow::handle(int event)
{
Expand Down Expand Up @@ -877,7 +897,9 @@ int DesktopWindow::handle(int event)
// We don't get FL_LEAVE with a grabbed pointer, so check manually
if ((Fl::event_x() < 0) || (Fl::event_x() >= w()) ||
(Fl::event_y() < 0) || (Fl::event_y() >= h())) {
ungrabPointer();
if (!forceGrabbed) {
ungrabPointer();
}
}
#if !defined(WIN32) && !defined(__APPLE__)
Window root, child;
Expand All @@ -888,7 +910,9 @@ int DesktopWindow::handle(int event)
if (XQueryPointer(fl_display, fl_xid(this), &root, &child,
&x, &y, &wx, &wy, &mask) &&
(root != XRootWindow(fl_display, fl_screen))) {
ungrabPointer();
if (!forceGrabbed) {
ungrabPointer();
}
}
#endif
}
Expand Down Expand Up @@ -1183,6 +1207,7 @@ void DesktopWindow::grabKeyboard()
#endif

keyboardGrabbed = true;
updateLabel();

if (contains(Fl::belowmouse()))
grabPointer();
Expand All @@ -1193,7 +1218,9 @@ void DesktopWindow::ungrabKeyboard()
{
Fl::remove_timeout(handleGrab, this);

forceGrabbed = false;
keyboardGrabbed = false;
updateLabel();

ungrabPointer();

Expand Down Expand Up @@ -1236,12 +1263,15 @@ void DesktopWindow::grabPointer()
#endif

mouseGrabbed = true;
updateLabel();
}


void DesktopWindow::ungrabPointer()
{
forceGrabbed = false;
mouseGrabbed = false;
updateLabel();

#if !defined(WIN32) && !defined(__APPLE__)
x11_ungrab_pointer(fl_xid(this));
Expand Down
13 changes: 12 additions & 1 deletion vncviewer/DesktopWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class Fl_Scrollbar;
class DesktopWindow : public Fl_Window {
public:

DesktopWindow(int w, int h, const char *name,
DesktopWindow(int w, int h, const char *name_,
const rfb::PixelFormat& serverPF, CConn* cc_);
~DesktopWindow();

Expand Down Expand Up @@ -82,6 +82,12 @@ class DesktopWindow : public Fl_Window {

void fullscreen_on();

void toggleForceGrab();

bool isKeyboardGrabbed() const;
bool isMouseGrabbed() const;
bool isForceGrabbed() const;

private:
static void menuOverlay(void *data);

Expand Down Expand Up @@ -122,6 +128,8 @@ class DesktopWindow : public Fl_Window {

static void handleStatsTimeout(void *data);

void updateLabel();

private:
CConn* cc;
Fl_Scrollbar *hscroll, *vscroll;
Expand All @@ -131,6 +139,8 @@ class DesktopWindow : public Fl_Window {
unsigned char overlayAlpha;
struct timeval overlayStart;

char *name;

bool firstUpdate;
bool delayedFullscreen;
bool sentDesktopSize;
Expand All @@ -140,6 +150,7 @@ class DesktopWindow : public Fl_Window {

bool keyboardGrabbed;
bool mouseGrabbed;
bool forceGrabbed;

struct statsEntry {
unsigned ups;
Expand Down
3 changes: 2 additions & 1 deletion vncviewer/Keyboard.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ class KeyboardHandler
public:
virtual void handleKeyPress(int systemKeyCode,
uint32_t keyCode, uint32_t keySym) = 0;
virtual void handleKeyRelease(int systemKeyCode) = 0;
virtual void handleKeyRelease(int systemKeyCode,
uint32_t keyCode, uint32_t keySym) = 0;
};

class Keyboard
Expand Down
4 changes: 2 additions & 2 deletions vncviewer/KeyboardMacOS.mm
Original file line number Diff line number Diff line change
Expand Up @@ -168,9 +168,9 @@
// We don't get any release events for CapsLock, so we have to
// send the release right away.
if (keySym == XK_Caps_Lock)
handler->handleKeyRelease(systemKeyCode);
handler->handleKeyRelease(systemKeyCode, keyCode, keySym);
} else {
handler->handleKeyRelease(systemKeyCode);
handler->handleKeyRelease(systemKeyCode, keyCode, keySym);
}

return true;
Expand Down
4 changes: 2 additions & 2 deletions vncviewer/KeyboardWin32.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ bool KeyboardWin32::handleEvent(const void* event)
case XK_Katakana:
case XK_Hiragana:
case XK_Romaji:
handler->handleKeyRelease(systemKeyCode);
handler->handleKeyRelease(systemKeyCode, keyCode, keySym);
}

// Shift key tracking, see below
Expand Down Expand Up @@ -335,7 +335,7 @@ bool KeyboardWin32::handleEvent(const void* event)

keyCode = translateSystemKeyCode(systemKeyCode);

handler->handleKeyRelease(keyCode);
handler->handleKeyRelease(keyCode, keyCode, keySym);

// Windows has a rather nasty bug where it won't send key release
// events for a Shift button if the other Shift is still pressed
Expand Down
11 changes: 6 additions & 5 deletions vncviewer/KeyboardX11.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ bool KeyboardX11::handleEvent(const void* event)

assert(event);

if (xevent->type == KeyPress) {
if (xevent->type == KeyPress || xevent->type == KeyRelease) {
int keycode;
char str;
KeySym keysym;
Expand All @@ -105,10 +105,11 @@ bool KeyboardX11::handleEvent(const void* event)
(int)xevent->xkey.keycode);
}

handler->handleKeyPress(xevent->xkey.keycode, keycode, keysym);
return true;
} else if (xevent->type == KeyRelease) {
handler->handleKeyRelease(xevent->xkey.keycode);
if (xevent->type == KeyPress) {
handler->handleKeyPress(xevent->xkey.keycode, keycode, keysym);
} else if (xevent->type == KeyRelease) {
handler->handleKeyRelease(xevent->xkey.keycode, keycode, keysym);
}
return true;
}

Expand Down
Loading