diff options
author | Brian Hinz <bphinz@users.sourceforge.net> | 2013-03-25 20:58:14 +0000 |
---|---|---|
committer | Brian Hinz <bphinz@users.sourceforge.net> | 2013-03-25 20:58:14 +0000 |
commit | accdd9518674c9c0111dd7263f4d94ecfba2534e (patch) | |
tree | 2efdb018d937b50db0348dc657bd232062970cc6 | |
parent | fc23895f80b6ab8d19add9bd3f18bfd5818e8935 (diff) | |
download | tigervnc-accdd9518674c9c0111dd7263f4d94ecfba2534e.tar.gz tigervnc-accdd9518674c9c0111dd7263f4d94ecfba2534e.zip |
More fixes for key event issues. It seems that on WindowsXP sending the actual key press/release separately can be mis-interpreted by the server as holding the key down. Using a keyTyped event for all character input ensures that we can send an immediate down/up. It also works around the broken AltGr detection in Java 6. Also added support for more keys (F13-F24, etc.). Some key definitions in java don't have X11 equivalents or I could not be sure so I've left them commented out.
git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@5066 3789f03b-4d11-0410-bbf8-ca57d06f2519
-rw-r--r-- | java/com/tigervnc/rfb/Keysyms.java | 40 | ||||
-rw-r--r-- | java/com/tigervnc/vncviewer/CConn.java | 161 | ||||
-rw-r--r-- | java/com/tigervnc/vncviewer/DesktopWindow.java | 15 |
3 files changed, 174 insertions, 42 deletions
diff --git a/java/com/tigervnc/rfb/Keysyms.java b/java/com/tigervnc/rfb/Keysyms.java index 93aea127..4cf17847 100644 --- a/java/com/tigervnc/rfb/Keysyms.java +++ b/java/com/tigervnc/rfb/Keysyms.java @@ -1,5 +1,6 @@ /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. * Copyright (C) 2012-2013 D. R. Commander. All Rights Reserved. + * Copyright (C) 2013 Brian P. Hinz * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,6 +28,7 @@ package com.tigervnc.rfb; public class Keysyms { + public static final int ISO_Level3_Shift = 0xFE03; public static final int BackSpace = 0xFF08; public static final int Tab = 0xFF09; public static final int Linefeed = 0xFF0A; @@ -38,6 +40,33 @@ public class Keysyms { public static final int Escape = 0xFF1B; public static final int Delete = 0xFFFF; + public static final int Multi_key = 0xFF20; /* Multi-key character compose */ + public static final int Codeinput = 0xFF37; + public static final int SingleCandidate = 0xFF3C; + public static final int MultipleCandidate = 0xFF3D; + public static final int PreviousCandidate = 0xFF3E; + + public static final int Kanji = 0xFF21; /* Kanji, Kanji convert */ + public static final int Muhenkan = 0xFF22; /* Cancel Conversion */ + public static final int Henkan_Mode = 0xFF23; /* Start/Stop Conversion */ + public static final int Henkan = 0xFF23; /* Alias for Henkan_Mode */ + public static final int Romaji = 0xFF24; /* to Romaji */ + public static final int Hiragana = 0xFF25; /* to Hiragana */ + public static final int Katakana = 0xFF26; /* to Katakana */ + public static final int Hiragana_Katakana = 0xFF27; /* Hiragana/Katakana toggle */ + public static final int Zenkaku = 0xFF28; /* to Zenkaku */ + public static final int Hankaku = 0xFF29; /* to Hankaku */ + public static final int Zenkaku_Hankaku = 0xFF2A; /* Zenkaku/Hankaku toggle */ + public static final int Touroku = 0xFF2B; /* Add to Dictionary */ + public static final int Massyo = 0xFF2C; /* Delete from Dictionary */ + public static final int Kana_Lock = 0xFF2D; /* Kana Lock */ + public static final int Kana_Shift = 0xFF2E; /* Kana Shift */ + public static final int Eisu_Shift = 0xFF2F; /* Alphanumeric Shift */ + public static final int Eisu_toggle = 0xFF30; /* Alphanumeric toggle */ + public static final int Kanji_Bangou = 0xFF37; /* Codeinput */ + public static final int Zen_Koho = 0xFF3D; /* Multiple/All Candidate(s) */ + public static final int Mae_Koho = 0xFF3E; /* Previous Candidate */ + public static final int Home = 0xFF50; public static final int Left = 0xFF51; public static final int Up = 0xFF52; @@ -78,6 +107,17 @@ public class Keysyms { public static final int F11 = 0xFFC8; public static final int F12 = 0xFFC9; public static final int F13 = 0xFFCA; + public static final int F14 = 0xFFCB; + public static final int F15 = 0xFFCC; + public static final int F16 = 0xFFCD; + public static final int F17 = 0xFFCE; + public static final int F18 = 0xFFCF; + public static final int F19 = 0xFFD0; + public static final int F20 = 0xFFD1; + public static final int F21 = 0xFFD2; + public static final int F22 = 0xFFD3; + public static final int F23 = 0xFFD4; + public static final int F24 = 0xFFD5; public static final int Shift_L = 0xFFE1; public static final int Shift_R = 0xFFE2; diff --git a/java/com/tigervnc/vncviewer/CConn.java b/java/com/tigervnc/vncviewer/CConn.java index 09fa2d78..97ba9da9 100644 --- a/java/com/tigervnc/vncviewer/CConn.java +++ b/java/com/tigervnc/vncviewer/CConn.java @@ -67,6 +67,9 @@ public class CConn extends CConnection new PixelFormat(8, 6, false, true, 3, 3, 3, 4, 2, 0); static final PixelFormat mediumColourPF = new PixelFormat(8, 8, false, false, 7, 7, 3, 0, 3, 6); + static final int KEY_LOC_SHIFT_R = 0; + static final int KEY_LOC_SHIFT_L = 16; + static final int SUPER_MASK = 1<<15; //////////////////////////////////////////////////////////////////// // The following methods are all called from the RFB thread @@ -1154,8 +1157,31 @@ public class CConn extends CConnection writer().writeKeyEvent(keysym, down); } + public void writeKeyEvent(KeyEvent ev, int keysym) { + if (keysym < 0) + return; + String fmt = ev.paramString().replaceAll("%","%%"); + vlog.debug(String.format(fmt.replaceAll(",","%n "))); + // Windows sends an extra CTRL_L + ALT_R when AltGr is down that need to + // be suppressed for keyTyped events. In Java 6 KeyEvent.isAltGraphDown() + // is broken for keyPressed/keyReleased events. + int ALTGR_MASK = ((Event.CTRL_MASK<<KEY_LOC_SHIFT_L) | Event.ALT_MASK); + String os = System.getProperty("os.name"); + if (os.startsWith("Windows") && ((modifiers & ALTGR_MASK) != 0)) { + writeKeyEvent(Keysyms.Control_L, false); + writeKeyEvent(Keysyms.Alt_R, false); + writeKeyEvent(keysym, true); + writeKeyEvent(keysym, false); + writeKeyEvent(Keysyms.Control_L, true); + writeKeyEvent(Keysyms.Alt_R, true); + } else { + writeKeyEvent(keysym, true); + writeKeyEvent(keysym, false); + } + } + public void writeKeyEvent(KeyEvent ev) { - int keysym = 0, keycode, key, location; + int keysym = 0, keycode, key, location, locationShift; if (shuttingDown) return; @@ -1163,11 +1189,14 @@ public class CConn extends CConnection boolean down = (ev.getID() == KeyEvent.KEY_PRESSED); keycode = ev.getKeyCode(); + if (keycode == KeyEvent.VK_UNDEFINED) + return; key = ev.getKeyChar(); location = ev.getKeyLocation(); - - String fmt = ev.paramString().replaceAll("%","%%"); - vlog.debug(String.format(fmt.replaceAll(",","%n "))); + if (location == KeyEvent.KEY_LOCATION_RIGHT) + locationShift = KEY_LOC_SHIFT_R; + else + locationShift = KEY_LOC_SHIFT_L; if (!ev.isActionKey()) { if (keycode >= KeyEvent.VK_0 && keycode <= KeyEvent.VK_9 && @@ -1209,43 +1238,37 @@ public class CConn extends CConnection else keysym = Keysyms.Clear; break; case KeyEvent.VK_CONTROL: - // Suppress CTRL+ALT when AltGr is pressed - if (ev.isAltGraphDown()) - return; if (down) - modifiers |= Event.CTRL_MASK; + modifiers |= (Event.CTRL_MASK<<locationShift); else - modifiers &= ~Event.CTRL_MASK; + modifiers &= ~(Event.CTRL_MASK<<locationShift); if (location == KeyEvent.KEY_LOCATION_RIGHT) keysym = Keysyms.Control_R; else keysym = Keysyms.Control_L; break; case KeyEvent.VK_ALT: - // Suppress CTRL+ALT when AltGr is pressed - if (ev.isAltGraphDown()) - return; if (down) - modifiers |= Event.ALT_MASK; + modifiers |= (Event.ALT_MASK<<locationShift); else - modifiers &= ~Event.ALT_MASK; + modifiers &= ~(Event.ALT_MASK<<locationShift); if (location == KeyEvent.KEY_LOCATION_RIGHT) keysym = Keysyms.Alt_R; else keysym = Keysyms.Alt_L; break; case KeyEvent.VK_SHIFT: if (down) - modifiers |= Event.SHIFT_MASK; + modifiers |= (Event.SHIFT_MASK<<locationShift); else - modifiers &= ~Event.SHIFT_MASK; + modifiers &= ~(Event.SHIFT_MASK<<locationShift); if (location == KeyEvent.KEY_LOCATION_RIGHT) keysym = Keysyms.Shift_R; else keysym = Keysyms.Shift_L; break; case KeyEvent.VK_META: if (down) - modifiers |= Event.META_MASK; + modifiers |= (Event.META_MASK<<locationShift); else - modifiers &= ~Event.META_MASK; + modifiers &= ~(Event.META_MASK<<locationShift); if (location == KeyEvent.KEY_LOCATION_RIGHT) keysym = Keysyms.Meta_R; else @@ -1269,6 +1292,7 @@ public class CConn extends CConnection keycode <= 127) key = keycode; } + keysym = UnicodeToKeysym.translate(key); if (keysym == -1) return; @@ -1316,6 +1340,15 @@ public class CConn extends CConnection keysym = Keysyms.KP_Right; else keysym = Keysyms.Right; break; + case KeyEvent.VK_BEGIN: + if (location == KeyEvent.KEY_LOCATION_NUMPAD) + keysym = Keysyms.KP_Begin; + else + keysym = Keysyms.Begin; break; + case KeyEvent.VK_KP_LEFT: keysym = Keysyms.KP_Left; break; + case KeyEvent.VK_KP_UP: keysym = Keysyms.KP_Up; break; + case KeyEvent.VK_KP_RIGHT: keysym = Keysyms.KP_Right; break; + case KeyEvent.VK_KP_DOWN: keysym = Keysyms.KP_Down; break; case KeyEvent.VK_F1: keysym = Keysyms.F1; break; case KeyEvent.VK_F2: keysym = Keysyms.F2; break; case KeyEvent.VK_F3: keysym = Keysyms.F3; break; @@ -1329,7 +1362,21 @@ public class CConn extends CConnection case KeyEvent.VK_F11: keysym = Keysyms.F11; break; case KeyEvent.VK_F12: keysym = Keysyms.F12; break; case KeyEvent.VK_F13: keysym = Keysyms.F13; break; + case KeyEvent.VK_F14: keysym = Keysyms.F14; break; + case KeyEvent.VK_F15: keysym = Keysyms.F15; break; + case KeyEvent.VK_F16: keysym = Keysyms.F16; break; + case KeyEvent.VK_F17: keysym = Keysyms.F17; break; + case KeyEvent.VK_F18: keysym = Keysyms.F18; break; + case KeyEvent.VK_F19: keysym = Keysyms.F19; break; + case KeyEvent.VK_F20: keysym = Keysyms.F20; break; + case KeyEvent.VK_F21: keysym = Keysyms.F21; break; + case KeyEvent.VK_F22: keysym = Keysyms.F22; break; + case KeyEvent.VK_F23: keysym = Keysyms.F23; break; + case KeyEvent.VK_F24: keysym = Keysyms.F24; break; case KeyEvent.VK_PRINTSCREEN: keysym = Keysyms.Print; break; + case KeyEvent.VK_SCROLL_LOCK: keysym = Keysyms.Scroll_Lock; break; + case KeyEvent.VK_CAPS_LOCK: keysym = Keysyms.Caps_Lock; break; + case KeyEvent.VK_NUM_LOCK: keysym = Keysyms.Num_Lock; break; case KeyEvent.VK_PAUSE: if (ev.isControlDown()) keysym = Keysyms.Break; @@ -1341,27 +1388,55 @@ public class CConn extends CConnection keysym = Keysyms.KP_Insert; else keysym = Keysyms.Insert; break; - case KeyEvent.VK_KP_DOWN: keysym = Keysyms.KP_Down; break; - case KeyEvent.VK_KP_LEFT: keysym = Keysyms.KP_Left; break; - case KeyEvent.VK_KP_RIGHT: keysym = Keysyms.KP_Right; break; - case KeyEvent.VK_KP_UP: keysym = Keysyms.KP_Up; break; - case KeyEvent.VK_NUM_LOCK: keysym = Keysyms.Num_Lock; break; - case KeyEvent.VK_WINDOWS: keysym = Keysyms.Super_L; break; - case KeyEvent.VK_CONTEXT_MENU: keysym = Keysyms.Menu; break; - case KeyEvent.VK_SCROLL_LOCK: keysym = Keysyms.Scroll_Lock; break; - case KeyEvent.VK_CAPS_LOCK: keysym = Keysyms.Caps_Lock; break; - case KeyEvent.VK_BEGIN: - if (location == KeyEvent.KEY_LOCATION_NUMPAD) - keysym = Keysyms.KP_Begin; + // case KeyEvent.VK_FINAL: keysym = Keysyms.?; break; + // case KeyEvent.VK_CONVERT: keysym = Keysyms.?; break; + // case KeyEvent.VK_NONCONVERT: keysym = Keysyms.?; break; + // case KeyEvent.VK_ACCEPT: keysym = Keysyms.?; break; + // case KeyEvent.VK_MODECHANGE: keysym = Keysyms.Mode_switch?; break; + // case KeyEvent.VK_KANA: keysym = Keysyms.Kana_shift?; break; + case KeyEvent.VK_KANJI: keysym = Keysyms.Kanji; break; + // case KeyEvent.VK_ALPHANUMERIC: keysym = Keysyms.Eisu_Shift?; break; + case KeyEvent.VK_KATAKANA: keysym = Keysyms.Katakana; break; + case KeyEvent.VK_HIRAGANA: keysym = Keysyms.Hiragana; break; + // case KeyEvent.VK_FULL_WIDTH: keysym = Keysyms.?; break; + // case KeyEvent.VK_HALF_WIDTH: keysym = Keysyms.?; break; + // case KeyEvent.VK_ROMAN_CHARACTERS: keysym = Keysyms.?; break; + // case KeyEvent.VK_ALL_CANDIDATES: keysym = Keysyms.MultipleCandidate?; break; + case KeyEvent.VK_PREVIOUS_CANDIDATE: keysym = Keysyms.PreviousCandidate; break; + case KeyEvent.VK_CODE_INPUT: keysym = Keysyms.Codeinput; break; + // case KeyEvent.VK_JAPANESE_KATAKANA: keysym = Keysyms.?; break; + // case KeyEvent.VK_JAPANESE_HIRAGANA: keysym = Keysyms.?; break; + case KeyEvent.VK_JAPANESE_ROMAN: keysym = Keysyms.Romaji; break; + case KeyEvent.VK_KANA_LOCK: keysym = Keysyms.Kana_Lock; break; + // case KeyEvent.VK_INPUT_METHOD_ON_OFF: keysym = Keysyms.?; break; + + case KeyEvent.VK_AGAIN: keysym = Keysyms.Redo; break; + case KeyEvent.VK_UNDO: keysym = Keysyms.Undo; break; + // case KeyEvent.VK_COPY: keysym = Keysyms.?; break; + // case KeyEvent.VK_PASTE: keysym = Keysyms.?; break; + // case KeyEvent.VK_CUT: keysym = Keysyms.?; break; + case KeyEvent.VK_FIND: keysym = Keysyms.Find; break; + // case KeyEvent.VK_PROPS: keysym = Keysyms.?; break; + case KeyEvent.VK_STOP: keysym = Keysyms.Cancel; break; + case KeyEvent.VK_HELP: keysym = Keysyms.Help; break; + case KeyEvent.VK_WINDOWS: + if (down) + modifiers |= SUPER_MASK; else - keysym = Keysyms.Begin; break; + modifiers &= ~SUPER_MASK; + keysym = Keysyms.Super_L; break; + case KeyEvent.VK_CONTEXT_MENU: keysym = Keysyms.Menu; break; default: return; } } - writeKeyEvent(keysym, down); - } + if (keysym > 0) { + String fmt = ev.paramString().replaceAll("%","%%"); + vlog.debug(String.format(fmt.replaceAll(",","%n "))); + writeKeyEvent(keysym, down); + } + } public void writePointerEvent(MouseEvent ev) { if (state() != RFBSTATE_NORMAL || shuttingDown) @@ -1390,7 +1465,6 @@ public class CConn extends CConnection writer().writePointerEvent(new Point(ev.getX(), ev.getY()), buttonMask); } - public void writeWheelEvent(MouseWheelEvent ev) { if (state() != RFBSTATE_NORMAL || shuttingDown) return; @@ -1411,16 +1485,25 @@ public class CConn extends CConnection } - synchronized void releaseModifiers() { - if ((modifiers & Event.SHIFT_MASK) != 0) + if ((modifiers & Event.SHIFT_MASK) == Event.SHIFT_MASK) + writeKeyEvent(Keysyms.Shift_R, false); + if (((modifiers>>KEY_LOC_SHIFT_L) & Event.SHIFT_MASK) == Event.SHIFT_MASK) writeKeyEvent(Keysyms.Shift_L, false); - if ((modifiers & Event.CTRL_MASK) != 0) + if ((modifiers & Event.CTRL_MASK) == Event.CTRL_MASK) + writeKeyEvent(Keysyms.Control_R, false); + if (((modifiers>>KEY_LOC_SHIFT_L) & Event.CTRL_MASK) == Event.CTRL_MASK) writeKeyEvent(Keysyms.Control_L, false); - if ((modifiers & Event.ALT_MASK) != 0) + if ((modifiers & Event.ALT_MASK) == Event.ALT_MASK) + writeKeyEvent(Keysyms.Alt_R, false); + if (((modifiers>>KEY_LOC_SHIFT_L) & Event.ALT_MASK) == Event.ALT_MASK) writeKeyEvent(Keysyms.Alt_L, false); - if ((modifiers & Event.META_MASK) != 0) + if ((modifiers & Event.META_MASK) == Event.META_MASK) + writeKeyEvent(Keysyms.Meta_R, false); + if (((modifiers>>KEY_LOC_SHIFT_L) & Event.META_MASK) == Event.META_MASK) writeKeyEvent(Keysyms.Meta_L, false); + if ((modifiers & SUPER_MASK) == SUPER_MASK) + writeKeyEvent(Keysyms.Super_L, false); modifiers = 0; } diff --git a/java/com/tigervnc/vncviewer/DesktopWindow.java b/java/com/tigervnc/vncviewer/DesktopWindow.java index 5f9ee1a3..7621af50 100644 --- a/java/com/tigervnc/vncviewer/DesktopWindow.java +++ b/java/com/tigervnc/vncviewer/DesktopWindow.java @@ -437,12 +437,19 @@ class DesktopWindow extends JPanel implements Runnable, MouseListener, } // Handle the key-typed event. - public void keyTyped(KeyEvent e) {} + public void keyTyped(KeyEvent e) { + int keysym = UnicodeToKeysym.translate(e.getKeyChar()); + if (!cc.viewer.viewOnly.getValue()) + if (!e.isActionKey() && keysym > 0) + cc.writeKeyEvent(e, keysym); + } // Handle the key-released event. public void keyReleased(KeyEvent e) { + int keysym = UnicodeToKeysym.translate(e.getKeyChar()); if (!cc.viewer.viewOnly.getValue()) - cc.writeKeyEvent(e); + if (e.isActionKey() || keysym < 0) + cc.writeKeyEvent(e); } // Handle the key-pressed event. @@ -499,8 +506,10 @@ class DesktopWindow extends JPanel implements Runnable, MouseListener, return; } } + int keysym = UnicodeToKeysym.translate(e.getKeyChar()); if (!cc.viewer.viewOnly.getValue()) - cc.writeKeyEvent(e); + if (e.isActionKey() || keysym < 0) + cc.writeKeyEvent(e); } //////////////////////////////////////////////////////////////////// |