From 4f3ac69a11b98aa7eea88a6336140bced4c66eae Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 22 Aug 2014 15:10:22 +0200 Subject: [PATCH] Add xhandler hook Boiler plate code to intercept system events from FLTK so that we can generate proper keyboard messages. --- CMakeLists.txt | 3 + config.h.in | 1 + contrib/fltk/12-fltk-1.3.2-xhandlers.patch | 194 +++++++++++++++++++++ vncviewer/Viewport.cxx | 31 ++++ vncviewer/Viewport.h | 2 + 5 files changed, 231 insertions(+) create mode 100644 contrib/fltk/12-fltk-1.3.2-xhandlers.patch diff --git a/CMakeLists.txt b/CMakeLists.txt index 30520a51..f5a016ac 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -300,6 +300,9 @@ if(FLTK_FOUND) # FLTK STR #2860 check_cxx_source_compiles("#include \nint main(int c, char** v) { void (Fl_Window::*foo)(int,int,int,int) = &Fl_Window::fullscreen_screens; return 0; }" HAVE_FLTK_FULLSCREEN_SCREENS) + # FLTK STR #xxxx + check_cxx_source_compiles("#include \nint main(int c, char** v) { Fl::add_xhandler(NULL, NULL); return 0; }" HAVE_FLTK_XHANDLERS) + set(CMAKE_REQUIRED_INCLUDES) set(CMAKE_REQUIRED_LIBRARIES) endif() diff --git a/config.h.in b/config.h.in index a88c31c5..bac626b7 100644 --- a/config.h.in +++ b/config.h.in @@ -17,6 +17,7 @@ #cmakedefine HAVE_FLTK_CURSOR #cmakedefine HAVE_FLTK_WORK_AREA #cmakedefine HAVE_FLTK_ICONS +#cmakedefine HAVE_FLTK_XHANDLERS #cmakedefine HAVE_ACTIVE_DESKTOP_H #cmakedefine HAVE_ACTIVE_DESKTOP_L #cmakedefine ENABLE_NLS 1 diff --git a/contrib/fltk/12-fltk-1.3.2-xhandlers.patch b/contrib/fltk/12-fltk-1.3.2-xhandlers.patch new file mode 100644 index 00000000..cf6cefbf --- /dev/null +++ b/contrib/fltk/12-fltk-1.3.2-xhandlers.patch @@ -0,0 +1,194 @@ +diff -up fltk-1.3.2/FL/Fl.H.xhandlers fltk-1.3.2/FL/Fl.H +--- fltk-1.3.2/FL/Fl.H.xhandlers 2014-07-22 15:23:18.087334467 +0200 ++++ fltk-1.3.2/FL/Fl.H 2014-07-22 15:23:18.094334589 +0200 +@@ -96,6 +96,9 @@ typedef void (*Fl_FD_Handler)(FL_SOCKET + /** Signature of add_handler functions passed as parameters */ + typedef int (*Fl_Event_Handler)(int event); + ++/** Signature of add_xhandler functions passed as parameters */ ++typedef bool (*Fl_XEvent_Handler)(void *event, void *data); ++ + /** Signature of set_abort functions passed as parameters */ + typedef void (*Fl_Abort_Handler)(const char *format,...); + +@@ -712,6 +715,8 @@ public: + static void focus(Fl_Widget*); + static void add_handler(Fl_Event_Handler h); + static void remove_handler(Fl_Event_Handler h); ++ static void add_xhandler(Fl_XEvent_Handler h, void *data); ++ static void remove_xhandler(Fl_XEvent_Handler h); + static void event_dispatch(Fl_Event_Dispatch d); + static Fl_Event_Dispatch event_dispatch(); + /** @} */ +diff -up fltk-1.3.2/src/Fl_cocoa.mm.xhandlers fltk-1.3.2/src/Fl_cocoa.mm +--- fltk-1.3.2/src/Fl_cocoa.mm.xhandlers 2014-07-22 15:23:18.089334502 +0200 ++++ fltk-1.3.2/src/Fl_cocoa.mm 2014-07-22 15:23:18.095334607 +0200 +@@ -1269,6 +1269,8 @@ void fl_open_callback(void (*cb)(const c + } + @end + ++extern bool fl_send_xhandlers(void *e); ++ + static void clipboard_check(void); + + @implementation FLApplication +@@ -1276,6 +1278,10 @@ static void clipboard_check(void); + { + // update clipboard status + clipboard_check(); ++ ++ if (fl_send_xhandlers(theEvent)) ++ return; ++ + NSEventType type = [theEvent type]; + if (type == NSLeftMouseDown) { + fl_lock_function(); +diff -up fltk-1.3.2/src/Fl.cxx.xhandlers fltk-1.3.2/src/Fl.cxx +--- fltk-1.3.2/src/Fl.cxx.xhandlers 2014-07-22 15:23:18.085334432 +0200 ++++ fltk-1.3.2/src/Fl.cxx 2014-07-22 15:23:18.095334607 +0200 +@@ -891,6 +891,67 @@ static int send_handlers(int e) { + return 0; + } + ++ ++//////////////////////////////////////////////////////////////// ++// System event handlers: ++ ++ ++struct xhandler_link { ++ Fl_XEvent_Handler handle; ++ void *data; ++ xhandler_link *next; ++}; ++ ++ ++static xhandler_link *xhandlers = 0; ++ ++ ++/** ++ Install a function to intercept system events. FLTK calls each of ++ these functions as soon as a new system event is received. The ++ processing will stop at the first function to return true. If all ++ functions return false then the event is passed on for normal ++ handling by FLTK. ++ ++ \see Fl::remove_xhandler(Fl_XEvent_Handler) ++*/ ++void Fl::add_xhandler(Fl_XEvent_Handler ha, void *data) { ++ xhandler_link *l = new xhandler_link; ++ l->handle = ha; ++ l->data = data; ++ l->next = xhandlers; ++ xhandlers = l; ++} ++ ++ ++/** ++ Removes a previously added system event handler. ++*/ ++void Fl::remove_xhandler(Fl_XEvent_Handler ha) { ++ xhandler_link *l, *p; ++ ++ // Search for the handler in the list... ++ for (l = xhandlers, p = 0; l && l->handle != ha; p = l, l = l->next); ++ ++ if (l) { ++ // Found it, so remove it from the list... ++ if (p) p->next = l->next; ++ else xhandlers = l->next; ++ ++ // And free the record... ++ delete l; ++ } ++} ++ ++bool fl_send_xhandlers(void *e) { ++ for (const xhandler_link *hl = xhandlers; hl; hl = hl->next) { ++ if (hl->handle(e, hl->data)) ++ return true; ++ } ++ return false; ++} ++ ++ + //////////////////////////////////////////////////////////////// + + Fl_Widget* fl_oldfocus; // kludge for Fl_Group... +diff -up fltk-1.3.2/src/Fl_win32.cxx.xhandlers fltk-1.3.2/src/Fl_win32.cxx +--- fltk-1.3.2/src/Fl_win32.cxx.xhandlers 2014-07-22 15:23:18.092334554 +0200 ++++ fltk-1.3.2/src/Fl_win32.cxx 2014-07-22 15:24:44.682843610 +0200 +@@ -336,6 +336,8 @@ void* Fl::thread_message() { + return r; + } + ++extern bool fl_send_xhandlers(void *e); ++ + IActiveIMMApp *fl_aimm = NULL; + MSG fl_msg; + +@@ -401,26 +403,25 @@ int fl_wait(double time_to_wait) { + + // Execute the message we got, and all other pending messages: + // have_message = PeekMessage(&fl_msg, NULL, 0, 0, PM_REMOVE); +- have_message = PeekMessageW(&fl_msg, NULL, 0, 0, PM_REMOVE); +- if (have_message > 0) { +- while (have_message != 0 && have_message != -1) { +- // Let applications treat WM_QUIT identical to SIGTERM on *nix +- if (fl_msg.message == WM_QUIT) +- raise(SIGTERM); +- if (fl_msg.message == fl_wake_msg) { +- // Used for awaking wait() from another thread +- thread_message_ = (void*)fl_msg.wParam; +- Fl_Awake_Handler func; +- void *data; +- while (Fl::get_awake_handler_(func, data)==0) { +- func(data); +- } +- } +- +- TranslateMessage(&fl_msg); +- DispatchMessageW(&fl_msg); +- have_message = PeekMessageW(&fl_msg, NULL, 0, 0, PM_REMOVE); ++ while ((have_message = PeekMessageW(&fl_msg, NULL, 0, 0, PM_REMOVE)) > 0) { ++ if (fl_send_xhandlers(&fl_msg)) ++ continue; ++ ++ // Let applications treat WM_QUIT identical to SIGTERM on *nix ++ if (fl_msg.message == WM_QUIT) ++ raise(SIGTERM); ++ ++ if (fl_msg.message == fl_wake_msg) { ++ // Used for awaking wait() from another thread ++ thread_message_ = (void*)fl_msg.wParam; ++ Fl_Awake_Handler func; ++ void *data; ++ while (Fl::get_awake_handler_(func, data)==0) ++ func(data); + } ++ ++ TranslateMessage(&fl_msg); ++ DispatchMessageW(&fl_msg); + } + Fl::flush(); + +diff -up fltk-1.3.2/src/Fl_x.cxx.xhandlers fltk-1.3.2/src/Fl_x.cxx +--- fltk-1.3.2/src/Fl_x.cxx.xhandlers 2014-07-22 15:23:18.093334572 +0200 ++++ fltk-1.3.2/src/Fl_x.cxx 2014-07-22 15:23:18.096334624 +0200 +@@ -188,6 +188,8 @@ void Fl::remove_fd(int n) { + remove_fd(n, -1); + } + ++extern bool fl_send_xhandlers(void *e); ++ + #if CONSOLIDATE_MOTION + static Fl_Window* send_motion; + extern Fl_Window* fl_xmousewin; +@@ -198,6 +200,8 @@ static void do_queued_events() { + while (XEventsQueued(fl_display,QueuedAfterReading)) { + XEvent xevent; + XNextEvent(fl_display, &xevent); ++ if (fl_send_xhandlers(&xevent)) ++ continue; + fl_handle(xevent); + } + // we send FL_LEAVE only if the mouse did not enter some other window: diff --git a/vncviewer/Viewport.cxx b/vncviewer/Viewport.cxx index 16b34e6c..2b22a973 100644 --- a/vncviewer/Viewport.cxx +++ b/vncviewer/Viewport.cxx @@ -100,6 +100,11 @@ Viewport::Viewport(int w, int h, const rfb::PixelFormat& serverPF, CConn* cc_) Fl::add_clipboard_notify(handleClipboardChange, this); #endif +#ifdef HAVE_FLTK_XHANDLERS + // We need to intercept keyboard events early + Fl::add_xhandler(handleXEvent, this); +#endif + frameBuffer = createFramebuffer(w, h); assert(frameBuffer); @@ -132,6 +137,10 @@ Viewport::~Viewport() // again later when this object is already gone. Fl::remove_timeout(handlePointerTimeout, this); +#ifdef HAVE_FLTK_XHANDLERS + Fl::remove_xhandler(handleXEvent); +#endif + #ifdef HAVE_FLTK_CLIPBOARD Fl::remove_clipboard_notify(handleClipboardChange); #endif @@ -620,6 +629,28 @@ void Viewport::handleKeyRelease(int keyCode) } +bool Viewport::handleXEvent(void *event, void *data) +{ + Viewport *self = (Viewport *)data; + Fl_Widget *focus; + + assert(self); + + focus = Fl::grab(); + if (!focus) + focus = Fl::focus(); + if (!focus) + return false; + + if (focus != self) + return false; + + assert(event); + + return false; +} + + rdr::U32 Viewport::translateKeyEvent(void) { unsigned ucs; diff --git a/vncviewer/Viewport.h b/vncviewer/Viewport.h index d9eea353..30dacad4 100644 --- a/vncviewer/Viewport.h +++ b/vncviewer/Viewport.h @@ -73,6 +73,8 @@ private: void handleKeyPress(int keyCode, rdr::U32 keySym); void handleKeyRelease(int keyCode); + static bool handleXEvent(void *event, void *data); + rdr::U32 translateKeyEvent(void); void handleFLTKKeyPress(void); -- 2.39.5