From 25188c448cef7c802b8e27e13d643a7c95aaa840 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 21 Jul 2014 16:30:08 +0200 Subject: [PATCH] Remove simple keyboard model Remove the FLTK simple keyboard system and reorganise things in preparation for a more direct approach. --- CMakeLists.txt | 3 - config.h.in | 1 - .../01-str2599-fltk-1.3.x-keyboard-x11.patch | 286 ------------- ... => 01-str2636-fltk-1.3.x-clipboard.patch} | 0 ...02-str2599-fltk-1.3.x-keyboard-win32.patch | 256 ------------ ...02-str2636-fltk-1.3.x-clipboard-x11.patch} | 0 .../03-str2599-fltk-1.3.x-keyboard-osx.patch | 375 ------------------ ...2636-fltk-1.3.x-clipboard-win32-fix.patch} | 0 ...-str2636-fltk-1.3.x-clipboard-win32.patch} | 0 ...05-str2636-fltk-1.3.x-clipboard-osx.patch} | 0 ...9-pixmap.patch => 06-str2659-pixmap.patch} | 0 ...tch => 07-str2660-fltk-1.3.x-cursor.patch} | 0 ...atch => 08-str2802-fltk-1.3.0-modal.patch} | 0 ...atch => 09-str2816-fltk-1.3.0-icons.patch} | 0 ...=> 10-str2860-fltk-1.3.x-screen_num.patch} | 0 ... => 11-str2860-fltk-1.3.x-multihead.patch} | 0 vncviewer/Viewport.cxx | 325 ++++++++------- vncviewer/Viewport.h | 8 +- vncviewer/menukey.cxx | 68 ++-- vncviewer/menukey.h | 5 +- 20 files changed, 224 insertions(+), 1103 deletions(-) delete mode 100644 contrib/fltk/01-str2599-fltk-1.3.x-keyboard-x11.patch rename contrib/fltk/{04-str2636-fltk-1.3.x-clipboard.patch => 01-str2636-fltk-1.3.x-clipboard.patch} (100%) delete mode 100644 contrib/fltk/02-str2599-fltk-1.3.x-keyboard-win32.patch rename contrib/fltk/{05-str2636-fltk-1.3.x-clipboard-x11.patch => 02-str2636-fltk-1.3.x-clipboard-x11.patch} (100%) delete mode 100644 contrib/fltk/03-str2599-fltk-1.3.x-keyboard-osx.patch rename contrib/fltk/{06-str2636-fltk-1.3.x-clipboard-win32-fix.patch => 03-str2636-fltk-1.3.x-clipboard-win32-fix.patch} (100%) rename contrib/fltk/{07-str2636-fltk-1.3.x-clipboard-win32.patch => 04-str2636-fltk-1.3.x-clipboard-win32.patch} (100%) rename contrib/fltk/{08-str2636-fltk-1.3.x-clipboard-osx.patch => 05-str2636-fltk-1.3.x-clipboard-osx.patch} (100%) rename contrib/fltk/{09-str2659-pixmap.patch => 06-str2659-pixmap.patch} (100%) rename contrib/fltk/{10-str2660-fltk-1.3.x-cursor.patch => 07-str2660-fltk-1.3.x-cursor.patch} (100%) rename contrib/fltk/{11-str2802-fltk-1.3.0-modal.patch => 08-str2802-fltk-1.3.0-modal.patch} (100%) rename contrib/fltk/{12-str2816-fltk-1.3.0-icons.patch => 09-str2816-fltk-1.3.0-icons.patch} (100%) rename contrib/fltk/{13-str2860-fltk-1.3.x-screen_num.patch => 10-str2860-fltk-1.3.x-screen_num.patch} (100%) rename contrib/fltk/{14-str2860-fltk-1.3.x-multihead.patch => 11-str2860-fltk-1.3.x-multihead.patch} (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index ce0a00af..30520a51 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -279,9 +279,6 @@ if(FLTK_FOUND) set(CMAKE_REQUIRED_INCLUDES ${FLTK_INCLUDE_DIR}) set(CMAKE_REQUIRED_LIBRARIES ${FLTK_LIBRARIES}) - # FLTK STR #2599 - check_cxx_source_compiles("#include \nint main(int c, char** v) { void (Fl_Widget::*foo)() = &Fl_Widget::set_simple_keyboard; return 0; }" HAVE_FLTK_DEAD_KEYS) - # FLTK STR #2636 check_cxx_source_compiles("#include \nint main(int c, char** v) { Fl::add_clipboard_notify(NULL, NULL); return 0; }" HAVE_FLTK_CLIPBOARD) diff --git a/config.h.in b/config.h.in index 0c9e71a5..a88c31c5 100644 --- a/config.h.in +++ b/config.h.in @@ -10,7 +10,6 @@ #cmakedefine HAVE_GNUTLS_DATUM_T #cmakedefine HAVE_GNUTLS_PK_ALGORITHM_T #cmakedefine HAVE_GNUTLS_SIGN_ALGORITHM_T -#cmakedefine HAVE_FLTK_DEAD_KEYS #cmakedefine HAVE_FLTK_CLIPBOARD #cmakedefine HAVE_FLTK_MEDIAKEYS #cmakedefine HAVE_FLTK_FULLSCREEN diff --git a/contrib/fltk/01-str2599-fltk-1.3.x-keyboard-x11.patch b/contrib/fltk/01-str2599-fltk-1.3.x-keyboard-x11.patch deleted file mode 100644 index cabc0f1c..00000000 --- a/contrib/fltk/01-str2599-fltk-1.3.x-keyboard-x11.patch +++ /dev/null @@ -1,286 +0,0 @@ -diff -ur fltk-1.3.0r9619.org/FL/Fl_Widget.H fltk-1.3.0r9619/FL/Fl_Widget.H ---- fltk-1.3.0r9619.org/FL/Fl_Widget.H 2012-04-23 22:12:06.000000000 +0200 -+++ fltk-1.3.0r9619/FL/Fl_Widget.H 2012-06-18 13:46:07.302320825 +0200 -@@ -171,6 +171,7 @@ - GROUP_RELATIVE = 1<<16, ///< position this widget relative to the parent group, not to the window - COPIED_TOOLTIP = 1<<17, ///< the widget tooltip is internally copied, its destruction is handled by the widget - FULLSCREEN = 1<<18, ///< a fullscreen window (Fl_Window) -+ SIMPLE_KEYBOARD = 1<<19, ///< the widget wants simple, consistent keypresses and not advanced input (like character composition and CJK input) - // (space for more flags) - USERFLAG3 = 1<<29, ///< reserved for 3rd party extensions - USERFLAG2 = 1<<30, ///< reserved for 3rd party extensions -@@ -776,6 +777,35 @@ - */ - void clear_changed() {flags_ &= ~CHANGED;} - -+ /** -+ Returns if the widget sees a simplified keyboard model or not. -+ -+ Normally widgets get a full-featured keyboard model that is geared -+ towards text input. This includes support for compose sequences and -+ advanced input methods, commonly used for asian writing system. This -+ system however has downsides in that extra graphic can be presented -+ to the user and that a physical key press doesn't correspond directly -+ to a FLTK event. -+ -+ Widgets that need a direct correspondence between actual key events -+ and those seen by the widget can swith to the simplified keyboard -+ model. -+ -+ \retval 0 if the widget uses the normal keyboard model -+ \see set_changed(), clear_changed() -+ */ -+ unsigned int simple_keyboard() const {return flags_&SIMPLE_KEYBOARD;} -+ -+ /** Marks a widget to use the simple keyboard model. -+ \see changed(), clear_changed() -+ */ -+ void set_simple_keyboard() {flags_ |= SIMPLE_KEYBOARD;} -+ -+ /** Marks a widget to use the normal keyboard model. -+ \see changed(), set_changed() -+ */ -+ void set_normal_keyboard() {flags_ &= ~SIMPLE_KEYBOARD;} -+ - /** Gives the widget the keyboard focus. - Tries to make this widget be the Fl::focus() widget, by first sending - it an FL_FOCUS event, and if it returns non-zero, setting -diff -ur fltk-1.3.0r9619.org/src/Fl.cxx fltk-1.3.0r9619/src/Fl.cxx ---- fltk-1.3.0r9619.org/src/Fl.cxx 2012-03-23 17:47:53.000000000 +0100 -+++ fltk-1.3.0r9619/src/Fl.cxx 2012-06-18 13:46:07.303320877 +0200 -@@ -70,6 +70,8 @@ - extern double fl_mac_flush_and_wait(double time_to_wait, char in_idle); - #endif // WIN32 - -+extern void fl_update_focus(void); -+ - // - // Globals... - // -@@ -876,6 +878,8 @@ - fl_oldfocus = p; - } - e_number = old_event; -+ // let the platform code do what it needs -+ fl_update_focus(); - } - } - -diff -ur fltk-1.3.0r9619.org/src/Fl_grab.cxx fltk-1.3.0r9619/src/Fl_grab.cxx ---- fltk-1.3.0r9619.org/src/Fl_grab.cxx 2012-03-23 17:47:53.000000000 +0100 -+++ fltk-1.3.0r9619/src/Fl_grab.cxx 2012-06-18 13:46:07.303320877 +0200 -@@ -29,6 +29,7 @@ - // override_redirect, it does similar things on WIN32. - - extern void fl_fix_focus(); // in Fl.cxx -+void fl_update_focus(void); - - #ifdef WIN32 - // We have to keep track of whether we have captured the mouse, since -@@ -80,6 +81,7 @@ - #endif - } - grab_ = win; -+ fl_update_focus(); - } else { - if (grab_) { - #ifdef WIN32 -@@ -98,6 +100,7 @@ - XFlush(fl_display); - #endif - grab_ = 0; -+ fl_update_focus(); - fl_fix_focus(); - } - } -diff -ur fltk-1.3.0r9619.org/src/Fl_x.cxx fltk-1.3.0r9619/src/Fl_x.cxx ---- fltk-1.3.0r9619.org/src/Fl_x.cxx 2012-06-18 13:46:07.205316173 +0200 -+++ fltk-1.3.0r9619/src/Fl_x.cxx 2012-06-18 13:46:18.216844629 +0200 -@@ -298,6 +298,7 @@ - Colormap fl_colormap; - XIM fl_xim_im = 0; - XIC fl_xim_ic = 0; -+Window fl_xim_win = 0; - char fl_is_over_the_spot = 0; - static XRectangle status_area; - -@@ -583,6 +584,65 @@ - if(xim_styles) XFree(xim_styles); - } - -+void fl_xim_deactivate(void); -+ -+void fl_xim_activate(Window xid) -+{ -+ if (!fl_xim_im) -+ return; -+ -+ // If the focused window has changed, then use the brute force method -+ // of completely recreating the input context. -+ if (fl_xim_win != xid) { -+ fl_xim_deactivate(); -+ -+ fl_new_ic(); -+ fl_xim_win = xid; -+ -+ XSetICValues(fl_xim_ic, -+ XNFocusWindow, fl_xim_win, -+ XNClientWindow, fl_xim_win, -+ NULL); -+ } -+ -+ fl_set_spot(spotf, spots, spot.x, spot.y, spot.width, spot.height); -+} -+ -+void fl_xim_deactivate(void) -+{ -+ if (!fl_xim_ic) -+ return; -+ -+ XDestroyIC(fl_xim_ic); -+ fl_xim_ic = NULL; -+ -+ fl_xim_win = 0; -+} -+ -+extern Fl_Window *fl_xfocus; -+ -+void fl_update_focus(void) -+{ -+ Fl_Widget *focus; -+ -+ focus = Fl::grab(); -+ if (!focus) -+ focus = Fl::focus(); -+ if (!focus) -+ return; -+ -+ if (focus->simple_keyboard()) { -+ fl_xim_deactivate(); -+ } else { -+ // fl_xfocus should always be set if something has focus, but let's -+ // play it safe -+ if (!fl_xfocus || !fl_xid(fl_xfocus)) -+ return; -+ -+ fl_xim_activate(fl_xid(fl_xfocus)); -+ } -+} -+ - void fl_open_display() { - if (fl_display) return; - -@@ -917,10 +977,9 @@ - XEvent xevent = thisevent; - fl_xevent = &thisevent; - Window xid = xevent.xany.window; -- static Window xim_win = 0; - - if (fl_xim_ic && xevent.type == DestroyNotify && -- xid != xim_win && !fl_find(xid)) -+ xid != fl_xim_win && !fl_find(xid)) - { - XIM xim_im; - xim_im = XOpenIM(fl_display, NULL, NULL, NULL); -@@ -935,48 +994,10 @@ - return 0; - } - -- if (fl_xim_ic && (xevent.type == FocusIn)) -- { --#define POOR_XIM --#ifdef POOR_XIM -- if (xim_win != xid) -- { -- xim_win = xid; -- XDestroyIC(fl_xim_ic); -- fl_xim_ic = NULL; -- fl_new_ic(); -- XSetICValues(fl_xim_ic, -- XNFocusWindow, xevent.xclient.window, -- XNClientWindow, xid, -- NULL); -- } -- fl_set_spot(spotf, spots, spot.x, spot.y, spot.width, spot.height); --#else -- if (Fl::first_window() && Fl::first_window()->modal()) { -- Window x = fl_xid(Fl::first_window()); -- if (x != xim_win) { -- xim_win = x; -- XSetICValues(fl_xim_ic, -- XNFocusWindow, xim_win, -- XNClientWindow, xim_win, -- NULL); -- fl_set_spot(spotf, spots, spot.x, spot.y, spot.width, spot.height); -- } -- } else if (xim_win != xid && xid) { -- xim_win = xid; -- XSetICValues(fl_xim_ic, -- XNFocusWindow, xevent.xclient.window, -- XNClientWindow, xid, -- //XNFocusWindow, xim_win, -- //XNClientWindow, xim_win, -- NULL); -- fl_set_spot(spotf, spots, spot.x, spot.y, spot.width, spot.height); -- } --#endif -+ if (fl_xim_ic) { -+ if (XFilterEvent((XEvent *)&xevent, 0)) -+ return 1; - } -- -- if ( XFilterEvent((XEvent *)&xevent, 0) ) -- return(1); - - #if USE_XRANDR - if( XRRUpdateConfiguration_f && xevent.type == randrEventBase + RRScreenChangeNotify) { -@@ -1326,15 +1347,15 @@ - //static XComposeStatus compose; - len = XLookupString((XKeyEvent*)&(xevent.xkey), - buffer, buffer_len, &keysym, 0/*&compose*/); -- if (keysym && keysym < 0x400) { // a character in latin-1,2,3,4 sets -- // force it to type a character (not sure if this ever is needed): -- // if (!len) {buffer[0] = char(keysym); len = 1;} -- len = fl_utf8encode(XKeysymToUcs(keysym), buffer); -- if (len < 1) len = 1; -- // ignore all effects of shift on the keysyms, which makes it a lot -- // easier to program shortcuts and is Windoze-compatible: -- keysym = XKeycodeToKeysym(fl_display, keycode, 0); -- } -+ // XLookupString() is only defined to return Latin-1 (although it -+ // often gives you more). To be safe, use our own lookups based on -+ // keysym. -+ len = fl_utf8encode(XKeysymToUcs(keysym), buffer); -+ if (len < 1) -+ len = 1; -+ // ignore all effects of shift on the keysyms, which makes it a lot -+ // easier to program shortcuts and is Windoze-compatable: -+ keysym = XKeycodeToKeysym(fl_display, keycode, 0); - } - // MRS: Can't use Fl::event_state(FL_CTRL) since the state is not - // set until set_event_xy() is called later... -diff -ur fltk-1.3.0r9619.org/src/xutf8/imKStoUCS.c fltk-1.3.0r9619/src/xutf8/imKStoUCS.c ---- fltk-1.3.0r9619.org/src/xutf8/imKStoUCS.c 2009-03-13 23:43:43.000000000 +0100 -+++ fltk-1.3.0r9619/src/xutf8/imKStoUCS.c 2012-06-18 13:46:07.304320930 +0200 -@@ -266,6 +266,12 @@ - 0x20a8, 0x20a9, 0x20aa, 0x20ab, 0x20ac /* 0x20a8-0x20af */ - }; - -+static unsigned short const keysym_to_unicode_fe50_fe60[] = { -+ 0x0300, 0x0301, 0x0302, 0x0303, 0x0304, 0x0306, 0x0307, 0x0308, /* 0xfe50-0xfe57 */ -+ 0x030a, 0x030b, 0x030c, 0x0327, 0x0328, 0x1da5, 0x3099, 0x309a, /* 0xfe58-0xfe5f */ -+ 0x0323 /* 0xfe60-0xfe67 */ -+}; -+ - unsigned int - KeySymToUcs4(KeySym keysym) - { -@@ -315,6 +321,8 @@ - return keysym_to_unicode_1e9f_1eff[keysym - 0x1e9f]; - else if (keysym > 0x209f && keysym < 0x20ad) - return keysym_to_unicode_20a0_20ac[keysym - 0x20a0]; -+ else if (keysym > 0xfe4f && keysym < 0xfe61) -+ return keysym_to_unicode_fe50_fe60[keysym - 0xfe50]; - else - return 0; - } diff --git a/contrib/fltk/04-str2636-fltk-1.3.x-clipboard.patch b/contrib/fltk/01-str2636-fltk-1.3.x-clipboard.patch similarity index 100% rename from contrib/fltk/04-str2636-fltk-1.3.x-clipboard.patch rename to contrib/fltk/01-str2636-fltk-1.3.x-clipboard.patch diff --git a/contrib/fltk/02-str2599-fltk-1.3.x-keyboard-win32.patch b/contrib/fltk/02-str2599-fltk-1.3.x-keyboard-win32.patch deleted file mode 100644 index c29d3b97..00000000 --- a/contrib/fltk/02-str2599-fltk-1.3.x-keyboard-win32.patch +++ /dev/null @@ -1,256 +0,0 @@ -diff -ur fltk-1.3.0r9293.org/src/Fl_win32.cxx fltk-1.3.0r9293/src/Fl_win32.cxx ---- fltk-1.3.0r9293.org/src/Fl_win32.cxx 2012-06-18 09:07:56.522314557 +0200 -+++ fltk-1.3.0r9293/src/Fl_win32.cxx 2012-06-18 09:08:07.392836285 +0200 -@@ -87,6 +87,8 @@ - static Fl_Display_Device fl_gdi_display(&fl_gdi_driver); - Fl_Display_Device *Fl_Display_Device::_display = &fl_gdi_display; // the platform display - -+bool use_simple_keyboard = false; -+ - // dynamic wsock dll handling api: - #if defined(__CYGWIN__) && !defined(SOCKET) - # define SOCKET int -@@ -120,6 +122,8 @@ - * size and link dependencies. - */ - static HMODULE s_imm_module = 0; -+typedef BOOL (WINAPI* flTypeImmAssociateContextEx)(HWND, HIMC, DWORD); -+static flTypeImmAssociateContextEx flImmAssociateContextEx = 0; - typedef HIMC (WINAPI* flTypeImmGetContext)(HWND); - static flTypeImmGetContext flImmGetContext = 0; - typedef BOOL (WINAPI* flTypeImmSetCompositionWindow)(HIMC, LPCOMPOSITIONFORM); -@@ -135,6 +139,7 @@ - if (!s_imm_module) - Fl::fatal("FLTK Lib Error: IMM32.DLL file not found!\n\n" - "Please check your input method manager library accessibility."); -+ flImmAssociateContextEx = (flTypeImmAssociateContextEx)GetProcAddress(s_imm_module, "ImmAssociateContextEx"); - flImmGetContext = (flTypeImmGetContext)GetProcAddress(s_imm_module, "ImmGetContext"); - flImmSetCompositionWindow = (flTypeImmSetCompositionWindow)GetProcAddress(s_imm_module, "ImmSetCompositionWindow"); - flImmReleaseContext = (flTypeImmReleaseContext)GetProcAddress(s_imm_module, "ImmReleaseContext"); -@@ -413,7 +418,12 @@ - } - } - -- TranslateMessage(&fl_msg); -+ // Don't bother with key to character translation as we do -+ // it manually for simpley keyboard widgets. In fact, calling -+ // TranslateMessage() just makes it more difficult as it sets -+ // a bunch of internal state. -+ if (!use_simple_keyboard) -+ TranslateMessage(&fl_msg); - DispatchMessageW(&fl_msg); - have_message = PeekMessageW(&fl_msg, NULL, 0, 0, PM_REMOVE); - } -@@ -638,6 +648,49 @@ - } - } - -+void fl_update_focus(void) -+{ -+ Fl_Widget *focus; -+ Fl_Window *win; -+ -+ get_imm_module(); -+ -+ focus = Fl::grab(); -+ if (!focus) -+ focus = Fl::focus(); -+ if (!focus) -+ return; -+ -+ // Grabs are special in that events are sent to the first -+ // available window -+ if (focus == Fl::grab()) -+ win = Fl::first_window(); -+ else { -+ win = focus->as_window(); -+ if (!win) -+ win = focus->window(); -+ } -+ -+ if (!win) { -+ Fl::warning("Cannot find window for widget receiving focus"); -+ return; -+ } -+ -+ // No Win32 window created yet -+ if (!Fl_X::i(win) || !fl_xid(win)) -+ return; -+ -+ if (focus->simple_keyboard()) { -+ use_simple_keyboard = true; -+ if (flImmGetContext(fl_xid(win)) != 0) -+ flImmAssociateContextEx(fl_xid(win), 0, 0); -+ } else { -+ use_simple_keyboard = false; -+ if (flImmGetContext(fl_xid(win)) == 0) -+ flImmAssociateContextEx(fl_xid(win), 0, IACE_DEFAULT); -+ } -+} -+ - HWND fl_capture; - - static int mouse_event(Fl_Window *window, int what, int button, -@@ -785,6 +838,27 @@ - return extended ? extendedlut[vk] : vklut[vk]; - } - -+static xchar msdead2fltk(xchar in) -+{ -+ switch (in) { -+ case 0x0060: // GRAVE ACCENT -+ return 0x0300; // COMBINING GRAVE ACCENT -+ case 0x00b4: // ACUTE ACCENT -+ return 0x0301; // COMBINING ACUTE ACCENT -+ case 0x005e: // CIRCUMFLEX ACCENT -+ return 0x0302; // COMBINING CIRCUMFLEX ACCENT -+ case 0x007e: // TILDE -+ return 0x0303; // COMBINING TILDE -+ case 0x00a8: // DIAERESIS -+ return 0x0308; // COMBINING DIAERESIS -+ // FIXME: Windows dead key behaviour isn't documented and I don't have -+ // any more keyboards to test with... -+ } -+ -+ // hope that Windows gave us something proper to begin with -+ return in; -+} -+ - #if USE_COLORMAP - extern HPALETTE fl_select_palette(void); // in fl_color_win32.cxx - #endif -@@ -846,6 +920,8 @@ - //fl_msg.pt = ??? - //fl_msg.lPrivate = ??? - -+ MSG fl_orig_msg = fl_msg; -+ - Fl_Window *window = fl_find(hWnd); - - if (window) switch (uMsg) { -@@ -1025,23 +1101,82 @@ - if (GetKeyState(VK_SCROLL)) state |= FL_SCROLL_LOCK; - Fl::e_state = state; - static char buffer[1024]; -- if (uMsg == WM_CHAR || uMsg == WM_SYSCHAR) { - -+ if (use_simple_keyboard) { -+ BYTE keystate[256]; -+ WCHAR wbuf[8]; -+ int ret; -+ -+ // I'm not sure if we ever get WM_CHAR (& friends) without an initial -+ // WM_KEYDOWN (& friends), but if we do then we should not send such -+ // side band events to simple keyboard widgets. -+ if ((fl_orig_msg.message != WM_KEYDOWN) && -+ (fl_orig_msg.message != WM_SYSKEYDOWN) && -+ (fl_orig_msg.message != WM_KEYUP) && -+ (fl_orig_msg.message != WM_SYSKEYUP)) -+ break; -+ -+ GetKeyboardState(keystate); -+ -+ // Pressing Ctrl wreaks havoc with the symbol lookup, so turn that off. -+ // But AltGr shows up as Ctrl+Alt in Windows, so keep Ctrl if Alt is -+ // active. -+ if (!(keystate[VK_MENU] & 0x80)) -+ keystate[VK_CONTROL] = keystate[VK_LCONTROL] = keystate[VK_RCONTROL] = 0; -+ -+ // We cannot inspect or modify Windows' internal state of the keyboard -+ // so we have to try to infer information from ToUnicode() and wedge -+ // things into a known state. -+ for (int i = 0;i < 2;i++) { -+ ret = ToUnicode(fl_orig_msg.wParam, 0, keystate, wbuf, -+ sizeof(wbuf)/sizeof(wbuf[0]), 0); -+ -+ // No symbol for this key (or unexpected length) -+ if ((ret == 0) || (ret < -1)) { -+ buffer[0] = 0; -+ Fl::e_length = 0; -+ break; -+ } -+ -+ // A dead key. Convert this to a Unicode combining character so -+ // that the application can tell the difference between dead and -+ // normal keys. -+ if (ret == -1) { -+ xchar u = (xchar) msdead2fltk(wbuf[0]); -+ Fl::e_length = fl_utf8fromwc(buffer, 1024, &u, 1); -+ buffer[Fl::e_length] = 0; -+ break; -+ } -+ -+ // If we have two characters (or more) from ToUnicode(), that's -+ // an invalid sequence. One character chould mean a proper symbol, -+ // or it could mean a composed one. In both cases we need to call -+ // ToUnicode() again to get something sane. -+ if (i == 0) -+ continue; -+ -+ // We should now have something sane. Give whatever we have to the -+ // application. -+ Fl::e_length = fl_utf8fromwc(buffer, 1024, wbuf, ret); -+ buffer[Fl::e_length] = 0; -+ } -+ } else if (uMsg == WM_CHAR || uMsg == WM_SYSCHAR) { - xchar u = (xchar) wParam; - // Fl::e_length = fl_unicode2utf(&u, 1, buffer); - Fl::e_length = fl_utf8fromwc(buffer, 1024, &u, 1); - buffer[Fl::e_length] = 0; -+ } else { -+ buffer[0] = 0; -+ Fl::e_length = 0; -+ } - -- -- } else if (Fl::e_keysym >= FL_KP && Fl::e_keysym <= FL_KP_Last) { -- if (state & FL_NUM_LOCK) { -- // Convert to regular keypress... -- buffer[0] = Fl::e_keysym-FL_KP; -- Fl::e_length = 1; -- } else { -- // Convert to special keypress... -- buffer[0] = 0; -- Fl::e_length = 0; -+ // The keypad area is a bit odd in that we need to change the keysym -+ // to properly indicate what the user meant, unlike other keys where -+ // we normally change the text and keep keysym stable. -+ if (Fl::e_keysym >= FL_KP && Fl::e_keysym <= FL_KP_Last) { -+ // The initial mapping tables give us a keysym that corresponds to -+ // numlock being on, so we only do something when it is off. -+ if (!(state & FL_NUM_LOCK)) { - switch (Fl::e_keysym) { - case FL_KP + '0' : - Fl::e_keysym = FL_Insert; -@@ -1073,30 +1208,10 @@ - case FL_KP + '.' : - Fl::e_keysym = FL_Delete; - break; -- case FL_KP + '/' : -- case FL_KP + '*' : -- case FL_KP + '-' : -- case FL_KP + '+' : -- buffer[0] = Fl::e_keysym-FL_KP; -- Fl::e_length = 1; -- break; - } - } -- } else if ((lParam & (1<<31))==0) { --#ifdef FLTK_PREVIEW_DEAD_KEYS -- if ((lParam & (1<<24))==0) { // clear if dead key (always?) -- xchar u = (xchar) wParam; -- Fl::e_length = fl_utf8fromwc(buffer, 1024, &u, 1); -- buffer[Fl::e_length] = 0; -- } else { // set if "extended key" (never printable?) -- buffer[0] = 0; -- Fl::e_length = 0; -- } --#else -- buffer[0] = 0; -- Fl::e_length = 0; --#endif - } -+ - Fl::e_text = buffer; - if (lParam & (1<<31)) { // key up events. - if (Fl::handle(FL_KEYUP, window)) return 0; diff --git a/contrib/fltk/05-str2636-fltk-1.3.x-clipboard-x11.patch b/contrib/fltk/02-str2636-fltk-1.3.x-clipboard-x11.patch similarity index 100% rename from contrib/fltk/05-str2636-fltk-1.3.x-clipboard-x11.patch rename to contrib/fltk/02-str2636-fltk-1.3.x-clipboard-x11.patch diff --git a/contrib/fltk/03-str2599-fltk-1.3.x-keyboard-osx.patch b/contrib/fltk/03-str2599-fltk-1.3.x-keyboard-osx.patch deleted file mode 100644 index cf13aad7..00000000 --- a/contrib/fltk/03-str2599-fltk-1.3.x-keyboard-osx.patch +++ /dev/null @@ -1,375 +0,0 @@ -diff -ur fltk-1.3.0r9619.org/configure.in fltk-1.3.0r9619/configure.in ---- fltk-1.3.0r9619.org/configure.in 2012-04-22 04:45:09.000000000 +0200 -+++ fltk-1.3.0r9619/configure.in 2012-06-18 13:47:33.290447462 +0200 -@@ -865,6 +865,8 @@ - Darwin*) - # MacOS X uses Cocoa for graphics. - LIBS="$LIBS -framework Cocoa" -+ # And some Carbon for keyboard handling -+ LIBS="$LIBS -framework Carbon" - - if test x$have_pthread = xyes; then - AC_DEFINE(HAVE_PTHREAD) -diff -ur fltk-1.3.0r9619.org/src/Fl_cocoa.mm fltk-1.3.0r9619/src/Fl_cocoa.mm ---- fltk-1.3.0r9619.org/src/Fl_cocoa.mm 2012-06-16 10:49:52.000000000 +0200 -+++ fltk-1.3.0r9619/src/Fl_cocoa.mm 2012-06-18 13:47:42.944910782 +0200 -@@ -53,6 +53,7 @@ - #include - - #import -+#import - - #ifndef NSINTEGER_DEFINED // appears with 10.5 in NSObjCRuntime.h - #if defined(__LP64__) && __LP64__ -@@ -114,6 +115,8 @@ - extern Fl_Window* fl_xmousewin; - #endif - -+bool use_simple_keyboard = false; -+ - enum { FLTKTimerEvent = 1, FLTKDataReadyEvent }; - - -@@ -130,6 +133,39 @@ - { - } - -+// Undocumented voodoo. Taken from Mozilla. -+#define ENABLE_ROMAN_KYBDS_ONLY -23 -+ -+void fl_update_focus(void) -+{ -+ Fl_Widget *focus; -+ -+ focus = Fl::grab(); -+ if (!focus) -+ focus = Fl::focus(); -+ if (!focus) -+ return; -+ -+ if (focus->simple_keyboard()) -+ use_simple_keyboard = true; -+ else -+ use_simple_keyboard = false; -+ -+ // Force a "Roman" or "ASCII" keyboard, which both the Mozilla and -+ // Safari people seem to think implies turning off advanced IME stuff -+ // (see nsTSMManager::SyncKeyScript in Mozilla and enableSecureTextInput -+ // in Safari/Webcore). Should be good enough for us then... -+#if (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5) -+ CFArrayRef inputSources = TISCreateASCIICapableInputSourceList(); -+ TSMSetDocumentProperty(TSMGetActiveDocument(), -+ kTSMDocumentEnabledInputSourcesPropertyTag, -+ sizeof(CFArrayRef), &inputSources); -+ CFRelease(inputSources); -+#else -+ KeyScript(use_simple_keyboard ? ENABLE_ROMAN_KYBDS_ONLY : smKeyEnableKybds); -+#endif -+} -+ - /* - * Mac keyboard lookup table - */ -@@ -908,6 +944,25 @@ - } - @end - -+static const char* cocoaDead2FLTK(const char *in) -+{ -+ if (strcmp(in, "\140") == 0) // GRAVE ACCENT -+ return "\314\200"; // COMBINING GRAVE ACCENT -+ if (strcmp(in, "\302\264") == 0) // ACUTE ACCENT -+ return "\314\201"; // COMBINING ACUTE ACCENT -+ if (strcmp(in, "\136") == 0) // CIRCUMFLEX ACCENT -+ return "\314\202"; // COMBINING CIRCUMFLEX ACCENT -+ if (strcmp(in, "\176") == 0) // TILDE -+ return "\314\203"; // COMBINING TILDE -+ if (strcmp(in, "\302\250") == 0) // DIAERESIS -+ return "\314\210"; // COMBINING DIAERESIS -+ // FIXME: OS X dead key behaviour isn't documented and I don't have -+ // any more keyboards to test with... -+ -+ // hope that OS X gave us something proper to begin with -+ return in; -+} -+ - /* - Handle cocoa keyboard events - Events during a character composition sequence: -@@ -1648,6 +1703,7 @@ - - (void)rightMouseDragged:(NSEvent *)theEvent; - - (void)otherMouseDragged:(NSEvent *)theEvent; - - (void)scrollWheel:(NSEvent *)theEvent; -++ (NSString *)keyTranslate:(UInt16)keyCode withModifierFlags:(UInt32)modifierFlags; - - (BOOL)handleKeyDown:(NSEvent *)theEvent; - - (void)keyDown:(NSEvent *)theEvent; - - (void)keyUp:(NSEvent *)theEvent; -@@ -1726,6 +1782,130 @@ - - (void)scrollWheel:(NSEvent *)theEvent { - cocoaMouseWheelHandler(theEvent); - } -++ (NSString *)keyTranslate:(UInt16)keyCode withModifierFlags:(UInt32)modifierFlags { -+ const UCKeyboardLayout *layout; -+ OSStatus err; -+ -+ layout = NULL; -+ -+#if (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5) -+ TISInputSourceRef keyboard; -+ CFDataRef uchr; -+ -+ keyboard = TISCopyCurrentKeyboardInputSource(); -+ uchr = (CFDataRef)TISGetInputSourceProperty(keyboard, -+ kTISPropertyUnicodeKeyLayoutData); -+ if (uchr == NULL) -+ return nil; -+ -+ layout = (const UCKeyboardLayout*)CFDataGetBytePtr(uchr); -+#else -+ KeyboardLayoutRef old_layout; -+ int kind; -+ -+ err = KLGetCurrentKeyboardLayout(&old_layout); -+ if (err != noErr) -+ return nil; -+ -+ err = KLGetKeyboardLayoutProperty(old_layout, kKLKind, -+ (const void**)&kind); -+ if (err != noErr) -+ return nil; -+ -+ // Old, crufty layout format? -+ if (kind == kKLKCHRKind) { -+ void *kchr_layout; -+ -+ UInt32 chars, state; -+ char buf[3]; -+ -+ unichar result[16]; -+ ByteCount in_len, out_len; -+ -+ err = KLGetKeyboardLayoutProperty(old_layout, kKLKCHRData, -+ (const void**)&kchr_layout); -+ if (err != noErr) -+ return nil; -+ -+ state = 0; -+ -+ keyCode &= 0x7f; -+ modifierFlags &= 0xff00; -+ -+ chars = KeyTranslate(kchr_layout, keyCode | modifierFlags, &state); -+ -+ buf[0] = (chars >> 16) & 0xff; -+ buf[1] = chars & 0xff; -+ buf[2] = '\0'; -+ -+ if (buf[0] == '\0') { -+ buf[0] = buf[1]; -+ buf[1] = '\0'; -+ } -+ -+ // The data is now in some layout specific encoding. Need to convert -+ // this to unicode. -+ -+ ScriptCode script; -+ TextEncoding encoding; -+ TECObjectRef converter; -+ -+ script = (ScriptCode)GetScriptManagerVariable(smKeyScript); -+ -+ err = UpgradeScriptInfoToTextEncoding(script, kTextLanguageDontCare, -+ kTextRegionDontCare, NULL, -+ &encoding); -+ if (err != noErr) -+ return nil; -+ -+ err = TECCreateConverter(&converter, encoding, kTextEncodingUnicodeV4_0); -+ if (err != noErr) -+ return nil; -+ -+ in_len = strlen(buf); -+ out_len = sizeof(result); -+ -+ err = TECConvertText(converter, (ConstTextPtr)buf, in_len, &in_len, -+ (TextPtr)result, out_len, &out_len); -+ -+ TECDisposeConverter(converter); -+ -+ if (err != noErr) -+ return nil; -+ -+ return [NSString stringWithCharacters:result -+ length:(out_len / sizeof(unichar))]; -+ } -+ -+ if ((kind != kKLKCHRuchrKind) && (kind != kKLuchrKind)) -+ return nil; -+ -+ err = KLGetKeyboardLayoutProperty(old_layout, kKLuchrData, -+ (const void**)&layout); -+ if (err != noErr) -+ return nil; -+#endif -+ -+ if (layout == NULL) -+ return nil; -+ -+ UInt32 dead_state; -+ UniCharCount max_len, actual_len; -+ UniChar string[255]; -+ -+ dead_state = 0; -+ max_len = sizeof(string)/sizeof(*string); -+ -+ modifierFlags = (modifierFlags >> 8) & 0xff; -+ -+ err = UCKeyTranslate(layout, keyCode, kUCKeyActionDown, modifierFlags, -+ LMGetKbdType(), 0, &dead_state, max_len, &actual_len, -+ string); -+ if (err != noErr) -+ return nil; -+ -+ return [NSString stringWithCharacters:string length:actual_len]; -+} - - (BOOL)handleKeyDown:(NSEvent *)theEvent { - //NSLog(@"handleKeyDown"); - fl_lock_function(); -@@ -1752,14 +1932,47 @@ - break; - } - } -- if (!no_text_key && !(Fl::e_state & FL_META) ) { -- // Don't send cmd- to interpretKeyEvents because it beeps. -+ if (!no_text_key) { -+ // The simple keyboard model will ignore insertText, so we need to grab -+ // the symbol directly from the event. Note that we still use setMarkedText. -+ if (use_simple_keyboard) { -+ NSString *simple_chars; -+ UInt32 modifiers; -+ -+ // We want a "normal" symbol out of the event, which basically means -+ // we only respect the shift and alt/altgr modifiers. Cocoa can help -+ // us if we only wanted shift, but as we also want alt/altgr, we'll -+ // have to do some lookup ourselves. This matches our behaviour on -+ // other platforms. -+ -+ modifiers = 0; -+ if ([theEvent modifierFlags] & NSAlphaShiftKeyMask) -+ modifiers |= alphaLock; -+ if ([theEvent modifierFlags] & NSShiftKeyMask) -+ modifiers |= shiftKey; -+ if ([theEvent modifierFlags] & NSAlternateKeyMask) -+ modifiers |= optionKey; -+ -+ simple_chars = [FLView keyTranslate:[theEvent keyCode] -+ withModifierFlags:modifiers]; -+ if (simple_chars == nil) { -+ // Something went wrong. Fall back to what Cocoa gave us... -+ simple_chars = [theEvent charactersIgnoringModifiers]; -+ } -+ -+ [FLView prepareEtext:simple_chars]; -+ } -+ - // Then we can let the OS have a stab at it and see if it thinks it - // should result in some text -- NSText *edit = [[theEvent window] fieldEditor:YES forObject:nil]; -- in_key_event = true; -- [edit interpretKeyEvents:[NSArray arrayWithObject:theEvent]]; -- in_key_event = false; -+ -+ // Don't send cmd- to interpretKeyEvents because it beeps. -+ if (!(Fl::e_state & FL_META)) { -+ NSText *edit = [[theEvent window] fieldEditor:YES forObject:nil]; -+ in_key_event = true; -+ [edit interpretKeyEvents:[NSArray arrayWithObject:theEvent]]; -+ in_key_event = false; -+ } - } - //NSLog(@"to text=%@ l=%d", [NSString stringWithUTF8String:Fl::e_text], Fl::e_length); - int handled = Fl::handle(FL_KEYDOWN, window); -@@ -1937,21 +2150,30 @@ - //NSLog(@"insertText: received=%@",received); - - if (!in_key_event) fl_lock_function(); -+ -+ // Simple keyboard widgets do not want these side channel inputs. -+ if (use_simple_keyboard) -+ goto end; -+ - [FLView prepareEtext:received]; -+ - // We can get called outside of key events (e.g. from the character -- // palette). Transform such actions to FL_PASTE events. -+ // palette). We need to fake our own key event at that point. - if (!in_key_event) { - Fl_Window *target = [(FLWindow*)[self window] getFl_Window]; -- Fl::handle(FL_PASTE, target); -+ Fl::e_keysym = Fl::e_original_keysym = 0; -+ Fl::handle(FL_KEYDOWN, target); - // for some reason, the window does not redraw until the next mouse move or button push - // sending a 'redraw()' or 'awake()' does not solve the issue! - Fl::flush(); - } -+ -+end: - if (!in_key_event) fl_unlock_function(); - } - - - (void)setMarkedText:(id)aString selectedRange:(NSRange)newSelection { -- NSString *received; -+ NSString *received, *current, *aggregate; - if (newSelection.location == 0) { - [self unmarkText]; - return; -@@ -1962,11 +2184,47 @@ - received = (NSString*)aString; - } - //NSLog(@"setMarkedText: %@ %d %d",received,newSelection.location,newSelection.length); -+ -+ fl_lock_function(); -+ -+ // Simple keyboard widgets generally do not want these side channel -+ // inputs, but we have no other way of getting dead keys so we make -+ // an exception in that case. -+ if (use_simple_keyboard) { -+ if (in_key_event && (Fl::e_length == 0)) { -+ [FLView prepareEtext:received]; -+ -+ Fl::e_text = (char*)cocoaDead2FLTK(Fl::e_text); -+ Fl::e_length = strlen(Fl::e_text); -+ } -+ goto end; -+ } -+ - // This code creates the OS X behaviour of seeing dead keys as things - // are being composed. -+ // -+ // Note: The concatenation thing is because of how OS X deals with -+ // invalid sequences. At that point it will spit out one call -+ // to insertText with the now aborted sequence, and one new -+ // call to setMarkedText with the new sequence. Since we want -+ // both to be visible, we need to concatenate. - next_compose_length = newSelection.location; -- [FLView prepareEtext:received]; -- //NSLog(@"Fl::e_text=%@ Fl::e_length=%d next_compose_length=%d", received, Fl::e_length, next_compose_length); -+ current = [NSString stringWithUTF8String:Fl::e_text]; -+ aggregate = [current stringByAppendingString:received]; -+ -+ [FLView prepareEtext:aggregate]; -+ //NSLog(@"Fl::e_text=%@ Fl::e_length=%d next_compose_length=%d", aggregate, Fl::e_length, next_compose_length); -+ -+ // We can get called outside of key events (e.g. from the character -+ // palette). We need to fake our own key event at that point. -+ if (!in_key_event) { -+ Fl_Window *target = [(FLWindow*)[self window] getFl_Window]; -+ Fl::e_keysym = Fl::e_original_keysym = 0; -+ Fl::handle(FL_KEYDOWN, target); -+ } -+ -+end: -+ fl_unlock_function(); - } - - - (void)unmarkText { diff --git a/contrib/fltk/06-str2636-fltk-1.3.x-clipboard-win32-fix.patch b/contrib/fltk/03-str2636-fltk-1.3.x-clipboard-win32-fix.patch similarity index 100% rename from contrib/fltk/06-str2636-fltk-1.3.x-clipboard-win32-fix.patch rename to contrib/fltk/03-str2636-fltk-1.3.x-clipboard-win32-fix.patch diff --git a/contrib/fltk/07-str2636-fltk-1.3.x-clipboard-win32.patch b/contrib/fltk/04-str2636-fltk-1.3.x-clipboard-win32.patch similarity index 100% rename from contrib/fltk/07-str2636-fltk-1.3.x-clipboard-win32.patch rename to contrib/fltk/04-str2636-fltk-1.3.x-clipboard-win32.patch diff --git a/contrib/fltk/08-str2636-fltk-1.3.x-clipboard-osx.patch b/contrib/fltk/05-str2636-fltk-1.3.x-clipboard-osx.patch similarity index 100% rename from contrib/fltk/08-str2636-fltk-1.3.x-clipboard-osx.patch rename to contrib/fltk/05-str2636-fltk-1.3.x-clipboard-osx.patch diff --git a/contrib/fltk/09-str2659-pixmap.patch b/contrib/fltk/06-str2659-pixmap.patch similarity index 100% rename from contrib/fltk/09-str2659-pixmap.patch rename to contrib/fltk/06-str2659-pixmap.patch diff --git a/contrib/fltk/10-str2660-fltk-1.3.x-cursor.patch b/contrib/fltk/07-str2660-fltk-1.3.x-cursor.patch similarity index 100% rename from contrib/fltk/10-str2660-fltk-1.3.x-cursor.patch rename to contrib/fltk/07-str2660-fltk-1.3.x-cursor.patch diff --git a/contrib/fltk/11-str2802-fltk-1.3.0-modal.patch b/contrib/fltk/08-str2802-fltk-1.3.0-modal.patch similarity index 100% rename from contrib/fltk/11-str2802-fltk-1.3.0-modal.patch rename to contrib/fltk/08-str2802-fltk-1.3.0-modal.patch diff --git a/contrib/fltk/12-str2816-fltk-1.3.0-icons.patch b/contrib/fltk/09-str2816-fltk-1.3.0-icons.patch similarity index 100% rename from contrib/fltk/12-str2816-fltk-1.3.0-icons.patch rename to contrib/fltk/09-str2816-fltk-1.3.0-icons.patch diff --git a/contrib/fltk/13-str2860-fltk-1.3.x-screen_num.patch b/contrib/fltk/10-str2860-fltk-1.3.x-screen_num.patch similarity index 100% rename from contrib/fltk/13-str2860-fltk-1.3.x-screen_num.patch rename to contrib/fltk/10-str2860-fltk-1.3.x-screen_num.patch diff --git a/contrib/fltk/14-str2860-fltk-1.3.x-multihead.patch b/contrib/fltk/11-str2860-fltk-1.3.x-multihead.patch similarity index 100% rename from contrib/fltk/14-str2860-fltk-1.3.x-multihead.patch rename to contrib/fltk/11-str2860-fltk-1.3.x-multihead.patch diff --git a/vncviewer/Viewport.cxx b/vncviewer/Viewport.cxx index 7d551682..2209fe58 100644 --- a/vncviewer/Viewport.cxx +++ b/vncviewer/Viewport.cxx @@ -86,16 +86,14 @@ enum { ID_EXIT, ID_FULLSCREEN, ID_RESIZE, ID_CTRL, ID_ALT, ID_MENUKEY, ID_CTRLALTDEL, ID_REFRESH, ID_OPTIONS, ID_INFO, ID_ABOUT, ID_DISMISS }; +// Fake key presses use this value and above +static const int fakeKeyBase = 0x200; + 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), cursor(NULL), menuCtrlKey(false), menuAltKey(false) { -// FLTK STR #2599 must be fixed for proper dead keys support -#ifdef HAVE_FLTK_DEAD_KEYS - set_simple_keyboard(); -#endif - // FLTK STR #2636 gives us the ability to monitor clipboard changes #ifdef HAVE_FLTK_CLIPBOARD Fl::add_clipboard_notify(handleClipboardChange, this); @@ -399,26 +397,15 @@ int Viewport::handle(int event) // Release all keys that were pressed as that generally makes most // sense (e.g. Alt+Tab where we only see the Alt press) while (!downKeySym.empty()) - handleKeyEvent(downKeySym.begin()->first, downKeySym.begin()->first, - "", false); + handleKeyRelease(downKeySym.begin()->first); return 1; case FL_KEYDOWN: - if (menuKeyCode && (Fl::event_key() == menuKeyCode)) { - popupContextMenu(); - return 1; - } - - handleKeyEvent(Fl::event_key(), Fl::event_original_key(), - Fl::event_text(), true); + handleFLTKKeyPress(); return 1; case FL_KEYUP: - if (menuKeyCode && (Fl::event_key() == menuKeyCode)) - return 1; - - handleKeyEvent(Fl::event_key(), Fl::event_original_key(), - Fl::event_text(), false); + handleKeyRelease(Fl::event_original_key()); return 1; } @@ -495,9 +482,156 @@ void Viewport::handlePointerTimeout(void *data) } -rdr::U32 Viewport::translateKeyEvent(int keyCode, int origKeyCode, const char *keyText) +void Viewport::handleKeyPress(int keyCode, rdr::U32 keySym) +{ + static bool menuRecursion = false; + + // Prevent recursion if the menu wants to send its own + // activation key. + if (menuKeySym && (keySym == menuKeySym) && !menuRecursion) { + menuRecursion = true; + popupContextMenu(); + menuRecursion = false; + return; + } + + if (viewOnly) + 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: + case XK_Alt_R: + keySym = XK_ISO_Level3_Shift; + break; + } +#endif + +#ifdef WIN32 + // Ugly hack alert! + // + // Windows doesn't have a proper AltGr, but handles it using fake + // Ctrl+Alt. Unfortunately X11 doesn't generally like the combination + // Ctrl+Alt+AltGr, which we usually end up with when Xvnc tries to + // get everything in the correct state. Cheat and temporarily release + // Ctrl and Alt when we send some other symbol. + bool ctrlPressed, altPressed; + DownMap::iterator iter; + + ctrlPressed = false; + altPressed = false; + for (iter = downKeySym.begin();iter != downKeySym.end();++iter) { + if (iter->second == XK_Control_L) + ctrlPressed = true; + else if (iter->second == XK_Alt_R) + altPressed = true; + } + + if (ctrlPressed && altPressed) { + vlog.debug("Faking release of AltGr (Ctrl_L+Alt_R)"); + try { + cc->writer()->keyEvent(XK_Control_L, false); + cc->writer()->keyEvent(XK_Alt_R, false); + } catch (rdr::Exception& e) { + vlog.error("%s", e.str()); + exit_vncviewer(e.str()); + } + } +#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. + downKeySym[keyCode] = keySym; + +#if defined(WIN32) || defined(__APPLE__) + vlog.debug("Key pressed: 0x%04x => 0x%04x", keyCode, keySym); +#else + vlog.debug("Key pressed: 0x%04x => XK_%s (0x%04x)", + keyCode, XKeysymToString(keySym), keySym); +#endif + + try { + cc->writer()->keyEvent(keySym, true); + } catch (rdr::Exception& e) { + vlog.error("%s", e.str()); + exit_vncviewer(e.str()); + } + +#ifdef WIN32 + // Ugly hack continued... + if (ctrlPressed && altPressed) { + vlog.debug("Restoring AltGr state"); + try { + cc->writer()->keyEvent(XK_Control_L, true); + cc->writer()->keyEvent(XK_Alt_R, true); + } catch (rdr::Exception& e) { + vlog.error("%s", e.str()); + exit_vncviewer(e.str()); + } + } +#endif +} + + +void Viewport::handleKeyRelease(int keyCode) +{ + DownMap::iterator iter; + + if (viewOnly) + return; + + iter = downKeySym.find(keyCode); + if (iter == downKeySym.end()) { + // These occur somewhat frequently so let's not spam them unless + // logging is turned up. + vlog.debug("Unexpected release of key code %d", keyCode); + return; + } + +#if defined(WIN32) || defined(__APPLE__) + vlog.debug("Key released: 0x%04x => 0x%04x", keyCode, iter->second); +#else + vlog.debug("Key released: 0x%04x => XK_%s (0x%04x)", + keyCode, XKeysymToString(iter->second), iter->second); +#endif + + try { + cc->writer()->keyEvent(iter->second, false); + } catch (rdr::Exception& e) { + vlog.error("%s", e.str()); + exit_vncviewer(e.str()); + } + + downKeySym.erase(iter); +} + + +rdr::U32 Viewport::translateKeyEvent(void) { unsigned ucs; + int keyCode, origKeyCode; + const char *keyText; + int keyTextLen; + + keyCode = Fl::event_key(); + origKeyCode = Fl::event_original_key(); + keyText = Fl::event_text(); + keyTextLen = Fl::event_length(); + + vlog.debug("FLTK key %d (%d) '%s'[%d]", origKeyCode, keyCode, keyText, keyTextLen); // First check for function keys if ((keyCode > FL_F) && (keyCode <= FL_F_Last)) @@ -541,23 +675,6 @@ rdr::U32 Viewport::translateKeyEvent(int keyCode, int origKeyCode, const char *k } } -#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 (keyCode) { - case FL_Meta_L: - return XK_Alt_L; - case FL_Meta_R: - return XK_Super_L; - case FL_Alt_L: - case FL_Alt_R: - return XK_ISO_Level3_Shift; - } -#endif - #if defined(WIN32) || defined(__APPLE__) // X11 fairly consistently uses XK_KP_Separator for comma and // XK_KP_Decimal for period. Windows and OS X are a different matter @@ -722,113 +839,15 @@ rdr::U32 Viewport::translateKeyEvent(int keyCode, int origKeyCode, const char *k } -void Viewport::handleKeyEvent(int keyCode, int origKeyCode, const char *keyText, bool down) +void Viewport::handleFLTKKeyPress(void) { rdr::U32 keySym; - if (viewOnly) - 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. - if (!down) { - DownMap::iterator iter; - - iter = downKeySym.find(origKeyCode); - if (iter == downKeySym.end()) { - vlog.error(_("Unexpected release of FLTK key code %d (0x%04x)"), - origKeyCode, origKeyCode); - return; - } - - vlog.debug("Key released: 0x%04x => 0x%04x", origKeyCode, iter->second); - - try { - cc->writer()->keyEvent(iter->second, false); - } catch (rdr::Exception& e) { - vlog.error("%s", e.str()); - exit_vncviewer(e.str()); - } - - downKeySym.erase(iter); - - return; - } - - keySym = translateKeyEvent(keyCode, origKeyCode, keyText); + keySym = translateKeyEvent(); if (keySym == NoSymbol) return; -#ifdef WIN32 - // Ugly hack alert! - // - // Windows doesn't have a proper AltGr, but handles it using fake - // Ctrl+Alt. Unfortunately X11 doesn't generally like the combination - // Ctrl+Alt+AltGr, which we usually end up with when Xvnc tries to - // get everything in the correct state. Cheat and temporarily release - // Ctrl and Alt whenever we get a key with a symbol. - bool need_cheat = true; - - if (keyText[0] == '\0') - need_cheat = false; - else if ((downKeySym.find(FL_Control_L) == downKeySym.end()) && - (downKeySym.find(FL_Control_R) == downKeySym.end())) - need_cheat = false; - else if ((downKeySym.find(FL_Alt_L) == downKeySym.end()) && - (downKeySym.find(FL_Alt_R) == downKeySym.end())) - need_cheat = false; - - if (need_cheat) { - vlog.debug("Faking release of AltGr (Ctrl+Alt)"); - try { - if (downKeySym.find(FL_Control_L) != downKeySym.end()) - cc->writer()->keyEvent(XK_Control_L, false); - if (downKeySym.find(FL_Control_R) != downKeySym.end()) - cc->writer()->keyEvent(XK_Control_R, false); - if (downKeySym.find(FL_Alt_L) != downKeySym.end()) - cc->writer()->keyEvent(XK_Alt_L, false); - if (downKeySym.find(FL_Alt_R) != downKeySym.end()) - cc->writer()->keyEvent(XK_Alt_R, false); - } catch (rdr::Exception& e) { - vlog.error("%s", e.str()); - exit_vncviewer(e.str()); - } - } -#endif - - vlog.debug("Key pressed: 0x%04x (0x%04x) '%s' => 0x%04x", - origKeyCode, keyCode, keyText, keySym); - - downKeySym[origKeyCode] = keySym; - - try { - cc->writer()->keyEvent(keySym, down); - } catch (rdr::Exception& e) { - vlog.error("%s", e.str()); - exit_vncviewer(e.str()); - } - -#ifdef WIN32 - // Ugly hack continued... - if (need_cheat) { - vlog.debug("Restoring AltGr state"); - try { - if (downKeySym.find(FL_Control_L) != downKeySym.end()) - cc->writer()->keyEvent(XK_Control_L, true); - if (downKeySym.find(FL_Control_R) != downKeySym.end()) - cc->writer()->keyEvent(XK_Control_R, true); - if (downKeySym.find(FL_Alt_L) != downKeySym.end()) - cc->writer()->keyEvent(XK_Alt_L, true); - if (downKeySym.find(FL_Alt_R) != downKeySym.end()) - cc->writer()->keyEvent(XK_Alt_R, true); - } catch (rdr::Exception& e) { - vlog.error(e.str()); - exit_vncviewer(e.str()); - } - } -#endif + handleKeyPress(Fl::event_original_key(), keySym); } @@ -853,7 +872,7 @@ void Viewport::initContextMenu() contextMenu->add(_("Alt"), 0, NULL, (void*)ID_ALT, FL_MENU_TOGGLE | (menuAltKey?FL_MENU_VALUE:0)); - if (menuKeyCode) { + if (menuKeySym) { char sendMenuKey[64]; snprintf(sendMenuKey, 64, _("Send %s"), (const char *)menuKey); contextMenu->add(sendMenuKey, 0, NULL, (void*)ID_MENUKEY, 0); @@ -922,25 +941,31 @@ void Viewport::popupContextMenu() window()->size(w(), h()); break; case ID_CTRL: - handleKeyEvent(FL_Control_L, FL_Control_L, "", m->value()); + if (m->value()) + handleKeyPress(fakeKeyBase + 0, XK_Control_L); + else + handleKeyRelease(fakeKeyBase + 0); menuCtrlKey = !menuCtrlKey; break; case ID_ALT: - handleKeyEvent(FL_Alt_L, FL_Alt_L, "", m->value()); + if (m->value()) + handleKeyPress(fakeKeyBase + 1, XK_Alt_L); + else + handleKeyRelease(fakeKeyBase + 1); menuAltKey = !menuAltKey; break; case ID_MENUKEY: - handleKeyEvent(menuKeyCode, menuKeyCode, "", true); - handleKeyEvent(menuKeyCode, menuKeyCode, "", false); + handleKeyPress(fakeKeyBase + 2, menuKeySym); + handleKeyRelease(fakeKeyBase + 2); break; case ID_CTRLALTDEL: - handleKeyEvent(FL_Control_L, FL_Control_L, "", true); - handleKeyEvent(FL_Alt_L, FL_Alt_L, "", true); - handleKeyEvent(FL_Delete, FL_Delete, "", true); + handleKeyPress(fakeKeyBase + 3, XK_Control_L); + handleKeyPress(fakeKeyBase + 4, XK_Alt_L); + handleKeyPress(fakeKeyBase + 5, XK_Delete); - handleKeyEvent(FL_Delete, FL_Delete, "", false); - handleKeyEvent(FL_Alt_L, FL_Alt_L, "", false); - handleKeyEvent(FL_Control_L, FL_Control_L, "", false); + handleKeyRelease(fakeKeyBase + 5); + handleKeyRelease(fakeKeyBase + 4); + handleKeyRelease(fakeKeyBase + 3); break; case ID_REFRESH: cc->refreshFramebuffer(); @@ -966,7 +991,7 @@ void Viewport::popupContextMenu() void Viewport::setMenuKey() { - menuKeyCode = getMenuKeyCode(); + getMenuKey(&menuKeyCode, &menuKeySym); } diff --git a/vncviewer/Viewport.h b/vncviewer/Viewport.h index 0523cd14..d9eea353 100644 --- a/vncviewer/Viewport.h +++ b/vncviewer/Viewport.h @@ -70,8 +70,11 @@ private: void handlePointerEvent(const rfb::Point& pos, int buttonMask); static void handlePointerTimeout(void *data); - rdr::U32 translateKeyEvent(int keyCode, int origKeyCode, const char *keyText); - void handleKeyEvent(int keyCode, int origKeyCode, const char *keyText, bool down); + void handleKeyPress(int keyCode, rdr::U32 keySym); + void handleKeyRelease(int keyCode); + + rdr::U32 translateKeyEvent(void); + void handleFLTKKeyPress(void); void initContextMenu(); void popupContextMenu(); @@ -91,6 +94,7 @@ private: typedef std::map DownMap; DownMap downKeySym; + rdr::U32 menuKeySym; int menuKeyCode; Fl_Menu_Button *contextMenu; diff --git a/vncviewer/menukey.cxx b/vncviewer/menukey.cxx index 2e3a568a..9c52f5e7 100644 --- a/vncviewer/menukey.cxx +++ b/vncviewer/menukey.cxx @@ -20,31 +20,37 @@ #include #include +// FLTK can pull in the X11 headers on some systems +#ifndef XK_VoidSymbol +#define XK_MISCELLANY +#include +#endif + #include "menukey.h" #include "parameters.h" static const MenuKeySymbol menuSymbols[] = { - {"F1", FL_F + 1}, - {"F2", FL_F + 2}, - {"F3", FL_F + 3}, - {"F4", FL_F + 4}, - {"F5", FL_F + 5}, - {"F6", FL_F + 6}, - {"F7", FL_F + 7}, - {"F8", FL_F + 8}, - {"F9", FL_F + 9}, - {"F10", FL_F + 10}, - {"F11", FL_F + 11}, - {"F12", FL_F + 12}, - {"Pause", FL_Pause}, - {"Print", FL_Print}, - {"Scroll_Lock", FL_Scroll_Lock}, - {"Escape", FL_Escape}, - {"Insert", FL_Insert}, - {"Delete", FL_Delete}, - {"Home", FL_Home}, - {"Page_Up", FL_Page_Up}, - {"Page_Down", FL_Page_Down}, + {"F1", FL_F + 1, XK_F1}, + {"F2", FL_F + 2, XK_F2}, + {"F3", FL_F + 3, XK_F3}, + {"F4", FL_F + 4, XK_F4}, + {"F5", FL_F + 5, XK_F5}, + {"F6", FL_F + 6, XK_F6}, + {"F7", FL_F + 7, XK_F7}, + {"F8", FL_F + 8, XK_F8}, + {"F9", FL_F + 9, XK_F9}, + {"F10", FL_F + 10, XK_F10}, + {"F11", FL_F + 11, XK_F11}, + {"F12", FL_F + 12, XK_F12}, + {"Pause", FL_Pause, XK_Pause}, + {"Print", FL_Print, XK_Print}, + {"Scroll_Lock", FL_Scroll_Lock, XK_Scroll_Lock}, + {"Escape", FL_Escape, XK_Escape}, + {"Insert", FL_Insert, XK_Insert}, + {"Delete", FL_Delete, XK_Delete}, + {"Home", FL_Home, XK_Home}, + {"Page_Up", FL_Page_Up, XK_Page_Up}, + {"Page_Down", FL_Page_Down, XK_Page_Down}, }; int getMenuKeySymbolCount() @@ -57,15 +63,19 @@ const MenuKeySymbol* getMenuKeySymbols() return menuSymbols; } -int getMenuKeyCode() +void getMenuKey(int *keycode, rdr::U32 *keysym) { - const char *menuKeyStr; - int menuKeyCode = 0; + const char *menuKeyStr; - menuKeyStr = menuKey; - for(int i = 0; i < getMenuKeySymbolCount(); i++) - if (!strcmp(menuSymbols[i].name, menuKeyStr)) - menuKeyCode = menuSymbols[i].keycode; + menuKeyStr = menuKey; + for(int i = 0; i < getMenuKeySymbolCount(); i++) { + if (!strcmp(menuSymbols[i].name, menuKeyStr)) { + *keycode = menuSymbols[i].keycode; + *keysym = menuSymbols[i].keysym; + return; + } + } - return menuKeyCode; + *keycode = 0; + *keysym = 0; } diff --git a/vncviewer/menukey.h b/vncviewer/menukey.h index ecb46ed6..fcc51353 100644 --- a/vncviewer/menukey.h +++ b/vncviewer/menukey.h @@ -18,12 +18,15 @@ #ifndef __KEYSYM_H__ #define __KEYSYM_H__ +#include + typedef struct { const char* name; int keycode; + rdr::U32 keysym; } MenuKeySymbol; -int getMenuKeyCode(); +void getMenuKey(int *keycode, rdr::U32 *keysym); int getMenuKeySymbolCount(); const MenuKeySymbol* getMenuKeySymbols(); -- 2.39.5