/*
 * This file is part of Xpra.
 * Copyright (C) 2010-2017 Antoine Martin <antoine@xpra.org>
 * Licensed under MPL 2.0, see:
 * http://www.mozilla.org/MPL/2.0/
 *
 */

/**
 * Map javascript key names to the X11 naming convention the server expects:
 */
const KEY_TO_NAME = {
  Escape: "Escape",
  Tab: "Tab",
  CapsLock: "Caps_Lock",
  ShiftLeft: "Shift_L",
  ControlLeft: "Control_L",
  MetaLeft: "Meta_L",
  AltLeft: "Alt_L",
  Space: "space",
  AltRight: "Alt_R",
  MetaRight: "Meta_R",
  ContextMenu: "Menu_R",
  ControlRight: "Control_L",
  ShiftRight: "Shift_R",
  Enter: "Return",
  Backspace: "BackSpace",
  //special keys:
  ScrollLock: "Scroll_Lock",
  Pause: "Pause",
  NumLock: "Num_Lock",
  //Arrow pad:
  Insert: "Insert",
  Home: "Home",
  PageUp: "Prior",
  Delete: "Delete",
  End: "End",
  PageDown: "Next",
};
const DEAD_KEYS = {
  "`": "dead_grave",
  "'": "dead_acute",
};
const NUMPAD_TO_NAME = {
  //Num pad:
  NumpadDivide: "KP_Divide",
  NumpadMultiply: "KP_Multiply",
  NumpadSubstract: "KP_Substract",
  NumpadAdd: "KP_Add",
  NumpadEnter: "KP_Enter",
  NumpadDecimal: "KP_Decimal", //TODO: send KP_Delete when Num_Lock is off
  //Num_Lock off:
  Insert: "KP_Insert",
  End: "KP_End",
  ArrowDown: "KP_Down",
  PageDown: "KP_Next",
  ArrowLeft: "KP_Left",
  Clear: "KP_Begin",
  ArrowRight: "KP_Right",
  Home: "KP_Home",
  ArrowUp: "KP_Up",
  PageUp: "KP_Prior",
};
for (let index = 0; index <= 9; index++) {
  KEY_TO_NAME[`Numpad${index}`] = `${index}`;
  KEY_TO_NAME[`KP${index}`] = `KP${index}`;
}
for (let index = 1; index <= 20; index++) {
  KEY_TO_NAME[`F${index}`] = `F${index}`;
}

/**
 * This table was generated using:
 * grep "#define XKB_KEY_" /usr/include/xkbcommon/xkbcommon-keysyms.h | \
 * 		grep "/* U+" | grep -v "A-Z" | \
 * 		sed 's/#define XKB_KEY_//g; s/ *0x.*U+/ 0x/g' | \
 * 		awk '{print "\""$1"\" : "$2","}'
 */
