gohook/hook/x11/input_c.h

1978 lines
112 KiB
C
Raw Normal View History

2018-09-18 02:09:59 +08:00
/* Copyright (C) 2006-2017 Alexander Barker.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*/
2017-02-06 16:55:01 +08:00
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#define USE_XKB 0
#define USE_XKBCOMMON 0
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <X11/keysym.h>
#include <X11/Xlib.h>
#ifdef USE_XKB
#ifdef USE_EVDEV
#include <linux/input.h>
static bool is_evdev = false;
#endif
#include <X11/XKBlib.h>
static XkbDescPtr keyboard_map;
#else
#include <X11/Xutil.h>
static KeySym *keyboard_map;
static int keysym_per_keycode;
static bool is_caps_lock = false, is_shift_lock = false;
#endif
#ifdef USE_XKBCOMMON
#include <X11/Xlib-xcb.h>
#include <xkbcommon/xkbcommon.h>
#include <xkbcommon/xkbcommon-x11.h>
#ifdef USE_XKBFILE
#include <X11/extensions/XKBrules.h>
static struct xkb_rule_names xkb_names = {
.rules = "base",
.model = "us",
.layout = "pc105",
.variant = NULL,
.options = NULL
};
#endif
#endif
#include "../logger_c.h"
/* The follwoing two tables are based on QEMU's x_keymap.c, under the following
* terms:
*
* Copyright (C) 2003 Fabrice Bellard <fabrice@bellard.org>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#if defined(USE_EVDEV) && defined(USE_XKB)
/* This table is generated based off the evdev -> scancode mapping above
* and the keycode mappings in the following files:
* /usr/include/linux/input.h
* /usr/share/X11/xkb/keycodes/evdev
*
* NOTE This table only works for Linux.
*/
static const uint16_t evdev_scancode_table[][2] = {
/* idx { keycode, scancode }, idx evdev code */
/* 0 */ { VC_UNDEFINED, 0x00 }, /* 0x00 KEY_RESERVED */
/* 1 */ { VC_UNDEFINED, 0x09 }, /* 0x01 KEY_ESC */
/* 2 */ { VC_UNDEFINED, 0x0A }, /* 0x02 KEY_1 */
/* 3 */ { VC_UNDEFINED, 0x0B }, /* 0x03 KEY_2 */
/* 4 */ { VC_UNDEFINED, 0x0C }, /* 0x04 KEY_3 */
/* 5 */ { VC_UNDEFINED, 0x0D }, /* 0x05 KEY_4 */
/* 6 */ { VC_UNDEFINED, 0x0E }, /* 0x06 KEY_5 */
/* 7 */ { VC_UNDEFINED, 0x0F }, /* 0x07 KEY_6 */
/* 8 */ { VC_UNDEFINED, 0x10 }, /* 0x08 KEY_7 */
/* 9 */ { VC_ESCAPE, 0x11 }, /* 0x09 KEY_8 */
/* 10 */ { VC_1, 0x12 }, /* 0x0A KEY_9 */
/* 11 */ { VC_2, 0x13 }, /* 0x0B KEY_0 */
/* 12 */ { VC_3, 0x14 }, /* 0x0C KEY_MINUS */
/* 13 */ { VC_4, 0x15 }, /* 0x0D KEY_EQUAL */
/* 14 */ { VC_5, 0x16 }, /* 0x0E KEY_BACKSPACE */
/* 15 */ { VC_6, 0x17 }, /* 0x0F KEY_TAB */
/* 16 */ { VC_7, 0x18 }, /* 0x10 KEY_Q */
/* 17 */ { VC_8, 0x19 }, /* 0x11 KEY_W */
/* 18 */ { VC_9, 0x1A }, /* 0x12 KEY_E */
/* 19 */ { VC_0, 0x1B }, /* 0x13 KEY_T */
/* 20 */ { VC_MINUS, 0x1C }, /* 0x14 KEY_R */
/* 21 */ { VC_EQUALS, 0x1D }, /* 0x15 KEY_Y */
/* 22 */ { VC_BACKSPACE, 0x1E }, /* 0x16 KEY_U */
/* 23 */ { VC_TAB, 0x1F }, /* 0x17 KEY_I */
/* 24 */ { VC_Q, 0x20 }, /* 0x18 KEY_O */
/* 25 */ { VC_W, 0x21 }, /* 0x19 KEY_P */
/* 26 */ { VC_E, 0x22 }, /* 0x1A KEY_LEFTBRACE */
/* 27 */ { VC_R, 0x23 }, /* 0x1B KEY_RIGHTBRACE */
/* 28 */ { VC_T, 0x24 }, /* 0x1C KEY_ENTER */
/* 29 */ { VC_Y, 0x25 }, /* 0x1D KEY_LEFTCTRL */
/* 30 */ { VC_U, 0x26 }, /* 0x1E KEY_A */
/* 31 */ { VC_I, 0x27 }, /* 0x1F KEY_S */
/* 32 */ { VC_O, 0x28 }, /* 0x20 KEY_D */
/* 33 */ { VC_P, 0x29 }, /* 0x21 KEY_F */
/* 34 */ { VC_OPEN_BRACKET, 0x2A }, /* 0x22 KEY_G */
/* 35 */ { VC_CLOSE_BRACKET, 0x2B }, /* 0x23 KEY_H */
/* 36 */ { VC_ENTER, 0x2C }, /* 0x24 KEY_J */
/* 37 */ { VC_CONTROL_L, 0x2D }, /* 0x25 KEY_K */
/* 38 */ { VC_A, 0x2E }, /* 0x26 KEY_L */
/* 39 */ { VC_S, 0x2F }, /* 0x27 KEY_SEMICOLON */
/* 40 */ { VC_D, 0x30 }, /* 0x28 KEY_APOSTROPHE */
/* 41 */ { VC_F, 0x31 }, /* 0x29 KEY_GRAVE */
/* 42 */ { VC_G, 0x32 }, /* 0x2A KEY_LEFTSHIFT */
/* 43 */ { VC_H, 0x33 }, /* 0x2B KEY_BACKSLASH */
/* 44 */ { VC_J, 0x34 }, /* 0x2C KEY_Z */
/* 45 */ { VC_K, 0x35 }, /* 0x2D KEY_X */
/* 46 */ { VC_L, 0x36 }, /* 0x2E KEY_C */
/* 47 */ { VC_SEMICOLON, 0x37 }, /* 0x2F KEY_V */
/* 48 */ { VC_QUOTE, 0x38 }, /* 0x30 KEY_B */
/* 49 */ { VC_BACKQUOTE, 0x39 }, /* 0x31 KEY_N */
/* 50 */ { VC_SHIFT_L, 0x3A }, /* 0x32 KEY_M */
/* 51 */ { VC_BACK_SLASH, 0x3B }, /* 0x33 KEY_COMMA */
/* 52 */ { VC_Z, 0x3C }, /* 0x34 KEY_DOT */
/* 53 */ { VC_X, 0x3D }, /* 0x35 KEY_SLASH */
/* 54 */ { VC_C, 0x3E }, /* 0x36 KEY_RIGHTSHIFT */
/* 55 */ { VC_V, 0x3F }, /* 0x37 KEY_KPASTERISK */
/* 56 */ { VC_B, 0x40 }, /* 0x38 KEY_LEFTALT */
/* 57 */ { VC_N, 0x41 }, /* 0x39 KEY_SPACE */
/* 58 */ { VC_M, 0x42 }, /* 0x3A KEY_CAPSLOCK */
/* 59 */ { VC_COMMA, 0x43 }, /* 0x3B KEY_F1 */
/* 60 */ { VC_PERIOD, 0x44 }, /* 0x3C KEY_F2 */
/* 61 */ { VC_SLASH, 0x45 }, /* 0x3D KEY_F3 */
/* 62 */ { VC_SHIFT_R, 0x46 }, /* 0x3E KEY_F4 */
/* 63 */ { VC_KP_MULTIPLY, 0x47 }, /* 0x3F KEY_F5 */
/* 64 */ { VC_ALT_L, 0x48 }, /* 0x40 KEY_F6 */
/* 65 */ { VC_SPACE, 0x49 }, /* 0x41 KEY_F7 */
/* 66 */ { VC_CAPS_LOCK, 0x4A }, /* 0x42 KEY_F8 */
/* 67 */ { VC_F1, 0x4B }, /* 0x43 KEY_F9 */
/* 68 */ { VC_F2, 0x4C }, /* 0x44 KEY_F10 */
/* 69 */ { VC_F3, 0x4D }, /* 0x45 KEY_NUMLOCK */
/* 70 */ { VC_F4, 0x4E }, /* 0x46 KEY_SCROLLLOCK */
/* 71 */ { VC_F5, 0x4F }, /* 0x47 KEY_KP7 */
/* 72 */ { VC_F6, 0x50 }, /* 0x48 KEY_KP8 */
/* 73 */ { VC_F7, 0x51 }, /* 0x49 KEY_KP9 */
/* 74 */ { VC_F8, 0x52 }, /* 0x4A KEY_KPMINUS */
/* 75 */ { VC_F9, 0x53 }, /* 0x4B KEY_KP4 */
/* 76 */ { VC_F10, 0x54 }, /* 0x4C KEY_KP5 */
/* 77 */ { VC_NUM_LOCK, 0x55 }, /* 0x4D KEY_KP6 */
/* 78 */ { VC_SCROLL_LOCK, 0x56 }, /* 0x4E KEY_KPPLUS */
/* 79 */ { VC_KP_7, 0x57 }, /* 0x4F KEY_KP1 */
/* 80 */ { VC_KP_8, 0x58 }, /* 0x50 KEY_KP2 */
/* 81 */ { VC_KP_9, 0x59 }, /* 0x51 KEY_KP3 */
/* 82 */ { VC_KP_SUBTRACT, 0x5A }, /* 0x52 KEY_KP0 */
/* 83 */ { VC_KP_4, 0x5B }, /* 0x53 KEY_KPDOT */
/* 84 */ { VC_KP_5, 0x00 }, /* 0x54 */
/* 85 */ { VC_KP_6, 0x00 }, /* 0x55 TODO [KEY_ZENKAKUHANKAKU][0] == [VC_?][1] */
/* 86 */ { VC_KP_ADD, 0x00 }, /* 0x56 TODO [KEY_102ND][0] == [VC_?][1] */
/* 87 */ { VC_KP_1, 0x5F }, /* 0x57 KEY_F11 */
/* 88 */ { VC_KP_2, 0x60 }, /* 0x58 KEY_F12 */
/* 89 */ { VC_KP_3, 0x00 }, /* 0x59 TODO [KEY_RO][0] == [VC_?][1] */
/* 90 */ { VC_KP_0, 0x00 }, /* 0x5A */
/* 91 */ { VC_KP_SEPARATOR, 0xBF }, /* 0x5B KEY_F13 */
/* 92 */ { VC_UNDEFINED, 0xC0 }, /* 0x5C KEY_F14 */
/* 93 */ { VC_UNDEFINED, 0xC1 }, /* 0x5D KEY_F15 */
/* 94 */ { VC_UNDEFINED, 0x00 }, /* 0x5E TODO [KEY_MUHENKAN][0] == [VC_?][1] */
/* 95 */ { VC_F11, 0x00 }, /* 0x5F */
/* 96 */ { VC_F12, 0x00 }, /* 0x60 */
/* First 97 chars are identical to XFree86! */
/* 97 */ { VC_UNDEFINED, 0x00 }, /* 0x61 */
/* 98 */ { VC_KATAKANA, 0x00 }, /* 0x62 */
/* 99 */ { VC_HIRAGANA, 0xC2 }, /* 0x63 KEY_F16 */
/* 100 */ { VC_KANJI, 0xC3 }, /* 0x64 KEY_F17 */
/* 101 */ { VC_UNDEFINED, 0xC4 }, /* 0x65 KEY_F18 */
/* 102 */ { VC_UNDEFINED, 0xC5 }, /* 0x66 KEY_F19 */
/* 103 */ { VC_KP_COMMA, 0xC6 }, /* 0x67 KEY_F20 */
/* 104 */ { VC_KP_ENTER, 0xC7 }, /* 0x68 KEY_F21 */
/* 105 */ { VC_CONTROL_R, 0xC8 }, /* 0x69 KEY_F22 */
/* 106 */ { VC_KP_DIVIDE, 0xC9 }, /* 0x6A KEY_F23 */
/* 107 */ { VC_PRINTSCREEN, 0xCA }, /* 0x6B KEY_F24 */
/* 108 */ { VC_ALT_R, 0x00 }, /* 0x6C */
/* 109 */ { VC_UNDEFINED, 0x00 }, /* 0x6D */
/* 110 */ { VC_HOME, 0x00 }, /* 0x6E */
/* 111 */ { VC_UP, 0x00 }, /* 0x6F */
/* 112 */ { VC_PAGE_UP, 0x62 }, /* 0x70 KEY_KATAKANA */
/* 113 */ { VC_LEFT, 0x00 }, /* 0x71 */
/* 114 */ { VC_RIGHT, 0x00 }, /* 0x72 */
/* 115 */ { VC_END, 0x00 }, /* 0x73 TODO KEY_? = [VC_UNDERSCORE][1] */
/* 116 */ { VC_DOWN, 0x00 }, /* 0x74 TODO KEY_? = [VC_FURIGANA][1] */
/* 117 */ { VC_PAGE_DOWN, 0x00 }, /* 0x75 */
/* 118 */ { VC_INSERT, 0x00 }, /* 0x76 TODO [KEY_KPPLUSMINUS][0] = [VC_?][1] */
/* 119 */ { VC_DELETE, 0x00 }, /* 0x77 */
/* 120 */ { VC_UNDEFINED, 0x00 }, /* 0x78 TODO [KEY_SCALE][0] = [VC_?][1] */
/* 121 */ { VC_VOLUME_MUTE, 0x64 }, /* 0x79 KEY_HENKAN */
/* 122 */ { VC_VOLUME_DOWN, 0x00 }, /* 0x7A */
/* 123 */ { VC_VOLUME_UP, 0x63 }, /* 0x7B KEY_HIRAGANA */
/* 124 */ { VC_POWER, 0x00 }, /* 0x7C */
/* 125 */ { VC_KP_EQUALS, 0x84 }, /* 0x7D KEY_YEN */
/* 126 */ { VC_UNDEFINED, 0x67 }, /* 0x7E KEY_KPJPCOMMA */
/* 127 */ { VC_PAUSE, 0x00 }, /* 0x7F */
/* No Offset Offset (i & 0x007F) + 128 */
/* 128 */ { VC_UNDEFINED, 0 }, /* 0x80 */
/* 129 */ { VC_UNDEFINED, 0 }, /* 0x81 */
/* 130 */ { VC_UNDEFINED, 0 }, /* 0x82 */
/* 131 */ { VC_UNDEFINED, 0 }, /* 0x83 */
/* 132 */ { VC_YEN, 0 }, /* 0x84 */
/* 133 */ { VC_META_L, 0 }, /* 0x85 */
/* 134 */ { VC_META_R, 0 }, /* 0x86 */
/* 135 */ { VC_CONTEXT_MENU, 0 }, /* 0x87 */
/* 136 */ { VC_SUN_STOP, 0 }, /* 0x88 */
/* 137 */ { VC_SUN_AGAIN, 0 }, /* 0x89 */
/* 138 */ { VC_SUN_PROPS, 0 }, /* 0x8A */
/* 139 */ { VC_SUN_UNDO, 0 }, /* 0x8B */
/* 140 */ { VC_SUN_FRONT, 0 }, /* 0x8C */
/* 141 */ { VC_SUN_COPY, 0x7D }, /* 0x8D KEY_KPEQUAL */
/* 142 */ { VC_SUN_OPEN, 0 }, /* 0x8E */
/* 143 */ { VC_SUN_INSERT, 0 }, /* 0x8F */
/* 144 */ { VC_SUN_FIND, 0 }, /* 0x90 */
/* 145 */ { VC_SUN_CUT, 0 }, /* 0x91 */
/* 146 */ { VC_SUN_HELP, 0 }, /* 0x92 */
/* 147 */ { VC_UNDEFINED, 0 }, /* 0x93 */
/* 148 */ { VC_APP_CALCULATOR, 0 }, /* 0x94 */
/* 149 */ { VC_UNDEFINED, 0 }, /* 0x95 */
/* 150 */ { VC_SLEEP, 0 }, /* 0x96 */
/* 151 */ { VC_UNDEFINED, 0 }, /* 0x97 */
/* 152 */ { VC_UNDEFINED, 0 }, /* 0x98 */
/* 153 */ { VC_UNDEFINED, 0 }, /* 0x99 */
/* 154 */ { VC_UNDEFINED, 0 }, /* 0x9A */
/* 155 */ { VC_UNDEFINED, 0 }, /* 0x9B */
/* 156 */ { VC_UNDEFINED, 0x68 }, /* 0x9C KEY_KPENTER */
/* 157 */ { VC_UNDEFINED, 0x69 }, /* 0x9D KEY_RIGHTCTRL */
/* 158 */ { VC_UNDEFINED, 0 }, /* 0x9E */
/* 159 */ { VC_UNDEFINED, 0 }, /* 0x9F */
/* 160 */ { VC_UNDEFINED, 0x79 }, /* 0xA0 KEY_MUTE */
/* 161 */ { VC_UNDEFINED, 0x94 }, /* 0xA1 KEY_CALC */
/* 162 */ { VC_UNDEFINED, 0xA7 }, /* 0xA2 KEY_FORWARD */
/* 163 */ { VC_UNDEFINED, 0 }, /* 0xA3 */
/* 164 */ { VC_UNDEFINED, 0 }, /* 0xA4 */
/* 165 */ { VC_UNDEFINED, 0 }, /* 0xA5 */
/* 166 */ { VC_APP_MAIL, 0 }, /* 0xA6 */
/* 167 */ { VC_MEDIA_PLAY, 0 }, /* 0xA7 */
/* 168 */ { VC_UNDEFINED, 0 }, /* 0xA8 */
/* 169 */ { VC_UNDEFINED, 0 }, /* 0xA9 */
/* 170 */ { VC_UNDEFINED, 0 }, /* 0xAA */
/* 171 */ { VC_UNDEFINED, 0 }, /* 0xAB */
/* 172 */ { VC_UNDEFINED, 0 }, /* 0xAC */
/* 173 */ { VC_UNDEFINED, 0 }, /* 0xAD */
/* 174 */ { VC_UNDEFINED, 0x7A }, /* 0xAE KEY_VOLUMEDOWN */
/* 175 */ { VC_UNDEFINED, 0 }, /* 0xAF */
/* 176 */ { VC_UNDEFINED, 0x7B }, /* 0xB0 KEY_VOLUMEUP */
/* 177 */ { VC_UNDEFINED, 0x00 }, /* 0xB1 */
/* 178 */ { VC_UNDEFINED, 0xBA }, /* 0xB2 KEY_SCROLLUP */
/* 179 */ { VC_UNDEFINED, 0x00 }, /* 0xB3 */
/* 180 */ { VC_UNDEFINED, 0x00 }, /* 0xB4 */
/* 181 */ { VC_UNDEFINED, 0x6A }, /* 0xB5 KEY_KPSLASH */
/* 182 */ { VC_UNDEFINED, 0x00 }, /* 0xB6 */
/* 183 */ { VC_UNDEFINED, 0x6B }, /* 0xB7 KEY_SYSRQ */
/* 184 */ { VC_UNDEFINED, 0x6C }, /* 0xB8 KEY_RIGHTALT */
/* 185 */ { VC_UNDEFINED, 0x00 }, /* 0xB9 */
/* 186 */ { VC_BROWSER_HOME, 0x00 }, /* 0xBA */
/* 187 */ { VC_UNDEFINED, 0x00 }, /* 0xBB */
/* 188 */ { VC_UNDEFINED, 0x00 }, /* 0xBC */
/* 189 */ { VC_UNDEFINED, 0x00 }, /* 0xBD */
/* 190 */ { VC_UNDEFINED, 0x00 }, /* 0xBE */
/* 191 */ { VC_F13, 0x00 }, /* 0xBF */
/* 192 */ { VC_F14, 0x00 }, /* 0xC0 */
/* 193 */ { VC_F15, 0x00 }, /* 0xC1 */
/* 194 */ { VC_F16, 0x00 }, /* 0xC2 */
/* 195 */ { VC_F17, 0x00 }, /* 0xC3 */
/* 196 */ { VC_F18, 0x00 }, /* 0xC4 */
/* 197 */ { VC_F19, 0x7F }, /* 0xC5 KEY_PAUSE */
/* 198 */ { VC_F20, 0x00 }, /* 0xC6 */
/* 199 */ { VC_F21, 0x6E }, /* 0xC7 KEY_HOME */
/* 200 */ { VC_F22, 0x6F }, /* 0xC8 KEY_UP */
/* 201 */ { VC_F23, 0x70 }, /* 0xC9 KEY_PAGEUP */
/* 202 */ { VC_F24, 0x00 }, /* 0xCA */
/* 203 */ { VC_UNDEFINED, 0x71 }, /* 0xCB KEY_LEFT */
/* 204 */ { VC_UNDEFINED, 0x00 }, /* 0xCC */
/* 205 */ { VC_UNDEFINED, 0x72 }, /* 0xCD KEY_RIGHT */
/* 206 */ { VC_UNDEFINED, 0x00 }, /* 0xCE */
/* 207 */ { VC_UNDEFINED, 0x73 }, /* 0xCF KEY_END */
/* 208 */ { VC_UNDEFINED, 0x74 }, /* 0xD0 KEY_DOWN */
/* 209 */ { VC_UNDEFINED, 0x75 }, /* 0xD1 KEY_PAGEDOWN */
/* 210 */ { VC_UNDEFINED, 0x76 }, /* 0xD2 KEY_INSERT */
/* 211 */ { VC_UNDEFINED, 0x77 }, /* 0xD3 KEY_DELETE */
/* 212 */ { VC_UNDEFINED, 0x00 }, /* 0xD4 */
/* 213 */ { VC_UNDEFINED, 0x00 }, /* 0xD5 */
/* 214 */ { VC_UNDEFINED, 0x00 }, /* 0xD6 */
/* 215 */ { VC_UNDEFINED, 0x00 }, /* 0xD7 */
/* 216 */ { VC_UNDEFINED, 0x00 }, /* 0xD8 */
/* 217 */ { VC_UNDEFINED, 0x00 }, /* 0xD9 */
/* 218 */ { VC_UNDEFINED, 0x00 }, /* 0xDA */
/* 219 */ { VC_UNDEFINED, 0x85 }, /* 0xDB KEY_LEFTMETA */
/* 220 */ { VC_UNDEFINED, 0x86 }, /* 0xDC KEY_RIGHTMETA */
/* 221 */ { VC_UNDEFINED, 0x87 }, /* 0xDD KEY_COMPOSE */
/* 222 */ { VC_UNDEFINED, 0x7C }, /* 0xDE KEY_POWER */
/* 223 */ { VC_UNDEFINED, 0x96 }, /* 0xDF KEY_SLEEP */
/* 224 */ { VC_UNDEFINED, 0x00 }, /* 0xE0 */
/* 225 */ { VC_BROWSER_SEARCH, 0x00 }, /* 0xE1 */
/* 226 */ { VC_UNDEFINED, 0x00 }, /* 0xE2 */
/* 227 */ { VC_UNDEFINED, 0x00 }, /* 0xE3 */
/* 228 */ { VC_UNDEFINED, 0x00 }, /* 0xE4 */
/* 229 */ { VC_UNDEFINED, 0xE1 }, /* 0xE5 KEY_SEARCH */
/* 230 */ { VC_UNDEFINED, 0x00 }, /* 0xE6 */
/* 231 */ { VC_UNDEFINED, 0x00 }, /* 0xE7 */
/* 232 */ { VC_UNDEFINED, 0x00 }, /* 0xE8 */
/* 233 */ { VC_UNDEFINED, 0x00 }, /* 0xE9 */
/* 234 */ { VC_UNDEFINED, 0x00 }, /* 0xEA */
/* 235 */ { VC_UNDEFINED, 0x00 }, /* 0xEB */
/* 236 */ { VC_UNDEFINED, 0xA6 }, /* 0xEC KEY_BACK */
/* 237 */ { VC_UNDEFINED, 0x00 }, /* 0xED */
/* 238 */ { VC_UNDEFINED, 0x00 }, /* 0xEE */
/* 239 */ { VC_UNDEFINED, 0x00 }, /* 0xEF */
/* 240 */ { VC_UNDEFINED, 0x00 }, /* 0xF0 */
/* 241 */ { VC_UNDEFINED, 0x00 }, /* 0xF1 */
/* 242 */ { VC_UNDEFINED, 0x00 }, /* 0xF2 */
/* 243 */ { VC_UNDEFINED, 0x00 }, /* 0xF3 */
/* 244 */ { VC_UNDEFINED, 0x8E }, /* 0xF4 KEY_OPEN */
/* 245 */ { VC_UNDEFINED, 0x92 }, /* 0xF5 KEY_HELP */
/* 246 */ { VC_UNDEFINED, 0x8A }, /* 0xF6 KEY_PROPS */
/* 247 */ { VC_UNDEFINED, 0x8C }, /* 0xF7 KEY_FRONT */
/* 248 */ { VC_UNDEFINED, 0x88 }, /* 0xF8 KEY_STOP */
/* 249 */ { VC_UNDEFINED, 0x89 }, /* 0xF9 KEY_AGAIN */
/* 250 */ { VC_UNDEFINED, 0x8B }, /* 0xFA KEY_UNDO */
/* 251 */ { VC_UNDEFINED, 0x91 }, /* 0xFB KEY_CUT */
/* 252 */ { VC_UNDEFINED, 0x8D }, /* 0xFC KEY_COPY */
/* 253 */ { VC_UNDEFINED, 0x8F }, /* 0xFD KEY_PASTE */
/* 254 */ { VC_UNDEFINED, 0x90 }, /* 0xFE KEY_FIND */
/* 255 */ { VC_UNDEFINED, 0x00 }, /* 0xFF */
};
#endif
/* This table is generated based off the xfree86 -> scancode mapping above
* and the keycode mappings in the following files:
* /usr/share/X11/xkb/keycodes/xfree86
*
* TODO Everything after 157 needs to be populated with scancodes for media
* controls and internet keyboards.
*/
static const uint16_t xfree86_scancode_table[][2] = {
/* idx { keycode, scancode }, */
/* 0 */ { VC_UNDEFINED, 0 /* <MDSW> */ }, // Unused
/* 1 */ { VC_UNDEFINED, 9 /* <ESC> */ }, //
/* 2 */ { VC_UNDEFINED, 10 /* <AE01> */ }, //
/* 3 */ { VC_UNDEFINED, 11 /* <AE02> */ }, //
/* 4 */ { VC_UNDEFINED, 12 /* <AE03> */ }, //
/* 5 */ { VC_UNDEFINED, 13 /* <AE04> */ }, //
/* 6 */ { VC_UNDEFINED, 14 /* <AE05> */ }, //
/* 7 */ { VC_UNDEFINED, 15 /* <AE06> */ }, //
/* 8 */ { VC_UNDEFINED, 16 /* <AE07> */ }, //
/* 9 */ { VC_ESCAPE, 17 /* <AE08> */ }, //
/* 10 */ { VC_1, 18 /* <AE009> */ }, //
/* 11 */ { VC_2, 19 /* <AE010> */ }, //
/* 12 */ { VC_3, 20 /* <AE011> */ }, //
/* 13 */ { VC_4, 21 /* <AE012> */ }, //
/* 14 */ { VC_5, 22 /* <BKSP> */ }, //
/* 15 */ { VC_6, 23 /* <TAB> */ }, //
/* 16 */ { VC_7, 24 /* <AD01> */ }, //
/* 17 */ { VC_8, 25 /* <AD02> */ }, //
/* 18 */ { VC_9, 26 /* <AD03> */ }, //
/* 19 */ { VC_0, 27 /* <AD04> */ }, //
/* 20 */ { VC_MINUS, 28 /* <AD05> */ }, //
/* 21 */ { VC_EQUALS, 29 /* <AD06> */ }, //
/* 22 */ { VC_BACKSPACE, 30 /* <AD07> */ }, //
/* 23 */ { VC_TAB, 31 /* <AD08> */ }, //
/* 24 */ { VC_Q, 32 /* <AD09> */ }, //
/* 25 */ { VC_W, 33 /* <AD10> */ }, //
/* 26 */ { VC_E, 34 /* <AD11> */ }, //
/* 27 */ { VC_R, 35 /* <AD12> */ }, //
/* 28 */ { VC_T, 36 /* <RTRN> */ }, //
/* 29 */ { VC_Y, 37 /* <LCTL> */ }, //
/* 30 */ { VC_U, 38 /* <AC01> */ }, //
/* 31 */ { VC_I, 39 /* <AC02> */ }, //
/* 32 */ { VC_O, 40 /* <AC03> */ }, //
/* 33 */ { VC_P, 41 /* <AC04> */ }, //
/* 34 */ { VC_OPEN_BRACKET, 42 /* <AC05> */ }, //
/* 35 */ { VC_CLOSE_BRACKET, 43 /* <AC06> */ }, //
/* 36 */ { VC_ENTER, 44 /* <AC07> */ }, //
/* 37 */ { VC_CONTROL_L, 45 /* <AC08> */ }, //
/* 38 */ { VC_A, 46 /* <AC09> */ }, //
/* 39 */ { VC_S, 47 /* <AC10> */ }, //
/* 40 */ { VC_D, 48 /* <AC11> */ }, //
/* 41 */ { VC_F, 49 /* <TLDE> */ }, //
/* 42 */ { VC_G, 50 /* <LFSH> */ }, //
/* 43 */ { VC_H, 51 /* <BKSL> */ }, //
/* 44 */ { VC_J, 52 /* <AB01> */ }, //
/* 45 */ { VC_K, 53 /* <AB02> */ }, //
/* 46 */ { VC_L, 54 /* <AB03> */ }, //
/* 47 */ { VC_SEMICOLON, 55 /* <AB04> */ }, //
/* 48 */ { VC_QUOTE, 56 /* <AB05> */ }, //
/* 49 */ { VC_BACKQUOTE, 57 /* <AB06> */ }, //
/* 50 */ { VC_SHIFT_L, 58 /* <AB07> */ }, //
/* 51 */ { VC_BACK_SLASH, 59 /* <AB08> */ }, //
/* 52 */ { VC_Z, 60 /* <AB09> */ }, //
/* 53 */ { VC_X, 61 /* <AB10> */ }, //
/* 54 */ { VC_C, 62 /* <RTSH> */ }, //
/* 55 */ { VC_V, 63 /* <KPMU> */ }, //
/* 56 */ { VC_B, 64 /* <LALT> */ }, //
/* 57 */ { VC_N, 65 /* <SPCE> */ }, //
/* 58 */ { VC_M, 66 /* <CAPS> */ }, //
/* 59 */ { VC_COMMA, 67 /* <FK01> */ }, //
/* 60 */ { VC_PERIOD, 68 /* <FK02> */ }, //
/* 61 */ { VC_SLASH, 69 /* <FK03> */ }, //
/* 62 */ { VC_SHIFT_R, 70 /* <FK04> */ }, //
/* 63 */ { VC_KP_MULTIPLY, 71 /* <FK05> */ }, //
/* 64 */ { VC_ALT_L, 72 /* <FK06> */ }, //
/* 65 */ { VC_SPACE, 73 /* <FK07> */ }, //
/* 66 */ { VC_CAPS_LOCK, 74 /* <FK08> */ }, //
/* 67 */ { VC_F1, 75 /* <FK09> */ }, //
/* 68 */ { VC_F2, 76 /* <FK10> */ }, //
/* 69 */ { VC_F3, 77 /* <NMLK> */ }, //
/* 70 */ { VC_F4, 78 /* <SCLK> */ }, //
/* 71 */ { VC_F5, 79 /* <KP7> */ }, //
/* 72 */ { VC_F6, 80 /* <KP8> */ }, //
/* 73 */ { VC_F7, 81 /* <KP9> */ }, //
/* 74 */ { VC_F8, 82 /* <KPSU> */ }, //
/* 75 */ { VC_F9, 83 /* <KP4> */ }, //
/* 76 */ { VC_F10, 84 /* <KP5> */ }, //
/* 77 */ { VC_NUM_LOCK, 85 /* <KP6> */ }, //
/* 78 */ { VC_SCROLL_LOCK, 86 /* <KPAD> */ }, //
/* 79 */ { VC_KP_7, 87 /* <KP1> */ }, //
/* 80 */ { VC_KP_8, 88 /* <KP2> */ }, //
/* 81 */ { VC_KP_9, 89 /* <KP3> */ }, //
/* 82 */ { VC_KP_SUBTRACT, 90 /* <KP0> */ }, //
/* 83 */ { VC_KP_4, 91 /* <KPDL> */ }, //
/* 84 */ { VC_KP_5, 0 }, //
/* 85 */ { VC_KP_6, 0 }, //
/* 86 */ { VC_KP_ADD, 0 }, //
/* 87 */ { VC_KP_1, 95 /* <FK11> */ }, //
/* 88 */ { VC_KP_2, 96 /* <FK12> */ },
/* 89 */ { VC_KP_3, 0 },
/* 90 */ { VC_KP_0, 0 },
/* 91 */ { VC_KP_SEPARATOR, 118 /* <FK13> */ },
/* 92 */ { VC_UNDEFINED, 119 /* <FK14> */ },
/* 93 */ { VC_UNDEFINED, 120 /* <FK15> */ },
/* 94 */ { VC_UNDEFINED, 0 },
/* 95 */ { VC_F11, 0 },
/* 96 */ { VC_F12, 0 },
/* First 97 chars are identical to XFree86! */
/* 97 */ { VC_HOME, 0 },
/* 98 */ { VC_UP, 0 },
/* 99 */ { VC_PAGE_UP, 121 /* <FK16> */ },
/* 100 */ { VC_LEFT, 122 /* <FK17> */ },
/* 101 */ { VC_UNDEFINED, 0 }, // TODO lower brightness key?
/* 102 */ { VC_RIGHT, 0 },
/* 103 */ { VC_END, 0 },
/* 104 */ { VC_DOWN, 0 },
/* 105 */ { VC_PAGE_DOWN, 0 },
/* 106 */ { VC_INSERT, 0 },
/* 107 */ { VC_DELETE, 0 },
/* 108 */ { VC_KP_ENTER, 0 },
/* 109 */ { VC_CONTROL_R, 0 },
/* 110 */ { VC_PAUSE, 0 },
/* 111 */ { VC_PRINTSCREEN, 0 },
/* 112 */ { VC_KP_DIVIDE, 0 },
/* 113 */ { VC_ALT_R, 0 },
/* 114 */ { VC_UNDEFINED, 0 }, // VC_BREAK?
/* 115 */ { VC_META_L, 0 },
/* 116 */ { VC_META_R, 0 },
/* 117 */ { VC_CONTEXT_MENU, 0 },
/* 118 */ { VC_F13, 0 },
/* 119 */ { VC_F14, 0 },
/* 120 */ { VC_F15, 0 },
/* 121 */ { VC_F16, 0 },
/* 122 */ { VC_F17, 0 },
/* 123 */ { VC_UNDEFINED, 0 }, // <KPDC> FIXME What is this key?
/* 124 */ { VC_UNDEFINED, 0 }, // <LVL3> Never Generated
/* 125 */ { VC_UNDEFINED, 133 /* <AE13> */ }, // <ALT> Never Generated
/* 126 */ { VC_KP_EQUALS, 0 },
/* 127 */ { VC_UNDEFINED, 0 }, // <SUPR> Never Generated
/* 128 */ { VC_UNDEFINED, 0 }, // <HYPR> Never Generated
/* 129 */ { VC_UNDEFINED, 0 }, // <XFER> Henkan
/* 130 */ { VC_UNDEFINED, 0 }, // <I02> Some extended Internet key
/* 131 */ { VC_UNDEFINED, 0 }, // <NFER> Muhenkan
/* 132 */ { VC_UNDEFINED, 0 }, // <I04>
/* 133 */ { VC_YEN, 0 }, // <AE13>
/* 134 */ { VC_UNDEFINED, 0 }, // <I06>
/* 135 */ { VC_UNDEFINED, 0 }, // <I07>
/* 136 */ { VC_UNDEFINED, 0 }, // <I08>
/* 137 */ { VC_UNDEFINED, 0 }, // <I09>
/* 138 */ { VC_UNDEFINED, 0 }, // <I0A>
/* 139 */ { VC_UNDEFINED, 0 }, // <I0B>
/* 140 */ { VC_UNDEFINED, 0 }, // <I0C>
/* 141 */ { VC_UNDEFINED, 126 }, // <I0D>
/* 142 */ { VC_UNDEFINED, 0 }, // <I0E>
/* 143 */ { VC_UNDEFINED, 0 }, // <I0F>
/* 144 */ { VC_UNDEFINED, 0 }, // <I10>
/* 145 */ { VC_UNDEFINED, 0 }, // <I11>
/* 146 */ { VC_UNDEFINED, 0 }, // <I12>
/* 147 */ { VC_UNDEFINED, 0 }, // <I13>
/* 148 */ { VC_UNDEFINED, 0 }, // <I14>
/* 149 */ { VC_UNDEFINED, 0 }, // <I15>
/* 150 */ { VC_UNDEFINED, 0 }, // <I16>
/* 151 */ { VC_UNDEFINED, 0 }, // <I17>
/* 152 */ { VC_UNDEFINED, 0 }, // <I18>
/* 153 */ { VC_UNDEFINED, 0 }, // <I19>
/* 154 */ { VC_UNDEFINED, 0 }, // <I1A>
/* 155 */ { VC_UNDEFINED, 0 }, // <I1B>
/* 156 */ { VC_UNDEFINED, 108 /* <KPEN> */ }, // <I1C> Never Generated
/* 157 */ { VC_UNDEFINED, 109 /* <RCTL> */ }, // <I1D>
/* 158 */ { VC_UNDEFINED, 0 }, // <I1E>
/* 159 */ { VC_UNDEFINED, 0 }, // <I1F>
/* 160 */ { VC_UNDEFINED, 0 }, // <I20>
/* 161 */ { VC_UNDEFINED, 0 }, // <I21>
/* 162 */ { VC_UNDEFINED, 0 }, // <I22>
/* 163 */ { VC_UNDEFINED, 0 }, // <I23>
/* 164 */ { VC_UNDEFINED, 0 }, // <I24>
/* 165 */ { VC_UNDEFINED, 0 }, // <I25>
/* 166 */ { VC_UNDEFINED, 0 }, // <I26>
/* 167 */ { VC_UNDEFINED, 0 }, // <I27>
/* 168 */ { VC_UNDEFINED, 0 }, // <I28>
/* 169 */ { VC_UNDEFINED, 0 }, // <I29>
/* 170 */ { VC_UNDEFINED, 0 }, // <I2A> <K5A>
/* 171 */ { VC_UNDEFINED, 0 }, // <I2B>
/* 172 */ { VC_UNDEFINED, 0 }, // <I2C>
/* 173 */ { VC_UNDEFINED, 0 }, // <I2D>
/* 174 */ { VC_UNDEFINED, 0 }, // <I2E>
/* 175 */ { VC_UNDEFINED, 0 }, // <I2F>
/* 176 */ { VC_UNDEFINED, 0 }, // <I30>
/* 177 */ { VC_UNDEFINED, 0 }, // <I31>
/* 178 */ { VC_UNDEFINED, 0 }, // <I32>
/* 179 */ { VC_UNDEFINED, 0 }, // <I33>
/* 180 */ { VC_UNDEFINED, 0 }, // <I34>
/* 181 */ { VC_UNDEFINED, 112 }, // <I35> <K5B>
/* 182 */ { VC_UNDEFINED, 0 }, // <I36> <K5D>
/* 183 */ { VC_UNDEFINED, 111 }, // <I37> <K5E>
/* 184 */ { VC_UNDEFINED, 113 }, // <I38> <K5F>
/* 185 */ { VC_UNDEFINED, 0 }, // <I39>
/* 186 */ { VC_UNDEFINED, 0 }, // <I3A>
/* 187 */ { VC_UNDEFINED, 0 }, // <I3B>
/* 188 */ { VC_UNDEFINED, 0 }, // <I3C>
/* 189 */ { VC_UNDEFINED, 0 }, // <I3D> <K62>
/* 190 */ { VC_UNDEFINED, 0 }, // <I3E> <K63>
/* 191 */ { VC_UNDEFINED, 0 }, // <I3F> <K64>
/* 192 */ { VC_UNDEFINED, 0 }, // <I40> <K65>
/* 193 */ { VC_UNDEFINED, 0 }, // <I41> <K66>
/* 194 */ { VC_UNDEFINED, 0 }, // <I42>
/* 195 */ { VC_UNDEFINED, 0 }, // <I43>
/* 196 */ { VC_UNDEFINED, 0 }, // <I44> // 114 <BRK>?
/* 197 */ { VC_UNDEFINED, 110 }, // <I45>
/* 198 */ { VC_UNDEFINED, 0 }, // <I46> <K67>
/* 199 */ { VC_UNDEFINED, 97 /* <HOME> */ }, // <I47> <K68>
/* 200 */ { VC_UNDEFINED, 98 }, // <I48> <K69>
/* 201 */ { VC_UNDEFINED, 99 }, // <I49> <K6A>
/* 202 */ { VC_UNDEFINED, 0 }, // <I4A
/* 203 */ { VC_UNDEFINED, 100 }, // <I4B> <K6B>
/* 204 */ { VC_UNDEFINED, 0 }, // <I4C> <K6C>
/* 205 */ { VC_UNDEFINED, 102 }, // <I4D> <K6D>
/* 206 */ { VC_UNDEFINED, 0 }, // <I4E> <K6E>
/* 207 */ { VC_UNDEFINED, 103 }, // <I4F> <K6F>
/* 208 */ { VC_UNDEFINED, 104 }, // <I50> <K70>
/* 209 */ { VC_UNDEFINED, 105 }, // <I51> <K71>
/* 210 */ { VC_UNDEFINED, 106 }, // <I52> <K72>
/* 211 */ { VC_UNDEFINED, 107 }, // <I53> <K73>
/* 212 */ { VC_UNDEFINED, 0 }, // <I54>
/* 213 */ { VC_UNDEFINED, 0 }, // <I55>
/* 214 */ { VC_UNDEFINED, 0 }, // <I56>
/* 215 */ { VC_UNDEFINED, 0 }, // <I57>
/* 216 */ { VC_UNDEFINED, 0 }, // <I58>
/* 217 */ { VC_UNDEFINED, 0 }, // <I59>
/* 218 */ { VC_UNDEFINED, 0 }, // <I5A>
/* 219 */ { VC_UNDEFINED, 115 /* <LWIN> */ }, // <I5B> <K74>
/* 220 */ { VC_UNDEFINED, 116 /* <RWIN> */ }, // <I5C> <K75>
/* 221 */ { VC_UNDEFINED, 117 /* <MENU> */ }, // <I5D> <K76>
/* 222 */ { VC_UNDEFINED, 0 }, // <I5E>
/* 223 */ { VC_UNDEFINED, 0 }, // <I5F>
/* 224 */ { VC_UNDEFINED, 0 }, // <I60>
/* 225 */ { VC_UNDEFINED, 0 }, // <I61>
/* 226 */ { VC_UNDEFINED, 0 }, // <I62>
/* 227 */ { VC_UNDEFINED, 0 }, // <I63>
/* 228 */ { VC_UNDEFINED, 0 }, // <I64>
/* 229 */ { VC_UNDEFINED, 0 }, // <I65>
/* 230 */ { VC_UNDEFINED, 0 }, // <I66>
/* 231 */ { VC_UNDEFINED, 0 }, // <I67>
/* 232 */ { VC_UNDEFINED, 0 }, // <I68>
/* 233 */ { VC_UNDEFINED, 0 }, // <I69>
/* 234 */ { VC_UNDEFINED, 0 }, // <I6A>
/* 235 */ { VC_UNDEFINED, 0 }, // <I6B>
/* 236 */ { VC_UNDEFINED, 0 }, // <I6C>
/* 237 */ { VC_UNDEFINED, 0 }, // <I6D>
/* 238 */ { VC_UNDEFINED, 0 }, // <I6E>
/* 239 */ { VC_UNDEFINED, 0 }, // <I6F>
/* 240 */ { VC_UNDEFINED, 0 }, // <I70>
/* 241 */ { VC_UNDEFINED, 0 }, // <I71>
/* 242 */ { VC_UNDEFINED, 0 }, // <I72>
/* 243 */ { VC_UNDEFINED, 0 }, // <I73>
/* 244 */ { VC_UNDEFINED, 0 }, // <I74>
/* 245 */ { VC_UNDEFINED, 0 }, // <I75>
/* 246 */ { VC_UNDEFINED, 0 }, // <I76>
/* 247 */ { VC_UNDEFINED, 0 }, // <I77>
/* 248 */ { VC_UNDEFINED, 0 }, // <I78>
/* 249 */ { VC_UNDEFINED, 0 }, // <I79>
/* 250 */ { VC_UNDEFINED, 0 }, // <I7A>
/* 251 */ { VC_UNDEFINED, 0 }, // <I7B>
/* 252 */ { VC_UNDEFINED, 0 }, // <I7C>
/* 253 */ { VC_UNDEFINED, 0 }, // <I7D>
/* 254 */ { VC_UNDEFINED, 0 }, // <I7E>
/* 255 */ { VC_UNDEFINED, 0 }, // <I7F>
};
/***********************************************************************
* The following table contains pairs of X11 keysym values for graphical
* characters and the corresponding Unicode value. The function
* keysym_to_unicode() maps a keysym onto a Unicode value using a binary
* search, therefore keysym_unicode_table[] must remain SORTED by KeySym
* value.
*
* We allow to represent any UCS character in the range U+00000000 to
* U+00FFFFFF by a keysym value in the range 0x01000000 to 0x01FFFFFF.
* This admittedly does not cover the entire 31-bit space of UCS, but
* it does cover all of the characters up to U+10FFFF, which can be
* represented by UTF-16, and more, and it is very unlikely that higher
* UCS codes will ever be assigned by ISO. So to get Unicode character
* U+ABCD you can directly use keysym 0x1000ABCD.
*
* NOTE: The comments in the table below contain the actual character
* encoded in UTF-8, so for viewing and editing best use an editor in
* UTF-8 mode.
*
* Author: Markus G. Kuhn <mkuhn@acm.org>, University of Cambridge,
* June 1999
*
* Special thanks to Richard Verhoeven <river@win.tue.nl> for preparing
* an initial draft of the mapping table.
*
* This table is in the public domain. Share and enjoy!
***********************************************************************/
static struct codepair {
uint16_t keysym;
uint16_t unicode;
} keysym_unicode_table[] = {
{ 0x01A1, 0x0104 }, /* Aogonek Ą LATIN CAPITAL LETTER A WITH OGONEK */
{ 0x01A2, 0x02D8 }, /* breve ˘ BREVE */
{ 0x01A3, 0x0141 }, /* Lstroke Ł LATIN CAPITAL LETTER L WITH STROKE */
{ 0x01A5, 0x013D }, /* Lcaron Ľ LATIN CAPITAL LETTER L WITH CARON */
{ 0x01A6, 0x015A }, /* Sacute Ś LATIN CAPITAL LETTER S WITH ACUTE */
{ 0x01A9, 0x0160 }, /* Scaron Š LATIN CAPITAL LETTER S WITH CARON */
{ 0x01AA, 0x015E }, /* Scedilla Ş LATIN CAPITAL LETTER S WITH CEDILLA */
{ 0x01AB, 0x0164 }, /* Tcaron Ť LATIN CAPITAL LETTER T WITH CARON */
{ 0x01AC, 0x0179 }, /* Zacute Ź LATIN CAPITAL LETTER Z WITH ACUTE */
{ 0x01AE, 0x017D }, /* Zcaron Ž LATIN CAPITAL LETTER Z WITH CARON */
{ 0x01AF, 0x017B }, /* Zabovedot Ż LATIN CAPITAL LETTER Z WITH DOT ABOVE */
{ 0x01B1, 0x0105 }, /* aogonek ą LATIN SMALL LETTER A WITH OGONEK */
{ 0x01B2, 0x02DB }, /* ogonek ˛ OGONEK */
{ 0x01B3, 0x0142 }, /* lstroke ł LATIN SMALL LETTER L WITH STROKE */
{ 0x01B5, 0x013E }, /* lcaron ľ LATIN SMALL LETTER L WITH CARON */
{ 0x01B6, 0x015B }, /* sacute ś LATIN SMALL LETTER S WITH ACUTE */
{ 0x01B7, 0x02C7 }, /* caron ˇ CARON */
{ 0x01B9, 0x0161 }, /* scaron š LATIN SMALL LETTER S WITH CARON */
{ 0x01BA, 0x015F }, /* scedilla ş LATIN SMALL LETTER S WITH CEDILLA */
{ 0x01BB, 0x0165 }, /* tcaron ť LATIN SMALL LETTER T WITH CARON */
{ 0x01BC, 0x017A }, /* zacute ź LATIN SMALL LETTER Z WITH ACUTE */
{ 0x01BD, 0x02DD }, /* doubleacute ˝ DOUBLE ACUTE ACCENT */
{ 0x01BE, 0x017E }, /* zcaron ž LATIN SMALL LETTER Z WITH CARON */
{ 0x01BF, 0x017C }, /* zabovedot ż LATIN SMALL LETTER Z WITH DOT ABOVE */
{ 0x01C0, 0x0154 }, /* Racute Ŕ LATIN CAPITAL LETTER R WITH ACUTE */
{ 0x01C3, 0x0102 }, /* Abreve Ă LATIN CAPITAL LETTER A WITH BREVE */
{ 0x01C5, 0x0139 }, /* Lacute Ĺ LATIN CAPITAL LETTER L WITH ACUTE */
{ 0x01C6, 0x0106 }, /* Cacute Ć LATIN CAPITAL LETTER C WITH ACUTE */
{ 0x01C8, 0x010C }, /* Ccaron Č LATIN CAPITAL LETTER C WITH CARON */
{ 0x01CA, 0x0118 }, /* Eogonek Ę LATIN CAPITAL LETTER E WITH OGONEK */
{ 0x01CC, 0x011A }, /* Ecaron Ě LATIN CAPITAL LETTER E WITH CARON */
{ 0x01CF, 0x010E }, /* Dcaron Ď LATIN CAPITAL LETTER D WITH CARON */
{ 0x01D0, 0x0110 }, /* Dstroke Đ LATIN CAPITAL LETTER D WITH STROKE */
{ 0x01D1, 0x0143 }, /* Nacute Ń LATIN CAPITAL LETTER N WITH ACUTE */
{ 0x01D2, 0x0147 }, /* Ncaron Ň LATIN CAPITAL LETTER N WITH CARON */
{ 0x01D5, 0x0150 }, /* Odoubleacute Ő LATIN CAPITAL LETTER O WITH DOUBLE ACUTE */
{ 0x01D8, 0x0158 }, /* Rcaron Ř LATIN CAPITAL LETTER R WITH CARON */
{ 0x01D9, 0x016E }, /* Uring Ů LATIN CAPITAL LETTER U WITH RING ABOVE */
{ 0x01DB, 0x0170 }, /* Udoubleacute Ű LATIN CAPITAL LETTER U WITH DOUBLE ACUTE */
{ 0x01DE, 0x0162 }, /* Tcedilla Ţ LATIN CAPITAL LETTER T WITH CEDILLA */
{ 0x01E0, 0x0155 }, /* racute ŕ LATIN SMALL LETTER R WITH ACUTE */
{ 0x01E3, 0x0103 }, /* abreve ă LATIN SMALL LETTER A WITH BREVE */
{ 0x01E5, 0x013A }, /* lacute ĺ LATIN SMALL LETTER L WITH ACUTE */
{ 0x01E6, 0x0107 }, /* cacute ć LATIN SMALL LETTER C WITH ACUTE */
{ 0x01E8, 0x010D }, /* ccaron č LATIN SMALL LETTER C WITH CARON */
{ 0x01EA, 0x0119 }, /* eogonek ę LATIN SMALL LETTER E WITH OGONEK */
{ 0x01EC, 0x011B }, /* ecaron ě LATIN SMALL LETTER E WITH CARON */
{ 0x01EF, 0x010F }, /* dcaron ď LATIN SMALL LETTER D WITH CARON */
{ 0x01F0, 0x0111 }, /* dstroke đ LATIN SMALL LETTER D WITH STROKE */
{ 0x01F1, 0x0144 }, /* nacute ń LATIN SMALL LETTER N WITH ACUTE */
{ 0x01F2, 0x0148 }, /* ncaron ň LATIN SMALL LETTER N WITH CARON */
{ 0x01F5, 0x0151 }, /* odoubleacute ő LATIN SMALL LETTER O WITH DOUBLE ACUTE */
{ 0x01F8, 0x0159 }, /* rcaron ř LATIN SMALL LETTER R WITH CARON */
{ 0x01F9, 0x016F }, /* uring ů LATIN SMALL LETTER U WITH RING ABOVE */
{ 0x01FB, 0x0171 }, /* udoubleacute ű LATIN SMALL LETTER U WITH DOUBLE ACUTE */
{ 0x01FE, 0x0163 }, /* tcedilla ţ LATIN SMALL LETTER T WITH CEDILLA */
{ 0x01FF, 0x02D9 }, /* abovedot ˙ DOT ABOVE */
{ 0x02A1, 0x0126 }, /* Hstroke Ħ LATIN CAPITAL LETTER H WITH STROKE */
{ 0x02A6, 0x0124 }, /* Hcircumflex Ĥ LATIN CAPITAL LETTER H WITH CIRCUMFLEX */
{ 0x02A9, 0x0130 }, /* Iabovedot İ LATIN CAPITAL LETTER I WITH DOT ABOVE */
{ 0x02AB, 0x011E }, /* Gbreve Ğ LATIN CAPITAL LETTER G WITH BREVE */
{ 0x02AC, 0x0134 }, /* Jcircumflex Ĵ LATIN CAPITAL LETTER J WITH CIRCUMFLEX */
{ 0x02B1, 0x0127 }, /* hstroke ħ LATIN SMALL LETTER H WITH STROKE */
{ 0x02B6, 0x0125 }, /* hcircumflex ĥ LATIN SMALL LETTER H WITH CIRCUMFLEX */
{ 0x02B9, 0x0131 }, /* idotless ı LATIN SMALL LETTER DOTLESS I */
{ 0x02BB, 0x011F }, /* gbreve ğ LATIN SMALL LETTER G WITH BREVE */
{ 0x02BC, 0x0135 }, /* jcircumflex ĵ LATIN SMALL LETTER J WITH CIRCUMFLEX */
{ 0x02C5, 0x010A }, /* Cabovedot Ċ LATIN CAPITAL LETTER C WITH DOT ABOVE */
{ 0x02C6, 0x0108 }, /* Ccircumflex Ĉ LATIN CAPITAL LETTER C WITH CIRCUMFLEX */
{ 0x02D5, 0x0120 }, /* Gabovedot Ġ LATIN CAPITAL LETTER G WITH DOT ABOVE */
{ 0x02D8, 0x011C }, /* Gcircumflex Ĝ LATIN CAPITAL LETTER G WITH CIRCUMFLEX */
{ 0x02DD, 0x016C }, /* Ubreve Ŭ LATIN CAPITAL LETTER U WITH BREVE */
{ 0x02DE, 0x015C }, /* Scircumflex Ŝ LATIN CAPITAL LETTER S WITH CIRCUMFLEX */
{ 0x02E5, 0x010B }, /* cabovedot ċ LATIN SMALL LETTER C WITH DOT ABOVE */
{ 0x02E6, 0x0109 }, /* ccircumflex ĉ LATIN SMALL LETTER C WITH CIRCUMFLEX */
{ 0x02F5, 0x0121 }, /* gabovedot ġ LATIN SMALL LETTER G WITH DOT ABOVE */
{ 0x02F8, 0x011D }, /* gcircumflex ĝ LATIN SMALL LETTER G WITH CIRCUMFLEX */
{ 0x02FD, 0x016D }, /* ubreve ŭ LATIN SMALL LETTER U WITH BREVE */
{ 0x02FE, 0x015D }, /* scircumflex ŝ LATIN SMALL LETTER S WITH CIRCUMFLEX */
{ 0x03A2, 0x0138 }, /* kra ĸ LATIN SMALL LETTER KRA */
{ 0x03A3, 0x0156 }, /* Rcedilla Ŗ LATIN CAPITAL LETTER R WITH CEDILLA */
{ 0x03A5, 0x0128 }, /* Itilde Ĩ LATIN CAPITAL LETTER I WITH TILDE */
{ 0x03A6, 0x013B }, /* Lcedilla Ļ LATIN CAPITAL LETTER L WITH CEDILLA */
{ 0x03AA, 0x0112 }, /* Emacron Ē LATIN CAPITAL LETTER E WITH MACRON */
{ 0x03AB, 0x0122 }, /* Gcedilla Ģ LATIN CAPITAL LETTER G WITH CEDILLA */
{ 0x03AC, 0x0166 }, /* Tslash Ŧ LATIN CAPITAL LETTER T WITH STROKE */
{ 0x03B3, 0x0157 }, /* rcedilla ŗ LATIN SMALL LETTER R WITH CEDILLA */
{ 0x03B5, 0x0129 }, /* itilde ĩ LATIN SMALL LETTER I WITH TILDE */
{ 0x03B6, 0x013C }, /* lcedilla ļ LATIN SMALL LETTER L WITH CEDILLA */
{ 0x03BA, 0x0113 }, /* emacron ē LATIN SMALL LETTER E WITH MACRON */
{ 0x03BB, 0x0123 }, /* gcedilla ģ LATIN SMALL LETTER G WITH CEDILLA */
{ 0x03BC, 0x0167 }, /* tslash ŧ LATIN SMALL LETTER T WITH STROKE */
{ 0x03BD, 0x014A }, /* ENG Ŋ LATIN CAPITAL LETTER ENG */
{ 0x03BF, 0x014B }, /* eng ŋ LATIN SMALL LETTER ENG */
{ 0x03C0, 0x0100 }, /* Amacron Ā LATIN CAPITAL LETTER A WITH MACRON */
{ 0x03C7, 0x012E }, /* Iogonek Į LATIN CAPITAL LETTER I WITH OGONEK */
{ 0x03CC, 0x0116 }, /* Eabovedot Ė LATIN CAPITAL LETTER E WITH DOT ABOVE */
{ 0x03CF, 0x012A }, /* Imacron Ī LATIN CAPITAL LETTER I WITH MACRON */
{ 0x03D1, 0x0145 }, /* Ncedilla Ņ LATIN CAPITAL LETTER N WITH CEDILLA */
{ 0x03D2, 0x014C }, /* Omacron Ō LATIN CAPITAL LETTER O WITH MACRON */
{ 0x03D3, 0x0136 }, /* Kcedilla Ķ LATIN CAPITAL LETTER K WITH CEDILLA */
{ 0x03D9, 0x0172 }, /* Uogonek Ų LATIN CAPITAL LETTER U WITH OGONEK */
{ 0x03DD, 0x0168 }, /* Utilde Ũ LATIN CAPITAL LETTER U WITH TILDE */
{ 0x03DE, 0x016A }, /* Umacron Ū LATIN CAPITAL LETTER U WITH MACRON */
{ 0x03E0, 0x0101 }, /* amacron ā LATIN SMALL LETTER A WITH MACRON */
{ 0x03E7, 0x012F }, /* iogonek į LATIN SMALL LETTER I WITH OGONEK */
{ 0x03EC, 0x0117 }, /* eabovedot ė LATIN SMALL LETTER E WITH DOT ABOVE */
{ 0x03EF, 0x012B }, /* imacron ī LATIN SMALL LETTER I WITH MACRON */
{ 0x03F1, 0x0146 }, /* ncedilla ņ LATIN SMALL LETTER N WITH CEDILLA */
{ 0x03F2, 0x014D }, /* omacron ō LATIN SMALL LETTER O WITH MACRON */
{ 0x03F3, 0x0137 }, /* kcedilla ķ LATIN SMALL LETTER K WITH CEDILLA */
{ 0x03F9, 0x0173 }, /* uogonek ų LATIN SMALL LETTER U WITH OGONEK */
{ 0x03FD, 0x0169 }, /* utilde ũ LATIN SMALL LETTER U WITH TILDE */
{ 0x03FE, 0x016B }, /* umacron ū LATIN SMALL LETTER U WITH MACRON */
{ 0x047E, 0x203E }, /* overline ‾ OVERLINE */
{ 0x04A1, 0x3002 }, /* kana_fullstop 。 IDEOGRAPHIC FULL STOP */
{ 0x04A2, 0x300C }, /* kana_openingbracket 「 LEFT CORNER BRACKET */
{ 0x04A3, 0x300D }, /* kana_closingbracket 」 RIGHT CORNER BRACKET */
{ 0x04A4, 0x3001 }, /* kana_comma 、 IDEOGRAPHIC COMMA */
{ 0x04A5, 0x30FB }, /* kana_conjunctive ・ KATAKANA MIDDLE DOT */
{ 0x04A6, 0x30F2 }, /* kana_WO ヲ KATAKANA LETTER WO */
{ 0x04A7, 0x30A1 }, /* kana_a ァ KATAKANA LETTER SMALL A */
{ 0x04A8, 0x30A3 }, /* kana_i ィ KATAKANA LETTER SMALL I */
{ 0x04A9, 0x30A5 }, /* kana_u ゥ KATAKANA LETTER SMALL U */
{ 0x04AA, 0x30A7 }, /* kana_e ェ KATAKANA LETTER SMALL E */
{ 0x04AB, 0x30A9 }, /* kana_o ォ KATAKANA LETTER SMALL O */
{ 0x04AC, 0x30E3 }, /* kana_ya ャ KATAKANA LETTER SMALL YA */
{ 0x04AD, 0x30E5 }, /* kana_yu ュ KATAKANA LETTER SMALL YU */
{ 0x04AE, 0x30E7 }, /* kana_yo ョ KATAKANA LETTER SMALL YO */
{ 0x04AF, 0x30C3 }, /* kana_tsu ッ KATAKANA LETTER SMALL TU */
{ 0x04B0, 0x30FC }, /* prolongedsound ー KATAKANA-HIRAGANA PROLONGED SOUND MARK */
{ 0x04B1, 0x30A2 }, /* kana_A ア KATAKANA LETTER A */
{ 0x04B2, 0x30A4 }, /* kana_I イ KATAKANA LETTER I */
{ 0x04B3, 0x30A6 }, /* kana_U ウ KATAKANA LETTER U */
{ 0x04B4, 0x30A8 }, /* kana_E エ KATAKANA LETTER E */
{ 0x04B5, 0x30AA }, /* kana_O オ KATAKANA LETTER O */
{ 0x04B6, 0x30AB }, /* kana_KA カ KATAKANA LETTER KA */
{ 0x04B7, 0x30AD }, /* kana_KI キ KATAKANA LETTER KI */
{ 0x04B8, 0x30AF }, /* kana_KU ク KATAKANA LETTER KU */
{ 0x04B9, 0x30B1 }, /* kana_KE ケ KATAKANA LETTER KE */
{ 0x04BA, 0x30B3 }, /* kana_KO コ KATAKANA LETTER KO */
{ 0x04BB, 0x30B5 }, /* kana_SA サ KATAKANA LETTER SA */
{ 0x04BC, 0x30B7 }, /* kana_SHI シ KATAKANA LETTER SI */
{ 0x04BD, 0x30B9 }, /* kana_SU ス KATAKANA LETTER SU */
{ 0x04BE, 0x30BB }, /* kana_SE セ KATAKANA LETTER SE */
{ 0x04BF, 0x30BD }, /* kana_SO ソ KATAKANA LETTER SO */
{ 0x04C0, 0x30BF }, /* kana_TA タ KATAKANA LETTER TA */
{ 0x04C1, 0x30C1 }, /* kana_CHI チ KATAKANA LETTER TI */
{ 0x04C2, 0x30C4 }, /* kana_TSU ツ KATAKANA LETTER TU */
{ 0x04C3, 0x30C6 }, /* kana_TE テ KATAKANA LETTER TE */
{ 0x04C4, 0x30C8 }, /* kana_TO ト KATAKANA LETTER TO */
{ 0x04C5, 0x30CA }, /* kana_NA ナ KATAKANA LETTER NA */
{ 0x04C6, 0x30CB }, /* kana_NI ニ KATAKANA LETTER NI */
{ 0x04C7, 0x30CC }, /* kana_NU ヌ KATAKANA LETTER NU */
{ 0x04C8, 0x30CD }, /* kana_NE ネ KATAKANA LETTER NE */
{ 0x04C9, 0x30CE }, /* kana_NO KATAKANA LETTER NO */
{ 0x04CA, 0x30CF }, /* kana_HA ハ KATAKANA LETTER HA */
{ 0x04CB, 0x30D2 }, /* kana_HI ヒ KATAKANA LETTER HI */
{ 0x04CC, 0x30D5 }, /* kana_FU フ KATAKANA LETTER HU */
{ 0x04CD, 0x30D8 }, /* kana_HE ヘ KATAKANA LETTER HE */
{ 0x04CE, 0x30DB }, /* kana_HO ホ KATAKANA LETTER HO */
{ 0x04CF, 0x30DE }, /* kana_MA マ KATAKANA LETTER MA */
{ 0x04D0, 0x30DF }, /* kana_MI ミ KATAKANA LETTER MI */
{ 0x04D1, 0x30E0 }, /* kana_MU ム KATAKANA LETTER MU */
{ 0x04D2, 0x30E1 }, /* kana_ME メ KATAKANA LETTER ME */
{ 0x04D3, 0x30E2 }, /* kana_MO モ KATAKANA LETTER MO */
{ 0x04D4, 0x30E4 }, /* kana_YA ヤ KATAKANA LETTER YA */
{ 0x04D5, 0x30E6 }, /* kana_YU ユ KATAKANA LETTER YU */
{ 0x04D6, 0x30E8 }, /* kana_YO ヨ KATAKANA LETTER YO */
{ 0x04D7, 0x30E9 }, /* kana_RA ラ KATAKANA LETTER RA */
{ 0x04D8, 0x30EA }, /* kana_RI リ KATAKANA LETTER RI */
{ 0x04D9, 0x30EB }, /* kana_RU ル KATAKANA LETTER RU */
{ 0x04DA, 0x30EC }, /* kana_RE レ KATAKANA LETTER RE */
{ 0x04DB, 0x30ED }, /* kana_RO ロ KATAKANA LETTER RO */
{ 0x04DC, 0x30EF }, /* kana_WA ワ KATAKANA LETTER WA */
{ 0x04DD, 0x30F3 }, /* kana_N ン KATAKANA LETTER N */
{ 0x04DE, 0x309B }, /* voicedsound ゛ KATAKANA-HIRAGANA VOICED SOUND MARK */
{ 0x04DF, 0x309C }, /* semivoicedsound ゜ KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK */
{ 0x05AC, 0x060C }, /* Arabic_comma ، ARABIC COMMA */
{ 0x05BB, 0x061B }, /* Arabic_semicolon ؛ ARABIC SEMICOLON */
{ 0x05BF, 0x061F }, /* Arabic_question_mark ؟ ARABIC QUESTION MARK */
{ 0x05C1, 0x0621 }, /* Arabic_hamza ء ARABIC LETTER HAMZA */
{ 0x05C2, 0x0622 }, /* Arabic_maddaonalef آ ARABIC LETTER ALEF WITH MADDA ABOVE */
{ 0x05C3, 0x0623 }, /* Arabic_hamzaonalef أ ARABIC LETTER ALEF WITH HAMZA ABOVE */
{ 0x05C4, 0x0624 }, /* Arabic_hamzaonwaw ؤ ARABIC LETTER WAW WITH HAMZA ABOVE */
{ 0x05C5, 0x0625 }, /* Arabic_hamzaunderalef إ ARABIC LETTER ALEF WITH HAMZA BELOW */
{ 0x05C6, 0x0626 }, /* Arabic_hamzaonyeh ئ ARABIC LETTER YEH WITH HAMZA ABOVE */
{ 0x05C7, 0x0627 }, /* Arabic_alef ا ARABIC LETTER ALEF */
{ 0x05C8, 0x0628 }, /* Arabic_beh ب ARABIC LETTER BEH */
{ 0x05C9, 0x0629 }, /* Arabic_tehmarbuta ة ARABIC LETTER TEH MARBUTA */
{ 0x05CA, 0x062A }, /* Arabic_teh ت ARABIC LETTER TEH */
{ 0x05CB, 0x062B }, /* Arabic_theh ث ARABIC LETTER THEH */
{ 0x05CC, 0x062C }, /* Arabic_jeem ج ARABIC LETTER JEEM */
{ 0x05CD, 0x062D }, /* Arabic_hah ح ARABIC LETTER HAH */
{ 0x05CE, 0x062E }, /* Arabic_khah خ ARABIC LETTER KHAH */
{ 0x05CF, 0x062F }, /* Arabic_dal د ARABIC LETTER DAL */
{ 0x05D0, 0x0630 }, /* Arabic_thal ذ ARABIC LETTER THAL */
{ 0x05D1, 0x0631 }, /* Arabic_ra ر ARABIC LETTER REH */
{ 0x05D2, 0x0632 }, /* Arabic_zain ز ARABIC LETTER ZAIN */
{ 0x05D3, 0x0633 }, /* Arabic_seen س ARABIC LETTER SEEN */
{ 0x05D4, 0x0634 }, /* Arabic_sheen ش ARABIC LETTER SHEEN */
{ 0x05D5, 0x0635 }, /* Arabic_sad ص ARABIC LETTER SAD */
{ 0x05D6, 0x0636 }, /* Arabic_dad ض ARABIC LETTER DAD */
{ 0x05D7, 0x0637 }, /* Arabic_tah ط ARABIC LETTER TAH */
{ 0x05D8, 0x0638 }, /* Arabic_zah ظ ARABIC LETTER ZAH */
{ 0x05D9, 0x0639 }, /* Arabic_ain ع ARABIC LETTER AIN */
{ 0x05DA, 0x063A }, /* Arabic_ghain غ ARABIC LETTER GHAIN */
{ 0x05E0, 0x0640 }, /* Arabic_tatweel ـ ARABIC TATWEEL */
{ 0x05E1, 0x0641 }, /* Arabic_feh ف ARABIC LETTER FEH */
{ 0x05E2, 0x0642 }, /* Arabic_qaf ق ARABIC LETTER QAF */
{ 0x05E3, 0x0643 }, /* Arabic_kaf ك ARABIC LETTER KAF */
{ 0x05E4, 0x0644 }, /* Arabic_lam ل ARABIC LETTER LAM */
{ 0x05E5, 0x0645 }, /* Arabic_meem م ARABIC LETTER MEEM */
{ 0x05E6, 0x0646 }, /* Arabic_noon ن ARABIC LETTER NOON */
{ 0x05E7, 0x0647 }, /* Arabic_ha ه ARABIC LETTER HEH */
{ 0x05E8, 0x0648 }, /* Arabic_waw و ARABIC LETTER WAW */
{ 0x05E9, 0x0649 }, /* Arabic_alefmaksura ى ARABIC LETTER ALEF MAKSURA */
{ 0x05EA, 0x064A }, /* Arabic_yeh ي ARABIC LETTER YEH */
{ 0x05EB, 0x064B }, /* Arabic_fathatan ً ARABIC FATHATAN */
{ 0x05EC, 0x064C }, /* Arabic_dammatan ٌ ARABIC DAMMATAN */
{ 0x05ED, 0x064D }, /* Arabic_kasratan ٍ ARABIC KASRATAN */
{ 0x05EE, 0x064E }, /* Arabic_fatha َ ARABIC FATHA */
{ 0x05EF, 0x064F }, /* Arabic_damma ُ ARABIC DAMMA */
{ 0x05F0, 0x0650 }, /* Arabic_kasra ِ ARABIC KASRA */
{ 0x05F1, 0x0651 }, /* Arabic_shadda ّ ARABIC SHADDA */
{ 0x05F2, 0x0652 }, /* Arabic_sukun ْ ARABIC SUKUN */
{ 0x06A1, 0x0452 }, /* Serbian_dje ђ CYRILLIC SMALL LETTER DJE */
{ 0x06A2, 0x0453 }, /* Macedonia_gje ѓ CYRILLIC SMALL LETTER GJE */
{ 0x06A3, 0x0451 }, /* Cyrillic_io ё CYRILLIC SMALL LETTER IO */
{ 0x06A4, 0x0454 }, /* Ukrainian_ie є CYRILLIC SMALL LETTER UKRAINIAN IE */
{ 0x06A5, 0x0455 }, /* Macedonia_dse ѕ CYRILLIC SMALL LETTER DZE */
{ 0x06A6, 0x0456 }, /* Ukrainian_i і CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I */
{ 0x06A7, 0x0457 }, /* Ukrainian_yi ї CYRILLIC SMALL LETTER YI */
{ 0x06A8, 0x0458 }, /* Cyrillic_je ј CYRILLIC SMALL LETTER JE */
{ 0x06A9, 0x0459 }, /* Cyrillic_lje љ CYRILLIC SMALL LETTER LJE */
{ 0x06AA, 0x045A }, /* Cyrillic_nje њ CYRILLIC SMALL LETTER NJE */
{ 0x06AB, 0x045B }, /* Serbian_tshe ћ CYRILLIC SMALL LETTER TSHE */
{ 0x06AC, 0x045C }, /* Macedonia_kje ќ CYRILLIC SMALL LETTER KJE */
{ 0x06AE, 0x045E }, /* Byelorussian_shortu ў CYRILLIC SMALL LETTER SHORT U */
{ 0x06AF, 0x045F }, /* Cyrillic_dzhe џ CYRILLIC SMALL LETTER DZHE */
{ 0x06B0, 0x2116 }, /* numerosign № NUMERO SIGN */
{ 0x06B1, 0x0402 }, /* Serbian_DJE Ђ CYRILLIC CAPITAL LETTER DJE */
{ 0x06B2, 0x0403 }, /* Macedonia_GJE Ѓ CYRILLIC CAPITAL LETTER GJE */
{ 0x06B3, 0x0401 }, /* Cyrillic_IO Ё CYRILLIC CAPITAL LETTER IO */
{ 0x06B4, 0x0404 }, /* Ukrainian_IE Є CYRILLIC CAPITAL LETTER UKRAINIAN IE */
{ 0x06B5, 0x0405 }, /* Macedonia_DSE Ѕ CYRILLIC CAPITAL LETTER DZE */
{ 0x06B6, 0x0406 }, /* Ukrainian_I І CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I */
{ 0x06B7, 0x0407 }, /* Ukrainian_YI Ї CYRILLIC CAPITAL LETTER YI */
{ 0x06B8, 0x0408 }, /* Cyrillic_JE Ј CYRILLIC CAPITAL LETTER JE */
{ 0x06B9, 0x0409 }, /* Cyrillic_LJE Љ CYRILLIC CAPITAL LETTER LJE */
{ 0x06BA, 0x040A }, /* Cyrillic_NJE Њ CYRILLIC CAPITAL LETTER NJE */
{ 0x06BB, 0x040B }, /* Serbian_TSHE Ћ CYRILLIC CAPITAL LETTER TSHE */
{ 0x06BC, 0x040C }, /* Macedonia_KJE Ќ CYRILLIC CAPITAL LETTER KJE */
{ 0x06BE, 0x040E }, /* Byelorussian_SHORTU Ў CYRILLIC CAPITAL LETTER SHORT U */
{ 0x06BF, 0x040F }, /* Cyrillic_DZHE Џ CYRILLIC CAPITAL LETTER DZHE */
{ 0x06C0, 0x044E }, /* Cyrillic_yu ю CYRILLIC SMALL LETTER YU */
{ 0x06C1, 0x0430 }, /* Cyrillic_a а CYRILLIC SMALL LETTER A */
{ 0x06C2, 0x0431 }, /* Cyrillic_be б CYRILLIC SMALL LETTER BE */
{ 0x06C3, 0x0446 }, /* Cyrillic_tse ц CYRILLIC SMALL LETTER TSE */
{ 0x06C4, 0x0434 }, /* Cyrillic_de д CYRILLIC SMALL LETTER DE */
{ 0x06C5, 0x0435 }, /* Cyrillic_ie е CYRILLIC SMALL LETTER IE */
{ 0x06C6, 0x0444 }, /* Cyrillic_ef ф CYRILLIC SMALL LETTER EF */
{ 0x06C7, 0x0433 }, /* Cyrillic_ghe г CYRILLIC SMALL LETTER GHE */
{ 0x06C8, 0x0445 }, /* Cyrillic_ha х CYRILLIC SMALL LETTER HA */
{ 0x06C9, 0x0438 }, /* Cyrillic_i и CYRILLIC SMALL LETTER I */
{ 0x06CA, 0x0439 }, /* Cyrillic_shorti й CYRILLIC SMALL LETTER SHORT I */
{ 0x06CB, 0x043A }, /* Cyrillic_ka к CYRILLIC SMALL LETTER KA */
{ 0x06CC, 0x043B }, /* Cyrillic_el л CYRILLIC SMALL LETTER EL */
{ 0x06CD, 0x043C }, /* Cyrillic_em м CYRILLIC SMALL LETTER EM */
{ 0x06CE, 0x043D }, /* Cyrillic_en н CYRILLIC SMALL LETTER EN */
{ 0x06CF, 0x043E }, /* Cyrillic_o о CYRILLIC SMALL LETTER O */
{ 0x06D0, 0x043F }, /* Cyrillic_pe п CYRILLIC SMALL LETTER PE */
{ 0x06D1, 0x044F }, /* Cyrillic_ya я CYRILLIC SMALL LETTER YA */
{ 0x06D2, 0x0440 }, /* Cyrillic_er р CYRILLIC SMALL LETTER ER */
{ 0x06D3, 0x0441 }, /* Cyrillic_es с CYRILLIC SMALL LETTER ES */
{ 0x06D4, 0x0442 }, /* Cyrillic_te т CYRILLIC SMALL LETTER TE */
{ 0x06D5, 0x0443 }, /* Cyrillic_u у CYRILLIC SMALL LETTER U */
{ 0x06D6, 0x0436 }, /* Cyrillic_zhe ж CYRILLIC SMALL LETTER ZHE */
{ 0x06D7, 0x0432 }, /* Cyrillic_ve в CYRILLIC SMALL LETTER VE */
{ 0x06D8, 0x044C }, /* Cyrillic_softsign ь CYRILLIC SMALL LETTER SOFT SIGN */
{ 0x06D9, 0x044B }, /* Cyrillic_yeru ы CYRILLIC SMALL LETTER YERU */
{ 0x06DA, 0x0437 }, /* Cyrillic_ze з CYRILLIC SMALL LETTER ZE */
{ 0x06DB, 0x0448 }, /* Cyrillic_sha ш CYRILLIC SMALL LETTER SHA */
{ 0x06DC, 0x044D }, /* Cyrillic_e э CYRILLIC SMALL LETTER E */
{ 0x06DD, 0x0449 }, /* Cyrillic_shcha щ CYRILLIC SMALL LETTER SHCHA */
{ 0x06DE, 0x0447 }, /* Cyrillic_che ч CYRILLIC SMALL LETTER CHE */
{ 0x06DF, 0x044A }, /* Cyrillic_hardsign ъ CYRILLIC SMALL LETTER HARD SIGN */
{ 0x06E0, 0x042E }, /* Cyrillic_YU Ю CYRILLIC CAPITAL LETTER YU */
{ 0x06E1, 0x0410 }, /* Cyrillic_A А CYRILLIC CAPITAL LETTER A */
{ 0x06E2, 0x0411 }, /* Cyrillic_BE Б CYRILLIC CAPITAL LETTER BE */
{ 0x06E3, 0x0426 }, /* Cyrillic_TSE Ц CYRILLIC CAPITAL LETTER TSE */
{ 0x06E4, 0x0414 }, /* Cyrillic_DE Д CYRILLIC CAPITAL LETTER DE */
{ 0x06E5, 0x0415 }, /* Cyrillic_IE Е CYRILLIC CAPITAL LETTER IE */
{ 0x06E6, 0x0424 }, /* Cyrillic_EF Ф CYRILLIC CAPITAL LETTER EF */
{ 0x06E7, 0x0413 }, /* Cyrillic_GHE Г CYRILLIC CAPITAL LETTER GHE */
{ 0x06E8, 0x0425 }, /* Cyrillic_HA Х CYRILLIC CAPITAL LETTER HA */
{ 0x06E9, 0x0418 }, /* Cyrillic_I И CYRILLIC CAPITAL LETTER I */
{ 0x06EA, 0x0419 }, /* Cyrillic_SHORTI Й CYRILLIC CAPITAL LETTER SHORT I */
{ 0x06EB, 0x041A }, /* Cyrillic_KA К CYRILLIC CAPITAL LETTER KA */
{ 0x06EC, 0x041B }, /* Cyrillic_EL Л CYRILLIC CAPITAL LETTER EL */
{ 0x06ED, 0x041C }, /* Cyrillic_EM М CYRILLIC CAPITAL LETTER EM */
{ 0x06EE, 0x041D }, /* Cyrillic_EN Н CYRILLIC CAPITAL LETTER EN */
{ 0x06EF, 0x041E }, /* Cyrillic_O О CYRILLIC CAPITAL LETTER O */
{ 0x06F0, 0x041F }, /* Cyrillic_PE П CYRILLIC CAPITAL LETTER PE */
{ 0x06F1, 0x042F }, /* Cyrillic_YA Я CYRILLIC CAPITAL LETTER YA */
{ 0x06F2, 0x0420 }, /* Cyrillic_ER Р CYRILLIC CAPITAL LETTER ER */
{ 0x06F3, 0x0421 }, /* Cyrillic_ES С CYRILLIC CAPITAL LETTER ES */
{ 0x06F4, 0x0422 }, /* Cyrillic_TE Т CYRILLIC CAPITAL LETTER TE */
{ 0x06F5, 0x0423 }, /* Cyrillic_U У CYRILLIC CAPITAL LETTER U */
{ 0x06F6, 0x0416 }, /* Cyrillic_ZHE Ж CYRILLIC CAPITAL LETTER ZHE */
{ 0x06F7, 0x0412 }, /* Cyrillic_VE В CYRILLIC CAPITAL LETTER VE */
{ 0x06F8, 0x042C }, /* Cyrillic_SOFTSIGN Ь CYRILLIC CAPITAL LETTER SOFT SIGN */
{ 0x06F9, 0x042B }, /* Cyrillic_YERU Ы CYRILLIC CAPITAL LETTER YERU */
{ 0x06FA, 0x0417 }, /* Cyrillic_ZE З CYRILLIC CAPITAL LETTER ZE */
{ 0x06FB, 0x0428 }, /* Cyrillic_SHA Ш CYRILLIC CAPITAL LETTER SHA */
{ 0x06FC, 0x042D }, /* Cyrillic_E Э CYRILLIC CAPITAL LETTER E */
{ 0x06FD, 0x0429 }, /* Cyrillic_SHCHA Щ CYRILLIC CAPITAL LETTER SHCHA */
{ 0x06FE, 0x0427 }, /* Cyrillic_CHE Ч CYRILLIC CAPITAL LETTER CHE */
{ 0x06FF, 0x042A }, /* Cyrillic_HARDSIGN Ъ CYRILLIC CAPITAL LETTER HARD SIGN */
{ 0x07A1, 0x0386 }, /* Greek_ALPHAaccent Ά GREEK CAPITAL LETTER ALPHA WITH TONOS */
{ 0x07A2, 0x0388 }, /* Greek_EPSILONaccent Έ GREEK CAPITAL LETTER EPSILON WITH TONOS */
{ 0x07A3, 0x0389 }, /* Greek_ETAaccent Ή GREEK CAPITAL LETTER ETA WITH TONOS */
{ 0x07A4, 0x038A }, /* Greek_IOTAaccent Ί GREEK CAPITAL LETTER IOTA WITH TONOS */
{ 0x07A5, 0x03AA }, /* Greek_IOTAdiaeresis Ϊ GREEK CAPITAL LETTER IOTA WITH DIALYTIKA */
{ 0x07A7, 0x038C }, /* Greek_OMICRONaccent Ό GREEK CAPITAL LETTER OMICRON WITH TONOS */
{ 0x07A8, 0x038E }, /* Greek_UPSILONaccent Ύ GREEK CAPITAL LETTER UPSILON WITH TONOS */
{ 0x07A9, 0x03AB }, /* Greek_UPSILONdieresis Ϋ GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA */
{ 0x07AB, 0x038F }, /* Greek_OMEGAaccent Ώ GREEK CAPITAL LETTER OMEGA WITH TONOS */
{ 0x07AE, 0x0385 }, /* Greek_accentdieresis ΅ GREEK DIALYTIKA TONOS */
{ 0x07AF, 0x2015 }, /* Greek_horizbar ― HORIZONTAL BAR */
{ 0x07B1, 0x03AC }, /* Greek_alphaaccent ά GREEK SMALL LETTER ALPHA WITH TONOS */
{ 0x07B2, 0x03AD }, /* Greek_epsilonaccent έ GREEK SMALL LETTER EPSILON WITH TONOS */
{ 0x07B3, 0x03AE }, /* Greek_etaaccent ή GREEK SMALL LETTER ETA WITH TONOS */
{ 0x07B4, 0x03AF }, /* Greek_iotaaccent ί GREEK SMALL LETTER IOTA WITH TONOS */
{ 0x07B5, 0x03CA }, /* Greek_iotadieresis ϊ GREEK SMALL LETTER IOTA WITH DIALYTIKA */
{ 0x07B6, 0x0390 }, /* Greek_iotaaccentdieresis ΐ GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS */
{ 0x07B7, 0x03CC }, /* Greek_omicronaccent ό GREEK SMALL LETTER OMICRON WITH TONOS */
{ 0x07B8, 0x03CD }, /* Greek_upsilonaccent ύ GREEK SMALL LETTER UPSILON WITH TONOS */
{ 0x07B9, 0x03CB }, /* Greek_upsilondieresis ϋ GREEK SMALL LETTER UPSILON WITH DIALYTIKA */
{ 0x07BA, 0x03B0 }, /* Greek_upsilonaccentdieresis ΰ GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS */
{ 0x07BB, 0x03CE }, /* Greek_omegaaccent ώ GREEK SMALL LETTER OMEGA WITH TONOS */
{ 0x07C1, 0x0391 }, /* Greek_ALPHA Α GREEK CAPITAL LETTER ALPHA */
{ 0x07C2, 0x0392 }, /* Greek_BETA Β GREEK CAPITAL LETTER BETA */
{ 0x07C3, 0x0393 }, /* Greek_GAMMA Γ GREEK CAPITAL LETTER GAMMA */
{ 0x07C4, 0x0394 }, /* Greek_DELTA Δ GREEK CAPITAL LETTER DELTA */
{ 0x07C5, 0x0395 }, /* Greek_EPSILON Ε GREEK CAPITAL LETTER EPSILON */
{ 0x07C6, 0x0396 }, /* Greek_ZETA Ζ GREEK CAPITAL LETTER ZETA */
{ 0x07C7, 0x0397 }, /* Greek_ETA Η GREEK CAPITAL LETTER ETA */
{ 0x07C8, 0x0398 }, /* Greek_THETA Θ GREEK CAPITAL LETTER THETA */
{ 0x07C9, 0x0399 }, /* Greek_IOTA Ι GREEK CAPITAL LETTER IOTA */
{ 0x07CA, 0x039A }, /* Greek_KAPPA Κ GREEK CAPITAL LETTER KAPPA */
{ 0x07CB, 0x039B }, /* Greek_LAMBDA Λ GREEK CAPITAL LETTER LAMDA */
{ 0x07CC, 0x039C }, /* Greek_MU Μ GREEK CAPITAL LETTER MU */
{ 0x07CD, 0x039D }, /* Greek_NU Ν GREEK CAPITAL LETTER NU */
{ 0x07CE, 0x039E }, /* Greek_XI Ξ GREEK CAPITAL LETTER XI */
{ 0x07CF, 0x039F }, /* Greek_OMICRON Ο GREEK CAPITAL LETTER OMICRON */
{ 0x07D0, 0x03A0 }, /* Greek_PI Π GREEK CAPITAL LETTER PI */
{ 0x07D1, 0x03A1 }, /* Greek_RHO Ρ GREEK CAPITAL LETTER RHO */
{ 0x07D2, 0x03A3 }, /* Greek_SIGMA Σ GREEK CAPITAL LETTER SIGMA */
{ 0x07D4, 0x03A4 }, /* Greek_TAU Τ GREEK CAPITAL LETTER TAU */
{ 0x07D5, 0x03A5 }, /* Greek_UPSILON Υ GREEK CAPITAL LETTER UPSILON */
{ 0x07D6, 0x03A6 }, /* Greek_PHI Φ GREEK CAPITAL LETTER PHI */
{ 0x07D7, 0x03A7 }, /* Greek_CHI Χ GREEK CAPITAL LETTER CHI */
{ 0x07D8, 0x03A8 }, /* Greek_PSI Ψ GREEK CAPITAL LETTER PSI */
{ 0x07D9, 0x03A9 }, /* Greek_OMEGA Ω GREEK CAPITAL LETTER OMEGA */
{ 0x07E1, 0x03B1 }, /* Greek_alpha α GREEK SMALL LETTER ALPHA */
{ 0x07E2, 0x03B2 }, /* Greek_beta β GREEK SMALL LETTER BETA */
{ 0x07E3, 0x03B3 }, /* Greek_gamma γ GREEK SMALL LETTER GAMMA */
{ 0x07E4, 0x03B4 }, /* Greek_delta δ GREEK SMALL LETTER DELTA */
{ 0x07E5, 0x03B5 }, /* Greek_epsilon ε GREEK SMALL LETTER EPSILON */
{ 0x07E6, 0x03B6 }, /* Greek_zeta ζ GREEK SMALL LETTER ZETA */
{ 0x07E7, 0x03B7 }, /* Greek_eta η GREEK SMALL LETTER ETA */
{ 0x07E8, 0x03B8 }, /* Greek_theta θ GREEK SMALL LETTER THETA */
{ 0x07E9, 0x03B9 }, /* Greek_iota ι GREEK SMALL LETTER IOTA */
{ 0x07EA, 0x03BA }, /* Greek_kappa κ GREEK SMALL LETTER KAPPA */
{ 0x07EB, 0x03BB }, /* Greek_lambda λ GREEK SMALL LETTER LAMDA */
{ 0x07EC, 0x03BC }, /* Greek_mu μ GREEK SMALL LETTER MU */
{ 0x07ED, 0x03BD }, /* Greek_nu ν GREEK SMALL LETTER NU */
{ 0x07EE, 0x03BE }, /* Greek_xi ξ GREEK SMALL LETTER XI */
{ 0x07EF, 0x03BF }, /* Greek_omicron ο GREEK SMALL LETTER OMICRON */
{ 0x07F0, 0x03C0 }, /* Greek_pi π GREEK SMALL LETTER PI */
{ 0x07F1, 0x03C1 }, /* Greek_rho ρ GREEK SMALL LETTER RHO */
{ 0x07F2, 0x03C3 }, /* Greek_sigma σ GREEK SMALL LETTER SIGMA */
{ 0x07F3, 0x03C2 }, /* Greek_finalsmallsigma ς GREEK SMALL LETTER FINAL SIGMA */
{ 0x07F4, 0x03C4 }, /* Greek_tau τ GREEK SMALL LETTER TAU */
{ 0x07F5, 0x03C5 }, /* Greek_upsilon υ GREEK SMALL LETTER UPSILON */
{ 0x07F6, 0x03C6 }, /* Greek_phi φ GREEK SMALL LETTER PHI */
{ 0x07F7, 0x03C7 }, /* Greek_chi χ GREEK SMALL LETTER CHI */
{ 0x07F8, 0x03C8 }, /* Greek_psi ψ GREEK SMALL LETTER PSI */
{ 0x07F9, 0x03C9 }, /* Greek_omega ω GREEK SMALL LETTER OMEGA */
{ 0x08A1, 0x23B7 }, /* leftradical ⎷ ??? */
{ 0x08A2, 0x250C }, /* topleftradical ┌ BOX DRAWINGS LIGHT DOWN AND RIGHT */
{ 0x08A3, 0x2500 }, /* horizconnector ─ BOX DRAWINGS LIGHT HORIZONTAL */
{ 0x08A4, 0x2320 }, /* topintegral ⌠ TOP HALF INTEGRAL */
{ 0x08A5, 0x2321 }, /* botintegral ⌡ BOTTOM HALF INTEGRAL */
{ 0x08A6, 0x2502 }, /* vertconnector │ BOX DRAWINGS LIGHT VERTICAL */
{ 0x08A7, 0x23A1 }, /* topleftsqbracket ⎡ ??? */
{ 0x08A8, 0x23A3 }, /* botleftsqbracket ⎣ ??? */
{ 0x08A9, 0x23A4 }, /* toprightsqbracket ⎤ ??? */
{ 0x08AA, 0x23A6 }, /* botrightsqbracket ⎦ ??? */
{ 0x08AB, 0x239B }, /* topleftparens ⎛ ??? */
{ 0x08AC, 0x239D }, /* botleftparens ⎝ ??? */
{ 0x08AD, 0x239E }, /* toprightparens ⎞ ??? */
{ 0x08AE, 0x23A0 }, /* botrightparens ⎠ ??? */
{ 0x08AF, 0x23A8 }, /* leftmiddlecurlybrace ⎨ ??? */
{ 0x08B0, 0x23AC }, /* rightmiddlecurlybrace ⎬ ??? */
/* 0x08B1 topleftsummation ? ??? */
/* 0x08B2 botleftsummation ? ??? */
/* 0x08B3 topvertsummationconnector ? ??? */
/* 0x08B4 botvertsummationconnector ? ??? */
/* 0x08B5 toprightsummation ? ??? */
/* 0x08B6 botrightsummation ? ??? */
/* 0x08B7 rightmiddlesummation ? ??? */
{ 0x08BC, 0x2264 }, /* lessthanequal ≤ LESS-THAN OR EQUAL TO */
{ 0x08BD, 0x2260 }, /* notequal ≠ NOT EQUAL TO */
{ 0x08BE, 0x2265 }, /* greaterthanequal ≥ GREATER-THAN OR EQUAL TO */
{ 0x08BF, 0x222B }, /* integral ∫ INTEGRAL */
{ 0x08C0, 0x2234 }, /* therefore ∴ THEREFORE */
{ 0x08C1, 0x221D }, /* variation ∝ PROPORTIONAL TO */
{ 0x08C2, 0x221E }, /* infinity ∞ INFINITY */
{ 0x08C5, 0x2207 }, /* nabla ∇ NABLA */
{ 0x08C8, 0x223C }, /* approximate TILDE OPERATOR */
{ 0x08C9, 0x2243 }, /* similarequal ≃ ASYMPTOTICALLY EQUAL TO */
{ 0x08CD, 0x21D4 }, /* ifonlyif ⇔ LEFT RIGHT DOUBLE ARROW */
{ 0x08CE, 0x21D2 }, /* implies ⇒ RIGHTWARDS DOUBLE ARROW */
{ 0x08CF, 0x2261 }, /* identical ≡ IDENTICAL TO */
{ 0x08D6, 0x221A }, /* radical √ SQUARE ROOT */
{ 0x08DA, 0x2282 }, /* includedin ⊂ SUBSET OF */
{ 0x08DB, 0x2283 }, /* includes ⊃ SUPERSET OF */
{ 0x08DC, 0x2229 }, /* intersection ∩ INTERSECTION */
{ 0x08DD, 0x222A }, /* union UNION */
{ 0x08DE, 0x2227 }, /* logicaland ∧ LOGICAL AND */
{ 0x08DF, 0x2228 }, /* logicalor LOGICAL OR */
{ 0x08EF, 0x2202 }, /* partialderivative ∂ PARTIAL DIFFERENTIAL */
{ 0x08F6, 0x0192 }, /* function ƒ LATIN SMALL LETTER F WITH HOOK */
{ 0x08FB, 0x2190 }, /* leftarrow ← LEFTWARDS ARROW */
{ 0x08FC, 0x2191 }, /* uparrow ↑ UPWARDS ARROW */
{ 0x08FD, 0x2192 }, /* rightarrow → RIGHTWARDS ARROW */
{ 0x08FE, 0x2193 }, /* downarrow ↓ DOWNWARDS ARROW */
/* 0x09DF blank ? ??? */
{ 0x09E0, 0x25C6 }, /* soliddiamond ◆ BLACK DIAMOND */
{ 0x09E1, 0x2592 }, /* checkerboard ▒ MEDIUM SHADE */
{ 0x09E2, 0x2409 }, /* ht ␉ SYMBOL FOR HORIZONTAL TABULATION */
{ 0x09E3, 0x240C }, /* ff ␌ SYMBOL FOR FORM FEED */
{ 0x09E4, 0x240D }, /* cr ␍ SYMBOL FOR CARRIAGE RETURN */
{ 0x09E5, 0x240A }, /* lf ␊ SYMBOL FOR LINE FEED */
{ 0x09E8, 0x2424 }, /* nl ␤ SYMBOL FOR NEWLINE */
{ 0x09E9, 0x240B }, /* vt ␋ SYMBOL FOR VERTICAL TABULATION */
{ 0x09EA, 0x2518 }, /* lowrightcorner ┘ BOX DRAWINGS LIGHT UP AND LEFT */
{ 0x09EB, 0x2510 }, /* uprightcorner ┐ BOX DRAWINGS LIGHT DOWN AND LEFT */
{ 0x09EC, 0x250C }, /* upleftcorner ┌ BOX DRAWINGS LIGHT DOWN AND RIGHT */
{ 0x09ED, 0x2514 }, /* lowleftcorner └ BOX DRAWINGS LIGHT UP AND RIGHT */
{ 0x09EE, 0x253C }, /* crossinglines ┼ BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL */
{ 0x09EF, 0x23BA }, /* horizlinescan1 ⎺ HORIZONTAL SCAN LINE-1 (Unicode 3.2 draft) */
{ 0x09F0, 0x23BB }, /* horizlinescan3 ⎻ HORIZONTAL SCAN LINE-3 (Unicode 3.2 draft) */
{ 0x09F1, 0x2500 }, /* horizlinescan5 ─ BOX DRAWINGS LIGHT HORIZONTAL */
{ 0x09F2, 0x23BC }, /* horizlinescan7 ⎼ HORIZONTAL SCAN LINE-7 (Unicode 3.2 draft) */
{ 0x09F3, 0x23BD }, /* horizlinescan9 ⎽ HORIZONTAL SCAN LINE-9 (Unicode 3.2 draft) */
{ 0x09F4, 0x251C }, /* leftt ├ BOX DRAWINGS LIGHT VERTICAL AND RIGHT */
{ 0x09F5, 0x2524 }, /* rightt ┤ BOX DRAWINGS LIGHT VERTICAL AND LEFT */
{ 0x09F6, 0x2534 }, /* bott ┴ BOX DRAWINGS LIGHT UP AND HORIZONTAL */
{ 0x09F7, 0x252C }, /* topt ┬ BOX DRAWINGS LIGHT DOWN AND HORIZONTAL */
{ 0x09F8, 0x2502 }, /* vertbar │ BOX DRAWINGS LIGHT VERTICAL */
{ 0x0AA1, 0x2003 }, /* emspace EM SPACE */
{ 0x0AA2, 0x2002 }, /* enspace EN SPACE */
{ 0x0AA3, 0x2004 }, /* em3space THREE-PER-EM SPACE */
{ 0x0AA4, 0x2005 }, /* em4space FOUR-PER-EM SPACE */
{ 0x0AA5, 0x2007 }, /* digitspace FIGURE SPACE */
{ 0x0AA6, 0x2008 }, /* punctspace PUNCTUATION SPACE */
{ 0x0AA7, 0x2009 }, /* thinspace THIN SPACE */
{ 0x0AA8, 0x200A }, /* hairspace HAIR SPACE */
{ 0x0AA9, 0x2014 }, /* emdash — EM DASH */
{ 0x0AAA, 0x2013 }, /* endash EN DASH */
/* 0x0AAC signifblank ? ??? */
{ 0x0AAE, 0x2026 }, /* ellipsis … HORIZONTAL ELLIPSIS */
{ 0x0AAF, 0x2025 }, /* doubbaselinedot ‥ TWO DOT LEADER */
{ 0x0AB0, 0x2153 }, /* onethird ⅓ VULGAR FRACTION ONE THIRD */
{ 0x0AB1, 0x2154 }, /* twothirds ⅔ VULGAR FRACTION TWO THIRDS */
{ 0x0AB2, 0x2155 }, /* onefifth ⅕ VULGAR FRACTION ONE FIFTH */
{ 0x0AB3, 0x2156 }, /* twofifths ⅖ VULGAR FRACTION TWO FIFTHS */
{ 0x0AB4, 0x2157 }, /* threefifths ⅗ VULGAR FRACTION THREE FIFTHS */
{ 0x0AB5, 0x2158 }, /* fourfifths ⅘ VULGAR FRACTION FOUR FIFTHS */
{ 0x0AB6, 0x2159 }, /* onesixth ⅙ VULGAR FRACTION ONE SIXTH */
{ 0x0AB7, 0x215A }, /* fivesixths ⅚ VULGAR FRACTION FIVE SIXTHS */
{ 0x0AB8, 0x2105 }, /* careof ℅ CARE OF */
{ 0x0ABB, 0x2012 }, /* figdash FIGURE DASH */
{ 0x0ABC, 0x2329 }, /* leftanglebracket 〈 LEFT-POINTING ANGLE BRACKET */
/* 0x0ABD decimalpoint ? ??? */
{ 0x0ABE, 0x232A }, /* rightanglebracket 〉 RIGHT-POINTING ANGLE BRACKET */
/* 0x0ABF marker ? ??? */
{ 0x0AC3, 0x215B }, /* oneeighth ⅛ VULGAR FRACTION ONE EIGHTH */
{ 0x0AC4, 0x215C }, /* threeeighths ⅜ VULGAR FRACTION THREE EIGHTHS */
{ 0x0AC5, 0x215D }, /* fiveeighths ⅝ VULGAR FRACTION FIVE EIGHTHS */
{ 0x0AC6, 0x215E }, /* seveneighths ⅞ VULGAR FRACTION SEVEN EIGHTHS */
{ 0x0AC9, 0x2122 }, /* trademark ™ TRADE MARK SIGN */
{ 0x0ACA, 0x2613 }, /* signaturemark ☓ SALTIRE */
/* 0x0ACB trademarkincircle ? ??? */
{ 0x0ACC, 0x25C1 }, /* leftopentriangle ◁ WHITE LEFT-POINTING TRIANGLE */
{ 0x0ACD, 0x25B7 }, /* rightopentriangle ▷ WHITE RIGHT-POINTING TRIANGLE */
{ 0x0ACE, 0x25CB }, /* emopencircle ○ WHITE CIRCLE */
{ 0x0ACF, 0x25AF }, /* emopenrectangle ▯ WHITE VERTICAL RECTANGLE */
{ 0x0AD0, 0x2018 }, /* leftsinglequotemark LEFT SINGLE QUOTATION MARK */
{ 0x0AD1, 0x2019 }, /* rightsinglequotemark RIGHT SINGLE QUOTATION MARK */
{ 0x0AD2, 0x201C }, /* leftdoublequotemark “ LEFT DOUBLE QUOTATION MARK */
{ 0x0AD3, 0x201D }, /* rightdoublequotemark ” RIGHT DOUBLE QUOTATION MARK */
{ 0x0AD4, 0x211E }, /* prescription ℞ PRESCRIPTION TAKE */
{ 0x0AD6, 0x2032 }, /* minutes PRIME */
{ 0x0AD7, 0x2033 }, /* seconds ″ DOUBLE PRIME */
{ 0x0AD9, 0x271D }, /* latincross ✝ LATIN CROSS */
/* 0x0ADA hexagram ? ??? */
{ 0x0ADB, 0x25AC }, /* filledrectbullet ▬ BLACK RECTANGLE */
{ 0x0ADC, 0x25C0 }, /* filledlefttribullet ◀ BLACK LEFT-POINTING TRIANGLE */
{ 0x0ADD, 0x25B6 }, /* filledrighttribullet ▶ BLACK RIGHT-POINTING TRIANGLE */
{ 0x0ADE, 0x25CF }, /* emfilledcircle ● BLACK CIRCLE */
{ 0x0ADF, 0x25AE }, /* emfilledrect ▮ BLACK VERTICAL RECTANGLE */
{ 0x0AE0, 0x25E6 }, /* enopencircbullet ◦ WHITE BULLET */
{ 0x0AE1, 0x25AB }, /* enopensquarebullet ▫ WHITE SMALL SQUARE */
{ 0x0AE2, 0x25AD }, /* openrectbullet ▭ WHITE RECTANGLE */
{ 0x0AE3, 0x25B3 }, /* opentribulletup △ WHITE UP-POINTING TRIANGLE */
{ 0x0AE4, 0x25BD }, /* opentribulletdown ▽ WHITE DOWN-POINTING TRIANGLE */
{ 0x0AE5, 0x2606 }, /* openstar ☆ WHITE STAR */
{ 0x0AE6, 0x2022 }, /* enfilledcircbullet • BULLET */
{ 0x0AE7, 0x25AA }, /* enfilledsqbullet ▪ BLACK SMALL SQUARE */
{ 0x0AE8, 0x25B2 }, /* filledtribulletup ▲ BLACK UP-POINTING TRIANGLE */
{ 0x0AE9, 0x25BC }, /* filledtribulletdown ▼ BLACK DOWN-POINTING TRIANGLE */
{ 0x0AEA, 0x261C }, /* leftpointer ☜ WHITE LEFT POINTING INDEX */
{ 0x0AEB, 0x261E }, /* rightpointer ☞ WHITE RIGHT POINTING INDEX */
{ 0x0AEC, 0x2663 }, /* club ♣ BLACK CLUB SUIT */
{ 0x0AED, 0x2666 }, /* diamond ♦ BLACK DIAMOND SUIT */
{ 0x0AEE, 0x2665 }, /* heart ♥ BLACK HEART SUIT */
{ 0x0AF0, 0x2720 }, /* maltesecross ✠ MALTESE CROSS */
{ 0x0AF1, 0x2020 }, /* dagger † DAGGER */
{ 0x0AF2, 0x2021 }, /* doubledagger ‡ DOUBLE DAGGER */
{ 0x0AF3, 0x2713 }, /* checkmark ✓ CHECK MARK */
{ 0x0AF4, 0x2717 }, /* ballotcross ✗ BALLOT X */
{ 0x0AF5, 0x266F }, /* musicalsharp ♯ MUSIC SHARP SIGN */
{ 0x0AF6, 0x266D }, /* musicalflat ♭ MUSIC FLAT SIGN */
{ 0x0AF7, 0x2642 }, /* malesymbol ♂ MALE SIGN */
{ 0x0AF8, 0x2640 }, /* femalesymbol ♀ FEMALE SIGN */
{ 0x0AF9, 0x260E }, /* telephone ☎ BLACK TELEPHONE */
{ 0x0AFA, 0x2315 }, /* telephonerecorder ⌕ TELEPHONE RECORDER */
{ 0x0AFB, 0x2117 }, /* phonographcopyright ℗ SOUND RECORDING COPYRIGHT */
{ 0x0AFC, 0x2038 }, /* caret ‸ CARET */
{ 0x0AFD, 0x201A }, /* singlelowquotemark SINGLE LOW-9 QUOTATION MARK */
{ 0x0AFE, 0x201E }, /* doublelowquotemark „ DOUBLE LOW-9 QUOTATION MARK */
/* 0x0AFF cursor ? ??? */
{ 0x0BA3, 0x003C }, /* leftcaret < LESS-THAN SIGN */
{ 0x0BA6, 0x003E }, /* rightcaret > GREATER-THAN SIGN */
{ 0x0BA8, 0x2228 }, /* downcaret LOGICAL OR */
{ 0x0BA9, 0x2227 }, /* upcaret ∧ LOGICAL AND */
{ 0x0BC0, 0x00AF }, /* overbar ¯ MACRON */
{ 0x0BC2, 0x22A5 }, /* downtack ⊥ UP TACK */
{ 0x0BC3, 0x2229 }, /* upshoe ∩ INTERSECTION */
{ 0x0BC4, 0x230A }, /* downstile ⌊ LEFT FLOOR */
{ 0x0BC6, 0x005F }, /* underbar _ LOW LINE */
{ 0x0BCA, 0x2218 }, /* jot ∘ RING OPERATOR */
{ 0x0BCC, 0x2395 }, /* quad ⎕ APL FUNCTIONAL SYMBOL QUAD */
{ 0x0BCE, 0x22A4 }, /* uptack DOWN TACK */
{ 0x0BCF, 0x25CB }, /* circle ○ WHITE CIRCLE */
{ 0x0BD3, 0x2308 }, /* upstile ⌈ LEFT CEILING */
{ 0x0BD6, 0x222A }, /* downshoe UNION */
{ 0x0BD8, 0x2283 }, /* rightshoe ⊃ SUPERSET OF */
{ 0x0BDA, 0x2282 }, /* leftshoe ⊂ SUBSET OF */
{ 0x0BDC, 0x22A2 }, /* lefttack ⊢ RIGHT TACK */
{ 0x0BFC, 0x22A3 }, /* righttack ⊣ LEFT TACK */
{ 0x0CDF, 0x2017 }, /* hebrew_doublelowline ‗ DOUBLE LOW LINE */
{ 0x0CE0, 0x05D0 }, /* hebrew_aleph א HEBREW LETTER ALEF */
{ 0x0CE1, 0x05D1 }, /* hebrew_bet ב HEBREW LETTER BET */
{ 0x0CE2, 0x05D2 }, /* hebrew_gimel ג HEBREW LETTER GIMEL */
{ 0x0CE3, 0x05D3 }, /* hebrew_dalet ד HEBREW LETTER DALET */
{ 0x0CE4, 0x05D4 }, /* hebrew_he ה HEBREW LETTER HE */
{ 0x0CE5, 0x05D5 }, /* hebrew_waw ו HEBREW LETTER VAV */
{ 0x0CE6, 0x05D6 }, /* hebrew_zain ז HEBREW LETTER ZAYIN */
{ 0x0CE7, 0x05D7 }, /* hebrew_chet ח HEBREW LETTER HET */
{ 0x0CE8, 0x05D8 }, /* hebrew_tet ט HEBREW LETTER TET */
{ 0x0CE9, 0x05D9 }, /* hebrew_yod י HEBREW LETTER YOD */
{ 0x0CEA, 0x05DA }, /* hebrew_finalkaph ך HEBREW LETTER FINAL KAF */
{ 0x0CEB, 0x05DB }, /* hebrew_kaph כ HEBREW LETTER KAF */
{ 0x0CEC, 0x05DC }, /* hebrew_lamed ל HEBREW LETTER LAMED */
{ 0x0CED, 0x05DD }, /* hebrew_finalmem ם HEBREW LETTER FINAL MEM */
{ 0x0CEE, 0x05DE }, /* hebrew_mem מ HEBREW LETTER MEM */
{ 0x0CEF, 0x05DF }, /* hebrew_finalnun ן HEBREW LETTER FINAL NUN */
{ 0x0CF0, 0x05E0 }, /* hebrew_nun נ HEBREW LETTER NUN */
{ 0x0CF1, 0x05E1 }, /* hebrew_samech ס HEBREW LETTER SAMEKH */
{ 0x0CF2, 0x05E2 }, /* hebrew_ayin ע HEBREW LETTER AYIN */
{ 0x0CF3, 0x05E3 }, /* hebrew_finalpe ף HEBREW LETTER FINAL PE */
{ 0x0CF4, 0x05E4 }, /* hebrew_pe פ HEBREW LETTER PE */
{ 0x0CF5, 0x05E5 }, /* hebrew_finalzade ץ HEBREW LETTER FINAL TSADI */
{ 0x0CF6, 0x05E6 }, /* hebrew_zade צ HEBREW LETTER TSADI */
{ 0x0CF7, 0x05E7 }, /* hebrew_qoph ק HEBREW LETTER QOF */
{ 0x0CF8, 0x05E8 }, /* hebrew_resh ר HEBREW LETTER RESH */
{ 0x0CF9, 0x05E9 }, /* hebrew_shin ש HEBREW LETTER SHIN */
{ 0x0CFA, 0x05EA }, /* hebrew_taw ת HEBREW LETTER TAV */
{ 0x0DA1, 0x0E01 }, /* Thai_kokai ก THAI CHARACTER KO KAI */
{ 0x0DA2, 0x0E02 }, /* Thai_khokhai ข THAI CHARACTER KHO KHAI */
{ 0x0DA3, 0x0E03 }, /* Thai_khokhuat ฃ THAI CHARACTER KHO KHUAT */
{ 0x0DA4, 0x0E04 }, /* Thai_khokhwai ค THAI CHARACTER KHO KHWAI */
{ 0x0DA5, 0x0E05 }, /* Thai_khokhon ฅ THAI CHARACTER KHO KHON */
{ 0x0DA6, 0x0E06 }, /* Thai_khorakhang ฆ THAI CHARACTER KHO RAKHANG */
{ 0x0DA7, 0x0E07 }, /* Thai_ngongu ง THAI CHARACTER NGO NGU */
{ 0x0DA8, 0x0E08 }, /* Thai_chochan จ THAI CHARACTER CHO CHAN */
{ 0x0DA9, 0x0E09 }, /* Thai_choching ฉ THAI CHARACTER CHO CHING */
{ 0x0DAA, 0x0E0A }, /* Thai_chochang ช THAI CHARACTER CHO CHANG */
{ 0x0DAB, 0x0E0B }, /* Thai_soso ซ THAI CHARACTER SO SO */
{ 0x0DAC, 0x0E0C }, /* Thai_chochoe ฌ THAI CHARACTER CHO CHOE */
{ 0x0DAD, 0x0E0D }, /* Thai_yoying ญ THAI CHARACTER YO YING */
{ 0x0DAE, 0x0E0E }, /* Thai_dochada ฎ THAI CHARACTER DO CHADA */
{ 0x0DAF, 0x0E0F }, /* Thai_topatak ฏ THAI CHARACTER TO PATAK */
{ 0x0DB0, 0x0E10 }, /* Thai_thothan ฐ THAI CHARACTER THO THAN */
{ 0x0DB1, 0x0E11 }, /* Thai_thonangmontho ฑ THAI CHARACTER THO NANGMONTHO */
{ 0x0DB2, 0x0E12 }, /* Thai_thophuthao ฒ THAI CHARACTER THO PHUTHAO */
{ 0x0DB3, 0x0E13 }, /* Thai_nonen ณ THAI CHARACTER NO NEN */
{ 0x0DB4, 0x0E14 }, /* Thai_dodek ด THAI CHARACTER DO DEK */
{ 0x0DB5, 0x0E15 }, /* Thai_totao ต THAI CHARACTER TO TAO */
{ 0x0DB6, 0x0E16 }, /* Thai_thothung ถ THAI CHARACTER THO THUNG */
{ 0x0DB7, 0x0E17 }, /* Thai_thothahan ท THAI CHARACTER THO THAHAN */
{ 0x0DB8, 0x0E18 }, /* Thai_thothong ธ THAI CHARACTER THO THONG */
{ 0x0DB9, 0x0E19 }, /* Thai_nonu น THAI CHARACTER NO NU */
{ 0x0DBA, 0x0E1A }, /* Thai_bobaimai บ THAI CHARACTER BO BAIMAI */
{ 0x0DBB, 0x0E1B }, /* Thai_popla ป THAI CHARACTER PO PLA */
{ 0x0DBC, 0x0E1C }, /* Thai_phophung ผ THAI CHARACTER PHO PHUNG */
{ 0x0DBD, 0x0E1D }, /* Thai_fofa ฝ THAI CHARACTER FO FA */
{ 0x0DBE, 0x0E1E }, /* Thai_phophan พ THAI CHARACTER PHO PHAN */
{ 0x0DBF, 0x0E1F }, /* Thai_fofan ฟ THAI CHARACTER FO FAN */
{ 0x0DC0, 0x0E20 }, /* Thai_phosamphao ภ THAI CHARACTER PHO SAMPHAO */
{ 0x0DC1, 0x0E21 }, /* Thai_moma ม THAI CHARACTER MO MA */
{ 0x0DC2, 0x0E22 }, /* Thai_yoyak ย THAI CHARACTER YO YAK */
{ 0x0DC3, 0x0E23 }, /* Thai_rorua ร THAI CHARACTER RO RUA */
{ 0x0DC4, 0x0E24 }, /* Thai_ru ฤ THAI CHARACTER RU */
{ 0x0DC5, 0x0E25 }, /* Thai_loling ล THAI CHARACTER LO LING */
{ 0x0DC6, 0x0E26 }, /* Thai_lu ฦ THAI CHARACTER LU */
{ 0x0DC7, 0x0E27 }, /* Thai_wowaen ว THAI CHARACTER WO WAEN */
{ 0x0DC8, 0x0E28 }, /* Thai_sosala ศ THAI CHARACTER SO SALA */
{ 0x0DC9, 0x0E29 }, /* Thai_sorusi ษ THAI CHARACTER SO RUSI */
{ 0x0DCA, 0x0E2A }, /* Thai_sosua ส THAI CHARACTER SO SUA */
{ 0x0DCB, 0x0E2B }, /* Thai_hohip ห THAI CHARACTER HO HIP */
{ 0x0DCC, 0x0E2C }, /* Thai_lochula ฬ THAI CHARACTER LO CHULA */
{ 0x0DCD, 0x0E2D }, /* Thai_oang อ THAI CHARACTER O ANG */
{ 0x0DCE, 0x0E2E }, /* Thai_honokhuk ฮ THAI CHARACTER HO NOKHUK */
{ 0x0DCF, 0x0E2F }, /* Thai_paiyannoi ฯ THAI CHARACTER PAIYANNOI */
{ 0x0DD0, 0x0E30 }, /* Thai_saraa ะ THAI CHARACTER SARA A */
{ 0x0DD1, 0x0E31 }, /* Thai_maihanakat ั THAI CHARACTER MAI HAN-AKAT */
{ 0x0DD2, 0x0E32 }, /* Thai_saraaa า THAI CHARACTER SARA AA */
{ 0x0DD3, 0x0E33 }, /* Thai_saraam ำ THAI CHARACTER SARA AM */
{ 0x0DD4, 0x0E34 }, /* Thai_sarai ิ THAI CHARACTER SARA I */
{ 0x0DD5, 0x0E35 }, /* Thai_saraii ี THAI CHARACTER SARA II */
{ 0x0DD6, 0x0E36 }, /* Thai_saraue ึ THAI CHARACTER SARA UE */
{ 0x0DD7, 0x0E37 }, /* Thai_sarauee ื THAI CHARACTER SARA UEE */
{ 0x0DD8, 0x0E38 }, /* Thai_sarau ุ THAI CHARACTER SARA U */
{ 0x0DD9, 0x0E39 }, /* Thai_sarauu ู THAI CHARACTER SARA UU */
{ 0x0DDA, 0x0E3A }, /* Thai_phinthu ฺ THAI CHARACTER PHINTHU */
/* 0x0DDE Thai_maihanakat_maitho ? ??? */
{ 0x0DDF, 0x0E3F }, /* Thai_baht ฿ THAI CURRENCY SYMBOL BAHT */
{ 0x0DE0, 0x0E40 }, /* Thai_sarae เ THAI CHARACTER SARA E */
{ 0x0DE1, 0x0E41 }, /* Thai_saraae แ THAI CHARACTER SARA AE */
{ 0x0DE2, 0x0E42 }, /* Thai_sarao โ THAI CHARACTER SARA O */
{ 0x0DE3, 0x0E43 }, /* Thai_saraaimaimuan ใ THAI CHARACTER SARA AI MAIMUAN */
{ 0x0DE4, 0x0E44 }, /* Thai_saraaimaimalai ไ THAI CHARACTER SARA AI MAIMALAI */
{ 0x0DE5, 0x0E45 }, /* Thai_lakkhangyao ๅ THAI CHARACTER LAKKHANGYAO */
{ 0x0DE6, 0x0E46 }, /* Thai_maiyamok ๆ THAI CHARACTER MAIYAMOK */
{ 0x0DE7, 0x0E47 }, /* Thai_maitaikhu ็ THAI CHARACTER MAITAIKHU */
{ 0x0DE8, 0x0E48 }, /* Thai_maiek ่ THAI CHARACTER MAI EK */
{ 0x0DE9, 0x0E49 }, /* Thai_maitho ้ THAI CHARACTER MAI THO */
{ 0x0DEA, 0x0E4A }, /* Thai_maitri ๊ THAI CHARACTER MAI TRI */
{ 0x0DEB, 0x0E4B }, /* Thai_maichattawa ๋ THAI CHARACTER MAI CHATTAWA */
{ 0x0DEC, 0x0E4C }, /* Thai_thanthakhat ์ THAI CHARACTER THANTHAKHAT */
{ 0x0DED, 0x0E4D }, /* Thai_nikhahit ํ THAI CHARACTER NIKHAHIT */
{ 0x0DF0, 0x0E50 }, /* Thai_leksun THAI DIGIT ZERO */
{ 0x0DF1, 0x0E51 }, /* Thai_leknung ๑ THAI DIGIT ONE */
{ 0x0DF2, 0x0E52 }, /* Thai_leksong ๒ THAI DIGIT TWO */
{ 0x0DF3, 0x0E53 }, /* Thai_leksam ๓ THAI DIGIT THREE */
{ 0x0DF4, 0x0E54 }, /* Thai_leksi ๔ THAI DIGIT FOUR */
{ 0x0DF5, 0x0E55 }, /* Thai_lekha ๕ THAI DIGIT FIVE */
{ 0x0DF6, 0x0E56 }, /* Thai_lekhok ๖ THAI DIGIT SIX */
{ 0x0DF7, 0x0E57 }, /* Thai_lekchet ๗ THAI DIGIT SEVEN */
{ 0x0DF8, 0x0E58 }, /* Thai_lekpaet ๘ THAI DIGIT EIGHT */
{ 0x0DF9, 0x0E59 }, /* Thai_lekkao ๙ THAI DIGIT NINE */
{ 0x0EA1, 0x3131 }, /* Hangul_Kiyeog ㄱ HANGUL LETTER KIYEOK */
{ 0x0EA2, 0x3132 }, /* Hangul_SsangKiyeog ㄲ HANGUL LETTER SSANGKIYEOK */
{ 0x0EA3, 0x3133 }, /* Hangul_KiyeogSios ㄳ HANGUL LETTER KIYEOK-SIOS */
{ 0x0EA4, 0x3134 }, /* Hangul_Nieun ㄴ HANGUL LETTER NIEUN */
{ 0x0EA5, 0x3135 }, /* Hangul_NieunJieuj ㄵ HANGUL LETTER NIEUN-CIEUC */
{ 0x0EA6, 0x3136 }, /* Hangul_NieunHieuh ㄶ HANGUL LETTER NIEUN-HIEUH */
{ 0x0EA7, 0x3137 }, /* Hangul_Dikeud ㄷ HANGUL LETTER TIKEUT */
{ 0x0EA8, 0x3138 }, /* Hangul_SsangDikeud ㄸ HANGUL LETTER SSANGTIKEUT */
{ 0x0EA9, 0x3139 }, /* Hangul_Rieul ㄹ HANGUL LETTER RIEUL */
{ 0x0EAA, 0x313A }, /* Hangul_RieulKiyeog ㄺ HANGUL LETTER RIEUL-KIYEOK */
{ 0x0EAB, 0x313B }, /* Hangul_RieulMieum ㄻ HANGUL LETTER RIEUL-MIEUM */
{ 0x0EAC, 0x313C }, /* Hangul_RieulPieub ㄼ HANGUL LETTER RIEUL-PIEUP */
{ 0x0EAD, 0x313D }, /* Hangul_RieulSios ㄽ HANGUL LETTER RIEUL-SIOS */
{ 0x0EAE, 0x313E }, /* Hangul_RieulTieut ㄾ HANGUL LETTER RIEUL-THIEUTH */
{ 0x0EAF, 0x313F }, /* Hangul_RieulPhieuf ㄿ HANGUL LETTER RIEUL-PHIEUPH */
{ 0x0EB0, 0x3140 }, /* Hangul_RieulHieuh ㅀ HANGUL LETTER RIEUL-HIEUH */
{ 0x0EB1, 0x3141 }, /* Hangul_Mieum ㅁ HANGUL LETTER MIEUM */
{ 0x0EB2, 0x3142 }, /* Hangul_Pieub ㅂ HANGUL LETTER PIEUP */
{ 0x0EB3, 0x3143 }, /* Hangul_SsangPieub ㅃ HANGUL LETTER SSANGPIEUP */
{ 0x0EB4, 0x3144 }, /* Hangul_PieubSios ㅄ HANGUL LETTER PIEUP-SIOS */
{ 0x0EB5, 0x3145 }, /* Hangul_Sios ㅅ HANGUL LETTER SIOS */
{ 0x0EB6, 0x3146 }, /* Hangul_SsangSios ㅆ HANGUL LETTER SSANGSIOS */
{ 0x0EB7, 0x3147 }, /* Hangul_Ieung ㅇ HANGUL LETTER IEUNG */
{ 0x0EB8, 0x3148 }, /* Hangul_Jieuj ㅈ HANGUL LETTER CIEUC */
{ 0x0EB9, 0x3149 }, /* Hangul_SsangJieuj ㅉ HANGUL LETTER SSANGCIEUC */
{ 0x0EBA, 0x314A }, /* Hangul_Cieuc ㅊ HANGUL LETTER CHIEUCH */
{ 0x0EBB, 0x314B }, /* Hangul_Khieuq ㅋ HANGUL LETTER KHIEUKH */
{ 0x0EBC, 0x314C }, /* Hangul_Tieut ㅌ HANGUL LETTER THIEUTH */
{ 0x0EBD, 0x314D }, /* Hangul_Phieuf ㅍ HANGUL LETTER PHIEUPH */
{ 0x0EBE, 0x314E }, /* Hangul_Hieuh ㅎ HANGUL LETTER HIEUH */
{ 0x0EBF, 0x314F }, /* Hangul_A ㅏ HANGUL LETTER A */
{ 0x0EC0, 0x3150 }, /* Hangul_AE ㅐ HANGUL LETTER AE */
{ 0x0EC1, 0x3151 }, /* Hangul_YA ㅑ HANGUL LETTER YA */
{ 0x0EC2, 0x3152 }, /* Hangul_YAE ㅒ HANGUL LETTER YAE */
{ 0x0EC3, 0x3153 }, /* Hangul_EO ㅓ HANGUL LETTER EO */
{ 0x0EC4, 0x3154 }, /* Hangul_E ㅔ HANGUL LETTER E */
{ 0x0EC5, 0x3155 }, /* Hangul_YEO ㅕ HANGUL LETTER YEO */
{ 0x0EC6, 0x3156 }, /* Hangul_YE ㅖ HANGUL LETTER YE */
{ 0x0EC7, 0x3157 }, /* Hangul_O ㅗ HANGUL LETTER O */
{ 0x0EC8, 0x3158 }, /* Hangul_WA ㅘ HANGUL LETTER WA */
{ 0x0EC9, 0x3159 }, /* Hangul_WAE ㅙ HANGUL LETTER WAE */
{ 0x0ECA, 0x315A }, /* Hangul_OE ㅚ HANGUL LETTER OE */
{ 0x0ECB, 0x315B }, /* Hangul_YO ㅛ HANGUL LETTER YO */
{ 0x0ECC, 0x315C }, /* Hangul_U ㅜ HANGUL LETTER U */
{ 0x0ECD, 0x315D }, /* Hangul_WEO ㅝ HANGUL LETTER WEO */
{ 0x0ECE, 0x315E }, /* Hangul_WE ㅞ HANGUL LETTER WE */
{ 0x0ECF, 0x315F }, /* Hangul_WI ㅟ HANGUL LETTER WI */
{ 0x0ED0, 0x3160 }, /* Hangul_YU ㅠ HANGUL LETTER YU */
{ 0x0ED1, 0x3161 }, /* Hangul_EU ㅡ HANGUL LETTER EU */
{ 0x0ED2, 0x3162 }, /* Hangul_YI ㅢ HANGUL LETTER YI */
{ 0x0ED3, 0x3163 }, /* Hangul_I ㅣ HANGUL LETTER I */
{ 0x0ED4, 0x11A8 }, /* Hangul_J_Kiyeog ᆨ HANGUL JONGSEONG KIYEOK */
{ 0x0ED5, 0x11A9 }, /* Hangul_J_SsangKiyeog ᆩ HANGUL JONGSEONG SSANGKIYEOK */
{ 0x0ED6, 0x11AA }, /* Hangul_J_KiyeogSios ᆪ HANGUL JONGSEONG KIYEOK-SIOS */
{ 0x0ED7, 0x11AB }, /* Hangul_J_Nieun ᆫ HANGUL JONGSEONG NIEUN */
{ 0x0ED8, 0x11AC }, /* Hangul_J_NieunJieuj ᆬ HANGUL JONGSEONG NIEUN-CIEUC */
{ 0x0ED9, 0x11AD }, /* Hangul_J_NieunHieuh ᆭ HANGUL JONGSEONG NIEUN-HIEUH */
{ 0x0EDA, 0x11AE }, /* Hangul_J_Dikeud ᆮ HANGUL JONGSEONG TIKEUT */
{ 0x0EDB, 0x11AF }, /* Hangul_J_Rieul ᆯ HANGUL JONGSEONG RIEUL */
{ 0x0EDC, 0x11B0 }, /* Hangul_J_RieulKiyeog ᆰ HANGUL JONGSEONG RIEUL-KIYEOK */
{ 0x0EDD, 0x11B1 }, /* Hangul_J_RieulMieum ᆱ HANGUL JONGSEONG RIEUL-MIEUM */
{ 0x0EDE, 0x11B2 }, /* Hangul_J_RieulPieub ᆲ HANGUL JONGSEONG RIEUL-PIEUP */
{ 0x0EDF, 0x11B3 }, /* Hangul_J_RieulSios ᆳ HANGUL JONGSEONG RIEUL-SIOS */
{ 0x0EE0, 0x11B4 }, /* Hangul_J_RieulTieut ᆴ HANGUL JONGSEONG RIEUL-THIEUTH */
{ 0x0EE1, 0x11B5 }, /* Hangul_J_RieulPhieuf ᆵ HANGUL JONGSEONG RIEUL-PHIEUPH */
{ 0x0EE2, 0x11B6 }, /* Hangul_J_RieulHieuh ᆶ HANGUL JONGSEONG RIEUL-HIEUH */
{ 0x0EE3, 0x11B7 }, /* Hangul_J_Mieum ᆷ HANGUL JONGSEONG MIEUM */
{ 0x0EE4, 0x11B8 }, /* Hangul_J_Pieub ᆸ HANGUL JONGSEONG PIEUP */
{ 0x0EE5, 0x11B9 }, /* Hangul_J_PieubSios ᆹ HANGUL JONGSEONG PIEUP-SIOS */
{ 0x0EE6, 0x11BA }, /* Hangul_J_Sios ᆺ HANGUL JONGSEONG SIOS */
{ 0x0EE7, 0x11BB }, /* Hangul_J_SsangSios ᆻ HANGUL JONGSEONG SSANGSIOS */
{ 0x0EE8, 0x11BC }, /* Hangul_J_Ieung ᆼ HANGUL JONGSEONG IEUNG */
{ 0x0EE9, 0x11BD }, /* Hangul_J_Jieuj ᆽ HANGUL JONGSEONG CIEUC */
{ 0x0EEA, 0x11BE }, /* Hangul_J_Cieuc ᆾ HANGUL JONGSEONG CHIEUCH */
{ 0x0EEB, 0x11BF }, /* Hangul_J_Khieuq ᆿ HANGUL JONGSEONG KHIEUKH */
{ 0x0EEC, 0x11C0 }, /* Hangul_J_Tieut ᇀ HANGUL JONGSEONG THIEUTH */
{ 0x0EED, 0x11C1 }, /* Hangul_J_Phieuf ᇁ HANGUL JONGSEONG PHIEUPH */
{ 0x0EEE, 0x11C2 }, /* Hangul_J_Hieuh ᇂ HANGUL JONGSEONG HIEUH */
{ 0x0EEF, 0x316D }, /* Hangul_RieulYeorinHieuh ㅭ HANGUL LETTER RIEUL-YEORINHIEUH */
{ 0x0EF0, 0x3171 }, /* Hangul_SunkyeongeumMieum ㅱ HANGUL LETTER KAPYEOUNMIEUM */
{ 0x0EF1, 0x3178 }, /* Hangul_SunkyeongeumPieub ㅸ HANGUL LETTER KAPYEOUNPIEUP */
{ 0x0EF2, 0x317F }, /* Hangul_PanSios ㅿ HANGUL LETTER PANSIOS */
{ 0x0EF3, 0x3181 }, /* Hangul_KkogjiDalrinIeung ㆁ HANGUL LETTER YESIEUNG */
{ 0x0EF4, 0x3184 }, /* Hangul_SunkyeongeumPhieuf ㆄ HANGUL LETTER KAPYEOUNPHIEUPH */
{ 0x0EF5, 0x3186 }, /* Hangul_YeorinHieuh ㆆ HANGUL LETTER YEORINHIEUH */
{ 0x0EF6, 0x318D }, /* Hangul_AraeA ㆍ HANGUL LETTER ARAEA */
{ 0x0EF7, 0x318E }, /* Hangul_AraeAE ㆎ HANGUL LETTER ARAEAE */
{ 0x0EF8, 0x11EB }, /* Hangul_J_PanSios ᇫ HANGUL JONGSEONG PANSIOS */
{ 0x0EF9, 0x11F0 }, /* Hangul_J_KkogjiDalrinIeung ᇰ HANGUL JONGSEONG YESIEUNG */
{ 0x0EFA, 0x11F9 }, /* Hangul_J_YeorinHieuh ᇹ HANGUL JONGSEONG YEORINHIEUH */
{ 0x0EFF, 0x20A9 }, /* Korean_Won ₩ WON SIGN */
{ 0x13A4, 0x20AC }, /* Euro € EURO SIGN */
{ 0x13BC, 0x0152 }, /* OE ΠLATIN CAPITAL LIGATURE OE */
{ 0x13BD, 0x0153 }, /* oe œ LATIN SMALL LIGATURE OE */
{ 0x13BE, 0x0178 }, /* Ydiaeresis Ÿ LATIN CAPITAL LETTER Y WITH DIAERESIS */
{ 0x20AC, 0x20AC }, /* EuroSign € EURO SIGN */
};
/***********************************************************************
* The following function converts ISO 10646-1 (UCS, Unicode) values to
* their corresponding KeySym values.
*
* The UTF-8 -> keysym conversion will hopefully one day be provided by
* Xlib via XmbLookupString() and should ideally not have to be
* done in X applications. But we are not there yet.
*
* Author: Markus G. Kuhn <mkuhn@acm.org>, University of Cambridge,
* June 1999
*
* Special thanks to Richard Verhoeven <river@win.tue.nl> for preparing
* an initial draft of the mapping table.
*
* This software is in the public domain. Share and enjoy!
***********************************************************************/
KeySym unicode_to_keysym(uint16_t unicode) {
int min = 0;
int max = sizeof(keysym_unicode_table) / sizeof(struct codepair) - 1;
int mid;
#ifdef XK_LATIN1
// First check for Latin-1 characters. (1:1 mapping)
if ((unicode >= 0x0020 && unicode <= 0x007E) ||
(unicode >= 0x00A0 && unicode <= 0x00FF)) {
return unicode;
}
#endif
// Binary search the lookup table.
while (max >= min) {
mid = (min + max) / 2;
if (keysym_unicode_table[mid].unicode < unicode) {
min = mid + 1;
}
else if (keysym_unicode_table[mid].unicode > unicode) {
max = mid - 1;
}
else {
// Found it.
return keysym_unicode_table[mid].keysym;
}
}
// No matching KeySym value found, return UCS2 with bit set.
return unicode | 0x01000000;
}
/***********************************************************************
* The following function converts KeySym values into the corresponding
* ISO 10646-1 (UCS, Unicode) values.
*
* The keysym -> UTF-8 conversion will hopefully one day be provided by
* Xlib via XLookupKeySym and should ideally not have to be done in X
* applications. But we are not there yet.
*
* Author: Markus G. Kuhn <mkuhn@acm.org>, University of Cambridge,
* June 1999
*
* Special thanks to Richard Verhoeven <river@win.tue.nl> for preparing
* an initial draft of the mapping table.
*
* This software is in the public domain. Share and enjoy!
***********************************************************************/
size_t keysym_to_unicode(KeySym keysym, uint16_t *buffer, size_t size) {
size_t count = 0;
int min = 0;
int max = sizeof(keysym_unicode_table) / sizeof(struct codepair) - 1;
int mid;
#ifdef XK_LATIN1
// First check for Latin-1 characters. (1:1 mapping)
if ((keysym >= 0x0020 && keysym <= 0x007E)
|| (keysym >= 0x00A0 && keysym <= 0x00FF)) {
if (count < size) {
buffer[count++] = keysym;
}
return count;
}
#endif
// Also check for directly encoded 24-bit UCS characters.
#if defined(XK_LATIN8) || defined(XK_ARABIC) || defined(XK_CYRILLIC) || \
defined(XK_ARMENIAN) || defined(XK_GEORGIAN) || defined(XK_CAUCASUS) || \
defined(XK_VIETNAMESE) || defined(XK_CURRENCY) || \
defined(XK_MATHEMATICAL) || defined(XK_BRAILLE) || defined(XK_SINHALA)
if ((keysym & 0xFF000000) == 0x01000000) {
if (count < size) {
buffer[count++] = keysym & 0x00FFFFFF;
}
return count;
}
#endif
// Binary search in table.
while (max >= min) {
mid = (min + max) / 2;
if (keysym_unicode_table[mid].keysym < keysym) {
min = mid + 1;
}
else if (keysym_unicode_table[mid].keysym > keysym) {
max = mid - 1;
}
else {
// Found it.
if (count < size) {
buffer[count++] = keysym_unicode_table[mid].unicode;
}
return count;
}
}
// No matching Unicode value found!
return count;
}
/* The following code is based on vncdisplaykeymap.c under the following terms:
*
* Copyright (C) 2008 Anthony Liguori <anthony@codemonkey.ws>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2 as
* published by the Free Software Foundation.
*/
uint16_t keycode_to_scancode(KeyCode keycode) {
uint16_t scancode = VC_UNDEFINED;
#if defined(USE_EVDEV) && defined(USE_XKB)
// Check to see if evdev is enabled.
if (is_evdev) {
unsigned short evdev_size = sizeof(evdev_scancode_table) / sizeof(evdev_scancode_table[0]);
// NOTE scancodes < 97 appear to be identical between Evdev and XFree86.
if (keycode < evdev_size) {
// For scancode < 97, a simple scancode - 8 offest could be applied,
// but math is generally slower than memory and we cannot save any
// extra space in the lookup table due to binary padding.
scancode = evdev_scancode_table[keycode][0];
}
}
else {
// Evdev was disabled, fallback to XFree86.
#endif
unsigned short xfree86_size = sizeof(xfree86_scancode_table) / sizeof(xfree86_scancode_table[0]);
// NOTE scancodes < 97 appear to be identical between Evdev and XFree86.
if (keycode < xfree86_size) {
// For scancode < 97, a simple scancode - 8 offest could be applied,
// but math is generally slower than memory and we cannot save any
// extra space in the lookup table due to binary padding.
scancode = xfree86_scancode_table[keycode][0];
}
#if defined(USE_EVDEV) && defined(USE_XKB)
}
#endif
return scancode;
}
KeyCode scancode_to_keycode(uint16_t scancode) {
KeyCode keycode = 0x0000;
#if defined(USE_EVDEV) && defined(USE_XKB)
// Check to see if Evdev is enabled.
if (is_evdev) {
unsigned short evdev_size = sizeof(evdev_scancode_table) / sizeof(evdev_scancode_table[0]);
// NOTE scancodes < 97 appear to be identical between Evdev and XFree86.
if (scancode < 128) {
// For scancode < 97, a simple scancode + 8 offest could be applied,
// but math is generally slower than memory and we cannot save any
// extra space in the lookup table due to binary padding.
keycode = evdev_scancode_table[scancode][1];
}
else {
// Offset is the lower order bits + 128
scancode = (scancode & 0x007F) | 0x80;
if (scancode < evdev_size) {
keycode = evdev_scancode_table[scancode][1];
}
}
}
else {
// Evdev was disabled, fallback to XFree86.
#endif
unsigned short xfree86_size = sizeof(xfree86_scancode_table) / sizeof(xfree86_scancode_table[0]);
// NOTE scancodes < 97 appear to be identical between Evdev and XFree86.
if (scancode < 128) {
// For scancode < 97, a simple scancode + 8 offest could be applied,
// but math is generally slower than memory and we cannot save any
// extra space in the lookup table due to binary padding.
keycode = xfree86_scancode_table[scancode][1];
}
else {
// Offset: lower order bits + 128 (If no size optimization!)
scancode = (scancode & 0x007F) | 0x80;
if (scancode < xfree86_size) {
keycode = xfree86_scancode_table[scancode][1];
}
}
#if defined(USE_EVDEV) && defined(USE_XKB)
}
#endif
return keycode;
}
#ifdef USE_XKBCOMMON
struct xkb_state * create_xkb_state(struct xkb_context *context, xcb_connection_t *connection) {
struct xkb_keymap *keymap;
struct xkb_state *state;
int32_t device_id = xkb_x11_get_core_keyboard_device_id(connection);
if (device_id >= 0) {
keymap = xkb_x11_keymap_new_from_device(context, connection, device_id, XKB_KEYMAP_COMPILE_NO_FLAGS);
state = xkb_x11_state_new_from_device(keymap, connection, device_id);
}
#ifdef USE_XKBFILE
else {
// Evdev fallback,
logger(LOG_LEVEL_WARN, "%s [%u]: Unable to retrieve core keyboard device id! (%d)\n",
__FUNCTION__, __LINE__, device_id);
keymap = xkb_keymap_new_from_names(context, &xkb_names, XKB_KEYMAP_COMPILE_NO_FLAGS);
state = xkb_state_new(keymap);
}
#endif
xkb_map_unref(keymap);
return xkb_state_ref(state);
}
void destroy_xkb_state(struct xkb_state* state) {
xkb_state_unref(state);
}
size_t keycode_to_unicode(struct xkb_state* state, KeyCode keycode, uint16_t *buffer, size_t length) {
size_t count = 0;
if (state != NULL) {
uint32_t unicode = xkb_state_key_get_utf32(state, keycode);
if (unicode <= 0x10FFFF) {
if ((unicode <= 0xD7FF || (unicode >= 0xE000 && unicode <= 0xFFFF)) && length >= 1) {
buffer[0] = unicode;
count = 1;
}
else if (unicode >= 0x10000) {
unsigned int code = (unicode - 0x10000);
buffer[0] = 0xD800 | (code >> 10);
buffer[1] = 0xDC00 | (code & 0x3FF);
count = 2;
}
}
}
return count;
}
#else
// Faster more flexible alternative to XKeycodeToKeysym...
KeySym keycode_to_keysym(KeyCode keycode, unsigned int modifier_mask) {
KeySym keysym = NoSymbol;
#ifdef USE_XKB
if (keyboard_map != NULL) {
// Get the range and number of symbols groups bound to the key.
unsigned char info = XkbKeyGroupInfo(keyboard_map, keycode);
unsigned int num_groups = XkbKeyNumGroups(keyboard_map, keycode);
// Get the group.
unsigned int group = 0x0000;
switch (XkbOutOfRangeGroupAction(info)) {
case XkbRedirectIntoRange:
/* If the RedirectIntoRange flag is set, the four least significant
* bits of the groups wrap control specify the index of a group to
* which all illegal groups correspond. If the specified group is
* also out of range, all illegal groups map to Group1.
*/
group = XkbOutOfRangeGroupInfo(info);
if (group >= num_groups) {
group = 0;
}
break;
case XkbClampIntoRange:
/* If the ClampIntoRange flag is set, out-of-range groups correspond
* to the nearest legal group. Effective groups larger than the
* highest supported group are mapped to the highest supported group;
* effective groups less than Group1 are mapped to Group1 . For
* example, a key with two groups of symbols uses Group2 type and
* symbols if the global effective group is either Group3 or Group4.
*/
group = num_groups - 1;
break;
case XkbWrapIntoRange:
/* If neither flag is set, group is wrapped into range using integer
* modulus. For example, a key with two groups of symbols for which
* groups wrap uses Group1 symbols if the global effective group is
* Group3 or Group2 symbols if the global effective group is Group4.
*/
default:
if (num_groups != 0) {
group %= num_groups;
}
break;
}
XkbKeyTypePtr key_type = XkbKeyKeyType(keyboard_map, keycode, group);
unsigned int active_mods = modifier_mask & key_type->mods.mask;
int i, level = 0;
for (i = 0; i < key_type->map_count; i++) {
if (key_type->map[i].active && key_type->map[i].mods.mask == active_mods) {
level = key_type->map[i].level;
}
}
keysym = XkbKeySymEntry(keyboard_map, keycode, level, group);
}
#else
if (keyboard_map != NULL) {
if (modifier_mask & Mod2Mask &&
((keyboard_map[keycode *keysym_per_keycode + 1] >= 0xFF80 && keyboard_map[keycode *keysym_per_keycode + 1] <= 0xFFBD) ||
(keyboard_map[keycode *keysym_per_keycode + 1] >= 0x11000000 && keyboard_map[keycode *keysym_per_keycode + 1] <= 0x1100FFFF))
) {
/* If the numlock modifier is on and the second KeySym is a keypad
* KeySym. In this case, if the Shift modifier is on, or if the
* Lock modifier is on and is interpreted as ShiftLock, then the
* first KeySym is used, otherwise the second KeySym is used.
*
* The standard KeySyms with the prefix ``XK_KP_'' in their name are
* called keypad KeySyms; these are KeySyms with numeric value in
* the hexadecimal range 0xFF80 to 0xFFBD inclusive. In addition,
* vendor-specific KeySyms in the hexadecimal range 0x11000000 to
* 0x1100FFFF are also keypad KeySyms.
*/
/* The numlock modifier is on and the second KeySym is a keypad
* KeySym. In this case, if the Shift modifier is on, or if the
* Lock modifier is on and is interpreted as ShiftLock, then the
* first KeySym is used, otherwise the second KeySym is used.
*/
if (modifier_mask & ShiftMask || (modifier_mask & LockMask && is_shift_lock)) {
// i = 0
keysym = keyboard_map[keycode *keysym_per_keycode];
}
else {
// i = 1
keysym = keyboard_map[keycode *keysym_per_keycode + 1];
}
}
else if (modifier_mask ^ ShiftMask && modifier_mask ^ LockMask) {
/* The Shift and Lock modifiers are both off. In this case,
* the first KeySym is used.
*/
// index = 0
keysym = keyboard_map[keycode *keysym_per_keycode];
}
else if (modifier_mask ^ ShiftMask && modifier_mask & LockMask && is_caps_lock) {
/* The Shift modifier is off, and the Lock modifier is on
* and is interpreted as CapsLock. In this case, the first
* KeySym is used, but if that KeySym is lowercase
* alphabetic, then the corresponding uppercase KeySym is
* used instead.
*/
// index = 0;
keysym = keyboard_map[keycode *keysym_per_keycode];
if (keysym >= 'a' && keysym <= 'z') {
// keysym is an alpha char.
KeySym lower_keysym, upper_keysym;
XConvertCase(keysym, &lower_keysym, &upper_keysym);
keysym = upper_keysym;
}
}
else if (modifier_mask & ShiftMask && modifier_mask & LockMask && is_caps_lock) {
/* The Shift modifier is on, and the Lock modifier is on and
* is interpreted as CapsLock. In this case, the second
* KeySym is used, but if that KeySym is lowercase
* alphabetic, then the corresponding uppercase KeySym is
* used instead.
*/
// index = 1
keysym = keyboard_map[keycode *keysym_per_keycode + 1];
if (keysym >= 'A' && keysym <= 'Z') {
// keysym is an alpha char.
KeySym lower_keysym, upper_keysym;
XConvertCase(keysym, &lower_keysym, &upper_keysym);
keysym = lower_keysym;
}
}
else if (modifier_mask & ShiftMask || (modifier_mask & LockMask && is_shift_lock) || modifier_mask & (ShiftMask + LockMask)) {
/* The Shift modifier is on, or the Lock modifier is on and
* is interpreted as ShiftLock, or both. In this case, the
* second KeySym is used.
*/
// index = 1
keysym = keyboard_map[keycode *keysym_per_keycode + 1];
}
else {
logger(LOG_LEVEL_ERROR, "%s [%u]: Unable to determine the KeySym index!\n",
__FUNCTION__, __LINE__);
}
}
#endif
return keysym;
}
#endif
void load_input_helper(Display *disp) {
#ifdef USE_XKB
/* The following code block is based on vncdisplaykeymap.c under the terms:
*
* Copyright (C) 2008 Anthony Liguori <anthony codemonkey ws>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2 as
* published by the Free Software Foundation.
*/
XkbDescPtr desc = XkbGetKeyboard(disp, XkbGBN_AllComponentsMask, XkbUseCoreKbd);
if (desc != NULL && desc->names != NULL) {
const char *layout_name = XGetAtomName(disp, desc->names->keycodes);
logger(LOG_LEVEL_DEBUG,
"%s [%u]: Found keycode atom '%s' (%i)!\n",
__FUNCTION__, __LINE__, layout_name,
(unsigned int) desc->names->keycodes);
const char *prefix_xfree86 = "xfree86_";
#if defined(USE_EVDEV) && defined(USE_XKB)
const char *prefix_evdev = "evdev_";
if (strncmp(layout_name, prefix_evdev, strlen(prefix_evdev)) == 0) {
is_evdev = true;
} else
#endif
if (strncmp(layout_name, prefix_xfree86, strlen(prefix_xfree86)) != 0) {
// logger(LOG_LEVEL_ERROR,
// "%s [%u]: Unknown keycode name '%s', please file a bug report!\n",
// __FUNCTION__, __LINE__, layout_name);
}
else if (layout_name == NULL) {
logger(LOG_LEVEL_ERROR,
"%s [%u]: X atom name failure for desc->names->keycodes!\n",
__FUNCTION__, __LINE__);
}
XkbFreeClientMap(desc, XkbGBN_AllComponentsMask, True);
}
else {
logger(LOG_LEVEL_ERROR,
"%s [%u]: XkbGetKeyboard failed to locate a valid keyboard!\n",
__FUNCTION__, __LINE__);
}
// Get the map.
keyboard_map = XkbGetMap(disp, XkbAllClientInfoMask, XkbUseCoreKbd);
#else
// No known alternative to determine scancode mapping, assume XFree86!
// printf("%s\n", "No known alternative to determine scancode mapping, assume XFree86!");
// #pragma message("*** Warning: XKB support is required to accurately determine keyboard scancodes!")
// #pragma message("... Assuming XFree86 keyboard layout.")
logger(LOG_LEVEL_WARN, "%s [%u]: Using XFree86 keyboard layout.\n",
__FUNCTION__, __LINE__);
logger(LOG_LEVEL_WARN, "%s [%u]: XKB support is required to accurately determine keyboard characters!\n",
__FUNCTION__, __LINE__);
int minKeyCode, maxKeyCode;
XDisplayKeycodes(disp, &minKeyCode, &maxKeyCode);
keyboard_map = XGetKeyboardMapping(disp, minKeyCode, (maxKeyCode - minKeyCode + 1), &keysym_per_keycode);
if (keyboard_map) {
XModifierKeymap *modifierMap = XGetModifierMapping(disp);
if (modifierMap) {
/* The Lock modifier is interpreted as CapsLock when the KeySym
* named XK_Caps_Lock is attached to some KeyCode and that KeyCode
* is attached to the Lock modifier. The Lock modifier is
* interpreted as ShiftLock when the KeySym named XK_Shift_Lock is
* attached to some KeyCode and that KeyCode is attached to the Lock
* modifier. If the Lock modifier could be interpreted as both
* CapsLock and ShiftLock, the CapsLock interpretation is used.
*/
KeyCode capsLock = XKeysymToKeycode(disp, XK_Caps_Lock);
KeyCode shiftLock = XKeysymToKeycode(disp, XK_Shift_Lock);
keysym_per_keycode--;
// Loop over the modifier map to find out if/where shift and caps locks are set.
int i;
for (i = LockMapIndex; i < LockMapIndex + modifierMap->max_keypermod && !is_caps_lock; i++) {
if (capsLock != 0 && modifierMap->modifiermap[i] == capsLock) {
is_caps_lock = true;
is_shift_lock = false;
}
else if (shiftLock != 0 && modifierMap->modifiermap[i] == shiftLock) {
is_shift_lock = true;
}
}
XFree(modifierMap);
}
else {
XFree(keyboard_map);
logger(LOG_LEVEL_ERROR,
"%s [%u]: Unable to get modifier mapping table!\n",
__FUNCTION__, __LINE__);
}
}
else {
logger(LOG_LEVEL_ERROR,
"%s [%u]: Unable to get keyboard mapping table!\n",
__FUNCTION__, __LINE__);
}
#endif
}
void unload_input_helper() {
if (keyboard_map) {
#ifdef USE_XKB
XkbFreeClientMap(keyboard_map, XkbAllClientInfoMask, true);
#if defined(USE_EVDEV) && defined(USE_XKB)
is_evdev = false;
#endif
#else
XFree(keyboard_map);
#endif
}
}