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 event taps for keyboard grab on macOS #1884

Draft
wants to merge 5 commits into
base: master
Choose a base branch
from
Draft
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
1 change: 1 addition & 0 deletions vncviewer/CConn.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ CConn::CConn(const char* vncServerName, network::Socket* socket=nullptr)

if(sock == nullptr) {
try {
// FIXME: This shouldn't block
#ifndef WIN32
if (strchr(vncServerName, '/') != nullptr) {
sock = new network::UnixSocket(vncServerName);
Expand Down
46 changes: 20 additions & 26 deletions vncviewer/DesktopWindow.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -195,15 +195,15 @@ DesktopWindow::DesktopWindow(int w, int h, const char *name,
#else
delayedFullscreen = true;
#endif

// Full screen events are not sent out for a hidden window,
// so send a fake one here to set up things properly.
if (fullscreen_active())
handle(FL_FULLSCREEN);
}

show();

// Full screen events are not sent out for a hidden window,
// so send a fake one here to set up things properly.
if (fullscreen_active())
handle(FL_FULLSCREEN);

// Unfortunately, current FLTK does not allow us to set the
// maximized property on Windows and X11 before showing the window.
// See STR #2083 and STR #2178
Expand Down Expand Up @@ -260,6 +260,8 @@ DesktopWindow::~DesktopWindow()
Fl::remove_timeout(menuOverlay, this);
Fl::remove_timeout(updateOverlay, this);

ungrabKeyboard();

OptionsDialog::removeCallback(handleOptions);

delete overlay;
Expand Down Expand Up @@ -677,10 +679,6 @@ void DesktopWindow::resize(int x, int y, int w, int h)

repositionWidgets();
}

// Some systems require a grab after the window size has been changed.
// Otherwise they might hold on to displays, resulting in them being unusable.
maybeGrabKeyboard();
}


Expand Down Expand Up @@ -823,6 +821,7 @@ int DesktopWindow::handle(int event)
{
switch (event) {
case FL_FULLSCREEN:
vlog.error("FL_FULLSCREEN");
fullScreen.setParam(fullscreen_active());

// Update scroll bars
Expand Down Expand Up @@ -908,9 +907,11 @@ int DesktopWindow::fltkDispatch(int event, Fl_Window *win)
// all monitors and the user clicked on another application.
// Make sure we update our grabs with the focus changes.
case FL_FOCUS:
vlog.error("FL_FOCUS");
dw->maybeGrabKeyboard();
break;
case FL_UNFOCUS:
vlog.error("FL_UNFOCUS");
if (fullscreenSystemKeys) {
dw->ungrabKeyboard();
}
Expand Down Expand Up @@ -941,14 +942,6 @@ int DesktopWindow::fltkHandle(int event)
// not be resized to cover the new screen. A timer makes sense
// also on other systems, to make sure that whatever desktop
// environment has a chance to deal with things before we do.
// Please note that when using FullscreenSystemKeys on macOS, the
// display configuration cannot be changed: macOS will not detect
// added or removed screens and there will be no
// FL_SCREEN_CONFIGURATION_CHANGED event. This is by design:
// "When you capture a display, you have exclusive use of the
// display. Other applications and system services are not allowed
// to use the display or change its configuration. In addition,
// they are not notified of display changes"
Fl::remove_timeout(reconfigureFullscreen);
Fl::add_timeout(0.5, reconfigureFullscreen);
}
Expand Down Expand Up @@ -1026,14 +1019,15 @@ void DesktopWindow::fullscreen_on()
}
#ifdef __APPLE__
// This is a workaround for a bug in FLTK, see: https://github.com/fltk/fltk/pull/277
int savedLevel;
savedLevel = cocoa_get_level(this);
// FIXME: Does this still happen? Maybe side effect of releasing displays
//int savedLevel;
//savedLevel = cocoa_get_level(this);
#endif
fullscreen_screens(top, bottom, left, right);
#ifdef __APPLE__
// This is a workaround for a bug in FLTK, see: https://github.com/fltk/fltk/pull/277
if (cocoa_get_level(this) != savedLevel)
cocoa_set_level(this, savedLevel);
//if (cocoa_get_level(this) != savedLevel)
// cocoa_set_level(this, savedLevel);
#endif

if (!fullscreen_active())
Expand Down Expand Up @@ -1095,10 +1089,10 @@ void DesktopWindow::grabKeyboard()
return;
}
#elif defined(__APPLE__)
int ret;
ret = cocoa_capture_displays(this);
if (ret != 0) {
bool ret;

ret = cocoa_tap_keyboard(this);
if (!ret) {
vlog.error(_("Failure grabbing keyboard"));
return;
}
Expand Down Expand Up @@ -1153,7 +1147,7 @@ void DesktopWindow::ungrabKeyboard()
#if defined(WIN32)
win32_disable_lowlevel_keyboard(fl_xid(this));
#elif defined(__APPLE__)
cocoa_release_displays(this);
cocoa_untap_keyboard();
#else
// FLTK has a grab so lets not mess with it
if (Fl::grab())
Expand Down
19 changes: 19 additions & 0 deletions vncviewer/OptionsDialog.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@
#include "fltk/Fl_Monitor_Arrangement.h"
#include "fltk/Fl_Navigation.h"

#ifdef __APPLE__
#include "cocoa.h"
#endif

#include <FL/Fl.H>
#include <FL/Fl_Tabs.H>
#include <FL/Fl_Button.H>
Expand Down Expand Up @@ -872,6 +876,7 @@ void OptionsDialog::createInputPage(int tx, int ty, int tw, int th)
CHECK_MIN_WIDTH,
CHECK_HEIGHT,
_("Pass system keys directly to server (full screen)")));
systemKeysCheckbox->callback(handleSystemKeys, this);
ty += CHECK_HEIGHT + TIGHT_MARGIN;

menuKeyChoice = new Fl_Choice(LBLLEFT(tx, ty, 150, CHOICE_HEIGHT, _("Menu key")));
Expand Down Expand Up @@ -1117,6 +1122,20 @@ void OptionsDialog::handleRSAAES(Fl_Widget* /*widget*/, void *data)
}


void OptionsDialog::handleSystemKeys(Fl_Widget* /*widget*/, void* data)
{
#ifdef __APPLE__
OptionsDialog* dialog = (OptionsDialog*)data;

// Pop up the access dialog if needed
if (dialog->systemKeysCheckbox->value())
cocoa_is_trusted(true);
#else
(void)data;
#endif
}


void OptionsDialog::handleClipboard(Fl_Widget* /*widget*/, void *data)
{
(void)data;
Expand Down
2 changes: 2 additions & 0 deletions vncviewer/OptionsDialog.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ class OptionsDialog : public Fl_Window {
static void handleX509(Fl_Widget *widget, void *data);
static void handleRSAAES(Fl_Widget *widget, void *data);

static void handleSystemKeys(Fl_Widget *widget, void *data);

static void handleClipboard(Fl_Widget *widget, void *data);

static void handleFullScreenMode(Fl_Widget *widget, void *data);
Expand Down
7 changes: 3 additions & 4 deletions vncviewer/cocoa.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,10 @@

class Fl_Window;

int cocoa_get_level(Fl_Window *win);
void cocoa_set_level(Fl_Window *win, int level);
bool cocoa_is_trusted(bool prompt=false);

int cocoa_capture_displays(Fl_Window *win);
void cocoa_release_displays(Fl_Window *win);
bool cocoa_tap_keyboard(Fl_Window* win);
void cocoa_untap_keyboard();

typedef struct CGColorSpace *CGColorSpaceRef;

Expand Down
Loading
Loading