const KEYSYM_TO_UNICODE = {
  space: 0x00_20,
  exclam: 0x00_21,
  quotedbl: 0x00_22,
  numbersign: 0x00_23,
  dollar: 0x00_24,
  percent: 0x00_25,
  ampersand: 0x00_26,
  apostrophe: 0x00_27,
  parenleft: 0x00_28,
  parenright: 0x00_29,
  asterisk: 0x00_2a,
  plus: 0x00_2b,
  comma: 0x00_2c,
  minus: 0x00_2d,
  period: 0x00_2e,
  slash: 0x00_2f,
  0: 0x00_30,
  1: 0x00_31,
  2: 0x00_32,
  3: 0x00_33,
  4: 0x00_34,
  5: 0x00_35,
  6: 0x00_36,
  7: 0x00_37,
  8: 0x00_38,
  9: 0x00_39,
  colon: 0x00_3a,
  semicolon: 0x00_3b,
  less: 0x00_3c,
  equal: 0x00_3d,
  greater: 0x00_3e,
  question: 0x00_3f,
  at: 0x00_40,
  A: 0x00_41,
  B: 0x00_42,
  C: 0x00_43,
  D: 0x00_44,
  E: 0x00_45,
  F: 0x00_46,
  G: 0x00_47,
  H: 0x00_48,
  I: 0x00_49,
  J: 0x00_4a,
  K: 0x00_4b,
  L: 0x00_4c,
  M: 0x00_4d,
  N: 0x00_4e,
  O: 0x00_4f,
  P: 0x00_50,
  Q: 0x00_51,
  R: 0x00_52,
  S: 0x00_53,
  T: 0x00_54,
  U: 0x00_55,
  V: 0x00_56,
  W: 0x00_57,
  X: 0x00_58,
  Y: 0x00_59,
  Z: 0x00_5a,
  bracketleft: 0x00_5b,
  backslash: 0x00_5c,
  bracketright: 0x00_5d,
  asciicircum: 0x00_5e,
  underscore: 0x00_5f,
  grave: 0x00_60,
  a: 0x00_61,
  b: 0x00_62,
  c: 0x00_63,
  d: 0x00_64,
  e: 0x00_65,
  f: 0x00_66,
  g: 0x00_67,
  h: 0x00_68,
  i: 0x00_69,
  j: 0x00_6a,
  k: 0x00_6b,
  l: 0x00_6c,
  m: 0x00_6d,
  n: 0x00_6e,
  o: 0x00_6f,
  p: 0x00_70,
  q: 0x00_71,
  r: 0x00_72,
  s: 0x00_73,
  t: 0x00_74,
  u: 0x00_75,
  v: 0x00_76,
  w: 0x00_77,
  x: 0x00_78,
  y: 0x00_79,
  z: 0x00_7a,
  braceleft: 0x00_7b,
  bar: 0x00_7c,
  braceright: 0x00_7d,
  asciitilde: 0x00_7e,
  nobreakspace: 0x00_a0,
  exclamdown: 0x00_a1,
  cent: 0x00_a2,
  sterling: 0x00_a3,
  currency: 0x00_a4,
  yen: 0x00_a5,
  brokenbar: 0x00_a6,
  section: 0x00_a7,
  diaeresis: 0x00_a8,
  copyright: 0x00_a9,
  ordfeminine: 0x00_aa,
  guillemotleft: 0x00_ab,
  notsign: 0x00_ac,
  hyphen: 0x00_ad,
  registered: 0x00_ae,
  macron: 0x00_af,
  degree: 0x00_b0,
  plusminus: 0x00_b1,
  twosuperior: 0x00_b2,
  threesuperior: 0x00_b3,
  acute: 0x00_b4,
  mu: 0x00_b5,
  paragraph: 0x00_b6,
  periodcentered: 0x00_b7,
  cedilla: 0x00_b8,
  onesuperior: 0x00_b9,
  masculine: 0x00_ba,
  guillemotright: 0x00_bb,
  onequarter: 0x00_bc,
  onehalf: 0x00_bd,
  threequarters: 0x00_be,
  questiondown: 0x00_bf,
  Agrave: 0x00_c0,
  Aacute: 0x00_c1,
  Acircumflex: 0x00_c2,
  Atilde: 0x00_c3,
  Adiaeresis: 0x00_c4,
  Aring: 0x00_c5,
  AE: 0x00_c6,
  Ccedilla: 0x00_c7,
  Egrave: 0x00_c8,
  Eacute: 0x00_c9,
  Ecircumflex: 0x00_ca,
  Ediaeresis: 0x00_cb,
  Igrave: 0x00_cc,
  Iacute: 0x00_cd,
  Icircumflex: 0x00_ce,
  Idiaeresis: 0x00_cf,
  ETH: 0x00_d0,
  Ntilde: 0x00_d1,
  Ograve: 0x00_d2,
  Oacute: 0x00_d3,
  Ocircumflex: 0x00_d4,
  Otilde: 0x00_d5,
  Odiaeresis: 0x00_d6,
  multiply: 0x00_d7,
  Ooblique: 0x00_d8,
  Oslash: 0x00_d8,
  Ugrave: 0x00_d9,
  Uacute: 0x00_da,
  Ucircumflex: 0x00_db,
  Udiaeresis: 0x00_dc,
  Yacute: 0x00_dd,
  THORN: 0x00_de,
  ssharp: 0x00_df,
  agrave: 0x00_e0,
  aacute: 0x00_e1,
  acircumflex: 0x00_e2,
  atilde: 0x00_e3,
  adiaeresis: 0x00_e4,
  aring: 0x00_e5,
  ae: 0x00_e6,
  ccedilla: 0x00_e7,
  egrave: 0x00_e8,
  eacute: 0x00_e9,
  ecircumflex: 0x00_ea,
  ediaeresis: 0x00_eb,
  igrave: 0x00_ec,
  iacute: 0x00_ed,
  icircumflex: 0x00_ee,
  idiaeresis: 0x00_ef,
  eth: 0x00_f0,
  ntilde: 0x00_f1,
  ograve: 0x00_f2,
  oacute: 0x00_f3,
  ocircumflex: 0x00_f4,
  otilde: 0x00_f5,
  odiaeresis: 0x00_f6,
  division: 0x00_f7,
  oslash: 0x00_f8,
  ooblique: 0x00_f8,
  ugrave: 0x00_f9,
  uacute: 0x00_fa,
  ucircumflex: 0x00_fb,
  udiaeresis: 0x00_fc,
  yacute: 0x00_fd,
  thorn: 0x00_fe,
  ydiaeresis: 0x00_ff,
  Aogonek: 0x01_04,
  breve: 0x02_d8,
  Lstroke: 0x01_41,
  Lcaron: 0x01_3d,
  Sacute: 0x01_5a,
  Scaron: 0x01_60,
  Scedilla: 0x01_5e,
  Tcaron: 0x01_64,
  Zacute: 0x01_79,
  Zcaron: 0x01_7d,
  Zabovedot: 0x01_7b,
  aogonek: 0x01_05,
  ogonek: 0x02_db,
  lstroke: 0x01_42,
  lcaron: 0x01_3e,
  sacute: 0x01_5b,
  caron: 0x02_c7,
  scaron: 0x01_61,
  scedilla: 0x01_5f,
  tcaron: 0x01_65,
  zacute: 0x01_7a,
  doubleacute: 0x02_dd,
  zcaron: 0x01_7e,
  zabovedot: 0x01_7c,
  Racute: 0x01_54,
  Abreve: 0x01_02,
  Lacute: 0x01_39,
  Cacute: 0x01_06,
  Ccaron: 0x01_0c,
  Eogonek: 0x01_18,
  Ecaron: 0x01_1a,
  Dcaron: 0x01_0e,
  Dstroke: 0x01_10,
  Nacute: 0x01_43,
  Ncaron: 0x01_47,
  Odoubleacute: 0x01_50,
  Rcaron: 0x01_58,
  Uring: 0x01_6e,
  Udoubleacute: 0x01_70,
  Tcedilla: 0x01_62,
  racute: 0x01_55,
  abreve: 0x01_03,
  lacute: 0x01_3a,
  cacute: 0x01_07,
  ccaron: 0x01_0d,
  eogonek: 0x01_19,
  ecaron: 0x01_1b,
  dcaron: 0x01_0f,
  dstroke: 0x01_11,
  nacute: 0x01_44,
  ncaron: 0x01_48,
  odoubleacute: 0x01_51,
  rcaron: 0x01_59,
  uring: 0x01_6f,
  udoubleacute: 0x01_71,
  tcedilla: 0x01_63,
  abovedot: 0x02_d9,
  Hstroke: 0x01_26,
  Hcircumflex: 0x01_24,
  Iabovedot: 0x01_30,
  Gbreve: 0x01_1e,
  Jcircumflex: 0x01_34,
  hstroke: 0x01_27,
  hcircumflex: 0x01_25,
  idotless: 0x01_31,
  gbreve: 0x01_1f,
  jcircumflex: 0x01_35,
  Cabovedot: 0x01_0a,
  Ccircumflex: 0x01_08,
  Gabovedot: 0x01_20,
  Gcircumflex: 0x01_1c,
  Ubreve: 0x01_6c,
  Scircumflex: 0x01_5c,
  cabovedot: 0x01_0b,
  ccircumflex: 0x01_09,
  gabovedot: 0x01_21,
  gcircumflex: 0x01_1d,
  ubreve: 0x01_6d,
  scircumflex: 0x01_5d,
  kra: 0x01_38,
  Rcedilla: 0x01_56,
  Itilde: 0x01_28,
  Lcedilla: 0x01_3b,
  Emacron: 0x01_12,
  Gcedilla: 0x01_22,
  Tslash: 0x01_66,
  rcedilla: 0x01_57,
  itilde: 0x01_29,
  lcedilla: 0x01_3c,
  emacron: 0x01_13,
  gcedilla: 0x01_23,
  tslash: 0x01_67,
  ENG: 0x01_4a,
  eng: 0x01_4b,
  Amacron: 0x01_00,
  Iogonek: 0x01_2e,
  Eabovedot: 0x01_16,
  Imacron: 0x01_2a,
  Ncedilla: 0x01_45,
  Omacron: 0x01_4c,
  Kcedilla: 0x01_36,
  Uogonek: 0x01_72,
  Utilde: 0x01_68,
  Umacron: 0x01_6a,
  amacron: 0x01_01,
  iogonek: 0x01_2f,
  eabovedot: 0x01_17,
  imacron: 0x01_2b,
  ncedilla: 0x01_46,
  omacron: 0x01_4d,
  kcedilla: 0x01_37,
  uogonek: 0x01_73,
  utilde: 0x01_69,
  umacron: 0x01_6b,
  Wcircumflex: 0x01_74,
  wcircumflex: 0x01_75,
  Ycircumflex: 0x01_76,
  ycircumflex: 0x01_77,
  Babovedot: 0x1e_02,
  babovedot: 0x1e_03,
  Dabovedot: 0x1e_0a,
  dabovedot: 0x1e_0b,
  Fabovedot: 0x1e_1e,
  fabovedot: 0x1e_1f,
  Mabovedot: 0x1e_40,
  mabovedot: 0x1e_41,
  Pabovedot: 0x1e_56,
  pabovedot: 0x1e_57,
  Sabovedot: 0x1e_60,
  sabovedot: 0x1e_61,
  Tabovedot: 0x1e_6a,
  tabovedot: 0x1e_6b,
  Wgrave: 0x1e_80,
  wgrave: 0x1e_81,
  Wacute: 0x1e_82,
  wacute: 0x1e_83,
  Wdiaeresis: 0x1e_84,
  wdiaeresis: 0x1e_85,
  Ygrave: 0x1e_f2,
  ygrave: 0x1e_f3,
  OE: 0x01_52,
  oe: 0x01_53,
  Ydiaeresis: 0x01_78,
  overline: 0x20_3e,
  kana_fullstop: 0x30_02,
  kana_openingbracket: 0x30_0c,
  kana_closingbracket: 0x30_0d,
  kana_comma: 0x30_01,
  kana_conjunctive: 0x30_fb,
  kana_WO: 0x30_f2,
  kana_a: 0x30_a1,
  kana_i: 0x30_a3,
  kana_u: 0x30_a5,
  kana_e: 0x30_a7,
  kana_o: 0x30_a9,
  kana_ya: 0x30_e3,
  kana_yu: 0x30_e5,
  kana_yo: 0x30_e7,
  kana_tsu: 0x30_c3,
  prolongedsound: 0x30_fc,
  kana_A: 0x30_a2,
  kana_I: 0x30_a4,
  kana_U: 0x30_a6,
  kana_E: 0x30_a8,
  kana_O: 0x30_aa,
  kana_KA: 0x30_ab,
  kana_KI: 0x30_ad,
  kana_KU: 0x30_af,
  kana_KE: 0x30_b1,
  kana_KO: 0x30_b3,
  kana_SA: 0x30_b5,
  kana_SHI: 0x30_b7,
  kana_SU: 0x30_b9,
  kana_SE: 0x30_bb,
  kana_SO: 0x30_bd,
  kana_TA: 0x30_bf,
  kana_CHI: 0x30_c1,
  kana_TSU: 0x30_c4,
  kana_TE: 0x30_c6,
  kana_TO: 0x30_c8,
  kana_NA: 0x30_ca,
  kana_NI: 0x30_cb,
  kana_NU: 0x30_cc,
  kana_NE: 0x30_cd,
  kana_NO: 0x30_ce,
  kana_HA: 0x30_cf,
  kana_HI: 0x30_d2,
  kana_FU: 0x30_d5,
  kana_HE: 0x30_d8,
  kana_HO: 0x30_db,
  kana_MA: 0x30_de,
  kana_MI: 0x30_df,
  kana_MU: 0x30_e0,
  kana_ME: 0x30_e1,
  kana_MO: 0x30_e2,
  kana_YA: 0x30_e4,
  kana_YU: 0x30_e6,
  kana_YO: 0x30_e8,
  kana_RA: 0x30_e9,
  kana_RI: 0x30_ea,
  kana_RU: 0x30_eb,
  kana_RE: 0x30_ec,
  kana_RO: 0x30_ed,
  kana_WA: 0x30_ef,
  kana_N: 0x30_f3,
  voicedsound: 0x30_9b,
  semivoicedsound: 0x30_9c,
  Farsi_0: 0x06_f0,
  Farsi_1: 0x06_f1,
  Farsi_2: 0x06_f2,
  Farsi_3: 0x06_f3,
  Farsi_4: 0x06_f4,
  Farsi_5: 0x06_f5,
  Farsi_6: 0x06_f6,
  Farsi_7: 0x06_f7,
  Farsi_8: 0x06_f8,
  Farsi_9: 0x06_f9,
  Arabic_percent: 0x06_6a,
  Arabic_superscript_alef: 0x06_70,
  Arabic_tteh: 0x06_79,
  Arabic_peh: 0x06_7e,
  Arabic_tcheh: 0x06_86,
  Arabic_ddal: 0x06_88,
  Arabic_rreh: 0x06_91,
  Arabic_comma: 0x06_0c,
  Arabic_fullstop: 0x06_d4,
  Arabic_0: 0x06_60,
  Arabic_1: 0x06_61,
  Arabic_2: 0x06_62,
  Arabic_3: 0x06_63,
  Arabic_4: 0x06_64,
  Arabic_5: 0x06_65,
  Arabic_6: 0x06_66,
  Arabic_7: 0x06_67,
  Arabic_8: 0x06_68,
  Arabic_9: 0x06_69,
  Arabic_semicolon: 0x06_1b,
  Arabic_question_mark: 0x06_1f,
  Arabic_hamza: 0x06_21,
  Arabic_maddaonalef: 0x06_22,
  Arabic_hamzaonalef: 0x06_23,
  Arabic_hamzaonwaw: 0x06_24,
  Arabic_hamzaunderalef: 0x06_25,
  Arabic_hamzaonyeh: 0x06_26,
  Arabic_alef: 0x06_27,
  Arabic_beh: 0x06_28,
  Arabic_tehmarbuta: 0x06_29,
  Arabic_teh: 0x06_2a,
  Arabic_theh: 0x06_2b,
  Arabic_jeem: 0x06_2c,
  Arabic_hah: 0x06_2d,
  Arabic_khah: 0x06_2e,
  Arabic_dal: 0x06_2f,
  Arabic_thal: 0x06_30,
  Arabic_ra: 0x06_31,
  Arabic_zain: 0x06_32,
  Arabic_seen: 0x06_33,
  Arabic_sheen: 0x06_34,
  Arabic_sad: 0x06_35,
  Arabic_dad: 0x06_36,
  Arabic_tah: 0x06_37,
  Arabic_zah: 0x06_38,
  Arabic_ain: 0x06_39,
  Arabic_ghain: 0x06_3a,
  Arabic_tatweel: 0x06_40,
  Arabic_feh: 0x06_41,
  Arabic_qaf: 0x06_42,
  Arabic_kaf: 0x06_43,
  Arabic_lam: 0x06_44,
  Arabic_meem: 0x06_45,
  Arabic_noon: 0x06_46,
  Arabic_ha: 0x06_47,
  Arabic_waw: 0x06_48,
  Arabic_alefmaksura: 0x06_49,
  Arabic_yeh: 0x06_4a,
  Arabic_fathatan: 0x06_4b,
  Arabic_dammatan: 0x06_4c,
  Arabic_kasratan: 0x06_4d,
  Arabic_fatha: 0x06_4e,
  Arabic_damma: 0x06_4f,
  Arabic_kasra: 0x06_50,
  Arabic_shadda: 0x06_51,
  Arabic_sukun: 0x06_52,
  Arabic_madda_above: 0x06_53,
  Arabic_hamza_above: 0x06_54,
  Arabic_hamza_below: 0x06_55,
  Arabic_jeh: 0x06_98,
  Arabic_veh: 0x06_a4,
  Arabic_keheh: 0x06_a9,
  Arabic_gaf: 0x06_af,
  Arabic_noon_ghunna: 0x06_ba,
  Arabic_heh_doachashmee: 0x06_be,
  Farsi_yeh: 0x06_cc,
  Arabic_farsi_yeh: 0x06_cc,
  Arabic_yeh_baree: 0x06_d2,
  Arabic_heh_goal: 0x06_c1,
  Cyrillic_GHE_bar: 0x04_92,
  Cyrillic_ghe_bar: 0x04_93,
  Cyrillic_ZHE_descender: 0x04_96,
  Cyrillic_zhe_descender: 0x04_97,
  Cyrillic_KA_descender: 0x04_9a,
  Cyrillic_ka_descender: 0x04_9b,
  Cyrillic_KA_vertstroke: 0x04_9c,
  Cyrillic_ka_vertstroke: 0x04_9d,
  Cyrillic_EN_descender: 0x04_a2,
  Cyrillic_en_descender: 0x04_a3,
  Cyrillic_U_straight: 0x04_ae,
  Cyrillic_u_straight: 0x04_af,
  Cyrillic_U_straight_bar: 0x04_b0,
  Cyrillic_u_straight_bar: 0x04_b1,
  Cyrillic_HA_descender: 0x04_b2,
  Cyrillic_ha_descender: 0x04_b3,
  Cyrillic_CHE_descender: 0x04_b6,
  Cyrillic_che_descender: 0x04_b7,
  Cyrillic_CHE_vertstroke: 0x04_b8,
  Cyrillic_che_vertstroke: 0x04_b9,
  Cyrillic_SHHA: 0x04_ba,
  Cyrillic_shha: 0x04_bb,
  Cyrillic_SCHWA: 0x04_d8,
  Cyrillic_schwa: 0x04_d9,
  Cyrillic_I_macron: 0x04_e2,
  Cyrillic_i_macron: 0x04_e3,
  Cyrillic_O_bar: 0x04_e8,
  Cyrillic_o_bar: 0x04_e9,
  Cyrillic_U_macron: 0x04_ee,
  Cyrillic_u_macron: 0x04_ef,
  Serbian_dje: 0x04_52,
  Macedonia_gje: 0x04_53,
  Cyrillic_io: 0x04_51,
  Ukrainian_ie: 0x04_54,
  Macedonia_dse: 0x04_55,
  Ukrainian_i: 0x04_56,
  Ukrainian_yi: 0x04_57,
  Cyrillic_je: 0x04_58,
  Cyrillic_lje: 0x04_59,
  Cyrillic_nje: 0x04_5a,
  Serbian_tshe: 0x04_5b,
  Macedonia_kje: 0x04_5c,
  Ukrainian_ghe_with_upturn: 0x04_91,
  Byelorussian_shortu: 0x04_5e,
  Cyrillic_dzhe: 0x04_5f,
  numerosign: 0x21_16,
  Serbian_DJE: 0x04_02,
  Macedonia_GJE: 0x04_03,
  Cyrillic_IO: 0x04_01,
  Ukrainian_IE: 0x04_04,
  Macedonia_DSE: 0x04_05,
  Ukrainian_I: 0x04_06,
  Ukrainian_YI: 0x04_07,
  Cyrillic_JE: 0x04_08,
  Cyrillic_LJE: 0x04_09,
  Cyrillic_NJE: 0x04_0a,
  Serbian_TSHE: 0x04_0b,
  Macedonia_KJE: 0x04_0c,
  Ukrainian_GHE_WITH_UPTURN: 0x04_90,
  Byelorussian_SHORTU: 0x04_0e,
  Cyrillic_DZHE: 0x04_0f,
  Cyrillic_yu: 0x04_4e,
  Cyrillic_a: 0x04_30,
  Cyrillic_be: 0x04_31,
  Cyrillic_tse: 0x04_46,
  Cyrillic_de: 0x04_34,
  Cyrillic_ie: 0x04_35,
  Cyrillic_ef: 0x04_44,
  Cyrillic_ghe: 0x04_33,
  Cyrillic_ha: 0x04_45,
  Cyrillic_i: 0x04_38,
  Cyrillic_shorti: 0x04_39,
  Cyrillic_ka: 0x04_3a,
  Cyrillic_el: 0x04_3b,
  Cyrillic_em: 0x04_3c,
  Cyrillic_en: 0x04_3d,
  Cyrillic_o: 0x04_3e,
  Cyrillic_pe: 0x04_3f,
  Cyrillic_ya: 0x04_4f,
  Cyrillic_er: 0x04_40,
  Cyrillic_es: 0x04_41,
  Cyrillic_te: 0x04_42,
  Cyrillic_u: 0x04_43,
  Cyrillic_zhe: 0x04_36,
  Cyrillic_ve: 0x04_32,
  Cyrillic_softsign: 0x04_4c,
  Cyrillic_yeru: 0x04_4b,
  Cyrillic_ze: 0x04_37,
  Cyrillic_sha: 0x04_48,
  Cyrillic_e: 0x04_4d,
  Cyrillic_shcha: 0x04_49,
  Cyrillic_che: 0x04_47,
  Cyrillic_hardsign: 0x04_4a,
  Cyrillic_YU: 0x04_2e,
  Cyrillic_A: 0x04_10,
  Cyrillic_BE: 0x04_11,
  Cyrillic_TSE: 0x04_26,
  Cyrillic_DE: 0x04_14,
  Cyrillic_IE: 0x04_15,
  Cyrillic_EF: 0x04_24,
  Cyrillic_GHE: 0x04_13,
  Cyrillic_HA: 0x04_25,
  Cyrillic_I: 0x04_18,
  Cyrillic_SHORTI: 0x04_19,
  Cyrillic_KA: 0x04_1a,
  Cyrillic_EL: 0x04_1b,
  Cyrillic_EM: 0x04_1c,
  Cyrillic_EN: 0x04_1d,
  Cyrillic_O: 0x04_1e,
  Cyrillic_PE: 0x04_1f,
  Cyrillic_YA: 0x04_2f,
  Cyrillic_ER: 0x04_20,
  Cyrillic_ES: 0x04_21,
  Cyrillic_TE: 0x04_22,
  Cyrillic_U: 0x04_23,
  Cyrillic_ZHE: 0x04_16,
  Cyrillic_VE: 0x04_12,
  Cyrillic_SOFTSIGN: 0x04_2c,
  Cyrillic_YERU: 0x04_2b,
  Cyrillic_ZE: 0x04_17,
  Cyrillic_SHA: 0x04_28,
  Cyrillic_E: 0x04_2d,
  Cyrillic_SHCHA: 0x04_29,
  Cyrillic_CHE: 0x04_27,
  Cyrillic_HARDSIGN: 0x04_2a,
  Greek_ALPHAaccent: 0x03_86,
  Greek_EPSILONaccent: 0x03_88,
  Greek_ETAaccent: 0x03_89,
  Greek_IOTAaccent: 0x03_8a,
  Greek_IOTAdieresis: 0x03_aa,
  Greek_OMICRONaccent: 0x03_8c,
  Greek_UPSILONaccent: 0x03_8e,
  Greek_UPSILONdieresis: 0x03_ab,
  Greek_OMEGAaccent: 0x03_8f,
  Greek_accentdieresis: 0x03_85,
  Greek_horizbar: 0x20_15,
  Greek_alphaaccent: 0x03_ac,
  Greek_epsilonaccent: 0x03_ad,
  Greek_etaaccent: 0x03_ae,
  Greek_iotaaccent: 0x03_af,
  Greek_iotadieresis: 0x03_ca,
  Greek_iotaaccentdieresis: 0x03_90,
  Greek_omicronaccent: 0x03_cc,
  Greek_upsilonaccent: 0x03_cd,
  Greek_upsilondieresis: 0x03_cb,
  Greek_upsilonaccentdieresis: 0x03_b0,
  Greek_omegaaccent: 0x03_ce,
  Greek_ALPHA: 0x03_91,
  Greek_BETA: 0x03_92,
  Greek_GAMMA: 0x03_93,
  Greek_DELTA: 0x03_94,
  Greek_EPSILON: 0x03_95,
  Greek_ZETA: 0x03_96,
  Greek_ETA: 0x03_97,
  Greek_THETA: 0x03_98,
  Greek_IOTA: 0x03_99,
  Greek_KAPPA: 0x03_9a,
  Greek_LAMDA: 0x03_9b,
  Greek_LAMBDA: 0x03_9b,
  Greek_MU: 0x03_9c,
  Greek_NU: 0x03_9d,
  Greek_XI: 0x03_9e,
  Greek_OMICRON: 0x03_9f,
  Greek_PI: 0x03_a0,
  Greek_RHO: 0x03_a1,
  Greek_SIGMA: 0x03_a3,
  Greek_TAU: 0x03_a4,
  Greek_UPSILON: 0x03_a5,
  Greek_PHI: 0x03_a6,
  Greek_CHI: 0x03_a7,
  Greek_PSI: 0x03_a8,
  Greek_OMEGA: 0x03_a9,
  Greek_alpha: 0x03_b1,
  Greek_beta: 0x03_b2,
  Greek_gamma: 0x03_b3,
  Greek_delta: 0x03_b4,
  Greek_epsilon: 0x03_b5,
  Greek_zeta: 0x03_b6,
  Greek_eta: 0x03_b7,
  Greek_theta: 0x03_b8,
  Greek_iota: 0x03_b9,
  Greek_kappa: 0x03_ba,
  Greek_lamda: 0x03_bb,
  Greek_lambda: 0x03_bb,
  Greek_mu: 0x03_bc,
  Greek_nu: 0x03_bd,
  Greek_xi: 0x03_be,
  Greek_omicron: 0x03_bf,
  Greek_pi: 0x03_c0,
  Greek_rho: 0x03_c1,
  Greek_sigma: 0x03_c3,
  Greek_finalsmallsigma: 0x03_c2,
  Greek_tau: 0x03_c4,
  Greek_upsilon: 0x03_c5,
  Greek_phi: 0x03_c6,
  Greek_chi: 0x03_c7,
  Greek_psi: 0x03_c8,
  Greek_omega: 0x03_c9,
  leftradical: 0x23_b7,
  topintegral: 0x23_20,
  botintegral: 0x23_21,
  topleftsqbracket: 0x23_a1,
  botleftsqbracket: 0x23_a3,
  toprightsqbracket: 0x23_a4,
  botrightsqbracket: 0x23_a6,
  topleftparens: 0x23_9b,
  botleftparens: 0x23_9d,
  toprightparens: 0x23_9e,
  botrightparens: 0x23_a0,
  leftmiddlecurlybrace: 0x23_a8,
  rightmiddlecurlybrace: 0x23_ac,
  lessthanequal: 0x22_64,
  notequal: 0x22_60,
  greaterthanequal: 0x22_65,
  integral: 0x22_2b,
  therefore: 0x22_34,
  variation: 0x22_1d,
  infinity: 0x22_1e,
  nabla: 0x22_07,
  approximate: 0x22_3c,
  similarequal: 0x22_43,
  ifonlyif: 0x21_d4,
  implies: 0x21_d2,
  identical: 0x22_61,
  radical: 0x22_1a,
  includedin: 0x22_82,
  includes: 0x22_83,
  intersection: 0x22_29,
  union: 0x22_2a,
  logicaland: 0x22_27,
  logicalor: 0x22_28,
  partialderivative: 0x22_02,
  function: 0x01_92,
  leftarrow: 0x21_90,
  uparrow: 0x21_91,
  rightarrow: 0x21_92,
  downarrow: 0x21_93,
  soliddiamond: 0x25_c6,
  checkerboard: 0x25_92,
  ht: 0x24_09,
  ff: 0x24_0c,
  cr: 0x24_0d,
  lf: 0x24_0a,
  nl: 0x24_24,
  vt: 0x24_0b,
  lowrightcorner: 0x25_18,
  uprightcorner: 0x25_10,
  upleftcorner: 0x25_0c,
  lowleftcorner: 0x25_14,
  crossinglines: 0x25_3c,
  horizlinescan1: 0x23_ba,
  horizlinescan3: 0x23_bb,
  horizlinescan5: 0x25_00,
  horizlinescan7: 0x23_bc,
  horizlinescan9: 0x23_bd,
  leftt: 0x25_1c,
  rightt: 0x25_24,
  bott: 0x25_34,
  topt: 0x25_2c,
  vertbar: 0x25_02,
  emspace: 0x20_03,
  enspace: 0x20_02,
  em3space: 0x20_04,
  em4space: 0x20_05,
  digitspace: 0x20_07,
  punctspace: 0x20_08,
  thinspace: 0x20_09,
  hairspace: 0x20_0a,
  emdash: 0x20_14,
  endash: 0x20_13,
  ellipsis: 0x20_26,
  doubbaselinedot: 0x20_25,
  onethird: 0x21_53,
  twothirds: 0x21_54,
  onefifth: 0x21_55,
  twofifths: 0x21_56,
  threefifths: 0x21_57,
  fourfifths: 0x21_58,
  onesixth: 0x21_59,
  fivesixths: 0x21_5a,
  careof: 0x21_05,
  figdash: 0x20_12,
  oneeighth: 0x21_5b,
  threeeighths: 0x21_5c,
  fiveeighths: 0x21_5d,
  seveneighths: 0x21_5e,
  trademark: 0x21_22,
  leftsinglequotemark: 0x20_18,
  rightsinglequotemark: 0x20_19,
  leftdoublequotemark: 0x20_1c,
  rightdoublequotemark: 0x20_1d,
  prescription: 0x21_1e,
  permille: 0x20_30,
  minutes: 0x20_32,
  seconds: 0x20_33,
  latincross: 0x27_1d,
  club: 0x26_63,
  diamond: 0x26_66,
  heart: 0x26_65,
  maltesecross: 0x27_20,
  dagger: 0x20_20,
  doubledagger: 0x20_21,
  checkmark: 0x27_13,
  ballotcross: 0x27_17,
  musicalsharp: 0x26_6f,
  musicalflat: 0x26_6d,
  malesymbol: 0x26_42,
  femalesymbol: 0x26_40,
  telephone: 0x26_0e,
  telephonerecorder: 0x23_15,
  phonographcopyright: 0x21_17,
  caret: 0x20_38,
  singlelowquotemark: 0x20_1a,
  doublelowquotemark: 0x20_1e,
  downtack: 0x22_a4,
  downstile: 0x23_0a,
  jot: 0x22_18,
  quad: 0x23_95,
  uptack: 0x22_a5,
  circle: 0x25_cb,
  upstile: 0x23_08,
  lefttack: 0x22_a3,
  righttack: 0x22_a2,
  hebrew_doublelowline: 0x20_17,
  hebrew_aleph: 0x05_d0,
  hebrew_bet: 0x05_d1,
  hebrew_gimel: 0x05_d2,
  hebrew_dalet: 0x05_d3,
  hebrew_he: 0x05_d4,
  hebrew_waw: 0x05_d5,
  hebrew_zain: 0x05_d6,
  hebrew_chet: 0x05_d7,
  hebrew_tet: 0x05_d8,
  hebrew_yod: 0x05_d9,
  hebrew_finalkaph: 0x05_da,
  hebrew_kaph: 0x05_db,
  hebrew_lamed: 0x05_dc,
  hebrew_finalmem: 0x05_dd,
  hebrew_mem: 0x05_de,
  hebrew_finalnun: 0x05_df,
  hebrew_nun: 0x05_e0,
  hebrew_samech: 0x05_e1,
  hebrew_ayin: 0x05_e2,
  hebrew_finalpe: 0x05_e3,
  hebrew_pe: 0x05_e4,
  hebrew_finalzade: 0x05_e5,
  hebrew_zade: 0x05_e6,
  hebrew_qoph: 0x05_e7,
  hebrew_resh: 0x05_e8,
  hebrew_shin: 0x05_e9,
  hebrew_taw: 0x05_ea,
  Thai_kokai: 0x0e_01,
  Thai_khokhai: 0x0e_02,
  Thai_khokhuat: 0x0e_03,
  Thai_khokhwai: 0x0e_04,
  Thai_khokhon: 0x0e_05,
  Thai_khorakhang: 0x0e_06,
  Thai_ngongu: 0x0e_07,
  Thai_chochan: 0x0e_08,
  Thai_choching: 0x0e_09,
  Thai_chochang: 0x0e_0a,
  Thai_soso: 0x0e_0b,
  Thai_chochoe: 0x0e_0c,
  Thai_yoying: 0x0e_0d,
  Thai_dochada: 0x0e_0e,
  Thai_topatak: 0x0e_0f,
  Thai_thothan: 0x0e_10,
  Thai_thonangmontho: 0x0e_11,
  Thai_thophuthao: 0x0e_12,
  Thai_nonen: 0x0e_13,
  Thai_dodek: 0x0e_14,
  Thai_totao: 0x0e_15,
  Thai_thothung: 0x0e_16,
  Thai_thothahan: 0x0e_17,
  Thai_thothong: 0x0e_18,
  Thai_nonu: 0x0e_19,
  Thai_bobaimai: 0x0e_1a,
  Thai_popla: 0x0e_1b,
  Thai_phophung: 0x0e_1c,
  Thai_fofa: 0x0e_1d,
  Thai_phophan: 0x0e_1e,
  Thai_fofan: 0x0e_1f,
  Thai_phosamphao: 0x0e_20,
  Thai_moma: 0x0e_21,
  Thai_yoyak: 0x0e_22,
  Thai_rorua: 0x0e_23,
  Thai_ru: 0x0e_24,
  Thai_loling: 0x0e_25,
  Thai_lu: 0x0e_26,
  Thai_wowaen: 0x0e_27,
  Thai_sosala: 0x0e_28,
  Thai_sorusi: 0x0e_29,
  Thai_sosua: 0x0e_2a,
  Thai_hohip: 0x0e_2b,
  Thai_lochula: 0x0e_2c,
  Thai_oang: 0x0e_2d,
  Thai_honokhuk: 0x0e_2e,
  Thai_paiyannoi: 0x0e_2f,
  Thai_saraa: 0x0e_30,
  Thai_maihanakat: 0x0e_31,
  Thai_saraaa: 0x0e_32,
  Thai_saraam: 0x0e_33,
  Thai_sarai: 0x0e_34,
  Thai_saraii: 0x0e_35,
  Thai_saraue: 0x0e_36,
  Thai_sarauee: 0x0e_37,
  Thai_sarau: 0x0e_38,
  Thai_sarauu: 0x0e_39,
  Thai_phinthu: 0x0e_3a,
  Thai_baht: 0x0e_3f,
  Thai_sarae: 0x0e_40,
  Thai_saraae: 0x0e_41,
  Thai_sarao: 0x0e_42,
  Thai_saraaimaimuan: 0x0e_43,
  Thai_saraaimaimalai: 0x0e_44,
  Thai_lakkhangyao: 0x0e_45,
  Thai_maiyamok: 0x0e_46,
  Thai_maitaikhu: 0x0e_47,
  Thai_maiek: 0x0e_48,
  Thai_maitho: 0x0e_49,
  Thai_maitri: 0x0e_4a,
  Thai_maichattawa: 0x0e_4b,
  Thai_thanthakhat: 0x0e_4c,
  Thai_nikhahit: 0x0e_4d,
  Thai_leksun: 0x0e_50,
  Thai_leknung: 0x0e_51,
  Thai_leksong: 0x0e_52,
  Thai_leksam: 0x0e_53,
  Thai_leksi: 0x0e_54,
  Thai_lekha: 0x0e_55,
  Thai_lekhok: 0x0e_56,
  Thai_lekchet: 0x0e_57,
  Thai_lekpaet: 0x0e_58,
  Thai_lekkao: 0x0e_59,
  Armenian_ligature_ew: 0x05_87,
  Armenian_full_stop: 0x05_89,
  Armenian_verjaket: 0x05_89,
  Armenian_separation_mark: 0x05_5d,
  Armenian_but: 0x05_5d,
  Armenian_hyphen: 0x05_8a,
  Armenian_yentamna: 0x05_8a,
  Armenian_exclam: 0x05_5c,
  Armenian_amanak: 0x05_5c,
  Armenian_accent: 0x05_5b,
  Armenian_shesht: 0x05_5b,
  Armenian_question: 0x05_5e,
  Armenian_paruyk: 0x05_5e,
  Armenian_AYB: 0x05_31,
  Armenian_ayb: 0x05_61,
  Armenian_BEN: 0x05_32,
  Armenian_ben: 0x05_62,
  Armenian_GIM: 0x05_33,
  Armenian_gim: 0x05_63,
  Armenian_DA: 0x05_34,
  Armenian_da: 0x05_64,
  Armenian_YECH: 0x05_35,
  Armenian_yech: 0x05_65,
  Armenian_ZA: 0x05_36,
  Armenian_za: 0x05_66,
  Armenian_E: 0x05_37,
  Armenian_e: 0x05_67,
  Armenian_AT: 0x05_38,
  Armenian_at: 0x05_68,
  Armenian_TO: 0x05_39,
  Armenian_to: 0x05_69,
  Armenian_ZHE: 0x05_3a,
  Armenian_zhe: 0x05_6a,
  Armenian_INI: 0x05_3b,
  Armenian_ini: 0x05_6b,
  Armenian_LYUN: 0x05_3c,
  Armenian_lyun: 0x05_6c,
  Armenian_KHE: 0x05_3d,
  Armenian_khe: 0x05_6d,
  Armenian_TSA: 0x05_3e,
  Armenian_tsa: 0x05_6e,
  Armenian_KEN: 0x05_3f,
  Armenian_ken: 0x05_6f,
  Armenian_HO: 0x05_40,
  Armenian_ho: 0x05_70,
  Armenian_DZA: 0x05_41,
  Armenian_dza: 0x05_71,
  Armenian_GHAT: 0x05_42,
  Armenian_ghat: 0x05_72,
  Armenian_TCHE: 0x05_43,
  Armenian_tche: 0x05_73,
  Armenian_MEN: 0x05_44,
  Armenian_men: 0x05_74,
  Armenian_HI: 0x05_45,
  Armenian_hi: 0x05_75,
  Armenian_NU: 0x05_46,
  Armenian_nu: 0x05_76,
  Armenian_SHA: 0x05_47,
  Armenian_sha: 0x05_77,
  Armenian_VO: 0x05_48,
  Armenian_vo: 0x05_78,
  Armenian_CHA: 0x05_49,
  Armenian_cha: 0x05_79,
  Armenian_PE: 0x05_4a,
  Armenian_pe: 0x05_7a,
  Armenian_JE: 0x05_4b,
  Armenian_je: 0x05_7b,
  Armenian_RA: 0x05_4c,
  Armenian_ra: 0x05_7c,
  Armenian_SE: 0x05_4d,
  Armenian_se: 0x05_7d,
  Armenian_VEV: 0x05_4e,
  Armenian_vev: 0x05_7e,
  Armenian_TYUN: 0x05_4f,
  Armenian_tyun: 0x05_7f,
  Armenian_RE: 0x05_50,
  Armenian_re: 0x05_80,
  Armenian_TSO: 0x05_51,
  Armenian_tso: 0x05_81,
  Armenian_VYUN: 0x05_52,
  Armenian_vyun: 0x05_82,
  Armenian_PYUR: 0x05_53,
  Armenian_pyur: 0x05_83,
  Armenian_KE: 0x05_54,
  Armenian_ke: 0x05_84,
  Armenian_O: 0x05_55,
  Armenian_o: 0x05_85,
  Armenian_FE: 0x05_56,
  Armenian_fe: 0x05_86,
  Armenian_apostrophe: 0x05_5a,
  Georgian_an: 0x10_d0,
  Georgian_ban: 0x10_d1,
  Georgian_gan: 0x10_d2,
  Georgian_don: 0x10_d3,
  Georgian_en: 0x10_d4,
  Georgian_vin: 0x10_d5,
  Georgian_zen: 0x10_d6,
  Georgian_tan: 0x10_d7,
  Georgian_in: 0x10_d8,
  Georgian_kan: 0x10_d9,
  Georgian_las: 0x10_da,
  Georgian_man: 0x10_db,
  Georgian_nar: 0x10_dc,
  Georgian_on: 0x10_dd,
  Georgian_par: 0x10_de,
  Georgian_zhar: 0x10_df,
  Georgian_rae: 0x10_e0,
  Georgian_san: 0x10_e1,
  Georgian_tar: 0x10_e2,
  Georgian_un: 0x10_e3,
  Georgian_phar: 0x10_e4,
  Georgian_khar: 0x10_e5,
  Georgian_ghan: 0x10_e6,
  Georgian_qar: 0x10_e7,
  Georgian_shin: 0x10_e8,
  Georgian_chin: 0x10_e9,
  Georgian_can: 0x10_ea,
  Georgian_jil: 0x10_eb,
  Georgian_cil: 0x10_ec,
  Georgian_char: 0x10_ed,
  Georgian_xan: 0x10_ee,
  Georgian_jhan: 0x10_ef,
  Georgian_hae: 0x10_f0,
  Georgian_he: 0x10_f1,
  Georgian_hie: 0x10_f2,
  Georgian_we: 0x10_f3,
  Georgian_har: 0x10_f4,
  Georgian_hoe: 0x10_f5,
  Georgian_fi: 0x10_f6,
  Xabovedot: 0x1e_8a,
  Ibreve: 0x01_2c,
  Zstroke: 0x01_b5,
  Gcaron: 0x01_e6,
  Ocaron: 0x01_d2,
  Obarred: 0x01_9f,
  xabovedot: 0x1e_8b,
  ibreve: 0x01_2d,
  zstroke: 0x01_b6,
  gcaron: 0x01_e7,
  ocaron: 0x01_d2,
  obarred: 0x02_75,
  SCHWA: 0x01_8f,
  schwa: 0x02_59,
  EZH: 0x01_b7,
  ezh: 0x02_92,
  Lbelowdot: 0x1e_36,
  lbelowdot: 0x1e_37,
  Abelowdot: 0x1e_a0,
  abelowdot: 0x1e_a1,
  Ahook: 0x1e_a2,
  ahook: 0x1e_a3,
  Acircumflexacute: 0x1e_a4,
  acircumflexacute: 0x1e_a5,
  Acircumflexgrave: 0x1e_a6,
  acircumflexgrave: 0x1e_a7,
  Acircumflexhook: 0x1e_a8,
  acircumflexhook: 0x1e_a9,
  Acircumflextilde: 0x1e_aa,
  acircumflextilde: 0x1e_ab,
  Acircumflexbelowdot: 0x1e_ac,
  acircumflexbelowdot: 0x1e_ad,
  Abreveacute: 0x1e_ae,
  abreveacute: 0x1e_af,
  Abrevegrave: 0x1e_b0,
  abrevegrave: 0x1e_b1,
  Abrevehook: 0x1e_b2,
  abrevehook: 0x1e_b3,
  Abrevetilde: 0x1e_b4,
  abrevetilde: 0x1e_b5,
  Abrevebelowdot: 0x1e_b6,
  abrevebelowdot: 0x1e_b7,
  Ebelowdot: 0x1e_b8,
  ebelowdot: 0x1e_b9,
  Ehook: 0x1e_ba,
  ehook: 0x1e_bb,
  Etilde: 0x1e_bc,
  etilde: 0x1e_bd,
  Ecircumflexacute: 0x1e_be,
  ecircumflexacute: 0x1e_bf,
  Ecircumflexgrave: 0x1e_c0,
  ecircumflexgrave: 0x1e_c1,
  Ecircumflexhook: 0x1e_c2,
  ecircumflexhook: 0x1e_c3,
  Ecircumflextilde: 0x1e_c4,
  ecircumflextilde: 0x1e_c5,
  Ecircumflexbelowdot: 0x1e_c6,
  ecircumflexbelowdot: 0x1e_c7,
  Ihook: 0x1e_c8,
  ihook: 0x1e_c9,
  Ibelowdot: 0x1e_ca,
  ibelowdot: 0x1e_cb,
  Obelowdot: 0x1e_cc,
  obelowdot: 0x1e_cd,
  Ohook: 0x1e_ce,
  ohook: 0x1e_cf,
  Ocircumflexacute: 0x1e_d0,
  ocircumflexacute: 0x1e_d1,
  Ocircumflexgrave: 0x1e_d2,
  ocircumflexgrave: 0x1e_d3,
  Ocircumflexhook: 0x1e_d4,
  ocircumflexhook: 0x1e_d5,
  Ocircumflextilde: 0x1e_d6,
  ocircumflextilde: 0x1e_d7,
  Ocircumflexbelowdot: 0x1e_d8,
  ocircumflexbelowdot: 0x1e_d9,
  Ohornacute: 0x1e_da,
  ohornacute: 0x1e_db,
  Ohorngrave: 0x1e_dc,
  ohorngrave: 0x1e_dd,
  Ohornhook: 0x1e_de,
  ohornhook: 0x1e_df,
  Ohorntilde: 0x1e_e0,
  ohorntilde: 0x1e_e1,
  Ohornbelowdot: 0x1e_e2,
  ohornbelowdot: 0x1e_e3,
  Ubelowdot: 0x1e_e4,
  ubelowdot: 0x1e_e5,
  Uhook: 0x1e_e6,
  uhook: 0x1e_e7,
  Uhornacute: 0x1e_e8,
  uhornacute: 0x1e_e9,
  Uhorngrave: 0x1e_ea,
  uhorngrave: 0x1e_eb,
  Uhornhook: 0x1e_ec,
  uhornhook: 0x1e_ed,
  Uhorntilde: 0x1e_ee,
  uhorntilde: 0x1e_ef,
  Uhornbelowdot: 0x1e_f0,
  uhornbelowdot: 0x1e_f1,
  Ybelowdot: 0x1e_f4,
  ybelowdot: 0x1e_f5,
  Yhook: 0x1e_f6,
  yhook: 0x1e_f7,
  Ytilde: 0x1e_f8,
  ytilde: 0x1e_f9,
  Ohorn: 0x01_a0,
  ohorn: 0x01_a1,
  Uhorn: 0x01_af,
  uhorn: 0x01_b0,
  EcuSign: 0x20_a0,
  ColonSign: 0x20_a1,
  CruzeiroSign: 0x20_a2,
  FFrancSign: 0x20_a3,
  LiraSign: 0x20_a4,
  MillSign: 0x20_a5,
  NairaSign: 0x20_a6,
  PesetaSign: 0x20_a7,
  RupeeSign: 0x20_a8,
  WonSign: 0x20_a9,
  NewSheqelSign: 0x20_aa,
  DongSign: 0x20_ab,
  EuroSign: 0x20_ac,
  zerosuperior: 0x20_70,
  foursuperior: 0x20_74,
  fivesuperior: 0x20_75,
  sixsuperior: 0x20_76,
  sevensuperior: 0x20_77,
  eightsuperior: 0x20_78,
  ninesuperior: 0x20_79,
  zerosubscript: 0x20_80,
  onesubscript: 0x20_81,
  twosubscript: 0x20_82,
  threesubscript: 0x20_83,
  foursubscript: 0x20_84,
  fivesubscript: 0x20_85,
  sixsubscript: 0x20_86,
  sevensubscript: 0x20_87,
  eightsubscript: 0x20_88,
  ninesubscript: 0x20_89,
  partdifferential: 0x22_02,
  emptyset: 0x22_05,
  elementof: 0x22_08,
  notelementof: 0x22_09,
  containsas: 0x22_0b,
  squareroot: 0x22_1a,
  cuberoot: 0x22_1b,
  fourthroot: 0x22_1c,
  dintegral: 0x22_2c,
  tintegral: 0x22_2d,
  because: 0x22_35,
  approxeq: 0x22_45,
  notapproxeq: 0x22_47,
  notidentical: 0x22_62,
  stricteq: 0x22_63,
  braille_blank: 0x28_00,
  braille_dots_1: 0x28_01,
  braille_dots_2: 0x28_02,
  braille_dots_12: 0x28_03,
  braille_dots_3: 0x28_04,
  braille_dots_13: 0x28_05,
  braille_dots_23: 0x28_06,
  braille_dots_123: 0x28_07,
  braille_dots_4: 0x28_08,
  braille_dots_14: 0x28_09,
  braille_dots_24: 0x28_0a,
  braille_dots_124: 0x28_0b,
  braille_dots_34: 0x28_0c,
  braille_dots_134: 0x28_0d,
  braille_dots_234: 0x28_0e,
  braille_dots_1234: 0x28_0f,
  braille_dots_5: 0x28_10,
  braille_dots_15: 0x28_11,
  braille_dots_25: 0x28_12,
  braille_dots_125: 0x28_13,
  braille_dots_35: 0x28_14,
  braille_dots_135: 0x28_15,
  braille_dots_235: 0x28_16,
  braille_dots_1235: 0x28_17,
  braille_dots_45: 0x28_18,
  braille_dots_145: 0x28_19,
  braille_dots_245: 0x28_1a,
  braille_dots_1245: 0x28_1b,
  braille_dots_345: 0x28_1c,
  braille_dots_1345: 0x28_1d,
  braille_dots_2345: 0x28_1e,
  braille_dots_12345: 0x28_1f,
  braille_dots_6: 0x28_20,
  braille_dots_16: 0x28_21,
  braille_dots_26: 0x28_22,
  braille_dots_126: 0x28_23,
  braille_dots_36: 0x28_24,
  braille_dots_136: 0x28_25,
  braille_dots_236: 0x28_26,
  braille_dots_1236: 0x28_27,
  braille_dots_46: 0x28_28,
  braille_dots_146: 0x28_29,
  braille_dots_246: 0x28_2a,
  braille_dots_1246: 0x28_2b,
  braille_dots_346: 0x28_2c,
  braille_dots_1346: 0x28_2d,
  braille_dots_2346: 0x28_2e,
  braille_dots_12346: 0x28_2f,
  braille_dots_56: 0x28_30,
  braille_dots_156: 0x28_31,
  braille_dots_256: 0x28_32,
  braille_dots_1256: 0x28_33,
  braille_dots_356: 0x28_34,
  braille_dots_1356: 0x28_35,
  braille_dots_2356: 0x28_36,
  braille_dots_12356: 0x28_37,
  braille_dots_456: 0x28_38,
  braille_dots_1456: 0x28_39,
  braille_dots_2456: 0x28_3a,
  braille_dots_12456: 0x28_3b,
  braille_dots_3456: 0x28_3c,
  braille_dots_13456: 0x28_3d,
  braille_dots_23456: 0x28_3e,
  braille_dots_123456: 0x28_3f,
  braille_dots_7: 0x28_40,
  braille_dots_17: 0x28_41,
  braille_dots_27: 0x28_42,
  braille_dots_127: 0x28_43,
  braille_dots_37: 0x28_44,
  braille_dots_137: 0x28_45,
  braille_dots_237: 0x28_46,
  braille_dots_1237: 0x28_47,
  braille_dots_47: 0x28_48,
  braille_dots_147: 0x28_49,
  braille_dots_247: 0x28_4a,
  braille_dots_1247: 0x28_4b,
  braille_dots_347: 0x28_4c,
  braille_dots_1347: 0x28_4d,
  braille_dots_2347: 0x28_4e,
  braille_dots_12347: 0x28_4f,
  braille_dots_57: 0x28_50,
  braille_dots_157: 0x28_51,
  braille_dots_257: 0x28_52,
  braille_dots_1257: 0x28_53,
  braille_dots_357: 0x28_54,
  braille_dots_1357: 0x28_55,
  braille_dots_2357: 0x28_56,
  braille_dots_12357: 0x28_57,
  braille_dots_457: 0x28_58,
  braille_dots_1457: 0x28_59,
  braille_dots_2457: 0x28_5a,
  braille_dots_12457: 0x28_5b,
  braille_dots_3457: 0x28_5c,
  braille_dots_13457: 0x28_5d,
  braille_dots_23457: 0x28_5e,
  braille_dots_123457: 0x28_5f,
  braille_dots_67: 0x28_60,
  braille_dots_167: 0x28_61,
  braille_dots_267: 0x28_62,
  braille_dots_1267: 0x28_63,
  braille_dots_367: 0x28_64,
  braille_dots_1367: 0x28_65,
  braille_dots_2367: 0x28_66,
  braille_dots_12367: 0x28_67,
  braille_dots_467: 0x28_68,
  braille_dots_1467: 0x28_69,
  braille_dots_2467: 0x28_6a,
  braille_dots_12467: 0x28_6b,
  braille_dots_3467: 0x28_6c,
  braille_dots_13467: 0x28_6d,
  braille_dots_23467: 0x28_6e,
  braille_dots_123467: 0x28_6f,
  braille_dots_567: 0x28_70,
  braille_dots_1567: 0x28_71,
  braille_dots_2567: 0x28_72,
  braille_dots_12567: 0x28_73,
  braille_dots_3567: 0x28_74,
  braille_dots_13567: 0x28_75,
  braille_dots_23567: 0x28_76,
  braille_dots_123567: 0x28_77,
  braille_dots_4567: 0x28_78,
  braille_dots_14567: 0x28_79,
  braille_dots_24567: 0x28_7a,
  braille_dots_124567: 0x28_7b,
  braille_dots_34567: 0x28_7c,
  braille_dots_134567: 0x28_7d,
  braille_dots_234567: 0x28_7e,
  braille_dots_1234567: 0x28_7f,
  braille_dots_8: 0x28_80,
  braille_dots_18: 0x28_81,
  braille_dots_28: 0x28_82,
  braille_dots_128: 0x28_83,
  braille_dots_38: 0x28_84,
  braille_dots_138: 0x28_85,
  braille_dots_238: 0x28_86,
  braille_dots_1238: 0x28_87,
  braille_dots_48: 0x28_88,
  braille_dots_148: 0x28_89,
  braille_dots_248: 0x28_8a,
  braille_dots_1248: 0x28_8b,
  braille_dots_348: 0x28_8c,
  braille_dots_1348: 0x28_8d,
  braille_dots_2348: 0x28_8e,
  braille_dots_12348: 0x28_8f,
  braille_dots_58: 0x28_90,
  braille_dots_158: 0x28_91,
  braille_dots_258: 0x28_92,
  braille_dots_1258: 0x28_93,
  braille_dots_358: 0x28_94,
  braille_dots_1358: 0x28_95,
  braille_dots_2358: 0x28_96,
  braille_dots_12358: 0x28_97,
  braille_dots_458: 0x28_98,
  braille_dots_1458: 0x28_99,
  braille_dots_2458: 0x28_9a,
  braille_dots_12458: 0x28_9b,
  braille_dots_3458: 0x28_9c,
  braille_dots_13458: 0x28_9d,
  braille_dots_23458: 0x28_9e,
  braille_dots_123458: 0x28_9f,
  braille_dots_68: 0x28_a0,
  braille_dots_168: 0x28_a1,
  braille_dots_268: 0x28_a2,
  braille_dots_1268: 0x28_a3,
  braille_dots_368: 0x28_a4,
  braille_dots_1368: 0x28_a5,
  braille_dots_2368: 0x28_a6,
  braille_dots_12368: 0x28_a7,
  braille_dots_468: 0x28_a8,
  braille_dots_1468: 0x28_a9,
  braille_dots_2468: 0x28_aa,
  braille_dots_12468: 0x28_ab,
  braille_dots_3468: 0x28_ac,
  braille_dots_13468: 0x28_ad,
  braille_dots_23468: 0x28_ae,
  braille_dots_123468: 0x28_af,
  braille_dots_568: 0x28_b0,
  braille_dots_1568: 0x28_b1,
  braille_dots_2568: 0x28_b2,
  braille_dots_12568: 0x28_b3,
  braille_dots_3568: 0x28_b4,
  braille_dots_13568: 0x28_b5,
  braille_dots_23568: 0x28_b6,
  braille_dots_123568: 0x28_b7,
  braille_dots_4568: 0x28_b8,
  braille_dots_14568: 0x28_b9,
  braille_dots_24568: 0x28_ba,
  braille_dots_124568: 0x28_bb,
  braille_dots_34568: 0x28_bc,
  braille_dots_134568: 0x28_bd,
  braille_dots_234568: 0x28_be,
  braille_dots_1234568: 0x28_bf,
  braille_dots_78: 0x28_c0,
  braille_dots_178: 0x28_c1,
  braille_dots_278: 0x28_c2,
  braille_dots_1278: 0x28_c3,
  braille_dots_378: 0x28_c4,
  braille_dots_1378: 0x28_c5,
  braille_dots_2378: 0x28_c6,
  braille_dots_12378: 0x28_c7,
  braille_dots_478: 0x28_c8,
  braille_dots_1478: 0x28_c9,
  braille_dots_2478: 0x28_ca,
  braille_dots_12478: 0x28_cb,
  braille_dots_3478: 0x28_cc,
  braille_dots_13478: 0x28_cd,
  braille_dots_23478: 0x28_ce,
  braille_dots_123478: 0x28_cf,
  braille_dots_578: 0x28_d0,
  braille_dots_1578: 0x28_d1,
  braille_dots_2578: 0x28_d2,
  braille_dots_12578: 0x28_d3,
  braille_dots_3578: 0x28_d4,
  braille_dots_13578: 0x28_d5,
  braille_dots_23578: 0x28_d6,
  braille_dots_123578: 0x28_d7,
  braille_dots_4578: 0x28_d8,
  braille_dots_14578: 0x28_d9,
  braille_dots_24578: 0x28_da,
  braille_dots_124578: 0x28_db,
  braille_dots_34578: 0x28_dc,
  braille_dots_134578: 0x28_dd,
  braille_dots_234578: 0x28_de,
  braille_dots_1234578: 0x28_df,
  braille_dots_678: 0x28_e0,
  braille_dots_1678: 0x28_e1,
  braille_dots_2678: 0x28_e2,
  braille_dots_12678: 0x28_e3,
  braille_dots_3678: 0x28_e4,
  braille_dots_13678: 0x28_e5,
  braille_dots_23678: 0x28_e6,
  braille_dots_123678: 0x28_e7,
  braille_dots_4678: 0x28_e8,
  braille_dots_14678: 0x28_e9,
  braille_dots_24678: 0x28_ea,
  braille_dots_124678: 0x28_eb,
  braille_dots_34678: 0x28_ec,
  braille_dots_134678: 0x28_ed,
  braille_dots_234678: 0x28_ee,
  braille_dots_1234678: 0x28_ef,
  braille_dots_5678: 0x28_f0,
  braille_dots_15678: 0x28_f1,
  braille_dots_25678: 0x28_f2,
  braille_dots_125678: 0x28_f3,
  braille_dots_35678: 0x28_f4,
  braille_dots_135678: 0x28_f5,
  braille_dots_235678: 0x28_f6,
  braille_dots_1235678: 0x28_f7,
  braille_dots_45678: 0x28_f8,
  braille_dots_145678: 0x28_f9,
  braille_dots_245678: 0x28_fa,
  braille_dots_1245678: 0x28_fb,
  braille_dots_345678: 0x28_fc,
  braille_dots_1345678: 0x28_fd,
  braille_dots_2345678: 0x28_fe,
  braille_dots_12345678: 0x28_ff,
  Sinh_ng: 0x0d_82,
  Sinh_h2: 0x0d_83,
  Sinh_a: 0x0d_85,
  Sinh_aa: 0x0d_86,
  Sinh_ae: 0x0d_87,
  Sinh_aee: 0x0d_88,
  Sinh_i: 0x0d_89,
  Sinh_ii: 0x0d_8a,
  Sinh_u: 0x0d_8b,
  Sinh_uu: 0x0d_8c,
  Sinh_ri: 0x0d_8d,
  Sinh_rii: 0x0d_8e,
  Sinh_lu: 0x0d_8f,
  Sinh_luu: 0x0d_90,
  Sinh_e: 0x0d_91,
  Sinh_ee: 0x0d_92,
  Sinh_ai: 0x0d_93,
  Sinh_o: 0x0d_94,
  Sinh_oo: 0x0d_95,
  Sinh_au: 0x0d_96,
  Sinh_ka: 0x0d_9a,
  Sinh_kha: 0x0d_9b,
  Sinh_ga: 0x0d_9c,
  Sinh_gha: 0x0d_9d,
  Sinh_ng2: 0x0d_9e,
  Sinh_nga: 0x0d_9f,
  Sinh_ca: 0x0d_a0,
  Sinh_cha: 0x0d_a1,
  Sinh_ja: 0x0d_a2,
  Sinh_jha: 0x0d_a3,
  Sinh_nya: 0x0d_a4,
  Sinh_jnya: 0x0d_a5,
  Sinh_nja: 0x0d_a6,
  Sinh_tta: 0x0d_a7,
  Sinh_ttha: 0x0d_a8,
  Sinh_dda: 0x0d_a9,
  Sinh_ddha: 0x0d_aa,
  Sinh_nna: 0x0d_ab,
  Sinh_ndda: 0x0d_ac,
  Sinh_tha: 0x0d_ad,
  Sinh_thha: 0x0d_ae,
  Sinh_dha: 0x0d_af,
  Sinh_dhha: 0x0d_b0,
  Sinh_na: 0x0d_b1,
  Sinh_ndha: 0x0d_b3,
  Sinh_pa: 0x0d_b4,
  Sinh_pha: 0x0d_b5,
  Sinh_ba: 0x0d_b6,
  Sinh_bha: 0x0d_b7,
  Sinh_ma: 0x0d_b8,
  Sinh_mba: 0x0d_b9,
  Sinh_ya: 0x0d_ba,
  Sinh_ra: 0x0d_bb,
  Sinh_la: 0x0d_bd,
  Sinh_va: 0x0d_c0,
  Sinh_sha: 0x0d_c1,
  Sinh_ssha: 0x0d_c2,
  Sinh_sa: 0x0d_c3,
  Sinh_ha: 0x0d_c4,
  Sinh_lla: 0x0d_c5,
  Sinh_fa: 0x0d_c6,
  Sinh_al: 0x0d_ca,
  Sinh_aa2: 0x0d_cf,
  Sinh_ae2: 0x0d_d0,
  Sinh_aee2: 0x0d_d1,
  Sinh_i2: 0x0d_d2,
  Sinh_ii2: 0x0d_d3,
  Sinh_u2: 0x0d_d4,
  Sinh_uu2: 0x0d_d6,
  Sinh_ru2: 0x0d_d8,
  Sinh_e2: 0x0d_d9,
  Sinh_ee2: 0x0d_da,
  Sinh_ai2: 0x0d_db,
  Sinh_o2: 0x0d_dc,
  Sinh_oo2: 0x0d_dd,
  Sinh_au2: 0x0d_de,
  Sinh_lu2: 0x0d_df,
  Sinh_ruu2: 0x0d_f2,
  Sinh_luu2: 0x0d_f3,
  Sinh_kunddaliya: 0x0d_f4,
};

