summaryrefslogtreecommitdiffstats
path: root/java/com/tigervnc/rfb/Keysyms.java
diff options
context:
space:
mode:
Diffstat (limited to 'java/com/tigervnc/rfb/Keysyms.java')
-rw-r--r--java/com/tigervnc/rfb/Keysyms.java291
1 files changed, 260 insertions, 31 deletions
diff --git a/java/com/tigervnc/rfb/Keysyms.java b/java/com/tigervnc/rfb/Keysyms.java
index 4cf17847..e5ece69c 100644
--- a/java/com/tigervnc/rfb/Keysyms.java
+++ b/java/com/tigervnc/rfb/Keysyms.java
@@ -21,14 +21,22 @@
//
// Keysyms - defines X keysyms for non-character keys. All keysyms
// corresponding to characters should be generated by calling
-// UnicodeToKeysym.translate().
+// UnicodeToKeysym.ucs2keysym().
//
package com.tigervnc.rfb;
+import java.awt.event.KeyEvent;
+import com.tigervnc.vncviewer.VncViewer;
+
public class Keysyms {
- public static final int ISO_Level3_Shift = 0xFE03;
+ public static final int VoidSymbol = 0xffffff;
+ /*
+ * TTY Functions, cleverly chosen to map to ascii, for convenience of
+ * programming, but could have been arbitrary (at the cost of lookup
+ * tables in client code.
+ */
public static final int BackSpace = 0xFF08;
public static final int Tab = 0xFF09;
public static final int Linefeed = 0xFF0A;
@@ -40,12 +48,14 @@ public class Keysyms {
public static final int Escape = 0xFF1B;
public static final int Delete = 0xFFFF;
+ /* International & multi-key character composition */
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;
+ /* Japanese keyboard support */
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 */
@@ -67,6 +77,7 @@ public class Keysyms {
public static final int Zen_Koho = 0xFF3D; /* Multiple/All Candidate(s) */
public static final int Mae_Koho = 0xFF3E; /* Previous Candidate */
+ /* Cursor control & motion */
public static final int Home = 0xFF50;
public static final int Left = 0xFF51;
public static final int Up = 0xFF52;
@@ -79,6 +90,7 @@ public class Keysyms {
public static final int End = 0xFF57;
public static final int Begin = 0xFF58;
+ /* Misc Functions */
public static final int Select = 0xFF60;
public static final int Print = 0xFF61;
public static final int Execute = 0xFF62;
@@ -94,6 +106,42 @@ public class Keysyms {
public static final int script_switch = 0xFF7E;
public static final int Num_Lock = 0xFF7F;
+ /* Keypad Functions, keypad numbers cleverly chosen to map to ascii */
+ public static final int KP_Enter = 0xFF8D;
+ public static final int KP_Home = 0xFF95;
+ public static final int KP_Left = 0xFF96;
+ public static final int KP_Up = 0xFF97;
+ public static final int KP_Right = 0xFF98;
+ public static final int KP_Down = 0xFF99;
+ public static final int KP_Page_Up = 0xFF9A;
+ public static final int KP_Page_Down = 0xFF9B;
+ public static final int KP_End = 0xFF9C;
+ public static final int KP_Begin = 0xFF9D;
+ public static final int KP_Insert = 0xFF9E;
+ public static final int KP_Delete = 0xFF9F;
+ public static final int KP_Equal = 0xFFBD;
+ public static final int KP_0 = 0xFFB0;
+ public static final int KP_1 = 0xFFB1;
+ public static final int KP_2 = 0xFFB2;
+ public static final int KP_3 = 0xFFB3;
+ public static final int KP_4 = 0xFFB4;
+ public static final int KP_5 = 0xFFB5;
+ public static final int KP_6 = 0xFFB6;
+ public static final int KP_7 = 0xFFB7;
+ public static final int KP_8 = 0xFFB8;
+ public static final int KP_9 = 0xFFB9;
+ public static final int KP_Decimal = 0xFFAE;
+ public static final int KP_Add = 0xFFAB;
+ public static final int KP_Subtract = 0xFFAD;
+ public static final int KP_Multiply = 0xFFAA;
+ public static final int KP_Divide = 0xFFAF;
+
+ /*
+ * Auxilliary Functions; note the duplicate definitions for left and right
+ * function keys; Sun keyboards and a few other manufactures have such
+ * function key groups on the left and/or right sides of the keyboard.
+ * We've not found a keyboard with more than 35 function keys total.
+ */
public static final int F1 = 0xFFBE;
public static final int F2 = 0xFFBF;
public static final int F3 = 0xFFC0;
@@ -119,43 +167,224 @@ public class Keysyms {
public static final int F23 = 0xFFD4;
public static final int F24 = 0xFFD5;
+ /* Modifiers */
public static final int Shift_L = 0xFFE1;
public static final int Shift_R = 0xFFE2;
public static final int Control_L = 0xFFE3;
public static final int Control_R = 0xFFE4;
+ public static final int Caps_Lock = 0xFFE5;
+ public static final int Shift_Lock = 0xFFE6;
+
public static final int Meta_L = 0xFFE7;
public static final int Meta_R = 0xFFE8;
public static final int Alt_L = 0xFFE9;
public static final int Alt_R = 0xFFEA;
-
public static final int Super_L = 0xFFEB;
- public static final int Caps_Lock = 0xFFE5;
+ public static final int Super_R = 0xFFEC;
+ public static final int Hyper_L = 0xFFED;
+ public static final int Hyper_R = 0xFFEE;
- public static final int KP_Enter = 0xFF8D;
- public static final int KP_Home = 0xFF95;
- public static final int KP_Left = 0xFF96;
- public static final int KP_Up = 0xFF97;
- public static final int KP_Right = 0xFF98;
- public static final int KP_Down = 0xFF99;
- public static final int KP_Page_Up = 0xFF9A;
- public static final int KP_Page_Down = 0xFF9B;
- public static final int KP_End = 0xFF9C;
- public static final int KP_Begin = 0xFF9D;
- public static final int KP_Insert = 0xFF9E;
- public static final int KP_Delete = 0xFF9F;
- public static final int KP_0 = 0xFFB0;
- public static final int KP_1 = 0xFFB1;
- public static final int KP_2 = 0xFFB2;
- public static final int KP_3 = 0xFFB3;
- public static final int KP_4 = 0xFFB4;
- public static final int KP_5 = 0xFFB5;
- public static final int KP_6 = 0xFFB6;
- public static final int KP_7 = 0xFFB7;
- public static final int KP_8 = 0xFFB8;
- public static final int KP_9 = 0xFFB9;
- public static final int KP_Decimal = 0xFFAE;
- public static final int KP_Add = 0xFFAB;
- public static final int KP_Subtract = 0xFFAD;
- public static final int KP_Multiply = 0xFFAA;
- public static final int KP_Divide = 0xFFAF;
+ /*
+ * ISO 9995 Function and Modifier Keys
+ * Byte 3 = 0xFE
+ */
+ public static final int ISO_Level3_Shift = 0xFE03;
+
+ /*
+ * Dead Modifier Keys
+ */
+ public static final int Dead_Grave = 0xfe50; /* COMBINING GRAVE ACCENT */
+ public static final int Dead_Acute = 0xfe51; /* COMBINING ACUTE ACCENT */
+ public static final int Dead_Circumflex = 0xfe52; /* COMBINING CIRCUMFLEX ACCENT */
+ public static final int Dead_Tilde = 0xfe53; /* COMBINING TILDE */
+ public static final int Dead_Macron = 0xfe54; /* COMBINING MACRON */
+ public static final int Dead_Breve = 0xfe55; /* COMBINING BREVE */
+ public static final int Dead_AboveDot = 0xfe56; /* COMBINING DOT ABOVE */
+ public static final int Dead_Diaeresis = 0xfe57; /* COMBINING DIAERESIS */
+ public static final int Dead_AboveRing = 0xfe58; /* COMBINING RING ABOVE */
+ public static final int Dead_DoubleAcute = 0xfe59; /* COMBINING DOUBLE ACUTE ACCENT */
+ public static final int Dead_Caron = 0xfe5a; /* COMBINING CARON */
+ public static final int Dead_Cedilla = 0xfe5b; /* COMBINING CEDILLA */
+ public static final int Dead_Ogonek = 0xfe5c; /* COMBINING OGONEK */
+ public static final int Dead_Iota = 0xfe5d; /* MODIFIER LETTER SMALL IOTA */
+ public static final int Dead_Voiced_Sound = 0xfe5e; /* COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK */
+ public static final int Dead_SemiVoiced_Sound = 0xfe5f; /* COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK */
+ public static final int Dead_BelowDot = 0xfe60; /* COMBINING DOT BELOW */
+
+ private static class KeySymbol {
+ public KeySymbol(int keycode_, int[] keysym_) {
+ keycode = keycode_;
+ keysym = new int[5];
+ System.arraycopy(keysym_, 0, keysym, 0, 5);
+ }
+ int keycode;
+ int[] keysym;
+ }
+
+ private static KeySymbol[] keySymbols = {
+ /* KEYCODE LOCATION */
+ /* UNKNOWN STANDARD LEFT RIGHT NUMPAD */
+ new KeySymbol(KeyEvent.VK_BACK_SPACE, new int[]{VoidSymbol, BackSpace, VoidSymbol, VoidSymbol, VoidSymbol}),
+ new KeySymbol(KeyEvent.VK_TAB, new int[]{VoidSymbol, Tab, VoidSymbol, VoidSymbol, VoidSymbol}),
+ new KeySymbol(KeyEvent.VK_ENTER, new int[]{VoidSymbol, Return, VoidSymbol, VoidSymbol, KP_Enter}),
+ new KeySymbol(KeyEvent.VK_ESCAPE, new int[]{VoidSymbol, Escape, VoidSymbol, VoidSymbol, VoidSymbol}),
+ new KeySymbol(KeyEvent.VK_CONTROL, new int[]{VoidSymbol, Control_L, Control_L, Control_R, VoidSymbol}),
+ new KeySymbol(KeyEvent.VK_ALT_GRAPH, new int[]{VoidSymbol, ISO_Level3_Shift, VoidSymbol, VoidSymbol, VoidSymbol}),
+ new KeySymbol(KeyEvent.VK_ALT, new int[]{VoidSymbol, ISO_Level3_Shift, Alt_L, Alt_R, VoidSymbol}),
+ new KeySymbol(KeyEvent.VK_SHIFT, new int[]{VoidSymbol, Shift_L, Shift_L, Shift_R, VoidSymbol}),
+ new KeySymbol(KeyEvent.VK_META, new int[]{VoidSymbol, Meta_L, Meta_L, Meta_R, VoidSymbol}),
+ new KeySymbol(KeyEvent.VK_NUMPAD0, new int[]{VoidSymbol, VoidSymbol, VoidSymbol, VoidSymbol, KP_0}),
+ new KeySymbol(KeyEvent.VK_NUMPAD1, new int[]{VoidSymbol, VoidSymbol, VoidSymbol, VoidSymbol, KP_1}),
+ new KeySymbol(KeyEvent.VK_NUMPAD2, new int[]{VoidSymbol, VoidSymbol, VoidSymbol, VoidSymbol, KP_2}),
+ new KeySymbol(KeyEvent.VK_NUMPAD3, new int[]{VoidSymbol, VoidSymbol, VoidSymbol, VoidSymbol, KP_3}),
+ new KeySymbol(KeyEvent.VK_NUMPAD4, new int[]{VoidSymbol, VoidSymbol, VoidSymbol, VoidSymbol, KP_4}),
+ new KeySymbol(KeyEvent.VK_NUMPAD5, new int[]{VoidSymbol, VoidSymbol, VoidSymbol, VoidSymbol, KP_5}),
+ new KeySymbol(KeyEvent.VK_NUMPAD6, new int[]{VoidSymbol, VoidSymbol, VoidSymbol, VoidSymbol, KP_6}),
+ new KeySymbol(KeyEvent.VK_NUMPAD7, new int[]{VoidSymbol, VoidSymbol, VoidSymbol, VoidSymbol, KP_7}),
+ new KeySymbol(KeyEvent.VK_NUMPAD8, new int[]{VoidSymbol, VoidSymbol, VoidSymbol, VoidSymbol, KP_8}),
+ new KeySymbol(KeyEvent.VK_NUMPAD9, new int[]{VoidSymbol, VoidSymbol, VoidSymbol, VoidSymbol, KP_9}),
+ new KeySymbol(KeyEvent.VK_DECIMAL, new int[]{VoidSymbol, KP_Decimal, VoidSymbol, VoidSymbol, KP_Decimal}),
+ new KeySymbol(KeyEvent.VK_ADD, new int[]{VoidSymbol, KP_Add, VoidSymbol, VoidSymbol, KP_Add}),
+ new KeySymbol(KeyEvent.VK_SUBTRACT, new int[]{VoidSymbol, KP_Subtract, VoidSymbol, VoidSymbol, KP_Subtract}),
+ new KeySymbol(KeyEvent.VK_MULTIPLY, new int[]{VoidSymbol, KP_Multiply, VoidSymbol, VoidSymbol, KP_Multiply}),
+ new KeySymbol(KeyEvent.VK_DIVIDE, new int[]{VoidSymbol, KP_Divide, VoidSymbol, VoidSymbol, KP_Divide}),
+ new KeySymbol(KeyEvent.VK_DELETE, new int[]{VoidSymbol, Delete, VoidSymbol, VoidSymbol, KP_Delete}),
+ new KeySymbol(KeyEvent.VK_CLEAR, new int[]{VoidSymbol, Clear, VoidSymbol, VoidSymbol, KP_Begin}),
+ new KeySymbol(KeyEvent.VK_HOME, new int[]{VoidSymbol, Home, VoidSymbol, VoidSymbol, KP_Home}),
+ new KeySymbol(KeyEvent.VK_END, new int[]{VoidSymbol, End, VoidSymbol, VoidSymbol, KP_End}),
+ new KeySymbol(KeyEvent.VK_PAGE_UP, new int[]{VoidSymbol, Page_Up, VoidSymbol, VoidSymbol, KP_Page_Up}),
+ new KeySymbol(KeyEvent.VK_PAGE_DOWN, new int[]{VoidSymbol, Page_Down, VoidSymbol, VoidSymbol, KP_Page_Down}),
+ new KeySymbol(KeyEvent.VK_UP, new int[]{VoidSymbol, Up, VoidSymbol, VoidSymbol, KP_Up}),
+ new KeySymbol(KeyEvent.VK_DOWN, new int[]{VoidSymbol, Down, VoidSymbol, VoidSymbol, KP_Down}),
+ new KeySymbol(KeyEvent.VK_LEFT, new int[]{VoidSymbol, Left, VoidSymbol, VoidSymbol, KP_Left}),
+ new KeySymbol(KeyEvent.VK_RIGHT, new int[]{VoidSymbol, Right, VoidSymbol, VoidSymbol, KP_Right}),
+ new KeySymbol(KeyEvent.VK_BEGIN, new int[]{VoidSymbol, Begin, VoidSymbol, VoidSymbol, KP_Begin}),
+ new KeySymbol(KeyEvent.VK_KP_LEFT, new int[]{VoidSymbol, KP_Left, VoidSymbol, VoidSymbol, KP_Left}),
+ new KeySymbol(KeyEvent.VK_KP_UP, new int[]{VoidSymbol, KP_Up, VoidSymbol, VoidSymbol, KP_Up}),
+ new KeySymbol(KeyEvent.VK_KP_RIGHT, new int[]{VoidSymbol, KP_Right, VoidSymbol, VoidSymbol, KP_Right}),
+ new KeySymbol(KeyEvent.VK_KP_DOWN, new int[]{VoidSymbol, KP_Down, VoidSymbol, VoidSymbol, KP_Down}),
+ new KeySymbol(KeyEvent.VK_PRINTSCREEN, new int[]{VoidSymbol, Print, VoidSymbol, VoidSymbol, VoidSymbol}),
+ new KeySymbol(KeyEvent.VK_SCROLL_LOCK, new int[]{VoidSymbol, Scroll_Lock, VoidSymbol, VoidSymbol, VoidSymbol}),
+ new KeySymbol(KeyEvent.VK_CAPS_LOCK, new int[]{VoidSymbol, Caps_Lock, VoidSymbol, VoidSymbol, VoidSymbol}),
+ new KeySymbol(KeyEvent.VK_NUM_LOCK, new int[]{VoidSymbol, Num_Lock, VoidSymbol, VoidSymbol, Num_Lock}),
+ new KeySymbol(KeyEvent.VK_INSERT, new int[]{VoidSymbol, Insert, VoidSymbol, VoidSymbol, KP_Insert}),
+ new KeySymbol(KeyEvent.VK_AGAIN, new int[]{VoidSymbol, Redo, VoidSymbol, VoidSymbol, VoidSymbol}),
+ new KeySymbol(KeyEvent.VK_UNDO, new int[]{VoidSymbol, Undo, VoidSymbol, VoidSymbol, VoidSymbol}),
+ new KeySymbol(KeyEvent.VK_FIND, new int[]{VoidSymbol, Find, VoidSymbol, VoidSymbol, VoidSymbol}),
+ new KeySymbol(KeyEvent.VK_STOP, new int[]{VoidSymbol, Cancel, VoidSymbol, VoidSymbol, VoidSymbol}),
+ new KeySymbol(KeyEvent.VK_HELP, new int[]{VoidSymbol, Help, VoidSymbol, VoidSymbol, VoidSymbol}),
+ new KeySymbol(KeyEvent.VK_WINDOWS, new int[]{VoidSymbol, Super_L, Super_L, Super_R, VoidSymbol}),
+ new KeySymbol(KeyEvent.VK_CONTEXT_MENU, new int[]{VoidSymbol, Menu, VoidSymbol, VoidSymbol, VoidSymbol}),
+ new KeySymbol(KeyEvent.VK_KANJI, new int[]{VoidSymbol, Kanji, VoidSymbol, VoidSymbol, VoidSymbol}),
+ new KeySymbol(KeyEvent.VK_KATAKANA, new int[]{VoidSymbol, Katakana, VoidSymbol, VoidSymbol, VoidSymbol}),
+ new KeySymbol(KeyEvent.VK_HIRAGANA, new int[]{VoidSymbol, Hiragana, VoidSymbol, VoidSymbol, VoidSymbol}),
+ new KeySymbol(KeyEvent.VK_PREVIOUS_CANDIDATE,
+ new int[]{VoidSymbol, PreviousCandidate,VoidSymbol, VoidSymbol, VoidSymbol}),
+ new KeySymbol(KeyEvent.VK_CODE_INPUT, new int[]{VoidSymbol, Codeinput, VoidSymbol, VoidSymbol, VoidSymbol}),
+ new KeySymbol(KeyEvent.VK_JAPANESE_ROMAN,
+ new int[]{VoidSymbol, Romaji, VoidSymbol, VoidSymbol, VoidSymbol}),
+ new KeySymbol(KeyEvent.VK_KANA_LOCK, new int[]{VoidSymbol, Kana_Lock, VoidSymbol, VoidSymbol, VoidSymbol}),
+ new KeySymbol(KeyEvent.VK_DEAD_ABOVEDOT,new int[]{VoidSymbol, Dead_AboveDot, VoidSymbol, VoidSymbol, VoidSymbol}),
+ new KeySymbol(KeyEvent.VK_DEAD_ABOVERING,
+ new int[]{VoidSymbol, Dead_AboveRing, VoidSymbol, VoidSymbol, VoidSymbol}),
+ new KeySymbol(KeyEvent.VK_DEAD_ACUTE, new int[]{VoidSymbol, Dead_Acute, VoidSymbol, VoidSymbol, VoidSymbol}),
+ new KeySymbol(KeyEvent.VK_DEAD_BREVE, new int[]{VoidSymbol, Dead_Breve, VoidSymbol, VoidSymbol, VoidSymbol}),
+ new KeySymbol(KeyEvent.VK_DEAD_CARON, new int[]{VoidSymbol, Dead_Caron, VoidSymbol, VoidSymbol, VoidSymbol}),
+ new KeySymbol(KeyEvent.VK_DEAD_CIRCUMFLEX,
+ new int[]{VoidSymbol, Dead_Circumflex, VoidSymbol, VoidSymbol, VoidSymbol}),
+ new KeySymbol(KeyEvent.VK_DEAD_DIAERESIS,
+ new int[]{VoidSymbol, Dead_Diaeresis, VoidSymbol, VoidSymbol, VoidSymbol}),
+ new KeySymbol(KeyEvent.VK_DEAD_DOUBLEACUTE,
+ new int[]{VoidSymbol, Dead_DoubleAcute, VoidSymbol, VoidSymbol, VoidSymbol}),
+ new KeySymbol(KeyEvent.VK_DEAD_GRAVE, new int[]{VoidSymbol, Dead_Grave, VoidSymbol, VoidSymbol, VoidSymbol}),
+ new KeySymbol(KeyEvent.VK_DEAD_IOTA, new int[]{VoidSymbol, Dead_Iota, VoidSymbol, VoidSymbol, VoidSymbol}),
+ new KeySymbol(KeyEvent.VK_DEAD_MACRON, new int[]{VoidSymbol, Dead_Macron, VoidSymbol, VoidSymbol, VoidSymbol}),
+ new KeySymbol(KeyEvent.VK_DEAD_OGONEK, new int[]{VoidSymbol, Dead_Ogonek, VoidSymbol, VoidSymbol, VoidSymbol}),
+ new KeySymbol(KeyEvent.VK_DEAD_SEMIVOICED_SOUND,
+ new int[]{VoidSymbol, Dead_SemiVoiced_Sound,VoidSymbol, VoidSymbol, VoidSymbol}),
+ new KeySymbol(KeyEvent.VK_DEAD_TILDE, new int[]{VoidSymbol, Dead_Tilde, VoidSymbol, VoidSymbol, VoidSymbol}),
+ new KeySymbol(KeyEvent.VK_DEAD_VOICED_SOUND,
+ new int[]{VoidSymbol, Dead_Voiced_Sound, VoidSymbol, VoidSymbol, VoidSymbol}),
+ };
+
+ public static int translateKeyEvent(KeyEvent ev) {
+ int location = ev.getKeyLocation();
+ int keyCode = ev.getKeyCode();
+
+ // First check for function keys
+ if (keyCode >= KeyEvent.VK_F1 && keyCode <= KeyEvent.VK_F12)
+ return Keysyms.F1 + keyCode - KeyEvent.VK_F1;
+ if (keyCode >= KeyEvent.VK_F13 && keyCode <= KeyEvent.VK_F24)
+ return Keysyms.F13 + keyCode - KeyEvent.VK_F13;
+
+ // Numpad numbers
+ if (keyCode >= KeyEvent.VK_0 && keyCode <= KeyEvent.VK_9 &&
+ location == KeyEvent.KEY_LOCATION_NUMPAD)
+ return Keysyms.KP_0 + keyCode - KeyEvent.VK_0;
+
+ if (VncViewer.os.startsWith("mac os x")) {
+ // 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 KeyEvent.VK_META:
+ if (location == KeyEvent.KEY_LOCATION_LEFT)
+ return Alt_L;
+ else
+ return Super_L;
+ case KeyEvent.VK_ALT:
+ if (location == KeyEvent.KEY_LOCATION_LEFT)
+ return Alt_L;
+ else
+ return ISO_Level3_Shift;
+ }
+ }
+
+ // Then other special keys
+ if (keyCode == KeyEvent.VK_PAUSE)
+ return (ev.isControlDown() ? Break : Pause);
+ else if (keyCode == KeyEvent.VK_PRINTSCREEN)
+ return (ev.isControlDown() ? Sys_Req : Print);
+ else
+ for(int i = 0; i < keySymbols.length; i++)
+ if (keySymbols[i].keycode == keyCode)
+ return (keySymbols[i].keysym)[location];
+
+ // Unknown special key?
+ if (KeyEvent.getKeyText(keyCode).isEmpty()) {
+ vlog.error("Unknown key code:");
+ String fmt = ev.paramString().replaceAll("%","%%");
+ vlog.error(String.format(fmt.replaceAll(",","%n ")));
+ return VoidSymbol;
+ }
+
+ char keyChar = ev.getKeyChar();
+ if (!ev.isControlDown() && keyChar != KeyEvent.CHAR_UNDEFINED)
+ return UnicodeToKeysym.ucs2keysym(Character.toString(keyChar).codePointAt(0));
+
+ int key = keyChar;
+ if (ev.isControlDown()) {
+ // For CTRL-<letter>, CTRL is sent separately, so just send <letter>.
+ if ((key >= 1 && key <= 26 && !ev.isShiftDown()) ||
+ // CTRL-{, CTRL-|, CTRL-} also map to ASCII 96-127
+ (key >= 27 && key <= 29 && ev.isShiftDown()))
+ key += 96;
+ // For CTRL-SHIFT-<letter>, send capital <letter> to emulate behavior
+ // of Linux. For CTRL-@, send @. For CTRL-_, send _. For CTRL-^,
+ // send ^.
+ else if (key < 32)
+ key += 64;
+ // Windows and Mac sometimes return CHAR_UNDEFINED with CTRL-SHIFT
+ // combinations, so best we can do is send the key code if it is
+ // a valid ASCII symbol.
+ else if (ev.getKeyChar() == KeyEvent.CHAR_UNDEFINED && keyCode >= 0 &&
+ keyCode <= 127)
+ key = keyCode;
+ }
+ return UnicodeToKeysym.ucs2keysym(key);
+ }
+
+ static LogWriter vlog = new LogWriter("Keysyms");
}