const CHAR_TO_NAME = {
  " ": "space",
};
for (const keysym in KEYSYM_TO_UNICODE) {
  const u = KEYSYM_TO_UNICODE[keysym];
  const character = String.fromCharCode(u);
  CHAR_TO_NAME[character] = keysym;
}

//some keysyms require specific layouts
const KEYSYM_TO_LAYOUT = {
  kana: "jp",
  Farsi: "ir",
  Arabic: "ar",
  Cyrillic: "ru",
  Ukrainian: "ua",
  Macedonia: "mk",
  Greek: "gr",
  hebrew: "he",
  Thai: "th",
  Armenian: "am",
  Georgian: "ge",
  braille: "brai",
};

/**
 * Maps web keycodes to the corresponding X11 keysym:
 *
 * TODO: some values are missing..
 */
const CHARCODE_TO_NAME = {
  8: "BackSpace",
  9: "Tab",
  12: "KP_Begin",
  13: "Return",
  16: "Shift_L",
  17: "Control_L",
  18: "Alt_L",
  19: "Pause", //pause/break
  20: "Caps_Lock",
  27: "Escape",
  31: "Mode_switch",
  32: "space",
  33: "Prior", //Page Up
  34: "Next", //Page Down
  35: "End",
  36: "Home",
  37: "Left",
  38: "Up",
  39: "Right",
  40: "Down",
  42: "Print",
  45: "Insert",
  46: "Delete",
  58: "colon",
  59: "semicolon",
  60: "less",
  61: "equal",
  62: "greater",
  63: "question",
  64: "at",
  91: "Menu", //Left Window Key
  92: "Menu", //Right Window Key
  93: "KP_Enter", //"select key"?
  106: "KP_Multiply",
  107: "KP_Add",
  109: "KP_Subtract",
  110: "KP_Delete",
  111: "KP_Divide",
  144: "Num_Lock",
  145: "Scroll_Lock",
  160: "dead_circumflex",
  161: "exclam",
  162: "quotedbl",
  163: "numbersign",
  164: "dollar",
  165: "percent",
  166: "ampersand",
  167: "underscore",
  168: "parenleft",
  169: "parenright",
  170: "asterisk",
  171: "plus",
  172: "bar",
  173: "minus",
  174: "braceleft",
  175: "braceright",
  176: "asciitilde",
  186: "semicolon",
  187: "equal",
  188: "comma",
  189: "minus",
  190: "period",
  191: "slash",
  192: "grave",
  219: "bracketleft",
  220: "backslash",
  221: "bracketright",
  222: "apostrophe",
};
for (let index = 0; index < 26; index++) {
  CHARCODE_TO_NAME[65 + index] = "abcdefghijklmnopqrstuvwxyz"[index];
}
for (let index = 0; index < 10; index++) {
  CHARCODE_TO_NAME[48 + index] = `${index}`;
  CHARCODE_TO_NAME[96 + index] = `${index}`;
  //fix for OSX numpad?: CHARCODE_TO_NAME[96+i] = "KP_"+i;
}
for (let index = 1; index <= 24; index++) {
  CHARCODE_TO_NAME[111 + index] = `F${index}`;
}
//overrides: only for 'de' layout?
CHARCODE_TO_NAME[192] = "dead_circumflex";
CHARCODE_TO_NAME[219] = "backtick";
CHARCODE_TO_NAME[221] = "dead_acute";
CHARCODE_TO_NAME[220] = "dead_circumflex";
CHARCODE_TO_NAME[187] = "dead_acute";
CHARCODE_TO_NAME_SHIFTED = {};
CHARCODE_TO_NAME_SHIFTED[187] = "dead_grave";
CHARCODE_TO_NAME_SHIFTED[221] = "dead_grave";

/**
 * Converts an event into a list of modifiers.
 *
 * @param event
 * @returns {Array} of strings
 */
function get_event_modifiers(event) {
  const modifiers = [];
  if (event.getModifierState) {
    if (event.getModifierState("Control")) modifiers.push("control");
    if (event.getModifierState("Alt")) modifiers.push("alt");
    if (event.getModifierState("Meta")) modifiers.push("meta");
    if (event.getModifierState("Shift")) modifiers.push("shift");
    if (event.getModifierState("CapsLock")) modifiers.push("capslock");
    if (event.getModifierState("NumLock")) modifiers.push("numlock");
    //ScrollLock
    //Fn
    //AltGraph
  } else if (event.modifiers) {
    if (event.modifiers & Event.ALT_MASK) modifiers.push("alt");
    if (event.modifiers & Event.CONTROL_MASK) modifiers.push("control");
    if (event.modifiers & Event.SHIFT_MASK) modifiers.push("shift");
    if (event.modifiers & Event.META_MASK) modifiers.push("meta");
  } else {
    if (event.altKey) modifiers.push("alt");
    if (event.ctrlKey) modifiers.push("control");
    if (event.metaKey) modifiers.push("meta");
    if (event.shiftKey) modifiers.push("shift");
  }
  return modifiers;
}
