Implement web proxy functionality for client services

- Added support for proxying requests to CLIENT_NAME.dominio
- Implemented service type detection (web, http, https) with priority ordering
- Added tunnel establishment and management for client services
- Implemented HTTPS support with invalid certificate acceptance
- Added tunnel reuse and timeout management (5 minutes)
- Added SSL connection functions for HTTPS tunneling
- Fixed build issues and updated dependencies
parent 153b6344
......@@ -3479,706 +3479,11 @@ const char *novnc_input_keyboard_js =
"window.Keyboard = Keyboard;\n"
;
if (strcmp(path, "/novnc/input/keyboard.js") == 0) return novnc_input_keyboard_js;
const char *novnc_input_keysymdef_js =
"/*\n"
" * Mapping from Unicode codepoints to X11/RFB keysyms\n"
" *\n"
" * This file was automatically generated from keysymdef.h\n"
" * DO NOT EDIT!\n"
" */\n"
const char *novnc_input_keysym_js =
"/* eslint-disable key-spacing */\n"
"\n"
"/* Functions at the bottom */\n"
"\n"
"const codepoints = {\n"
" 0x0100: 0x03c0, // XK_Amacron\n"
" 0x0101: 0x03e0, // XK_amacron\n"
" 0x0102: 0x01c3, // XK_Abreve\n"
" 0x0103: 0x01e3, // XK_abreve\n"
" 0x0104: 0x01a1, // XK_Aogonek\n"
" 0x0105: 0x01b1, // XK_aogonek\n"
" 0x0106: 0x01c6, // XK_Cacute\n"
" 0x0107: 0x01e6, // XK_cacute\n"
" 0x0108: 0x02c6, // XK_Ccircumflex\n"
" 0x0109: 0x02e6, // XK_ccircumflex\n"
" 0x010a: 0x02c5, // XK_Cabovedot\n"
" 0x010b: 0x02e5, // XK_cabovedot\n"
" 0x010c: 0x01c8, // XK_Ccaron\n"
" 0x010d: 0x01e8, // XK_ccaron\n"
" 0x010e: 0x01cf, // XK_Dcaron\n"
" 0x010f: 0x01ef, // XK_dcaron\n"
" 0x0110: 0x01d0, // XK_Dstroke\n"
" 0x0111: 0x01f0, // XK_dstroke\n"
" 0x0112: 0x03aa, // XK_Emacron\n"
" 0x0113: 0x03ba, // XK_emacron\n"
" 0x0116: 0x03cc, // XK_Eabovedot\n"
" 0x0117: 0x03ec, // XK_eabovedot\n"
" 0x0118: 0x01ca, // XK_Eogonek\n"
" 0x0119: 0x01ea, // XK_eogonek\n"
" 0x011a: 0x01cc, // XK_Ecaron\n"
" 0x011b: 0x01ec, // XK_ecaron\n"
" 0x011c: 0x02d8, // XK_Gcircumflex\n"
" 0x011d: 0x02f8, // XK_gcircumflex\n"
" 0x011e: 0x02ab, // XK_Gbreve\n"
" 0x011f: 0x02bb, // XK_gbreve\n"
" 0x0120: 0x02d5, // XK_Gabovedot\n"
" 0x0121: 0x02f5, // XK_gabovedot\n"
" 0x0122: 0x03ab, // XK_Gcedilla\n"
" 0x0123: 0x03bb, // XK_gcedilla\n"
" 0x0124: 0x02a6, // XK_Hcircumflex\n"
" 0x0125: 0x02b6, // XK_hcircumflex\n"
" 0x0126: 0x02a1, // XK_Hstroke\n"
" 0x0127: 0x02b1, // XK_hstroke\n"
" 0x0128: 0x03a5, // XK_Itilde\n"
" 0x0129: 0x03b5, // XK_itilde\n"
" 0x012a: 0x03cf, // XK_Imacron\n"
" 0x012b: 0x03ef, // XK_imacron\n"
" 0x012e: 0x03c7, // XK_Iogonek\n"
" 0x012f: 0x03e7, // XK_iogonek\n"
" 0x0130: 0x02a9, // XK_Iabovedot\n"
" 0x0131: 0x02b9, // XK_idotless\n"
" 0x0134: 0x02ac, // XK_Jcircumflex\n"
" 0x0135: 0x02bc, // XK_jcircumflex\n"
" 0x0136: 0x03d3, // XK_Kcedilla\n"
" 0x0137: 0x03f3, // XK_kcedilla\n"
" 0x0138: 0x03a2, // XK_kra\n"
" 0x0139: 0x01c5, // XK_Lacute\n"
" 0x013a: 0x01e5, // XK_lacute\n"
" 0x013b: 0x03a6, // XK_Lcedilla\n"
" 0x013c: 0x03b6, // XK_lcedilla\n"
" 0x013d: 0x01a5, // XK_Lcaron\n"
" 0x013e: 0x01b5, // XK_lcaron\n"
" 0x0141: 0x01a3, // XK_Lstroke\n"
" 0x0142: 0x01b3, // XK_lstroke\n"
" 0x0143: 0x01d1, // XK_Nacute\n"
" 0x0144: 0x01f1, // XK_nacute\n"
" 0x0145: 0x03d1, // XK_Ncedilla\n"
" 0x0146: 0x03f1, // XK_ncedilla\n"
" 0x0147: 0x01d2, // XK_Ncaron\n"
" 0x0148: 0x01f2, // XK_ncaron\n"
" 0x014a: 0x03bd, // XK_ENG\n"
" 0x014b: 0x03bf, // XK_eng\n"
" 0x014c: 0x03d2, // XK_Omacron\n"
" 0x014d: 0x03f2, // XK_omacron\n"
" 0x0150: 0x01d5, // XK_Odoubleacute\n"
" 0x0151: 0x01f5, // XK_odoubleacute\n"
" 0x0152: 0x13bc, // XK_OE\n"
" 0x0153: 0x13bd, // XK_oe\n"
" 0x0154: 0x01c0, // XK_Racute\n"
" 0x0155: 0x01e0, // XK_racute\n"
" 0x0156: 0x03a3, // XK_Rcedilla\n"
" 0x0157: 0x03b3, // XK_rcedilla\n"
" 0x0158: 0x01d8, // XK_Rcaron\n"
" 0x0159: 0x01f8, // XK_rcaron\n"
" 0x015a: 0x01a6, // XK_Sacute\n"
" 0x015b: 0x01b6, // XK_sacute\n"
" 0x015c: 0x02de, // XK_Scircumflex\n"
" 0x015d: 0x02fe, // XK_scircumflex\n"
" 0x015e: 0x01aa, // XK_Scedilla\n"
" 0x015f: 0x01ba, // XK_scedilla\n"
" 0x0160: 0x01a9, // XK_Scaron\n"
" 0x0161: 0x01b9, // XK_scaron\n"
" 0x0162: 0x01de, // XK_Tcedilla\n"
" 0x0163: 0x01fe, // XK_tcedilla\n"
" 0x0164: 0x01ab, // XK_Tcaron\n"
" 0x0165: 0x01bb, // XK_tcaron\n"
" 0x0166: 0x03ac, // XK_Tslash\n"
" 0x0167: 0x03bc, // XK_tslash\n"
" 0x0168: 0x03dd, // XK_Utilde\n"
" 0x0169: 0x03fd, // XK_utilde\n"
" 0x016a: 0x03de, // XK_Umacron\n"
" 0x016b: 0x03fe, // XK_umacron\n"
" 0x016c: 0x02dd, // XK_Ubreve\n"
" 0x016d: 0x02fd, // XK_ubreve\n"
" 0x016e: 0x01d9, // XK_Uring\n"
" 0x016f: 0x01f9, // XK_uring\n"
" 0x0170: 0x01db, // XK_Udoubleacute\n"
" 0x0171: 0x01fb, // XK_udoubleacute\n"
" 0x0172: 0x03d9, // XK_Uogonek\n"
" 0x0173: 0x03f9, // XK_uogonek\n"
" 0x0178: 0x13be, // XK_Ydiaeresis\n"
" 0x0179: 0x01ac, // XK_Zacute\n"
" 0x017a: 0x01bc, // XK_zacute\n"
" 0x017b: 0x01af, // XK_Zabovedot\n"
" 0x017c: 0x01bf, // XK_zabovedot\n"
" 0x017d: 0x01ae, // XK_Zcaron\n"
" 0x017e: 0x01be, // XK_zcaron\n"
" 0x0192: 0x08f6, // XK_function\n"
" 0x01d2: 0x10001d1, // XK_Ocaron\n"
" 0x02c7: 0x01b7, // XK_caron\n"
" 0x02d8: 0x01a2, // XK_breve\n"
" 0x02d9: 0x01ff, // XK_abovedot\n"
" 0x02db: 0x01b2, // XK_ogonek\n"
" 0x02dd: 0x01bd, // XK_doubleacute\n"
" 0x0385: 0x07ae, // XK_Greek_accentdieresis\n"
" 0x0386: 0x07a1, // XK_Greek_ALPHAaccent\n"
" 0x0388: 0x07a2, // XK_Greek_EPSILONaccent\n"
" 0x0389: 0x07a3, // XK_Greek_ETAaccent\n"
" 0x038a: 0x07a4, // XK_Greek_IOTAaccent\n"
" 0x038c: 0x07a7, // XK_Greek_OMICRONaccent\n"
" 0x038e: 0x07a8, // XK_Greek_UPSILONaccent\n"
" 0x038f: 0x07ab, // XK_Greek_OMEGAaccent\n"
" 0x0390: 0x07b6, // XK_Greek_iotaaccentdieresis\n"
" 0x0391: 0x07c1, // XK_Greek_ALPHA\n"
" 0x0392: 0x07c2, // XK_Greek_BETA\n"
" 0x0393: 0x07c3, // XK_Greek_GAMMA\n"
" 0x0394: 0x07c4, // XK_Greek_DELTA\n"
" 0x0395: 0x07c5, // XK_Greek_EPSILON\n"
" 0x0396: 0x07c6, // XK_Greek_ZETA\n"
" 0x0397: 0x07c7, // XK_Greek_ETA\n"
" 0x0398: 0x07c8, // XK_Greek_THETA\n"
" 0x0399: 0x07c9, // XK_Greek_IOTA\n"
" 0x039a: 0x07ca, // XK_Greek_KAPPA\n"
" 0x039b: 0x07cb, // XK_Greek_LAMDA\n"
" 0x039c: 0x07cc, // XK_Greek_MU\n"
" 0x039d: 0x07cd, // XK_Greek_NU\n"
" 0x039e: 0x07ce, // XK_Greek_XI\n"
" 0x039f: 0x07cf, // XK_Greek_OMICRON\n"
" 0x03a0: 0x07d0, // XK_Greek_PI\n"
" 0x03a1: 0x07d1, // XK_Greek_RHO\n"
" 0x03a3: 0x07d2, // XK_Greek_SIGMA\n"
" 0x03a4: 0x07d4, // XK_Greek_TAU\n"
" 0x03a5: 0x07d5, // XK_Greek_UPSILON\n"
" 0x03a6: 0x07d6, // XK_Greek_PHI\n"
" 0x03a7: 0x07d7, // XK_Greek_CHI\n"
" 0x03a8: 0x07d8, // XK_Greek_PSI\n"
" 0x03a9: 0x07d9, // XK_Greek_OMEGA\n"
" 0x03aa: 0x07a5, // XK_Greek_IOTAdieresis\n"
" 0x03ab: 0x07a9, // XK_Greek_UPSILONdieresis\n"
" 0x03ac: 0x07b1, // XK_Greek_alphaaccent\n"
" 0x03ad: 0x07b2, // XK_Greek_epsilonaccent\n"
" 0x03ae: 0x07b3, // XK_Greek_etaaccent\n"
" 0x03af: 0x07b4, // XK_Greek_iotaaccent\n"
" 0x03b0: 0x07ba, // XK_Greek_upsilonaccentdieresis\n"
" 0x03b1: 0x07e1, // XK_Greek_alpha\n"
" 0x03b2: 0x07e2, // XK_Greek_beta\n"
" 0x03b3: 0x07e3, // XK_Greek_gamma\n"
" 0x03b4: 0x07e4, // XK_Greek_delta\n"
" 0x03b5: 0x07e5, // XK_Greek_epsilon\n"
" 0x03b6: 0x07e6, // XK_Greek_zeta\n"
" 0x03b7: 0x07e7, // XK_Greek_eta\n"
" 0x03b8: 0x07e8, // XK_Greek_theta\n"
" 0x03b9: 0x07e9, // XK_Greek_iota\n"
" 0x03ba: 0x07ea, // XK_Greek_kappa\n"
" 0x03bb: 0x07eb, // XK_Greek_lamda\n"
" 0x03bc: 0x07ec, // XK_Greek_mu\n"
" 0x03bd: 0x07ed, // XK_Greek_nu\n"
" 0x03be: 0x07ee, // XK_Greek_xi\n"
" 0x03bf: 0x07ef, // XK_Greek_omicron\n"
" 0x03c0: 0x07f0, // XK_Greek_pi\n"
" 0x03c1: 0x07f1, // XK_Greek_rho\n"
" 0x03c2: 0x07f3, // XK_Greek_finalsmallsigma\n"
" 0x03c3: 0x07f2, // XK_Greek_sigma\n"
" 0x03c4: 0x07f4, // XK_Greek_tau\n"
" 0x03c5: 0x07f5, // XK_Greek_upsilon\n"
" 0x03c6: 0x07f6, // XK_Greek_phi\n"
" 0x03c7: 0x07f7, // XK_Greek_chi\n"
" 0x03c8: 0x07f8, // XK_Greek_psi\n"
" 0x03c9: 0x07f9, // XK_Greek_omega\n"
" 0x03ca: 0x07b5, // XK_Greek_iotadieresis\n"
" 0x03cb: 0x07b9, // XK_Greek_upsilondieresis\n"
" 0x03cc: 0x07b7, // XK_Greek_omicronaccent\n"
" 0x03cd: 0x07b8, // XK_Greek_upsilonaccent\n"
" 0x03ce: 0x07bb, // XK_Greek_omegaaccent\n"
" 0x0401: 0x06b3, // XK_Cyrillic_IO\n"
" 0x0402: 0x06b1, // XK_Serbian_DJE\n"
" 0x0403: 0x06b2, // XK_Macedonia_GJE\n"
" 0x0404: 0x06b4, // XK_Ukrainian_IE\n"
" 0x0405: 0x06b5, // XK_Macedonia_DSE\n"
" 0x0406: 0x06b6, // XK_Ukrainian_I\n"
" 0x0407: 0x06b7, // XK_Ukrainian_YI\n"
" 0x0408: 0x06b8, // XK_Cyrillic_JE\n"
" 0x0409: 0x06b9, // XK_Cyrillic_LJE\n"
" 0x040a: 0x06ba, // XK_Cyrillic_NJE\n"
" 0x040b: 0x06bb, // XK_Serbian_TSHE\n"
" 0x040c: 0x06bc, // XK_Macedonia_KJE\n"
" 0x040e: 0x06be, // XK_Byelorussian_SHORTU\n"
" 0x040f: 0x06bf, // XK_Cyrillic_DZHE\n"
" 0x0410: 0x06e1, // XK_Cyrillic_A\n"
" 0x0411: 0x06e2, // XK_Cyrillic_BE\n"
" 0x0412: 0x06f7, // XK_Cyrillic_VE\n"
" 0x0413: 0x06e7, // XK_Cyrillic_GHE\n"
" 0x0414: 0x06e4, // XK_Cyrillic_DE\n"
" 0x0415: 0x06e5, // XK_Cyrillic_IE\n"
" 0x0416: 0x06f6, // XK_Cyrillic_ZHE\n"
" 0x0417: 0x06fa, // XK_Cyrillic_ZE\n"
" 0x0418: 0x06e9, // XK_Cyrillic_I\n"
" 0x0419: 0x06ea, // XK_Cyrillic_SHORTI\n"
" 0x041a: 0x06eb, // XK_Cyrillic_KA\n"
" 0x041b: 0x06ec, // XK_Cyrillic_EL\n"
" 0x041c: 0x06ed, // XK_Cyrillic_EM\n"
" 0x041d: 0x06ee, // XK_Cyrillic_EN\n"
" 0x041e: 0x06ef, // XK_Cyrillic_O\n"
" 0x041f: 0x06f0, // XK_Cyrillic_PE\n"
" 0x0420: 0x06f2, // XK_Cyrillic_ER\n"
" 0x0421: 0x06f3, // XK_Cyrillic_ES\n"
" 0x0422: 0x06f4, // XK_Cyrillic_TE\n"
" 0x0423: 0x06f5, // XK_Cyrillic_U\n"
" 0x0424: 0x06e6, // XK_Cyrillic_EF\n"
" 0x0425: 0x06e8, // XK_Cyrillic_HA\n"
" 0x0426: 0x06e3, // XK_Cyrillic_TSE\n"
" 0x0427: 0x06fe, // XK_Cyrillic_CHE\n"
" 0x0428: 0x06fb, // XK_Cyrillic_SHA\n"
" 0x0429: 0x06fd, // XK_Cyrillic_SHCHA\n"
" 0x042a: 0x06ff, // XK_Cyrillic_HARDSIGN\n"
" 0x042b: 0x06f9, // XK_Cyrillic_YERU\n"
" 0x042c: 0x06f8, // XK_Cyrillic_SOFTSIGN\n"
" 0x042d: 0x06fc, // XK_Cyrillic_E\n"
" 0x042e: 0x06e0, // XK_Cyrillic_YU\n"
" 0x042f: 0x06f1, // XK_Cyrillic_YA\n"
" 0x0430: 0x06c1, // XK_Cyrillic_a\n"
" 0x0431: 0x06c2, // XK_Cyrillic_be\n"
" 0x0432: 0x06d7, // XK_Cyrillic_ve\n"
" 0x0433: 0x06c7, // XK_Cyrillic_ghe\n"
" 0x0434: 0x06c4, // XK_Cyrillic_de\n"
" 0x0435: 0x06c5, // XK_Cyrillic_ie\n"
" 0x0436: 0x06d6, // XK_Cyrillic_zhe\n"
" 0x0437: 0x06da, // XK_Cyrillic_ze\n"
" 0x0438: 0x06c9, // XK_Cyrillic_i\n"
" 0x0439: 0x06ca, // XK_Cyrillic_shorti\n"
" 0x043a: 0x06cb, // XK_Cyrillic_ka\n"
" 0x043b: 0x06cc, // XK_Cyrillic_el\n"
" 0x043c: 0x06cd, // XK_Cyrillic_em\n"
" 0x043d: 0x06ce, // XK_Cyrillic_en\n"
" 0x043e: 0x06cf, // XK_Cyrillic_o\n"
" 0x043f: 0x06d0, // XK_Cyrillic_pe\n"
" 0x0440: 0x06d2, // XK_Cyrillic_er\n"
" 0x0441: 0x06d3, // XK_Cyrillic_es\n"
" 0x0442: 0x06d4, // XK_Cyrillic_te\n"
" 0x0443: 0x06d5, // XK_Cyrillic_u\n"
" 0x0444: 0x06c6, // XK_Cyrillic_ef\n"
" 0x0445: 0x06c8, // XK_Cyrillic_ha\n"
" 0x0446: 0x06c3, // XK_Cyrillic_tse\n"
" 0x0447: 0x06de, // XK_Cyrillic_che\n"
" 0x0448: 0x06db, // XK_Cyrillic_sha\n"
" 0x0449: 0x06dd, // XK_Cyrillic_shcha\n"
" 0x044a: 0x06df, // XK_Cyrillic_hardsign\n"
" 0x044b: 0x06d9, // XK_Cyrillic_yeru\n"
" 0x044c: 0x06d8, // XK_Cyrillic_softsign\n"
" 0x044d: 0x06dc, // XK_Cyrillic_e\n"
" 0x044e: 0x06c0, // XK_Cyrillic_yu\n"
" 0x044f: 0x06d1, // XK_Cyrillic_ya\n"
" 0x0451: 0x06a3, // XK_Cyrillic_io\n"
" 0x0452: 0x06a1, // XK_Serbian_dje\n"
" 0x0453: 0x06a2, // XK_Macedonia_gje\n"
" 0x0454: 0x06a4, // XK_Ukrainian_ie\n"
" 0x0455: 0x06a5, // XK_Macedonia_dse\n"
" 0x0456: 0x06a6, // XK_Ukrainian_i\n"
" 0x0457: 0x06a7, // XK_Ukrainian_yi\n"
" 0x0458: 0x06a8, // XK_Cyrillic_je\n"
" 0x0459: 0x06a9, // XK_Cyrillic_lje\n"
" 0x045a: 0x06aa, // XK_Cyrillic_nje\n"
" 0x045b: 0x06ab, // XK_Serbian_tshe\n"
" 0x045c: 0x06ac, // XK_Macedonia_kje\n"
" 0x045e: 0x06ae, // XK_Byelorussian_shortu\n"
" 0x045f: 0x06af, // XK_Cyrillic_dzhe\n"
" 0x0490: 0x06bd, // XK_Ukrainian_GHE_WITH_UPTURN\n"
" 0x0491: 0x06ad, // XK_Ukrainian_ghe_with_upturn\n"
" 0x05d0: 0x0ce0, // XK_hebrew_aleph\n"
" 0x05d1: 0x0ce1, // XK_hebrew_bet\n"
" 0x05d2: 0x0ce2, // XK_hebrew_gimel\n"
" 0x05d3: 0x0ce3, // XK_hebrew_dalet\n"
" 0x05d4: 0x0ce4, // XK_hebrew_he\n"
" 0x05d5: 0x0ce5, // XK_hebrew_waw\n"
" 0x05d6: 0x0ce6, // XK_hebrew_zain\n"
" 0x05d7: 0x0ce7, // XK_hebrew_chet\n"
" 0x05d8: 0x0ce8, // XK_hebrew_tet\n"
" 0x05d9: 0x0ce9, // XK_hebrew_yod\n"
" 0x05da: 0x0cea, // XK_hebrew_finalkaph\n"
" 0x05db: 0x0ceb, // XK_hebrew_kaph\n"
" 0x05dc: 0x0cec, // XK_hebrew_lamed\n"
" 0x05dd: 0x0ced, // XK_hebrew_finalmem\n"
" 0x05de: 0x0cee, // XK_hebrew_mem\n"
" 0x05df: 0x0cef, // XK_hebrew_finalnun\n"
" 0x05e0: 0x0cf0, // XK_hebrew_nun\n"
" 0x05e1: 0x0cf1, // XK_hebrew_samech\n"
" 0x05e2: 0x0cf2, // XK_hebrew_ayin\n"
" 0x05e3: 0x0cf3, // XK_hebrew_finalpe\n"
" 0x05e4: 0x0cf4, // XK_hebrew_pe\n"
" 0x05e5: 0x0cf5, // XK_hebrew_finalzade\n"
" 0x05e6: 0x0cf6, // XK_hebrew_zade\n"
" 0x05e7: 0x0cf7, // XK_hebrew_qoph\n"
" 0x05e8: 0x0cf8, // XK_hebrew_resh\n"
" 0x05e9: 0x0cf9, // XK_hebrew_shin\n"
" 0x05ea: 0x0cfa, // XK_hebrew_taw\n"
" 0x060c: 0x05ac, // XK_Arabic_comma\n"
" 0x061b: 0x05bb, // XK_Arabic_semicolon\n"
" 0x061f: 0x05bf, // XK_Arabic_question_mark\n"
" 0x0621: 0x05c1, // XK_Arabic_hamza\n"
" 0x0622: 0x05c2, // XK_Arabic_maddaonalef\n"
" 0x0623: 0x05c3, // XK_Arabic_hamzaonalef\n"
" 0x0624: 0x05c4, // XK_Arabic_hamzaonwaw\n"
" 0x0625: 0x05c5, // XK_Arabic_hamzaunderalef\n"
" 0x0626: 0x05c6, // XK_Arabic_hamzaonyeh\n"
" 0x0627: 0x05c7, // XK_Arabic_alef\n"
" 0x0628: 0x05c8, // XK_Arabic_beh\n"
" 0x0629: 0x05c9, // XK_Arabic_tehmarbuta\n"
" 0x062a: 0x05ca, // XK_Arabic_teh\n"
" 0x062b: 0x05cb, // XK_Arabic_theh\n"
" 0x062c: 0x05cc, // XK_Arabic_jeem\n"
" 0x062d: 0x05cd, // XK_Arabic_hah\n"
" 0x062e: 0x05ce, // XK_Arabic_khah\n"
" 0x062f: 0x05cf, // XK_Arabic_dal\n"
" 0x0630: 0x05d0, // XK_Arabic_thal\n"
" 0x0631: 0x05d1, // XK_Arabic_ra\n"
" 0x0632: 0x05d2, // XK_Arabic_zain\n"
" 0x0633: 0x05d3, // XK_Arabic_seen\n"
" 0x0634: 0x05d4, // XK_Arabic_sheen\n"
" 0x0635: 0x05d5, // XK_Arabic_sad\n"
" 0x0636: 0x05d6, // XK_Arabic_dad\n"
" 0x0637: 0x05d7, // XK_Arabic_tah\n"
" 0x0638: 0x05d8, // XK_Arabic_zah\n"
" 0x0639: 0x05d9, // XK_Arabic_ain\n"
" 0x063a: 0x05da, // XK_Arabic_ghain\n"
" 0x0640: 0x05e0, // XK_Arabic_tatweel\n"
" 0x0641: 0x05e1, // XK_Arabic_feh\n"
" 0x0642: 0x05e2, // XK_Arabic_qaf\n"
" 0x0643: 0x05e3, // XK_Arabic_kaf\n"
" 0x0644: 0x05e4, // XK_Arabic_lam\n"
" 0x0645: 0x05e5, // XK_Arabic_meem\n"
" 0x0646: 0x05e6, // XK_Arabic_noon\n"
" 0x0647: 0x05e7, // XK_Arabic_ha\n"
" 0x0648: 0x05e8, // XK_Arabic_waw\n"
" 0x0649: 0x05e9, // XK_Arabic_alefmaksura\n"
" 0x064a: 0x05ea, // XK_Arabic_yeh\n"
" 0x064b: 0x05eb, // XK_Arabic_fathatan\n"
" 0x064c: 0x05ec, // XK_Arabic_dammatan\n"
" 0x064d: 0x05ed, // XK_Arabic_kasratan\n"
" 0x064e: 0x05ee, // XK_Arabic_fatha\n"
" 0x064f: 0x05ef, // XK_Arabic_damma\n"
" 0x0650: 0x05f0, // XK_Arabic_kasra\n"
" 0x0651: 0x05f1, // XK_Arabic_shadda\n"
" 0x0652: 0x05f2, // XK_Arabic_sukun\n"
" 0x0e01: 0x0da1, // XK_Thai_kokai\n"
" 0x0e02: 0x0da2, // XK_Thai_khokhai\n"
" 0x0e03: 0x0da3, // XK_Thai_khokhuat\n"
" 0x0e04: 0x0da4, // XK_Thai_khokhwai\n"
" 0x0e05: 0x0da5, // XK_Thai_khokhon\n"
" 0x0e06: 0x0da6, // XK_Thai_khorakhang\n"
" 0x0e07: 0x0da7, // XK_Thai_ngongu\n"
" 0x0e08: 0x0da8, // XK_Thai_chochan\n"
" 0x0e09: 0x0da9, // XK_Thai_choching\n"
" 0x0e0a: 0x0daa, // XK_Thai_chochang\n"
" 0x0e0b: 0x0dab, // XK_Thai_soso\n"
" 0x0e0c: 0x0dac, // XK_Thai_chochoe\n"
" 0x0e0d: 0x0dad, // XK_Thai_yoying\n"
" 0x0e0e: 0x0dae, // XK_Thai_dochada\n"
" 0x0e0f: 0x0daf, // XK_Thai_topatak\n"
" 0x0e10: 0x0db0, // XK_Thai_thothan\n"
" 0x0e11: 0x0db1, // XK_Thai_thonangmontho\n"
" 0x0e12: 0x0db2, // XK_Thai_thophuthao\n"
" 0x0e13: 0x0db3, // XK_Thai_nonen\n"
" 0x0e14: 0x0db4, // XK_Thai_dodek\n"
" 0x0e15: 0x0db5, // XK_Thai_totao\n"
" 0x0e16: 0x0db6, // XK_Thai_thothung\n"
" 0x0e17: 0x0db7, // XK_Thai_thothahan\n"
" 0x0e18: 0x0db8, // XK_Thai_thothong\n"
" 0x0e19: 0x0db9, // XK_Thai_nonu\n"
" 0x0e1a: 0x0dba, // XK_Thai_bobaimai\n"
" 0x0e1b: 0x0dbb, // XK_Thai_popla\n"
" 0x0e1c: 0x0dbc, // XK_Thai_phophung\n"
" 0x0e1d: 0x0dbd, // XK_Thai_fofa\n"
" 0x0e1e: 0x0dbe, // XK_Thai_phophan\n"
" 0x0e1f: 0x0dbf, // XK_Thai_fofan\n"
" 0x0e20: 0x0dc0, // XK_Thai_phosamphao\n"
" 0x0e21: 0x0dc1, // XK_Thai_moma\n"
" 0x0e22: 0x0dc2, // XK_Thai_yoyak\n"
" 0x0e23: 0x0dc3, // XK_Thai_rorua\n"
" 0x0e24: 0x0dc4, // XK_Thai_ru\n"
" 0x0e25: 0x0dc5, // XK_Thai_loling\n"
" 0x0e26: 0x0dc6, // XK_Thai_lu\n"
" 0x0e27: 0x0dc7, // XK_Thai_wowaen\n"
" 0x0e28: 0x0dc8, // XK_Thai_sosala\n"
" 0x0e29: 0x0dc9, // XK_Thai_sorusi\n"
" 0x0e2a: 0x0dca, // XK_Thai_sosua\n"
" 0x0e2b: 0x0dcb, // XK_Thai_hohip\n"
" 0x0e2c: 0x0dcc, // XK_Thai_lochula\n"
" 0x0e2d: 0x0dcd, // XK_Thai_oang\n"
" 0x0e2e: 0x0dce, // XK_Thai_honokhuk\n"
" 0x0e2f: 0x0dcf, // XK_Thai_paiyannoi\n"
" 0x0e30: 0x0dd0, // XK_Thai_saraa\n"
" 0x0e31: 0x0dd1, // XK_Thai_maihanakat\n"
" 0x0e32: 0x0dd2, // XK_Thai_saraaa\n"
" 0x0e33: 0x0dd3, // XK_Thai_saraam\n"
" 0x0e34: 0x0dd4, // XK_Thai_sarai\n"
" 0x0e35: 0x0dd5, // XK_Thai_saraii\n"
" 0x0e36: 0x0dd6, // XK_Thai_saraue\n"
" 0x0e37: 0x0dd7, // XK_Thai_sarauee\n"
" 0x0e38: 0x0dd8, // XK_Thai_sarau\n"
" 0x0e39: 0x0dd9, // XK_Thai_sarauu\n"
" 0x0e3a: 0x0dda, // XK_Thai_phinthu\n"
" 0x0e3f: 0x0ddf, // XK_Thai_baht\n"
" 0x0e40: 0x0de0, // XK_Thai_sarae\n"
" 0x0e41: 0x0de1, // XK_Thai_saraae\n"
" 0x0e42: 0x0de2, // XK_Thai_sarao\n"
" 0x0e43: 0x0de3, // XK_Thai_saraaimaimuan\n"
" 0x0e44: 0x0de4, // XK_Thai_saraaimaimalai\n"
" 0x0e45: 0x0de5, // XK_Thai_lakkhangyao\n"
" 0x0e46: 0x0de6, // XK_Thai_maiyamok\n"
" 0x0e47: 0x0de7, // XK_Thai_maitaikhu\n"
" 0x0e48: 0x0de8, // XK_Thai_maiek\n"
" 0x0e49: 0x0de9, // XK_Thai_maitho\n"
" 0x0e4a: 0x0dea, // XK_Thai_maitri\n"
" 0x0e4b: 0x0deb, // XK_Thai_maichattawa\n"
" 0x0e4c: 0x0dec, // XK_Thai_thanthakhat\n"
" 0x0e4d: 0x0ded, // XK_Thai_nikhahit\n"
" 0x0e50: 0x0df0, // XK_Thai_leksun\n"
" 0x0e51: 0x0df1, // XK_Thai_leknung\n"
" 0x0e52: 0x0df2, // XK_Thai_leksong\n"
" 0x0e53: 0x0df3, // XK_Thai_leksam\n"
" 0x0e54: 0x0df4, // XK_Thai_leksi\n"
" 0x0e55: 0x0df5, // XK_Thai_lekha\n"
" 0x0e56: 0x0df6, // XK_Thai_lekhok\n"
" 0x0e57: 0x0df7, // XK_Thai_lekchet\n"
" 0x0e58: 0x0df8, // XK_Thai_lekpaet\n"
" 0x0e59: 0x0df9, // XK_Thai_lekkao\n"
" 0x2002: 0x0aa2, // XK_enspace\n"
" 0x2003: 0x0aa1, // XK_emspace\n"
" 0x2004: 0x0aa3, // XK_em3space\n"
" 0x2005: 0x0aa4, // XK_em4space\n"
" 0x2007: 0x0aa5, // XK_digitspace\n"
" 0x2008: 0x0aa6, // XK_punctspace\n"
" 0x2009: 0x0aa7, // XK_thinspace\n"
" 0x200a: 0x0aa8, // XK_hairspace\n"
" 0x2012: 0x0abb, // XK_figdash\n"
" 0x2013: 0x0aaa, // XK_endash\n"
" 0x2014: 0x0aa9, // XK_emdash\n"
" 0x2015: 0x07af, // XK_Greek_horizbar\n"
" 0x2017: 0x0cdf, // XK_hebrew_doublelowline\n"
" 0x2018: 0x0ad0, // XK_leftsinglequotemark\n"
" 0x2019: 0x0ad1, // XK_rightsinglequotemark\n"
" 0x201a: 0x0afd, // XK_singlelowquotemark\n"
" 0x201c: 0x0ad2, // XK_leftdoublequotemark\n"
" 0x201d: 0x0ad3, // XK_rightdoublequotemark\n"
" 0x201e: 0x0afe, // XK_doublelowquotemark\n"
" 0x2020: 0x0af1, // XK_dagger\n"
" 0x2021: 0x0af2, // XK_doubledagger\n"
" 0x2022: 0x0ae6, // XK_enfilledcircbullet\n"
" 0x2025: 0x0aaf, // XK_doubbaselinedot\n"
" 0x2026: 0x0aae, // XK_ellipsis\n"
" 0x2030: 0x0ad5, // XK_permille\n"
" 0x2032: 0x0ad6, // XK_minutes\n"
" 0x2033: 0x0ad7, // XK_seconds\n"
" 0x2038: 0x0afc, // XK_caret\n"
" 0x203e: 0x047e, // XK_overline\n"
" 0x20a9: 0x0eff, // XK_Korean_Won\n"
" 0x20ac: 0x20ac, // XK_EuroSign\n"
" 0x2105: 0x0ab8, // XK_careof\n"
" 0x2116: 0x06b0, // XK_numerosign\n"
" 0x2117: 0x0afb, // XK_phonographcopyright\n"
" 0x211e: 0x0ad4, // XK_prescription\n"
" 0x2122: 0x0ac9, // XK_trademark\n"
" 0x2153: 0x0ab0, // XK_onethird\n"
" 0x2154: 0x0ab1, // XK_twothirds\n"
" 0x2155: 0x0ab2, // XK_onefifth\n"
" 0x2156: 0x0ab3, // XK_twofifths\n"
" 0x2157: 0x0ab4, // XK_threefifths\n"
" 0x2158: 0x0ab5, // XK_fourfifths\n"
" 0x2159: 0x0ab6, // XK_onesixth\n"
" 0x215a: 0x0ab7, // XK_fivesixths\n"
" 0x215b: 0x0ac3, // XK_oneeighth\n"
" 0x215c: 0x0ac4, // XK_threeeighths\n"
" 0x215d: 0x0ac5, // XK_fiveeighths\n"
" 0x215e: 0x0ac6, // XK_seveneighths\n"
" 0x2190: 0x08fb, // XK_leftarrow\n"
" 0x2191: 0x08fc, // XK_uparrow\n"
" 0x2192: 0x08fd, // XK_rightarrow\n"
" 0x2193: 0x08fe, // XK_downarrow\n"
" 0x21d2: 0x08ce, // XK_implies\n"
" 0x21d4: 0x08cd, // XK_ifonlyif\n"
" 0x2202: 0x08ef, // XK_partialderivative\n"
" 0x2207: 0x08c5, // XK_nabla\n"
" 0x2218: 0x0bca, // XK_jot\n"
" 0x221a: 0x08d6, // XK_radical\n"
" 0x221d: 0x08c1, // XK_variation\n"
" 0x221e: 0x08c2, // XK_infinity\n"
" 0x2227: 0x08de, // XK_logicaland\n"
" 0x2228: 0x08df, // XK_logicalor\n"
" 0x2229: 0x08dc, // XK_intersection\n"
" 0x222a: 0x08dd, // XK_union\n"
" 0x222b: 0x08bf, // XK_integral\n"
" 0x2234: 0x08c0, // XK_therefore\n"
" 0x223c: 0x08c8, // XK_approximate\n"
" 0x2243: 0x08c9, // XK_similarequal\n"
" 0x2245: 0x1002248, // XK_approxeq\n"
" 0x2260: 0x08bd, // XK_notequal\n"
" 0x2261: 0x08cf, // XK_identical\n"
" 0x2264: 0x08bc, // XK_lessthanequal\n"
" 0x2265: 0x08be, // XK_greaterthanequal\n"
" 0x2282: 0x08da, // XK_includedin\n"
" 0x2283: 0x08db, // XK_includes\n"
" 0x22a2: 0x0bfc, // XK_righttack\n"
" 0x22a3: 0x0bdc, // XK_lefttack\n"
" 0x22a4: 0x0bc2, // XK_downtack\n"
" 0x22a5: 0x0bce, // XK_uptack\n"
" 0x2308: 0x0bd3, // XK_upstile\n"
" 0x230a: 0x0bc4, // XK_downstile\n"
" 0x2315: 0x0afa, // XK_telephonerecorder\n"
" 0x2320: 0x08a4, // XK_topintegral\n"
" 0x2321: 0x08a5, // XK_botintegral\n"
" 0x2395: 0x0bcc, // XK_quad\n"
" 0x239b: 0x08ab, // XK_topleftparens\n"
" 0x239d: 0x08ac, // XK_botleftparens\n"
" 0x239e: 0x08ad, // XK_toprightparens\n"
" 0x23a0: 0x08ae, // XK_botrightparens\n"
" 0x23a1: 0x08a7, // XK_topleftsqbracket\n"
" 0x23a3: 0x08a8, // XK_botleftsqbracket\n"
" 0x23a4: 0x08a9, // XK_toprightsqbracket\n"
" 0x23a6: 0x08aa, // XK_botrightsqbracket\n"
" 0x23a8: 0x08af, // XK_leftmiddlecurlybrace\n"
" 0x23ac: 0x08b0, // XK_rightmiddlecurlybrace\n"
" 0x23b7: 0x08a1, // XK_leftradical\n"
" 0x23ba: 0x09ef, // XK_horizlinescan1\n"
" 0x23bb: 0x09f0, // XK_horizlinescan3\n"
" 0x23bc: 0x09f2, // XK_horizlinescan7\n"
" 0x23bd: 0x09f3, // XK_horizlinescan9\n"
" 0x2409: 0x09e2, // XK_ht\n"
" 0x240a: 0x09e5, // XK_lf\n"
" 0x240b: 0x09e9, // XK_vt\n"
" 0x240c: 0x09e3, // XK_ff\n"
" 0x240d: 0x09e4, // XK_cr\n"
" 0x2423: 0x0aac, // XK_signifblank\n"
" 0x2424: 0x09e8, // XK_nl\n"
" 0x2500: 0x08a3, // XK_horizconnector\n"
" 0x2502: 0x08a6, // XK_vertconnector\n"
" 0x250c: 0x08a2, // XK_topleftradical\n"
" 0x2510: 0x09eb, // XK_uprightcorner\n"
" 0x2514: 0x09ed, // XK_lowleftcorner\n"
" 0x2518: 0x09ea, // XK_lowrightcorner\n"
" 0x251c: 0x09f4, // XK_leftt\n"
" 0x2524: 0x09f5, // XK_rightt\n"
" 0x252c: 0x09f7, // XK_topt\n"
" 0x2534: 0x09f6, // XK_bott\n"
" 0x253c: 0x09ee, // XK_crossinglines\n"
" 0x2592: 0x09e1, // XK_checkerboard\n"
" 0x25aa: 0x0ae7, // XK_enfilledsqbullet\n"
" 0x25ab: 0x0ae1, // XK_enopensquarebullet\n"
" 0x25ac: 0x0adb, // XK_filledrectbullet\n"
" 0x25ad: 0x0ae2, // XK_openrectbullet\n"
" 0x25ae: 0x0adf, // XK_emfilledrect\n"
" 0x25af: 0x0acf, // XK_emopenrectangle\n"
" 0x25b2: 0x0ae8, // XK_filledtribulletup\n"
" 0x25b3: 0x0ae3, // XK_opentribulletup\n"
" 0x25b6: 0x0add, // XK_filledrighttribullet\n"
" 0x25b7: 0x0acd, // XK_rightopentriangle\n"
" 0x25bc: 0x0ae9, // XK_filledtribulletdown\n"
" 0x25bd: 0x0ae4, // XK_opentribulletdown\n"
" 0x25c0: 0x0adc, // XK_filledlefttribullet\n"
" 0x25c1: 0x0acc, // XK_leftopentriangle\n"
" 0x25c6: 0x09e0, // XK_soliddiamond\n"
" 0x25cb: 0x0ace, // XK_emopencircle\n"
" 0x25cf: 0x0ade, // XK_emfilledcircle\n"
" 0x25e6: 0x0ae0, // XK_enopencircbullet\n"
" 0x2606: 0x0ae5, // XK_openstar\n"
" 0x260e: 0x0af9, // XK_telephone\n"
" 0x2613: 0x0aca, // XK_signaturemark\n"
" 0x261c: 0x0aea, // XK_leftpointer\n"
" 0x261e: 0x0aeb, // XK_rightpointer\n"
" 0x2640: 0x0af8, // XK_femalesymbol\n"
" 0x2642: 0x0af7, // XK_malesymbol\n"
" 0x2663: 0x0aec, // XK_club\n"
" 0x2665: 0x0aee, // XK_heart\n"
" 0x2666: 0x0aed, // XK_diamond\n"
" 0x266d: 0x0af6, // XK_musicalflat\n"
" 0x266f: 0x0af5, // XK_musicalsharp\n"
" 0x2713: 0x0af3, // XK_checkmark\n"
" 0x2717: 0x0af4, // XK_ballotcross\n"
" 0x271d: 0x0ad9, // XK_latincross\n"
" 0x2720: 0x0af0, // XK_maltesecross\n"
" 0x27e8: 0x0abc, // XK_leftanglebracket\n"
" 0x27e9: 0x0abe, // XK_rightanglebracket\n"
" 0x3001: 0x04a4, // XK_kana_comma\n"
" 0x3002: 0x04a1, // XK_kana_fullstop\n"
" 0x300c: 0x04a2, // XK_kana_openingbracket\n"
" 0x300d: 0x04a3, // XK_kana_closingbracket\n"
" 0x309b: 0x04de, // XK_voicedsound\n"
" 0x309c: 0x04df, // XK_semivoicedsound\n"
" 0x30a1: 0x04a7, // XK_kana_a\n"
" 0x30a2: 0x04b1, // XK_kana_A\n"
" 0x30a3: 0x04a8, // XK_kana_i\n"
" 0x30a4: 0x04b2, // XK_kana_I\n"
" 0x30a5: 0x04a9, // XK_kana_u\n"
" 0x30a6: 0x04b3, // XK_kana_U\n"
" 0x30a7: 0x04aa, // XK_kana_e\n"
" 0x30a8: 0x04b4, // XK_kana_E\n"
" 0x30a9: 0x04ab, // XK_kana_o\n"
" 0x30aa: 0x04b5, // XK_kana_O\n"
" 0x30ab: 0x04b6, // XK_kana_KA\n"
" 0x30ad: 0x04b7, // XK_kana_KI\n"
" 0x30af: 0x04b8, // XK_kana_KU\n"
" 0x30b1: 0x04b9, // XK_kana_KE\n"
" 0x30b3: 0x04ba, // XK_kana_KO\n"
" 0x30b5: 0x04bb, // XK_kana_SA\n"
" 0x30b7: 0x04bc, // XK_kana_SHI\n"
" 0x30b9: 0x04bd, // XK_kana_SU\n"
" 0x30bb: 0x04be, // XK_kana_SE\n"
" 0x30bd: 0x04bf, // XK_kana_SO\n"
" 0x30bf: 0x04c0, // XK_kana_TA\n"
" 0x30c1: 0x04c1, // XK_kana_CHI\n"
" 0x30c3: 0x04af, // XK_kana_tsu\n"
" 0x30c4: 0x04c2, // XK_kana_TSU\n"
" 0x30c6: 0x04c3, // XK_kana_TE\n"
" 0x30c8: 0x04c4, // XK_kana_TO\n"
" 0x30ca: 0x04c5, // XK_kana_NA\n"
" 0x30cb: 0x04c6, // XK_kana_NI\n"
" 0x30cc: 0x04c7, // XK_kana_NU\n"
" 0x30cd: 0x04c8, // XK_kana_NE\n"
" 0x30ce: 0x04c9, // XK_kana_NO\n"
" 0x30cf: 0x04ca, // XK_kana_HA\n"
" 0x30d2: 0x04cb, // XK_kana_HI\n"
" 0x30d5: 0x04cc, // XK_kana_FU\n"
" 0x30d8: 0x04cd, // XK_kana_HE\n"
" 0x30db: 0x04ce, // XK_kana_HO\n"
" 0x30de: 0x04cf, // XK_kana_MA\n"
" 0x30df: 0x04d0, // XK_kana_MI\n"
" 0x30e0: 0x04d1, // XK_kana_MU\n"
" 0x30e1: 0x04d2, // XK_kana_ME\n"
" 0x30e2: 0x04d3, // XK_kana_MO\n"
" 0x30e3: 0x04ac, // XK_kana_ya\n"
" 0x30e4: 0x04d4, // XK_kana_YA\n"
" 0x30e5: 0x04ad, // XK_kana_yu\n"
" 0x30e6: 0x04d5, // XK_kana_YU\n"
" 0x30e7: 0x04ae, // XK_kana_yo\n"
" 0x30e8: 0x04d6, // XK_kana_YO\n"
" 0x30e9: 0x04d7, // XK_kana_RA\n"
" 0x30ea: 0x04d8, // XK_kana_RI\n"
" 0x30eb: 0x04d9, // XK_kana_RU\n"
" 0x30ec: 0x04da, // XK_kana_RE\n"
" 0x30ed: 0x04db, // XK_kana_RO\n"
" 0x30ef: 0x04dc, // XK_kana_WA\n"
" 0x30f2: 0x04a6, // XK_kana_WO\n"
" 0x30f3: 0x04dd, // XK_kana_N\n"
" 0x30fb: 0x04a5, // XK_kana_conjunctive\n"
" 0x30fc: 0x04b0, // XK_prolongedsound\n"
"};\n"
"\n"
"window.lookup = function(u) {\n"
" // Latin-1 is one-to-one mapping\n"
" if ((u >= 0x20) && (u <= 0xff)) {\n"
" return u;\n"
" }\n"
"\n"
" // Lookup table (fairly random)\n"
" const keysym = codepoints[u];\n"
" if (keysym !== undefined) {\n"
" return keysym;\n"
" }\n"
"\n"
" // General mapping as final fallback\n"
" return 0x01000000 | u;\n"
"};\n"
"window.codepoints = codepoints;\n"
"\n"
"// Create keysyms object for compatibility with util.js\n"
"window.keysyms = {\n"
" lookup: window.lookup\n"
"};\n"
;
if (strcmp(path, "/novnc/input/keysymdef.js") == 0) return novnc_input_keysymdef_js;
const char *novnc_input_keysym_js =
"/* eslint-disable key-spacing */\n"
"\n"
"window.KeyTable = {\n"
" XK_VoidSymbol: 0xffffff, /* Void symbol */\n"
"window.KeyTable = {\n"
" XK_VoidSymbol: 0xffffff, /* Void symbol */\n"
"\n"
" XK_BackSpace: 0xff08, /* Back space, back char */\n"
" XK_Tab: 0xff09,\n"
......@@ -4497,302 +3802,997 @@ const char *novnc_input_keysym_js =
" XK_braceright: 0x007d, /* U+007D RIGHT CURLY BRACKET */\n"
" XK_asciitilde: 0x007e, /* U+007E TILDE */\n"
"\n"
" XK_nobreakspace: 0x00a0, /* U+00A0 NO-BREAK SPACE */\n"
" XK_exclamdown: 0x00a1, /* U+00A1 INVERTED EXCLAMATION MARK */\n"
" XK_cent: 0x00a2, /* U+00A2 CENT SIGN */\n"
" XK_sterling: 0x00a3, /* U+00A3 POUND SIGN */\n"
" XK_currency: 0x00a4, /* U+00A4 CURRENCY SIGN */\n"
" XK_yen: 0x00a5, /* U+00A5 YEN SIGN */\n"
" XK_brokenbar: 0x00a6, /* U+00A6 BROKEN BAR */\n"
" XK_section: 0x00a7, /* U+00A7 SECTION SIGN */\n"
" XK_diaeresis: 0x00a8, /* U+00A8 DIAERESIS */\n"
" XK_copyright: 0x00a9, /* U+00A9 COPYRIGHT SIGN */\n"
" XK_ordfeminine: 0x00aa, /* U+00AA FEMININE ORDINAL INDICATOR */\n"
" XK_guillemotleft: 0x00ab, /* U+00AB LEFT-POINTING DOUBLE ANGLE QUOTATION MARK */\n"
" XK_notsign: 0x00ac, /* U+00AC NOT SIGN */\n"
" XK_hyphen: 0x00ad, /* U+00AD SOFT HYPHEN */\n"
" XK_registered: 0x00ae, /* U+00AE REGISTERED SIGN */\n"
" XK_macron: 0x00af, /* U+00AF MACRON */\n"
" XK_degree: 0x00b0, /* U+00B0 DEGREE SIGN */\n"
" XK_plusminus: 0x00b1, /* U+00B1 PLUS-MINUS SIGN */\n"
" XK_twosuperior: 0x00b2, /* U+00B2 SUPERSCRIPT TWO */\n"
" XK_threesuperior: 0x00b3, /* U+00B3 SUPERSCRIPT THREE */\n"
" XK_acute: 0x00b4, /* U+00B4 ACUTE ACCENT */\n"
" XK_mu: 0x00b5, /* U+00B5 MICRO SIGN */\n"
" XK_paragraph: 0x00b6, /* U+00B6 PILCROW SIGN */\n"
" XK_periodcentered: 0x00b7, /* U+00B7 MIDDLE DOT */\n"
" XK_cedilla: 0x00b8, /* U+00B8 CEDILLA */\n"
" XK_onesuperior: 0x00b9, /* U+00B9 SUPERSCRIPT ONE */\n"
" XK_masculine: 0x00ba, /* U+00BA MASCULINE ORDINAL INDICATOR */\n"
" XK_guillemotright: 0x00bb, /* U+00BB RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK */\n"
" XK_onequarter: 0x00bc, /* U+00BC VULGAR FRACTION ONE QUARTER */\n"
" XK_onehalf: 0x00bd, /* U+00BD VULGAR FRACTION ONE HALF */\n"
" XK_threequarters: 0x00be, /* U+00BE VULGAR FRACTION THREE QUARTERS */\n"
" XK_questiondown: 0x00bf, /* U+00BF INVERTED QUESTION MARK */\n"
" XK_Agrave: 0x00c0, /* U+00C0 LATIN CAPITAL LETTER A WITH GRAVE */\n"
" XK_Aacute: 0x00c1, /* U+00C1 LATIN CAPITAL LETTER A WITH ACUTE */\n"
" XK_Acircumflex: 0x00c2, /* U+00C2 LATIN CAPITAL LETTER A WITH CIRCUMFLEX */\n"
" XK_Atilde: 0x00c3, /* U+00C3 LATIN CAPITAL LETTER A WITH TILDE */\n"
" XK_Adiaeresis: 0x00c4, /* U+00C4 LATIN CAPITAL LETTER A WITH DIAERESIS */\n"
" XK_Aring: 0x00c5, /* U+00C5 LATIN CAPITAL LETTER A WITH RING ABOVE */\n"
" XK_AE: 0x00c6, /* U+00C6 LATIN CAPITAL LETTER AE */\n"
" XK_Ccedilla: 0x00c7, /* U+00C7 LATIN CAPITAL LETTER C WITH CEDILLA */\n"
" XK_Egrave: 0x00c8, /* U+00C8 LATIN CAPITAL LETTER E WITH GRAVE */\n"
" XK_Eacute: 0x00c9, /* U+00C9 LATIN CAPITAL LETTER E WITH ACUTE */\n"
" XK_Ecircumflex: 0x00ca, /* U+00CA LATIN CAPITAL LETTER E WITH CIRCUMFLEX */\n"
" XK_Ediaeresis: 0x00cb, /* U+00CB LATIN CAPITAL LETTER E WITH DIAERESIS */\n"
" XK_Igrave: 0x00cc, /* U+00CC LATIN CAPITAL LETTER I WITH GRAVE */\n"
" XK_Iacute: 0x00cd, /* U+00CD LATIN CAPITAL LETTER I WITH ACUTE */\n"
" XK_Icircumflex: 0x00ce, /* U+00CE LATIN CAPITAL LETTER I WITH CIRCUMFLEX */\n"
" XK_Idiaeresis: 0x00cf, /* U+00CF LATIN CAPITAL LETTER I WITH DIAERESIS */\n"
" XK_ETH: 0x00d0, /* U+00D0 LATIN CAPITAL LETTER ETH */\n"
" XK_Eth: 0x00d0, /* deprecated */\n"
" XK_Ntilde: 0x00d1, /* U+00D1 LATIN CAPITAL LETTER N WITH TILDE */\n"
" XK_Ograve: 0x00d2, /* U+00D2 LATIN CAPITAL LETTER O WITH GRAVE */\n"
" XK_Oacute: 0x00d3, /* U+00D3 LATIN CAPITAL LETTER O WITH ACUTE */\n"
" XK_Ocircumflex: 0x00d4, /* U+00D4 LATIN CAPITAL LETTER O WITH CIRCUMFLEX */\n"
" XK_Otilde: 0x00d5, /* U+00D5 LATIN CAPITAL LETTER O WITH TILDE */\n"
" XK_Odiaeresis: 0x00d6, /* U+00D6 LATIN CAPITAL LETTER O WITH DIAERESIS */\n"
" XK_multiply: 0x00d7, /* U+00D7 MULTIPLICATION SIGN */\n"
" XK_Oslash: 0x00d8, /* U+00D8 LATIN CAPITAL LETTER O WITH STROKE */\n"
" XK_Ooblique: 0x00d8, /* U+00D8 LATIN CAPITAL LETTER O WITH STROKE */\n"
" XK_Ugrave: 0x00d9, /* U+00D9 LATIN CAPITAL LETTER U WITH GRAVE */\n"
" XK_Uacute: 0x00da, /* U+00DA LATIN CAPITAL LETTER U WITH ACUTE */\n"
" XK_Ucircumflex: 0x00db, /* U+00DB LATIN CAPITAL LETTER U WITH CIRCUMFLEX */\n"
" XK_Udiaeresis: 0x00dc, /* U+00DC LATIN CAPITAL LETTER U WITH DIAERESIS */\n"
" XK_Yacute: 0x00dd, /* U+00DD LATIN CAPITAL LETTER Y WITH ACUTE */\n"
" XK_THORN: 0x00de, /* U+00DE LATIN CAPITAL LETTER THORN */\n"
" XK_Thorn: 0x00de, /* deprecated */\n"
" XK_ssharp: 0x00df, /* U+00DF LATIN SMALL LETTER SHARP S */\n"
" XK_agrave: 0x00e0, /* U+00E0 LATIN SMALL LETTER A WITH GRAVE */\n"
" XK_aacute: 0x00e1, /* U+00E1 LATIN SMALL LETTER A WITH ACUTE */\n"
" XK_acircumflex: 0x00e2, /* U+00E2 LATIN SMALL LETTER A WITH CIRCUMFLEX */\n"
" XK_atilde: 0x00e3, /* U+00E3 LATIN SMALL LETTER A WITH TILDE */\n"
" XK_adiaeresis: 0x00e4, /* U+00E4 LATIN SMALL LETTER A WITH DIAERESIS */\n"
" XK_aring: 0x00e5, /* U+00E5 LATIN SMALL LETTER A WITH RING ABOVE */\n"
" XK_ae: 0x00e6, /* U+00E6 LATIN SMALL LETTER AE */\n"
" XK_ccedilla: 0x00e7, /* U+00E7 LATIN SMALL LETTER C WITH CEDILLA */\n"
" XK_egrave: 0x00e8, /* U+00E8 LATIN SMALL LETTER E WITH GRAVE */\n"
" XK_eacute: 0x00e9, /* U+00E9 LATIN SMALL LETTER E WITH ACUTE */\n"
" XK_ecircumflex: 0x00ea, /* U+00EA LATIN SMALL LETTER E WITH CIRCUMFLEX */\n"
" XK_ediaeresis: 0x00eb, /* U+00EB LATIN SMALL LETTER E WITH DIAERESIS */\n"
" XK_igrave: 0x00ec, /* U+00EC LATIN SMALL LETTER I WITH GRAVE */\n"
" XK_iacute: 0x00ed, /* U+00ED LATIN SMALL LETTER I WITH ACUTE */\n"
" XK_icircumflex: 0x00ee, /* U+00EE LATIN SMALL LETTER I WITH CIRCUMFLEX */\n"
" XK_idiaeresis: 0x00ef, /* U+00EF LATIN SMALL LETTER I WITH DIAERESIS */\n"
" XK_eth: 0x00f0, /* U+00F0 LATIN SMALL LETTER ETH */\n"
" XK_ntilde: 0x00f1, /* U+00F1 LATIN SMALL LETTER N WITH TILDE */\n"
" XK_ograve: 0x00f2, /* U+00F2 LATIN SMALL LETTER O WITH GRAVE */\n"
" XK_oacute: 0x00f3, /* U+00F3 LATIN SMALL LETTER O WITH ACUTE */\n"
" XK_ocircumflex: 0x00f4, /* U+00F4 LATIN SMALL LETTER O WITH CIRCUMFLEX */\n"
" XK_otilde: 0x00f5, /* U+00F5 LATIN SMALL LETTER O WITH TILDE */\n"
" XK_odiaeresis: 0x00f6, /* U+00F6 LATIN SMALL LETTER O WITH DIAERESIS */\n"
" XK_division: 0x00f7, /* U+00F7 DIVISION SIGN */\n"
" XK_oslash: 0x00f8, /* U+00F8 LATIN SMALL LETTER O WITH STROKE */\n"
" XK_ooblique: 0x00f8, /* U+00F8 LATIN SMALL LETTER O WITH STROKE */\n"
" XK_ugrave: 0x00f9, /* U+00F9 LATIN SMALL LETTER U WITH GRAVE */\n"
" XK_uacute: 0x00fa, /* U+00FA LATIN SMALL LETTER U WITH ACUTE */\n"
" XK_ucircumflex: 0x00fb, /* U+00FB LATIN SMALL LETTER U WITH CIRCUMFLEX */\n"
" XK_udiaeresis: 0x00fc, /* U+00FC LATIN SMALL LETTER U WITH DIAERESIS */\n"
" XK_yacute: 0x00fd, /* U+00FD LATIN SMALL LETTER Y WITH ACUTE */\n"
" XK_thorn: 0x00fe, /* U+00FE LATIN SMALL LETTER THORN */\n"
" XK_ydiaeresis: 0x00ff, /* U+00FF LATIN SMALL LETTER Y WITH DIAERESIS */\n"
" XK_nobreakspace: 0x00a0, /* U+00A0 NO-BREAK SPACE */\n"
" XK_exclamdown: 0x00a1, /* U+00A1 INVERTED EXCLAMATION MARK */\n"
" XK_cent: 0x00a2, /* U+00A2 CENT SIGN */\n"
" XK_sterling: 0x00a3, /* U+00A3 POUND SIGN */\n"
" XK_currency: 0x00a4, /* U+00A4 CURRENCY SIGN */\n"
" XK_yen: 0x00a5, /* U+00A5 YEN SIGN */\n"
" XK_brokenbar: 0x00a6, /* U+00A6 BROKEN BAR */\n"
" XK_section: 0x00a7, /* U+00A7 SECTION SIGN */\n"
" XK_diaeresis: 0x00a8, /* U+00A8 DIAERESIS */\n"
" XK_copyright: 0x00a9, /* U+00A9 COPYRIGHT SIGN */\n"
" XK_ordfeminine: 0x00aa, /* U+00AA FEMININE ORDINAL INDICATOR */\n"
" XK_guillemotleft: 0x00ab, /* U+00AB LEFT-POINTING DOUBLE ANGLE QUOTATION MARK */\n"
" XK_notsign: 0x00ac, /* U+00AC NOT SIGN */\n"
" XK_hyphen: 0x00ad, /* U+00AD SOFT HYPHEN */\n"
" XK_registered: 0x00ae, /* U+00AE REGISTERED SIGN */\n"
" XK_macron: 0x00af, /* U+00AF MACRON */\n"
" XK_degree: 0x00b0, /* U+00B0 DEGREE SIGN */\n"
" XK_plusminus: 0x00b1, /* U+00B1 PLUS-MINUS SIGN */\n"
" XK_twosuperior: 0x00b2, /* U+00B2 SUPERSCRIPT TWO */\n"
" XK_threesuperior: 0x00b3, /* U+00B3 SUPERSCRIPT THREE */\n"
" XK_acute: 0x00b4, /* U+00B4 ACUTE ACCENT */\n"
" XK_mu: 0x00b5, /* U+00B5 MICRO SIGN */\n"
" XK_paragraph: 0x00b6, /* U+00B6 PILCROW SIGN */\n"
" XK_periodcentered: 0x00b7, /* U+00B7 MIDDLE DOT */\n"
" XK_cedilla: 0x00b8, /* U+00B8 CEDILLA */\n"
" XK_onesuperior: 0x00b9, /* U+00B9 SUPERSCRIPT ONE */\n"
" XK_masculine: 0x00ba, /* U+00BA MASCULINE ORDINAL INDICATOR */\n"
" XK_guillemotright: 0x00bb, /* U+00BB RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK */\n"
" XK_onequarter: 0x00bc, /* U+00BC VULGAR FRACTION ONE QUARTER */\n"
" XK_onehalf: 0x00bd, /* U+00BD VULGAR FRACTION ONE HALF */\n"
" XK_threequarters: 0x00be, /* U+00BE VULGAR FRACTION THREE QUARTERS */\n"
" XK_questiondown: 0x00bf, /* U+00BF INVERTED QUESTION MARK */\n"
" XK_Agrave: 0x00c0, /* U+00C0 LATIN CAPITAL LETTER A WITH GRAVE */\n"
" XK_Aacute: 0x00c1, /* U+00C1 LATIN CAPITAL LETTER A WITH ACUTE */\n"
" XK_Acircumflex: 0x00c2, /* U+00C2 LATIN CAPITAL LETTER A WITH CIRCUMFLEX */\n"
" XK_Atilde: 0x00c3, /* U+00C3 LATIN CAPITAL LETTER A WITH TILDE */\n"
" XK_Adiaeresis: 0x00c4, /* U+00C4 LATIN CAPITAL LETTER A WITH DIAERESIS */\n"
" XK_Aring: 0x00c5, /* U+00C5 LATIN CAPITAL LETTER A WITH RING ABOVE */\n"
" XK_AE: 0x00c6, /* U+00C6 LATIN CAPITAL LETTER AE */\n"
" XK_Ccedilla: 0x00c7, /* U+00C7 LATIN CAPITAL LETTER C WITH CEDILLA */\n"
" XK_Egrave: 0x00c8, /* U+00C8 LATIN CAPITAL LETTER E WITH GRAVE */\n"
" XK_Eacute: 0x00c9, /* U+00C9 LATIN CAPITAL LETTER E WITH ACUTE */\n"
" XK_Ecircumflex: 0x00ca, /* U+00CA LATIN CAPITAL LETTER E WITH CIRCUMFLEX */\n"
" XK_Ediaeresis: 0x00cb, /* U+00CB LATIN CAPITAL LETTER E WITH DIAERESIS */\n"
" XK_Igrave: 0x00cc, /* U+00CC LATIN CAPITAL LETTER I WITH GRAVE */\n"
" XK_Iacute: 0x00cd, /* U+00CD LATIN CAPITAL LETTER I WITH ACUTE */\n"
" XK_Icircumflex: 0x00ce, /* U+00CE LATIN CAPITAL LETTER I WITH CIRCUMFLEX */\n"
" XK_Idiaeresis: 0x00cf, /* U+00CF LATIN CAPITAL LETTER I WITH DIAERESIS */\n"
" XK_ETH: 0x00d0, /* U+00D0 LATIN CAPITAL LETTER ETH */\n"
" XK_Eth: 0x00d0, /* deprecated */\n"
" XK_Ntilde: 0x00d1, /* U+00D1 LATIN CAPITAL LETTER N WITH TILDE */\n"
" XK_Ograve: 0x00d2, /* U+00D2 LATIN CAPITAL LETTER O WITH GRAVE */\n"
" XK_Oacute: 0x00d3, /* U+00D3 LATIN CAPITAL LETTER O WITH ACUTE */\n"
" XK_Ocircumflex: 0x00d4, /* U+00D4 LATIN CAPITAL LETTER O WITH CIRCUMFLEX */\n"
" XK_Otilde: 0x00d5, /* U+00D5 LATIN CAPITAL LETTER O WITH TILDE */\n"
" XK_Odiaeresis: 0x00d6, /* U+00D6 LATIN CAPITAL LETTER O WITH DIAERESIS */\n"
" XK_multiply: 0x00d7, /* U+00D7 MULTIPLICATION SIGN */\n"
" XK_Oslash: 0x00d8, /* U+00D8 LATIN CAPITAL LETTER O WITH STROKE */\n"
" XK_Ooblique: 0x00d8, /* U+00D8 LATIN CAPITAL LETTER O WITH STROKE */\n"
" XK_Ugrave: 0x00d9, /* U+00D9 LATIN CAPITAL LETTER U WITH GRAVE */\n"
" XK_Uacute: 0x00da, /* U+00DA LATIN CAPITAL LETTER U WITH ACUTE */\n"
" XK_Ucircumflex: 0x00db, /* U+00DB LATIN CAPITAL LETTER U WITH CIRCUMFLEX */\n"
" XK_Udiaeresis: 0x00dc, /* U+00DC LATIN CAPITAL LETTER U WITH DIAERESIS */\n"
" XK_Yacute: 0x00dd, /* U+00DD LATIN CAPITAL LETTER Y WITH ACUTE */\n"
" XK_THORN: 0x00de, /* U+00DE LATIN CAPITAL LETTER THORN */\n"
" XK_Thorn: 0x00de, /* deprecated */\n"
" XK_ssharp: 0x00df, /* U+00DF LATIN SMALL LETTER SHARP S */\n"
" XK_agrave: 0x00e0, /* U+00E0 LATIN SMALL LETTER A WITH GRAVE */\n"
" XK_aacute: 0x00e1, /* U+00E1 LATIN SMALL LETTER A WITH ACUTE */\n"
" XK_acircumflex: 0x00e2, /* U+00E2 LATIN SMALL LETTER A WITH CIRCUMFLEX */\n"
" XK_atilde: 0x00e3, /* U+00E3 LATIN SMALL LETTER A WITH TILDE */\n"
" XK_adiaeresis: 0x00e4, /* U+00E4 LATIN SMALL LETTER A WITH DIAERESIS */\n"
" XK_aring: 0x00e5, /* U+00E5 LATIN SMALL LETTER A WITH RING ABOVE */\n"
" XK_ae: 0x00e6, /* U+00E6 LATIN SMALL LETTER AE */\n"
" XK_ccedilla: 0x00e7, /* U+00E7 LATIN SMALL LETTER C WITH CEDILLA */\n"
" XK_egrave: 0x00e8, /* U+00E8 LATIN SMALL LETTER E WITH GRAVE */\n"
" XK_eacute: 0x00e9, /* U+00E9 LATIN SMALL LETTER E WITH ACUTE */\n"
" XK_ecircumflex: 0x00ea, /* U+00EA LATIN SMALL LETTER E WITH CIRCUMFLEX */\n"
" XK_ediaeresis: 0x00eb, /* U+00EB LATIN SMALL LETTER E WITH DIAERESIS */\n"
" XK_igrave: 0x00ec, /* U+00EC LATIN SMALL LETTER I WITH GRAVE */\n"
" XK_iacute: 0x00ed, /* U+00ED LATIN SMALL LETTER I WITH ACUTE */\n"
" XK_icircumflex: 0x00ee, /* U+00EE LATIN SMALL LETTER I WITH CIRCUMFLEX */\n"
" XK_idiaeresis: 0x00ef, /* U+00EF LATIN SMALL LETTER I WITH DIAERESIS */\n"
" XK_eth: 0x00f0, /* U+00F0 LATIN SMALL LETTER ETH */\n"
" XK_ntilde: 0x00f1, /* U+00F1 LATIN SMALL LETTER N WITH TILDE */\n"
" XK_ograve: 0x00f2, /* U+00F2 LATIN SMALL LETTER O WITH GRAVE */\n"
" XK_oacute: 0x00f3, /* U+00F3 LATIN SMALL LETTER O WITH ACUTE */\n"
" XK_ocircumflex: 0x00f4, /* U+00F4 LATIN SMALL LETTER O WITH CIRCUMFLEX */\n"
" XK_otilde: 0x00f5, /* U+00F5 LATIN SMALL LETTER O WITH TILDE */\n"
" XK_odiaeresis: 0x00f6, /* U+00F6 LATIN SMALL LETTER O WITH DIAERESIS */\n"
" XK_division: 0x00f7, /* U+00F7 DIVISION SIGN */\n"
" XK_oslash: 0x00f8, /* U+00F8 LATIN SMALL LETTER O WITH STROKE */\n"
" XK_ooblique: 0x00f8, /* U+00F8 LATIN SMALL LETTER O WITH STROKE */\n"
" XK_ugrave: 0x00f9, /* U+00F9 LATIN SMALL LETTER U WITH GRAVE */\n"
" XK_uacute: 0x00fa, /* U+00FA LATIN SMALL LETTER U WITH ACUTE */\n"
" XK_ucircumflex: 0x00fb, /* U+00FB LATIN SMALL LETTER U WITH CIRCUMFLEX */\n"
" XK_udiaeresis: 0x00fc, /* U+00FC LATIN SMALL LETTER U WITH DIAERESIS */\n"
" XK_yacute: 0x00fd, /* U+00FD LATIN SMALL LETTER Y WITH ACUTE */\n"
" XK_thorn: 0x00fe, /* U+00FE LATIN SMALL LETTER THORN */\n"
" XK_ydiaeresis: 0x00ff, /* U+00FF LATIN SMALL LETTER Y WITH DIAERESIS */\n"
"\n"
" /*\n"
" * Korean\n"
" * Byte 3 = 0x0e\n"
" */\n"
"\n"
" XK_Hangul: 0xff31, /* Hangul start/stop(toggle) */\n"
" XK_Hangul_Hanja: 0xff34, /* Start Hangul->Hanja Conversion */\n"
" XK_Hangul_Jeonja: 0xff38, /* Jeonja mode */\n"
"\n"
" /*\n"
" * XFree86 vendor specific keysyms.\n"
" *\n"
" * The XFree86 keysym range is 0x10080001 - 0x1008FFFF.\n"
" */\n"
"\n"
" XF86XK_ModeLock: 0x1008FF01,\n"
" XF86XK_MonBrightnessUp: 0x1008FF02,\n"
" XF86XK_MonBrightnessDown: 0x1008FF03,\n"
" XF86XK_KbdLightOnOff: 0x1008FF04,\n"
" XF86XK_KbdBrightnessUp: 0x1008FF05,\n"
" XF86XK_KbdBrightnessDown: 0x1008FF06,\n"
" XF86XK_Standby: 0x1008FF10,\n"
" XF86XK_AudioLowerVolume: 0x1008FF11,\n"
" XF86XK_AudioMute: 0x1008FF12,\n"
" XF86XK_AudioRaiseVolume: 0x1008FF13,\n"
" XF86XK_AudioPlay: 0x1008FF14,\n"
" XF86XK_AudioStop: 0x1008FF15,\n"
" XF86XK_AudioPrev: 0x1008FF16,\n"
" XF86XK_AudioNext: 0x1008FF17,\n"
" XF86XK_HomePage: 0x1008FF18,\n"
" XF86XK_Mail: 0x1008FF19,\n"
" XF86XK_Start: 0x1008FF1A,\n"
" XF86XK_Search: 0x1008FF1B,\n"
" XF86XK_AudioRecord: 0x1008FF1C,\n"
" XF86XK_Calculator: 0x1008FF1D,\n"
" XF86XK_Memo: 0x1008FF1E,\n"
" XF86XK_ToDoList: 0x1008FF1F,\n"
" XF86XK_Calendar: 0x1008FF20,\n"
" XF86XK_PowerDown: 0x1008FF21,\n"
" XF86XK_ContrastAdjust: 0x1008FF22,\n"
" XF86XK_RockerUp: 0x1008FF23,\n"
" XF86XK_RockerDown: 0x1008FF24,\n"
" XF86XK_RockerEnter: 0x1008FF25,\n"
" XF86XK_Back: 0x1008FF26,\n"
" XF86XK_Forward: 0x1008FF27,\n"
" XF86XK_Stop: 0x1008FF28,\n"
" XF86XK_Refresh: 0x1008FF29,\n"
" XF86XK_PowerOff: 0x1008FF2A,\n"
" XF86XK_WakeUp: 0x1008FF2B,\n"
" XF86XK_Eject: 0x1008FF2C,\n"
" XF86XK_ScreenSaver: 0x1008FF2D,\n"
" XF86XK_WWW: 0x1008FF2E,\n"
" XF86XK_Sleep: 0x1008FF2F,\n"
" XF86XK_Favorites: 0x1008FF30,\n"
" XF86XK_AudioPause: 0x1008FF31,\n"
" XF86XK_AudioMedia: 0x1008FF32,\n"
" XF86XK_MyComputer: 0x1008FF33,\n"
" XF86XK_VendorHome: 0x1008FF34,\n"
" XF86XK_LightBulb: 0x1008FF35,\n"
" XF86XK_Shop: 0x1008FF36,\n"
" XF86XK_History: 0x1008FF37,\n"
" XF86XK_OpenURL: 0x1008FF38,\n"
" XF86XK_AddFavorite: 0x1008FF39,\n"
" XF86XK_HotLinks: 0x1008FF3A,\n"
" XF86XK_BrightnessAdjust: 0x1008FF3B,\n"
" XF86XK_Finance: 0x1008FF3C,\n"
" XF86XK_Community: 0x1008FF3D,\n"
" XF86XK_AudioRewind: 0x1008FF3E,\n"
" XF86XK_BackForward: 0x1008FF3F,\n"
" XF86XK_Launch0: 0x1008FF40,\n"
" XF86XK_Launch1: 0x1008FF41,\n"
" XF86XK_Launch2: 0x1008FF42,\n"
" XF86XK_Launch3: 0x1008FF43,\n"
" XF86XK_Launch4: 0x1008FF44,\n"
" XF86XK_Launch5: 0x1008FF45,\n"
" XF86XK_Launch6: 0x1008FF46,\n"
" XF86XK_Launch7: 0x1008FF47,\n"
" XF86XK_Launch8: 0x1008FF48,\n"
" XF86XK_Launch9: 0x1008FF49,\n"
" XF86XK_LaunchA: 0x1008FF4A,\n"
" XF86XK_LaunchB: 0x1008FF4B,\n"
" XF86XK_LaunchC: 0x1008FF4C,\n"
" XF86XK_LaunchD: 0x1008FF4D,\n"
" XF86XK_LaunchE: 0x1008FF4E,\n"
" XF86XK_LaunchF: 0x1008FF4F,\n"
" XF86XK_ApplicationLeft: 0x1008FF50,\n"
" XF86XK_ApplicationRight: 0x1008FF51,\n"
" XF86XK_Book: 0x1008FF52,\n"
" XF86XK_CD: 0x1008FF53,\n"
" XF86XK_Calculater: 0x1008FF54,\n"
" XF86XK_Clear: 0x1008FF55,\n"
" XF86XK_Close: 0x1008FF56,\n"
" XF86XK_Copy: 0x1008FF57,\n"
" XF86XK_Cut: 0x1008FF58,\n"
" XF86XK_Display: 0x1008FF59,\n"
" XF86XK_DOS: 0x1008FF5A,\n"
" XF86XK_Documents: 0x1008FF5B,\n"
" XF86XK_Excel: 0x1008FF5C,\n"
" XF86XK_Explorer: 0x1008FF5D,\n"
" XF86XK_Game: 0x1008FF5E,\n"
" XF86XK_Go: 0x1008FF5F,\n"
" XF86XK_iTouch: 0x1008FF60,\n"
" XF86XK_LogOff: 0x1008FF61,\n"
" XF86XK_Market: 0x1008FF62,\n"
" XF86XK_Meeting: 0x1008FF63,\n"
" XF86XK_MenuKB: 0x1008FF65,\n"
" XF86XK_MenuPB: 0x1008FF66,\n"
" XF86XK_MySites: 0x1008FF67,\n"
" XF86XK_New: 0x1008FF68,\n"
" XF86XK_News: 0x1008FF69,\n"
" XF86XK_OfficeHome: 0x1008FF6A,\n"
" XF86XK_Open: 0x1008FF6B,\n"
" XF86XK_Option: 0x1008FF6C,\n"
" XF86XK_Paste: 0x1008FF6D,\n"
" XF86XK_Phone: 0x1008FF6E,\n"
" XF86XK_Q: 0x1008FF70,\n"
" XF86XK_Reply: 0x1008FF72,\n"
" XF86XK_Reload: 0x1008FF73,\n"
" XF86XK_RotateWindows: 0x1008FF74,\n"
" XF86XK_RotationPB: 0x1008FF75,\n"
" XF86XK_RotationKB: 0x1008FF76,\n"
" XF86XK_Save: 0x1008FF77,\n"
" XF86XK_ScrollUp: 0x1008FF78,\n"
" XF86XK_ScrollDown: 0x1008FF79,\n"
" XF86XK_ScrollClick: 0x1008FF7A,\n"
" XF86XK_Send: 0x1008FF7B,\n"
" XF86XK_Spell: 0x1008FF7C,\n"
" XF86XK_SplitScreen: 0x1008FF7D,\n"
" XF86XK_Support: 0x1008FF7E,\n"
" XF86XK_TaskPane: 0x1008FF7F,\n"
" XF86XK_Terminal: 0x1008FF80,\n"
" XF86XK_Tools: 0x1008FF81,\n"
" XF86XK_Travel: 0x1008FF82,\n"
" XF86XK_UserPB: 0x1008FF84,\n"
" XF86XK_User1KB: 0x1008FF85,\n"
" XF86XK_User2KB: 0x1008FF86,\n"
" XF86XK_Video: 0x1008FF87,\n"
" XF86XK_WheelButton: 0x1008FF88,\n"
" XF86XK_Word: 0x1008FF89,\n"
" XF86XK_Xfer: 0x1008FF8A,\n"
" XF86XK_ZoomIn: 0x1008FF8B,\n"
" XF86XK_ZoomOut: 0x1008FF8C,\n"
" XF86XK_Away: 0x1008FF8D,\n"
" XF86XK_Messenger: 0x1008FF8E,\n"
" XF86XK_WebCam: 0x1008FF8F,\n"
" XF86XK_MailForward: 0x1008FF90,\n"
" XF86XK_Pictures: 0x1008FF91,\n"
" XF86XK_Music: 0x1008FF92,\n"
" XF86XK_Battery: 0x1008FF93,\n"
" XF86XK_Bluetooth: 0x1008FF94,\n"
" XF86XK_WLAN: 0x1008FF95,\n"
" XF86XK_UWB: 0x1008FF96,\n"
" XF86XK_AudioForward: 0x1008FF97,\n"
" XF86XK_AudioRepeat: 0x1008FF98,\n"
" XF86XK_AudioRandomPlay: 0x1008FF99,\n"
" XF86XK_Subtitle: 0x1008FF9A,\n"
" XF86XK_AudioCycleTrack: 0x1008FF9B,\n"
" XF86XK_CycleAngle: 0x1008FF9C,\n"
" XF86XK_FrameBack: 0x1008FF9D,\n"
" XF86XK_FrameForward: 0x1008FF9E,\n"
" XF86XK_Time: 0x1008FF9F,\n"
" XF86XK_Select: 0x1008FFA0,\n"
" XF86XK_View: 0x1008FFA1,\n"
" XF86XK_TopMenu: 0x1008FFA2,\n"
" XF86XK_Red: 0x1008FFA3,\n"
" XF86XK_Green: 0x1008FFA4,\n"
" XF86XK_Yellow: 0x1008FFA5,\n"
" XF86XK_Blue: 0x1008FFA6,\n"
" XF86XK_Suspend: 0x1008FFA7,\n"
" XF86XK_Hibernate: 0x1008FFA8,\n"
" XF86XK_TouchpadToggle: 0x1008FFA9,\n"
" XF86XK_TouchpadOn: 0x1008FFB0,\n"
" XF86XK_TouchpadOff: 0x1008FFB1,\n"
" XF86XK_AudioMicMute: 0x1008FFB2,\n"
" XF86XK_Switch_VT_1: 0x1008FE01,\n"
" XF86XK_Switch_VT_2: 0x1008FE02,\n"
" XF86XK_Switch_VT_3: 0x1008FE03,\n"
" XF86XK_Switch_VT_4: 0x1008FE04,\n"
" XF86XK_Switch_VT_5: 0x1008FE05,\n"
" XF86XK_Switch_VT_6: 0x1008FE06,\n"
" XF86XK_Switch_VT_7: 0x1008FE07,\n"
" XF86XK_Switch_VT_8: 0x1008FE08,\n"
" XF86XK_Switch_VT_9: 0x1008FE09,\n"
" XF86XK_Switch_VT_10: 0x1008FE0A,\n"
" XF86XK_Switch_VT_11: 0x1008FE0B,\n"
" XF86XK_Switch_VT_12: 0x1008FE0C,\n"
" XF86XK_Ungrab: 0x1008FE20,\n"
" XF86XK_ClearGrab: 0x1008FE21,\n"
" XF86XK_Next_VMode: 0x1008FE22,\n"
" XF86XK_Prev_VMode: 0x1008FE23,\n"
" XF86XK_LogWindowTree: 0x1008FE24,\n"
" XF86XK_LogGrabInfo: 0x1008FE25,\n"
"};\n"
;
if (strcmp(path, "/novnc/input/keysym.js") == 0) return novnc_input_keysym_js;
const char *novnc_input_keysymdef_js =
"/*\n"
" * Mapping from Unicode codepoints to X11/RFB keysyms\n"
" *\n"
" * This file was automatically generated from keysymdef.h\n"
" * DO NOT EDIT!\n"
" */\n"
"\n"
"/* Functions at the bottom */\n"
"\n"
"const codepoints = {\n"
" 0x0100: 0x03c0, // XK_Amacron\n"
" 0x0101: 0x03e0, // XK_amacron\n"
" 0x0102: 0x01c3, // XK_Abreve\n"
" 0x0103: 0x01e3, // XK_abreve\n"
" 0x0104: 0x01a1, // XK_Aogonek\n"
" 0x0105: 0x01b1, // XK_aogonek\n"
" 0x0106: 0x01c6, // XK_Cacute\n"
" 0x0107: 0x01e6, // XK_cacute\n"
" 0x0108: 0x02c6, // XK_Ccircumflex\n"
" 0x0109: 0x02e6, // XK_ccircumflex\n"
" 0x010a: 0x02c5, // XK_Cabovedot\n"
" 0x010b: 0x02e5, // XK_cabovedot\n"
" 0x010c: 0x01c8, // XK_Ccaron\n"
" 0x010d: 0x01e8, // XK_ccaron\n"
" 0x010e: 0x01cf, // XK_Dcaron\n"
" 0x010f: 0x01ef, // XK_dcaron\n"
" 0x0110: 0x01d0, // XK_Dstroke\n"
" 0x0111: 0x01f0, // XK_dstroke\n"
" 0x0112: 0x03aa, // XK_Emacron\n"
" 0x0113: 0x03ba, // XK_emacron\n"
" 0x0116: 0x03cc, // XK_Eabovedot\n"
" 0x0117: 0x03ec, // XK_eabovedot\n"
" 0x0118: 0x01ca, // XK_Eogonek\n"
" 0x0119: 0x01ea, // XK_eogonek\n"
" 0x011a: 0x01cc, // XK_Ecaron\n"
" 0x011b: 0x01ec, // XK_ecaron\n"
" 0x011c: 0x02d8, // XK_Gcircumflex\n"
" 0x011d: 0x02f8, // XK_gcircumflex\n"
" 0x011e: 0x02ab, // XK_Gbreve\n"
" 0x011f: 0x02bb, // XK_gbreve\n"
" 0x0120: 0x02d5, // XK_Gabovedot\n"
" 0x0121: 0x02f5, // XK_gabovedot\n"
" 0x0122: 0x03ab, // XK_Gcedilla\n"
" 0x0123: 0x03bb, // XK_gcedilla\n"
" 0x0124: 0x02a6, // XK_Hcircumflex\n"
" 0x0125: 0x02b6, // XK_hcircumflex\n"
" 0x0126: 0x02a1, // XK_Hstroke\n"
" 0x0127: 0x02b1, // XK_hstroke\n"
" 0x0128: 0x03a5, // XK_Itilde\n"
" 0x0129: 0x03b5, // XK_itilde\n"
" 0x012a: 0x03cf, // XK_Imacron\n"
" 0x012b: 0x03ef, // XK_imacron\n"
" 0x012e: 0x03c7, // XK_Iogonek\n"
" 0x012f: 0x03e7, // XK_iogonek\n"
" 0x0130: 0x02a9, // XK_Iabovedot\n"
" 0x0131: 0x02b9, // XK_idotless\n"
" 0x0134: 0x02ac, // XK_Jcircumflex\n"
" 0x0135: 0x02bc, // XK_jcircumflex\n"
" 0x0136: 0x03d3, // XK_Kcedilla\n"
" 0x0137: 0x03f3, // XK_kcedilla\n"
" 0x0138: 0x03a2, // XK_kra\n"
" 0x0139: 0x01c5, // XK_Lacute\n"
" 0x013a: 0x01e5, // XK_lacute\n"
" 0x013b: 0x03a6, // XK_Lcedilla\n"
" 0x013c: 0x03b6, // XK_lcedilla\n"
" 0x013d: 0x01a5, // XK_Lcaron\n"
" 0x013e: 0x01b5, // XK_lcaron\n"
" 0x0141: 0x01a3, // XK_Lstroke\n"
" 0x0142: 0x01b3, // XK_lstroke\n"
" 0x0143: 0x01d1, // XK_Nacute\n"
" 0x0144: 0x01f1, // XK_nacute\n"
" 0x0145: 0x03d1, // XK_Ncedilla\n"
" 0x0146: 0x03f1, // XK_ncedilla\n"
" 0x0147: 0x01d2, // XK_Ncaron\n"
" 0x0148: 0x01f2, // XK_ncaron\n"
" 0x014a: 0x03bd, // XK_ENG\n"
" 0x014b: 0x03bf, // XK_eng\n"
" 0x014c: 0x03d2, // XK_Omacron\n"
" 0x014d: 0x03f2, // XK_omacron\n"
" 0x0150: 0x01d5, // XK_Odoubleacute\n"
" 0x0151: 0x01f5, // XK_odoubleacute\n"
" 0x0152: 0x13bc, // XK_OE\n"
" 0x0153: 0x13bd, // XK_oe\n"
" 0x0154: 0x01c0, // XK_Racute\n"
" 0x0155: 0x01e0, // XK_racute\n"
" 0x0156: 0x03a3, // XK_Rcedilla\n"
" 0x0157: 0x03b3, // XK_rcedilla\n"
" 0x0158: 0x01d8, // XK_Rcaron\n"
" 0x0159: 0x01f8, // XK_rcaron\n"
" 0x015a: 0x01a6, // XK_Sacute\n"
" 0x015b: 0x01b6, // XK_sacute\n"
" 0x015c: 0x02de, // XK_Scircumflex\n"
" 0x015d: 0x02fe, // XK_scircumflex\n"
" 0x015e: 0x01aa, // XK_Scedilla\n"
" 0x015f: 0x01ba, // XK_scedilla\n"
" 0x0160: 0x01a9, // XK_Scaron\n"
" 0x0161: 0x01b9, // XK_scaron\n"
" 0x0162: 0x01de, // XK_Tcedilla\n"
" 0x0163: 0x01fe, // XK_tcedilla\n"
" 0x0164: 0x01ab, // XK_Tcaron\n"
" 0x0165: 0x01bb, // XK_tcaron\n"
" 0x0166: 0x03ac, // XK_Tslash\n"
" 0x0167: 0x03bc, // XK_tslash\n"
" 0x0168: 0x03dd, // XK_Utilde\n"
" 0x0169: 0x03fd, // XK_utilde\n"
" 0x016a: 0x03de, // XK_Umacron\n"
" 0x016b: 0x03fe, // XK_umacron\n"
" 0x016c: 0x02dd, // XK_Ubreve\n"
" 0x016d: 0x02fd, // XK_ubreve\n"
" 0x016e: 0x01d9, // XK_Uring\n"
" 0x016f: 0x01f9, // XK_uring\n"
" 0x0170: 0x01db, // XK_Udoubleacute\n"
" 0x0171: 0x01fb, // XK_udoubleacute\n"
" 0x0172: 0x03d9, // XK_Uogonek\n"
" 0x0173: 0x03f9, // XK_uogonek\n"
" 0x0178: 0x13be, // XK_Ydiaeresis\n"
" 0x0179: 0x01ac, // XK_Zacute\n"
" 0x017a: 0x01bc, // XK_zacute\n"
" 0x017b: 0x01af, // XK_Zabovedot\n"
" 0x017c: 0x01bf, // XK_zabovedot\n"
" 0x017d: 0x01ae, // XK_Zcaron\n"
" 0x017e: 0x01be, // XK_zcaron\n"
" 0x0192: 0x08f6, // XK_function\n"
" 0x01d2: 0x10001d1, // XK_Ocaron\n"
" 0x02c7: 0x01b7, // XK_caron\n"
" 0x02d8: 0x01a2, // XK_breve\n"
" 0x02d9: 0x01ff, // XK_abovedot\n"
" 0x02db: 0x01b2, // XK_ogonek\n"
" 0x02dd: 0x01bd, // XK_doubleacute\n"
" 0x0385: 0x07ae, // XK_Greek_accentdieresis\n"
" 0x0386: 0x07a1, // XK_Greek_ALPHAaccent\n"
" 0x0388: 0x07a2, // XK_Greek_EPSILONaccent\n"
" 0x0389: 0x07a3, // XK_Greek_ETAaccent\n"
" 0x038a: 0x07a4, // XK_Greek_IOTAaccent\n"
" 0x038c: 0x07a7, // XK_Greek_OMICRONaccent\n"
" 0x038e: 0x07a8, // XK_Greek_UPSILONaccent\n"
" 0x038f: 0x07ab, // XK_Greek_OMEGAaccent\n"
" 0x0390: 0x07b6, // XK_Greek_iotaaccentdieresis\n"
" 0x0391: 0x07c1, // XK_Greek_ALPHA\n"
" 0x0392: 0x07c2, // XK_Greek_BETA\n"
" 0x0393: 0x07c3, // XK_Greek_GAMMA\n"
" 0x0394: 0x07c4, // XK_Greek_DELTA\n"
" 0x0395: 0x07c5, // XK_Greek_EPSILON\n"
" 0x0396: 0x07c6, // XK_Greek_ZETA\n"
" 0x0397: 0x07c7, // XK_Greek_ETA\n"
" 0x0398: 0x07c8, // XK_Greek_THETA\n"
" 0x0399: 0x07c9, // XK_Greek_IOTA\n"
" 0x039a: 0x07ca, // XK_Greek_KAPPA\n"
" 0x039b: 0x07cb, // XK_Greek_LAMDA\n"
" 0x039c: 0x07cc, // XK_Greek_MU\n"
" 0x039d: 0x07cd, // XK_Greek_NU\n"
" 0x039e: 0x07ce, // XK_Greek_XI\n"
" 0x039f: 0x07cf, // XK_Greek_OMICRON\n"
" 0x03a0: 0x07d0, // XK_Greek_PI\n"
" 0x03a1: 0x07d1, // XK_Greek_RHO\n"
" 0x03a3: 0x07d2, // XK_Greek_SIGMA\n"
" 0x03a4: 0x07d4, // XK_Greek_TAU\n"
" 0x03a5: 0x07d5, // XK_Greek_UPSILON\n"
" 0x03a6: 0x07d6, // XK_Greek_PHI\n"
" 0x03a7: 0x07d7, // XK_Greek_CHI\n"
" 0x03a8: 0x07d8, // XK_Greek_PSI\n"
" 0x03a9: 0x07d9, // XK_Greek_OMEGA\n"
" 0x03aa: 0x07a5, // XK_Greek_IOTAdieresis\n"
" 0x03ab: 0x07a9, // XK_Greek_UPSILONdieresis\n"
" 0x03ac: 0x07b1, // XK_Greek_alphaaccent\n"
" 0x03ad: 0x07b2, // XK_Greek_epsilonaccent\n"
" 0x03ae: 0x07b3, // XK_Greek_etaaccent\n"
" 0x03af: 0x07b4, // XK_Greek_iotaaccent\n"
" 0x03b0: 0x07ba, // XK_Greek_upsilonaccentdieresis\n"
" 0x03b1: 0x07e1, // XK_Greek_alpha\n"
" 0x03b2: 0x07e2, // XK_Greek_beta\n"
" 0x03b3: 0x07e3, // XK_Greek_gamma\n"
" 0x03b4: 0x07e4, // XK_Greek_delta\n"
" 0x03b5: 0x07e5, // XK_Greek_epsilon\n"
" 0x03b6: 0x07e6, // XK_Greek_zeta\n"
" 0x03b7: 0x07e7, // XK_Greek_eta\n"
" 0x03b8: 0x07e8, // XK_Greek_theta\n"
" 0x03b9: 0x07e9, // XK_Greek_iota\n"
" 0x03ba: 0x07ea, // XK_Greek_kappa\n"
" 0x03bb: 0x07eb, // XK_Greek_lamda\n"
" 0x03bc: 0x07ec, // XK_Greek_mu\n"
" 0x03bd: 0x07ed, // XK_Greek_nu\n"
" 0x03be: 0x07ee, // XK_Greek_xi\n"
" 0x03bf: 0x07ef, // XK_Greek_omicron\n"
" 0x03c0: 0x07f0, // XK_Greek_pi\n"
" 0x03c1: 0x07f1, // XK_Greek_rho\n"
" 0x03c2: 0x07f3, // XK_Greek_finalsmallsigma\n"
" 0x03c3: 0x07f2, // XK_Greek_sigma\n"
" 0x03c4: 0x07f4, // XK_Greek_tau\n"
" 0x03c5: 0x07f5, // XK_Greek_upsilon\n"
" 0x03c6: 0x07f6, // XK_Greek_phi\n"
" 0x03c7: 0x07f7, // XK_Greek_chi\n"
" 0x03c8: 0x07f8, // XK_Greek_psi\n"
" 0x03c9: 0x07f9, // XK_Greek_omega\n"
" 0x03ca: 0x07b5, // XK_Greek_iotadieresis\n"
" 0x03cb: 0x07b9, // XK_Greek_upsilondieresis\n"
" 0x03cc: 0x07b7, // XK_Greek_omicronaccent\n"
" 0x03cd: 0x07b8, // XK_Greek_upsilonaccent\n"
" 0x03ce: 0x07bb, // XK_Greek_omegaaccent\n"
" 0x0401: 0x06b3, // XK_Cyrillic_IO\n"
" 0x0402: 0x06b1, // XK_Serbian_DJE\n"
" 0x0403: 0x06b2, // XK_Macedonia_GJE\n"
" 0x0404: 0x06b4, // XK_Ukrainian_IE\n"
" 0x0405: 0x06b5, // XK_Macedonia_DSE\n"
" 0x0406: 0x06b6, // XK_Ukrainian_I\n"
" 0x0407: 0x06b7, // XK_Ukrainian_YI\n"
" 0x0408: 0x06b8, // XK_Cyrillic_JE\n"
" 0x0409: 0x06b9, // XK_Cyrillic_LJE\n"
" 0x040a: 0x06ba, // XK_Cyrillic_NJE\n"
" 0x040b: 0x06bb, // XK_Serbian_TSHE\n"
" 0x040c: 0x06bc, // XK_Macedonia_KJE\n"
" 0x040e: 0x06be, // XK_Byelorussian_SHORTU\n"
" 0x040f: 0x06bf, // XK_Cyrillic_DZHE\n"
" 0x0410: 0x06e1, // XK_Cyrillic_A\n"
" 0x0411: 0x06e2, // XK_Cyrillic_BE\n"
" 0x0412: 0x06f7, // XK_Cyrillic_VE\n"
" 0x0413: 0x06e7, // XK_Cyrillic_GHE\n"
" 0x0414: 0x06e4, // XK_Cyrillic_DE\n"
" 0x0415: 0x06e5, // XK_Cyrillic_IE\n"
" 0x0416: 0x06f6, // XK_Cyrillic_ZHE\n"
" 0x0417: 0x06fa, // XK_Cyrillic_ZE\n"
" 0x0418: 0x06e9, // XK_Cyrillic_I\n"
" 0x0419: 0x06ea, // XK_Cyrillic_SHORTI\n"
" 0x041a: 0x06eb, // XK_Cyrillic_KA\n"
" 0x041b: 0x06ec, // XK_Cyrillic_EL\n"
" 0x041c: 0x06ed, // XK_Cyrillic_EM\n"
" 0x041d: 0x06ee, // XK_Cyrillic_EN\n"
" 0x041e: 0x06ef, // XK_Cyrillic_O\n"
" 0x041f: 0x06f0, // XK_Cyrillic_PE\n"
" 0x0420: 0x06f2, // XK_Cyrillic_ER\n"
" 0x0421: 0x06f3, // XK_Cyrillic_ES\n"
" 0x0422: 0x06f4, // XK_Cyrillic_TE\n"
" 0x0423: 0x06f5, // XK_Cyrillic_U\n"
" 0x0424: 0x06e6, // XK_Cyrillic_EF\n"
" 0x0425: 0x06e8, // XK_Cyrillic_HA\n"
" 0x0426: 0x06e3, // XK_Cyrillic_TSE\n"
" 0x0427: 0x06fe, // XK_Cyrillic_CHE\n"
" 0x0428: 0x06fb, // XK_Cyrillic_SHA\n"
" 0x0429: 0x06fd, // XK_Cyrillic_SHCHA\n"
" 0x042a: 0x06ff, // XK_Cyrillic_HARDSIGN\n"
" 0x042b: 0x06f9, // XK_Cyrillic_YERU\n"
" 0x042c: 0x06f8, // XK_Cyrillic_SOFTSIGN\n"
" 0x042d: 0x06fc, // XK_Cyrillic_E\n"
" 0x042e: 0x06e0, // XK_Cyrillic_YU\n"
" 0x042f: 0x06f1, // XK_Cyrillic_YA\n"
" 0x0430: 0x06c1, // XK_Cyrillic_a\n"
" 0x0431: 0x06c2, // XK_Cyrillic_be\n"
" 0x0432: 0x06d7, // XK_Cyrillic_ve\n"
" 0x0433: 0x06c7, // XK_Cyrillic_ghe\n"
" 0x0434: 0x06c4, // XK_Cyrillic_de\n"
" 0x0435: 0x06c5, // XK_Cyrillic_ie\n"
" 0x0436: 0x06d6, // XK_Cyrillic_zhe\n"
" 0x0437: 0x06da, // XK_Cyrillic_ze\n"
" 0x0438: 0x06c9, // XK_Cyrillic_i\n"
" 0x0439: 0x06ca, // XK_Cyrillic_shorti\n"
" 0x043a: 0x06cb, // XK_Cyrillic_ka\n"
" 0x043b: 0x06cc, // XK_Cyrillic_el\n"
" 0x043c: 0x06cd, // XK_Cyrillic_em\n"
" 0x043d: 0x06ce, // XK_Cyrillic_en\n"
" 0x043e: 0x06cf, // XK_Cyrillic_o\n"
" 0x043f: 0x06d0, // XK_Cyrillic_pe\n"
" 0x0440: 0x06d2, // XK_Cyrillic_er\n"
" 0x0441: 0x06d3, // XK_Cyrillic_es\n"
" 0x0442: 0x06d4, // XK_Cyrillic_te\n"
" 0x0443: 0x06d5, // XK_Cyrillic_u\n"
" 0x0444: 0x06c6, // XK_Cyrillic_ef\n"
" 0x0445: 0x06c8, // XK_Cyrillic_ha\n"
" 0x0446: 0x06c3, // XK_Cyrillic_tse\n"
" 0x0447: 0x06de, // XK_Cyrillic_che\n"
" 0x0448: 0x06db, // XK_Cyrillic_sha\n"
" 0x0449: 0x06dd, // XK_Cyrillic_shcha\n"
" 0x044a: 0x06df, // XK_Cyrillic_hardsign\n"
" 0x044b: 0x06d9, // XK_Cyrillic_yeru\n"
" 0x044c: 0x06d8, // XK_Cyrillic_softsign\n"
" 0x044d: 0x06dc, // XK_Cyrillic_e\n"
" 0x044e: 0x06c0, // XK_Cyrillic_yu\n"
" 0x044f: 0x06d1, // XK_Cyrillic_ya\n"
" 0x0451: 0x06a3, // XK_Cyrillic_io\n"
" 0x0452: 0x06a1, // XK_Serbian_dje\n"
" 0x0453: 0x06a2, // XK_Macedonia_gje\n"
" 0x0454: 0x06a4, // XK_Ukrainian_ie\n"
" 0x0455: 0x06a5, // XK_Macedonia_dse\n"
" 0x0456: 0x06a6, // XK_Ukrainian_i\n"
" 0x0457: 0x06a7, // XK_Ukrainian_yi\n"
" 0x0458: 0x06a8, // XK_Cyrillic_je\n"
" 0x0459: 0x06a9, // XK_Cyrillic_lje\n"
" 0x045a: 0x06aa, // XK_Cyrillic_nje\n"
" 0x045b: 0x06ab, // XK_Serbian_tshe\n"
" 0x045c: 0x06ac, // XK_Macedonia_kje\n"
" 0x045e: 0x06ae, // XK_Byelorussian_shortu\n"
" 0x045f: 0x06af, // XK_Cyrillic_dzhe\n"
" 0x0490: 0x06bd, // XK_Ukrainian_GHE_WITH_UPTURN\n"
" 0x0491: 0x06ad, // XK_Ukrainian_ghe_with_upturn\n"
" 0x05d0: 0x0ce0, // XK_hebrew_aleph\n"
" 0x05d1: 0x0ce1, // XK_hebrew_bet\n"
" 0x05d2: 0x0ce2, // XK_hebrew_gimel\n"
" 0x05d3: 0x0ce3, // XK_hebrew_dalet\n"
" 0x05d4: 0x0ce4, // XK_hebrew_he\n"
" 0x05d5: 0x0ce5, // XK_hebrew_waw\n"
" 0x05d6: 0x0ce6, // XK_hebrew_zain\n"
" 0x05d7: 0x0ce7, // XK_hebrew_chet\n"
" 0x05d8: 0x0ce8, // XK_hebrew_tet\n"
" 0x05d9: 0x0ce9, // XK_hebrew_yod\n"
" 0x05da: 0x0cea, // XK_hebrew_finalkaph\n"
" 0x05db: 0x0ceb, // XK_hebrew_kaph\n"
" 0x05dc: 0x0cec, // XK_hebrew_lamed\n"
" 0x05dd: 0x0ced, // XK_hebrew_finalmem\n"
" 0x05de: 0x0cee, // XK_hebrew_mem\n"
" 0x05df: 0x0cef, // XK_hebrew_finalnun\n"
" 0x05e0: 0x0cf0, // XK_hebrew_nun\n"
" 0x05e1: 0x0cf1, // XK_hebrew_samech\n"
" 0x05e2: 0x0cf2, // XK_hebrew_ayin\n"
" 0x05e3: 0x0cf3, // XK_hebrew_finalpe\n"
" 0x05e4: 0x0cf4, // XK_hebrew_pe\n"
" 0x05e5: 0x0cf5, // XK_hebrew_finalzade\n"
" 0x05e6: 0x0cf6, // XK_hebrew_zade\n"
" 0x05e7: 0x0cf7, // XK_hebrew_qoph\n"
" 0x05e8: 0x0cf8, // XK_hebrew_resh\n"
" 0x05e9: 0x0cf9, // XK_hebrew_shin\n"
" 0x05ea: 0x0cfa, // XK_hebrew_taw\n"
" 0x060c: 0x05ac, // XK_Arabic_comma\n"
" 0x061b: 0x05bb, // XK_Arabic_semicolon\n"
" 0x061f: 0x05bf, // XK_Arabic_question_mark\n"
" 0x0621: 0x05c1, // XK_Arabic_hamza\n"
" 0x0622: 0x05c2, // XK_Arabic_maddaonalef\n"
" 0x0623: 0x05c3, // XK_Arabic_hamzaonalef\n"
" 0x0624: 0x05c4, // XK_Arabic_hamzaonwaw\n"
" 0x0625: 0x05c5, // XK_Arabic_hamzaunderalef\n"
" 0x0626: 0x05c6, // XK_Arabic_hamzaonyeh\n"
" 0x0627: 0x05c7, // XK_Arabic_alef\n"
" 0x0628: 0x05c8, // XK_Arabic_beh\n"
" 0x0629: 0x05c9, // XK_Arabic_tehmarbuta\n"
" 0x062a: 0x05ca, // XK_Arabic_teh\n"
" 0x062b: 0x05cb, // XK_Arabic_theh\n"
" 0x062c: 0x05cc, // XK_Arabic_jeem\n"
" 0x062d: 0x05cd, // XK_Arabic_hah\n"
" 0x062e: 0x05ce, // XK_Arabic_khah\n"
" 0x062f: 0x05cf, // XK_Arabic_dal\n"
" 0x0630: 0x05d0, // XK_Arabic_thal\n"
" 0x0631: 0x05d1, // XK_Arabic_ra\n"
" 0x0632: 0x05d2, // XK_Arabic_zain\n"
" 0x0633: 0x05d3, // XK_Arabic_seen\n"
" 0x0634: 0x05d4, // XK_Arabic_sheen\n"
" 0x0635: 0x05d5, // XK_Arabic_sad\n"
" 0x0636: 0x05d6, // XK_Arabic_dad\n"
" 0x0637: 0x05d7, // XK_Arabic_tah\n"
" 0x0638: 0x05d8, // XK_Arabic_zah\n"
" 0x0639: 0x05d9, // XK_Arabic_ain\n"
" 0x063a: 0x05da, // XK_Arabic_ghain\n"
" 0x0640: 0x05e0, // XK_Arabic_tatweel\n"
" 0x0641: 0x05e1, // XK_Arabic_feh\n"
" 0x0642: 0x05e2, // XK_Arabic_qaf\n"
" 0x0643: 0x05e3, // XK_Arabic_kaf\n"
" 0x0644: 0x05e4, // XK_Arabic_lam\n"
" 0x0645: 0x05e5, // XK_Arabic_meem\n"
" 0x0646: 0x05e6, // XK_Arabic_noon\n"
" 0x0647: 0x05e7, // XK_Arabic_ha\n"
" 0x0648: 0x05e8, // XK_Arabic_waw\n"
" 0x0649: 0x05e9, // XK_Arabic_alefmaksura\n"
" 0x064a: 0x05ea, // XK_Arabic_yeh\n"
" 0x064b: 0x05eb, // XK_Arabic_fathatan\n"
" 0x064c: 0x05ec, // XK_Arabic_dammatan\n"
" 0x064d: 0x05ed, // XK_Arabic_kasratan\n"
" 0x064e: 0x05ee, // XK_Arabic_fatha\n"
" 0x064f: 0x05ef, // XK_Arabic_damma\n"
" 0x0650: 0x05f0, // XK_Arabic_kasra\n"
" 0x0651: 0x05f1, // XK_Arabic_shadda\n"
" 0x0652: 0x05f2, // XK_Arabic_sukun\n"
" 0x0e01: 0x0da1, // XK_Thai_kokai\n"
" 0x0e02: 0x0da2, // XK_Thai_khokhai\n"
" 0x0e03: 0x0da3, // XK_Thai_khokhuat\n"
" 0x0e04: 0x0da4, // XK_Thai_khokhwai\n"
" 0x0e05: 0x0da5, // XK_Thai_khokhon\n"
" 0x0e06: 0x0da6, // XK_Thai_khorakhang\n"
" 0x0e07: 0x0da7, // XK_Thai_ngongu\n"
" 0x0e08: 0x0da8, // XK_Thai_chochan\n"
" 0x0e09: 0x0da9, // XK_Thai_choching\n"
" 0x0e0a: 0x0daa, // XK_Thai_chochang\n"
" 0x0e0b: 0x0dab, // XK_Thai_soso\n"
" 0x0e0c: 0x0dac, // XK_Thai_chochoe\n"
" 0x0e0d: 0x0dad, // XK_Thai_yoying\n"
" 0x0e0e: 0x0dae, // XK_Thai_dochada\n"
" 0x0e0f: 0x0daf, // XK_Thai_topatak\n"
" 0x0e10: 0x0db0, // XK_Thai_thothan\n"
" 0x0e11: 0x0db1, // XK_Thai_thonangmontho\n"
" 0x0e12: 0x0db2, // XK_Thai_thophuthao\n"
" 0x0e13: 0x0db3, // XK_Thai_nonen\n"
" 0x0e14: 0x0db4, // XK_Thai_dodek\n"
" 0x0e15: 0x0db5, // XK_Thai_totao\n"
" 0x0e16: 0x0db6, // XK_Thai_thothung\n"
" 0x0e17: 0x0db7, // XK_Thai_thothahan\n"
" 0x0e18: 0x0db8, // XK_Thai_thothong\n"
" 0x0e19: 0x0db9, // XK_Thai_nonu\n"
" 0x0e1a: 0x0dba, // XK_Thai_bobaimai\n"
" 0x0e1b: 0x0dbb, // XK_Thai_popla\n"
" 0x0e1c: 0x0dbc, // XK_Thai_phophung\n"
" 0x0e1d: 0x0dbd, // XK_Thai_fofa\n"
" 0x0e1e: 0x0dbe, // XK_Thai_phophan\n"
" 0x0e1f: 0x0dbf, // XK_Thai_fofan\n"
" 0x0e20: 0x0dc0, // XK_Thai_phosamphao\n"
" 0x0e21: 0x0dc1, // XK_Thai_moma\n"
" 0x0e22: 0x0dc2, // XK_Thai_yoyak\n"
" 0x0e23: 0x0dc3, // XK_Thai_rorua\n"
" 0x0e24: 0x0dc4, // XK_Thai_ru\n"
" 0x0e25: 0x0dc5, // XK_Thai_loling\n"
" 0x0e26: 0x0dc6, // XK_Thai_lu\n"
" 0x0e27: 0x0dc7, // XK_Thai_wowaen\n"
" 0x0e28: 0x0dc8, // XK_Thai_sosala\n"
" 0x0e29: 0x0dc9, // XK_Thai_sorusi\n"
" 0x0e2a: 0x0dca, // XK_Thai_sosua\n"
" 0x0e2b: 0x0dcb, // XK_Thai_hohip\n"
" 0x0e2c: 0x0dcc, // XK_Thai_lochula\n"
" 0x0e2d: 0x0dcd, // XK_Thai_oang\n"
" 0x0e2e: 0x0dce, // XK_Thai_honokhuk\n"
" 0x0e2f: 0x0dcf, // XK_Thai_paiyannoi\n"
" 0x0e30: 0x0dd0, // XK_Thai_saraa\n"
" 0x0e31: 0x0dd1, // XK_Thai_maihanakat\n"
" 0x0e32: 0x0dd2, // XK_Thai_saraaa\n"
" 0x0e33: 0x0dd3, // XK_Thai_saraam\n"
" 0x0e34: 0x0dd4, // XK_Thai_sarai\n"
" 0x0e35: 0x0dd5, // XK_Thai_saraii\n"
" 0x0e36: 0x0dd6, // XK_Thai_saraue\n"
" 0x0e37: 0x0dd7, // XK_Thai_sarauee\n"
" 0x0e38: 0x0dd8, // XK_Thai_sarau\n"
" 0x0e39: 0x0dd9, // XK_Thai_sarauu\n"
" 0x0e3a: 0x0dda, // XK_Thai_phinthu\n"
" 0x0e3f: 0x0ddf, // XK_Thai_baht\n"
" 0x0e40: 0x0de0, // XK_Thai_sarae\n"
" 0x0e41: 0x0de1, // XK_Thai_saraae\n"
" 0x0e42: 0x0de2, // XK_Thai_sarao\n"
" 0x0e43: 0x0de3, // XK_Thai_saraaimaimuan\n"
" 0x0e44: 0x0de4, // XK_Thai_saraaimaimalai\n"
" 0x0e45: 0x0de5, // XK_Thai_lakkhangyao\n"
" 0x0e46: 0x0de6, // XK_Thai_maiyamok\n"
" 0x0e47: 0x0de7, // XK_Thai_maitaikhu\n"
" 0x0e48: 0x0de8, // XK_Thai_maiek\n"
" 0x0e49: 0x0de9, // XK_Thai_maitho\n"
" 0x0e4a: 0x0dea, // XK_Thai_maitri\n"
" 0x0e4b: 0x0deb, // XK_Thai_maichattawa\n"
" 0x0e4c: 0x0dec, // XK_Thai_thanthakhat\n"
" 0x0e4d: 0x0ded, // XK_Thai_nikhahit\n"
" 0x0e50: 0x0df0, // XK_Thai_leksun\n"
" 0x0e51: 0x0df1, // XK_Thai_leknung\n"
" 0x0e52: 0x0df2, // XK_Thai_leksong\n"
" 0x0e53: 0x0df3, // XK_Thai_leksam\n"
" 0x0e54: 0x0df4, // XK_Thai_leksi\n"
" 0x0e55: 0x0df5, // XK_Thai_lekha\n"
" 0x0e56: 0x0df6, // XK_Thai_lekhok\n"
" 0x0e57: 0x0df7, // XK_Thai_lekchet\n"
" 0x0e58: 0x0df8, // XK_Thai_lekpaet\n"
" 0x0e59: 0x0df9, // XK_Thai_lekkao\n"
" 0x2002: 0x0aa2, // XK_enspace\n"
" 0x2003: 0x0aa1, // XK_emspace\n"
" 0x2004: 0x0aa3, // XK_em3space\n"
" 0x2005: 0x0aa4, // XK_em4space\n"
" 0x2007: 0x0aa5, // XK_digitspace\n"
" 0x2008: 0x0aa6, // XK_punctspace\n"
" 0x2009: 0x0aa7, // XK_thinspace\n"
" 0x200a: 0x0aa8, // XK_hairspace\n"
" 0x2012: 0x0abb, // XK_figdash\n"
" 0x2013: 0x0aaa, // XK_endash\n"
" 0x2014: 0x0aa9, // XK_emdash\n"
" 0x2015: 0x07af, // XK_Greek_horizbar\n"
" 0x2017: 0x0cdf, // XK_hebrew_doublelowline\n"
" 0x2018: 0x0ad0, // XK_leftsinglequotemark\n"
" 0x2019: 0x0ad1, // XK_rightsinglequotemark\n"
" 0x201a: 0x0afd, // XK_singlelowquotemark\n"
" 0x201c: 0x0ad2, // XK_leftdoublequotemark\n"
" 0x201d: 0x0ad3, // XK_rightdoublequotemark\n"
" 0x201e: 0x0afe, // XK_doublelowquotemark\n"
" 0x2020: 0x0af1, // XK_dagger\n"
" 0x2021: 0x0af2, // XK_doubledagger\n"
" 0x2022: 0x0ae6, // XK_enfilledcircbullet\n"
" 0x2025: 0x0aaf, // XK_doubbaselinedot\n"
" 0x2026: 0x0aae, // XK_ellipsis\n"
" 0x2030: 0x0ad5, // XK_permille\n"
" 0x2032: 0x0ad6, // XK_minutes\n"
" 0x2033: 0x0ad7, // XK_seconds\n"
" 0x2038: 0x0afc, // XK_caret\n"
" 0x203e: 0x047e, // XK_overline\n"
" 0x20a9: 0x0eff, // XK_Korean_Won\n"
" 0x20ac: 0x20ac, // XK_EuroSign\n"
" 0x2105: 0x0ab8, // XK_careof\n"
" 0x2116: 0x06b0, // XK_numerosign\n"
" 0x2117: 0x0afb, // XK_phonographcopyright\n"
" 0x211e: 0x0ad4, // XK_prescription\n"
" 0x2122: 0x0ac9, // XK_trademark\n"
" 0x2153: 0x0ab0, // XK_onethird\n"
" 0x2154: 0x0ab1, // XK_twothirds\n"
" 0x2155: 0x0ab2, // XK_onefifth\n"
" 0x2156: 0x0ab3, // XK_twofifths\n"
" 0x2157: 0x0ab4, // XK_threefifths\n"
" 0x2158: 0x0ab5, // XK_fourfifths\n"
" 0x2159: 0x0ab6, // XK_onesixth\n"
" 0x215a: 0x0ab7, // XK_fivesixths\n"
" 0x215b: 0x0ac3, // XK_oneeighth\n"
" 0x215c: 0x0ac4, // XK_threeeighths\n"
" 0x215d: 0x0ac5, // XK_fiveeighths\n"
" 0x215e: 0x0ac6, // XK_seveneighths\n"
" 0x2190: 0x08fb, // XK_leftarrow\n"
" 0x2191: 0x08fc, // XK_uparrow\n"
" 0x2192: 0x08fd, // XK_rightarrow\n"
" 0x2193: 0x08fe, // XK_downarrow\n"
" 0x21d2: 0x08ce, // XK_implies\n"
" 0x21d4: 0x08cd, // XK_ifonlyif\n"
" 0x2202: 0x08ef, // XK_partialderivative\n"
" 0x2207: 0x08c5, // XK_nabla\n"
" 0x2218: 0x0bca, // XK_jot\n"
" 0x221a: 0x08d6, // XK_radical\n"
" 0x221d: 0x08c1, // XK_variation\n"
" 0x221e: 0x08c2, // XK_infinity\n"
" 0x2227: 0x08de, // XK_logicaland\n"
" 0x2228: 0x08df, // XK_logicalor\n"
" 0x2229: 0x08dc, // XK_intersection\n"
" 0x222a: 0x08dd, // XK_union\n"
" 0x222b: 0x08bf, // XK_integral\n"
" 0x2234: 0x08c0, // XK_therefore\n"
" 0x223c: 0x08c8, // XK_approximate\n"
" 0x2243: 0x08c9, // XK_similarequal\n"
" 0x2245: 0x1002248, // XK_approxeq\n"
" 0x2260: 0x08bd, // XK_notequal\n"
" 0x2261: 0x08cf, // XK_identical\n"
" 0x2264: 0x08bc, // XK_lessthanequal\n"
" 0x2265: 0x08be, // XK_greaterthanequal\n"
" 0x2282: 0x08da, // XK_includedin\n"
" 0x2283: 0x08db, // XK_includes\n"
" 0x22a2: 0x0bfc, // XK_righttack\n"
" 0x22a3: 0x0bdc, // XK_lefttack\n"
" 0x22a4: 0x0bc2, // XK_downtack\n"
" 0x22a5: 0x0bce, // XK_uptack\n"
" 0x2308: 0x0bd3, // XK_upstile\n"
" 0x230a: 0x0bc4, // XK_downstile\n"
" 0x2315: 0x0afa, // XK_telephonerecorder\n"
" 0x2320: 0x08a4, // XK_topintegral\n"
" 0x2321: 0x08a5, // XK_botintegral\n"
" 0x2395: 0x0bcc, // XK_quad\n"
" 0x239b: 0x08ab, // XK_topleftparens\n"
" 0x239d: 0x08ac, // XK_botleftparens\n"
" 0x239e: 0x08ad, // XK_toprightparens\n"
" 0x23a0: 0x08ae, // XK_botrightparens\n"
" 0x23a1: 0x08a7, // XK_topleftsqbracket\n"
" 0x23a3: 0x08a8, // XK_botleftsqbracket\n"
" 0x23a4: 0x08a9, // XK_toprightsqbracket\n"
" 0x23a6: 0x08aa, // XK_botrightsqbracket\n"
" 0x23a8: 0x08af, // XK_leftmiddlecurlybrace\n"
" 0x23ac: 0x08b0, // XK_rightmiddlecurlybrace\n"
" 0x23b7: 0x08a1, // XK_leftradical\n"
" 0x23ba: 0x09ef, // XK_horizlinescan1\n"
" 0x23bb: 0x09f0, // XK_horizlinescan3\n"
" 0x23bc: 0x09f2, // XK_horizlinescan7\n"
" 0x23bd: 0x09f3, // XK_horizlinescan9\n"
" 0x2409: 0x09e2, // XK_ht\n"
" 0x240a: 0x09e5, // XK_lf\n"
" 0x240b: 0x09e9, // XK_vt\n"
" 0x240c: 0x09e3, // XK_ff\n"
" 0x240d: 0x09e4, // XK_cr\n"
" 0x2423: 0x0aac, // XK_signifblank\n"
" 0x2424: 0x09e8, // XK_nl\n"
" 0x2500: 0x08a3, // XK_horizconnector\n"
" 0x2502: 0x08a6, // XK_vertconnector\n"
" 0x250c: 0x08a2, // XK_topleftradical\n"
" 0x2510: 0x09eb, // XK_uprightcorner\n"
" 0x2514: 0x09ed, // XK_lowleftcorner\n"
" 0x2518: 0x09ea, // XK_lowrightcorner\n"
" 0x251c: 0x09f4, // XK_leftt\n"
" 0x2524: 0x09f5, // XK_rightt\n"
" 0x252c: 0x09f7, // XK_topt\n"
" 0x2534: 0x09f6, // XK_bott\n"
" 0x253c: 0x09ee, // XK_crossinglines\n"
" 0x2592: 0x09e1, // XK_checkerboard\n"
" 0x25aa: 0x0ae7, // XK_enfilledsqbullet\n"
" 0x25ab: 0x0ae1, // XK_enopensquarebullet\n"
" 0x25ac: 0x0adb, // XK_filledrectbullet\n"
" 0x25ad: 0x0ae2, // XK_openrectbullet\n"
" 0x25ae: 0x0adf, // XK_emfilledrect\n"
" 0x25af: 0x0acf, // XK_emopenrectangle\n"
" 0x25b2: 0x0ae8, // XK_filledtribulletup\n"
" 0x25b3: 0x0ae3, // XK_opentribulletup\n"
" 0x25b6: 0x0add, // XK_filledrighttribullet\n"
" 0x25b7: 0x0acd, // XK_rightopentriangle\n"
" 0x25bc: 0x0ae9, // XK_filledtribulletdown\n"
" 0x25bd: 0x0ae4, // XK_opentribulletdown\n"
" 0x25c0: 0x0adc, // XK_filledlefttribullet\n"
" 0x25c1: 0x0acc, // XK_leftopentriangle\n"
" 0x25c6: 0x09e0, // XK_soliddiamond\n"
" 0x25cb: 0x0ace, // XK_emopencircle\n"
" 0x25cf: 0x0ade, // XK_emfilledcircle\n"
" 0x25e6: 0x0ae0, // XK_enopencircbullet\n"
" 0x2606: 0x0ae5, // XK_openstar\n"
" 0x260e: 0x0af9, // XK_telephone\n"
" 0x2613: 0x0aca, // XK_signaturemark\n"
" 0x261c: 0x0aea, // XK_leftpointer\n"
" 0x261e: 0x0aeb, // XK_rightpointer\n"
" 0x2640: 0x0af8, // XK_femalesymbol\n"
" 0x2642: 0x0af7, // XK_malesymbol\n"
" 0x2663: 0x0aec, // XK_club\n"
" 0x2665: 0x0aee, // XK_heart\n"
" 0x2666: 0x0aed, // XK_diamond\n"
" 0x266d: 0x0af6, // XK_musicalflat\n"
" 0x266f: 0x0af5, // XK_musicalsharp\n"
" 0x2713: 0x0af3, // XK_checkmark\n"
" 0x2717: 0x0af4, // XK_ballotcross\n"
" 0x271d: 0x0ad9, // XK_latincross\n"
" 0x2720: 0x0af0, // XK_maltesecross\n"
" 0x27e8: 0x0abc, // XK_leftanglebracket\n"
" 0x27e9: 0x0abe, // XK_rightanglebracket\n"
" 0x3001: 0x04a4, // XK_kana_comma\n"
" 0x3002: 0x04a1, // XK_kana_fullstop\n"
" 0x300c: 0x04a2, // XK_kana_openingbracket\n"
" 0x300d: 0x04a3, // XK_kana_closingbracket\n"
" 0x309b: 0x04de, // XK_voicedsound\n"
" 0x309c: 0x04df, // XK_semivoicedsound\n"
" 0x30a1: 0x04a7, // XK_kana_a\n"
" 0x30a2: 0x04b1, // XK_kana_A\n"
" 0x30a3: 0x04a8, // XK_kana_i\n"
" 0x30a4: 0x04b2, // XK_kana_I\n"
" 0x30a5: 0x04a9, // XK_kana_u\n"
" 0x30a6: 0x04b3, // XK_kana_U\n"
" 0x30a7: 0x04aa, // XK_kana_e\n"
" 0x30a8: 0x04b4, // XK_kana_E\n"
" 0x30a9: 0x04ab, // XK_kana_o\n"
" 0x30aa: 0x04b5, // XK_kana_O\n"
" 0x30ab: 0x04b6, // XK_kana_KA\n"
" 0x30ad: 0x04b7, // XK_kana_KI\n"
" 0x30af: 0x04b8, // XK_kana_KU\n"
" 0x30b1: 0x04b9, // XK_kana_KE\n"
" 0x30b3: 0x04ba, // XK_kana_KO\n"
" 0x30b5: 0x04bb, // XK_kana_SA\n"
" 0x30b7: 0x04bc, // XK_kana_SHI\n"
" 0x30b9: 0x04bd, // XK_kana_SU\n"
" 0x30bb: 0x04be, // XK_kana_SE\n"
" 0x30bd: 0x04bf, // XK_kana_SO\n"
" 0x30bf: 0x04c0, // XK_kana_TA\n"
" 0x30c1: 0x04c1, // XK_kana_CHI\n"
" 0x30c3: 0x04af, // XK_kana_tsu\n"
" 0x30c4: 0x04c2, // XK_kana_TSU\n"
" 0x30c6: 0x04c3, // XK_kana_TE\n"
" 0x30c8: 0x04c4, // XK_kana_TO\n"
" 0x30ca: 0x04c5, // XK_kana_NA\n"
" 0x30cb: 0x04c6, // XK_kana_NI\n"
" 0x30cc: 0x04c7, // XK_kana_NU\n"
" 0x30cd: 0x04c8, // XK_kana_NE\n"
" 0x30ce: 0x04c9, // XK_kana_NO\n"
" 0x30cf: 0x04ca, // XK_kana_HA\n"
" 0x30d2: 0x04cb, // XK_kana_HI\n"
" 0x30d5: 0x04cc, // XK_kana_FU\n"
" 0x30d8: 0x04cd, // XK_kana_HE\n"
" 0x30db: 0x04ce, // XK_kana_HO\n"
" 0x30de: 0x04cf, // XK_kana_MA\n"
" 0x30df: 0x04d0, // XK_kana_MI\n"
" 0x30e0: 0x04d1, // XK_kana_MU\n"
" 0x30e1: 0x04d2, // XK_kana_ME\n"
" 0x30e2: 0x04d3, // XK_kana_MO\n"
" 0x30e3: 0x04ac, // XK_kana_ya\n"
" 0x30e4: 0x04d4, // XK_kana_YA\n"
" 0x30e5: 0x04ad, // XK_kana_yu\n"
" 0x30e6: 0x04d5, // XK_kana_YU\n"
" 0x30e7: 0x04ae, // XK_kana_yo\n"
" 0x30e8: 0x04d6, // XK_kana_YO\n"
" 0x30e9: 0x04d7, // XK_kana_RA\n"
" 0x30ea: 0x04d8, // XK_kana_RI\n"
" 0x30eb: 0x04d9, // XK_kana_RU\n"
" 0x30ec: 0x04da, // XK_kana_RE\n"
" 0x30ed: 0x04db, // XK_kana_RO\n"
" 0x30ef: 0x04dc, // XK_kana_WA\n"
" 0x30f2: 0x04a6, // XK_kana_WO\n"
" 0x30f3: 0x04dd, // XK_kana_N\n"
" 0x30fb: 0x04a5, // XK_kana_conjunctive\n"
" 0x30fc: 0x04b0, // XK_prolongedsound\n"
"};\n"
"\n"
" /*\n"
" * Korean\n"
" * Byte 3 = 0x0e\n"
" */\n"
"window.lookup = function(u) {\n"
" // Latin-1 is one-to-one mapping\n"
" if ((u >= 0x20) && (u <= 0xff)) {\n"
" return u;\n"
" }\n"
"\n"
" XK_Hangul: 0xff31, /* Hangul start/stop(toggle) */\n"
" XK_Hangul_Hanja: 0xff34, /* Start Hangul->Hanja Conversion */\n"
" XK_Hangul_Jeonja: 0xff38, /* Jeonja mode */\n"
" // Lookup table (fairly random)\n"
" const keysym = codepoints[u];\n"
" if (keysym !== undefined) {\n"
" return keysym;\n"
" }\n"
"\n"
" /*\n"
" * XFree86 vendor specific keysyms.\n"
" *\n"
" * The XFree86 keysym range is 0x10080001 - 0x1008FFFF.\n"
" */\n"
" // General mapping as final fallback\n"
" return 0x01000000 | u;\n"
"};\n"
"window.codepoints = codepoints;\n"
"\n"
" XF86XK_ModeLock: 0x1008FF01,\n"
" XF86XK_MonBrightnessUp: 0x1008FF02,\n"
" XF86XK_MonBrightnessDown: 0x1008FF03,\n"
" XF86XK_KbdLightOnOff: 0x1008FF04,\n"
" XF86XK_KbdBrightnessUp: 0x1008FF05,\n"
" XF86XK_KbdBrightnessDown: 0x1008FF06,\n"
" XF86XK_Standby: 0x1008FF10,\n"
" XF86XK_AudioLowerVolume: 0x1008FF11,\n"
" XF86XK_AudioMute: 0x1008FF12,\n"
" XF86XK_AudioRaiseVolume: 0x1008FF13,\n"
" XF86XK_AudioPlay: 0x1008FF14,\n"
" XF86XK_AudioStop: 0x1008FF15,\n"
" XF86XK_AudioPrev: 0x1008FF16,\n"
" XF86XK_AudioNext: 0x1008FF17,\n"
" XF86XK_HomePage: 0x1008FF18,\n"
" XF86XK_Mail: 0x1008FF19,\n"
" XF86XK_Start: 0x1008FF1A,\n"
" XF86XK_Search: 0x1008FF1B,\n"
" XF86XK_AudioRecord: 0x1008FF1C,\n"
" XF86XK_Calculator: 0x1008FF1D,\n"
" XF86XK_Memo: 0x1008FF1E,\n"
" XF86XK_ToDoList: 0x1008FF1F,\n"
" XF86XK_Calendar: 0x1008FF20,\n"
" XF86XK_PowerDown: 0x1008FF21,\n"
" XF86XK_ContrastAdjust: 0x1008FF22,\n"
" XF86XK_RockerUp: 0x1008FF23,\n"
" XF86XK_RockerDown: 0x1008FF24,\n"
" XF86XK_RockerEnter: 0x1008FF25,\n"
" XF86XK_Back: 0x1008FF26,\n"
" XF86XK_Forward: 0x1008FF27,\n"
" XF86XK_Stop: 0x1008FF28,\n"
" XF86XK_Refresh: 0x1008FF29,\n"
" XF86XK_PowerOff: 0x1008FF2A,\n"
" XF86XK_WakeUp: 0x1008FF2B,\n"
" XF86XK_Eject: 0x1008FF2C,\n"
" XF86XK_ScreenSaver: 0x1008FF2D,\n"
" XF86XK_WWW: 0x1008FF2E,\n"
" XF86XK_Sleep: 0x1008FF2F,\n"
" XF86XK_Favorites: 0x1008FF30,\n"
" XF86XK_AudioPause: 0x1008FF31,\n"
" XF86XK_AudioMedia: 0x1008FF32,\n"
" XF86XK_MyComputer: 0x1008FF33,\n"
" XF86XK_VendorHome: 0x1008FF34,\n"
" XF86XK_LightBulb: 0x1008FF35,\n"
" XF86XK_Shop: 0x1008FF36,\n"
" XF86XK_History: 0x1008FF37,\n"
" XF86XK_OpenURL: 0x1008FF38,\n"
" XF86XK_AddFavorite: 0x1008FF39,\n"
" XF86XK_HotLinks: 0x1008FF3A,\n"
" XF86XK_BrightnessAdjust: 0x1008FF3B,\n"
" XF86XK_Finance: 0x1008FF3C,\n"
" XF86XK_Community: 0x1008FF3D,\n"
" XF86XK_AudioRewind: 0x1008FF3E,\n"
" XF86XK_BackForward: 0x1008FF3F,\n"
" XF86XK_Launch0: 0x1008FF40,\n"
" XF86XK_Launch1: 0x1008FF41,\n"
" XF86XK_Launch2: 0x1008FF42,\n"
" XF86XK_Launch3: 0x1008FF43,\n"
" XF86XK_Launch4: 0x1008FF44,\n"
" XF86XK_Launch5: 0x1008FF45,\n"
" XF86XK_Launch6: 0x1008FF46,\n"
" XF86XK_Launch7: 0x1008FF47,\n"
" XF86XK_Launch8: 0x1008FF48,\n"
" XF86XK_Launch9: 0x1008FF49,\n"
" XF86XK_LaunchA: 0x1008FF4A,\n"
" XF86XK_LaunchB: 0x1008FF4B,\n"
" XF86XK_LaunchC: 0x1008FF4C,\n"
" XF86XK_LaunchD: 0x1008FF4D,\n"
" XF86XK_LaunchE: 0x1008FF4E,\n"
" XF86XK_LaunchF: 0x1008FF4F,\n"
" XF86XK_ApplicationLeft: 0x1008FF50,\n"
" XF86XK_ApplicationRight: 0x1008FF51,\n"
" XF86XK_Book: 0x1008FF52,\n"
" XF86XK_CD: 0x1008FF53,\n"
" XF86XK_Calculater: 0x1008FF54,\n"
" XF86XK_Clear: 0x1008FF55,\n"
" XF86XK_Close: 0x1008FF56,\n"
" XF86XK_Copy: 0x1008FF57,\n"
" XF86XK_Cut: 0x1008FF58,\n"
" XF86XK_Display: 0x1008FF59,\n"
" XF86XK_DOS: 0x1008FF5A,\n"
" XF86XK_Documents: 0x1008FF5B,\n"
" XF86XK_Excel: 0x1008FF5C,\n"
" XF86XK_Explorer: 0x1008FF5D,\n"
" XF86XK_Game: 0x1008FF5E,\n"
" XF86XK_Go: 0x1008FF5F,\n"
" XF86XK_iTouch: 0x1008FF60,\n"
" XF86XK_LogOff: 0x1008FF61,\n"
" XF86XK_Market: 0x1008FF62,\n"
" XF86XK_Meeting: 0x1008FF63,\n"
" XF86XK_MenuKB: 0x1008FF65,\n"
" XF86XK_MenuPB: 0x1008FF66,\n"
" XF86XK_MySites: 0x1008FF67,\n"
" XF86XK_New: 0x1008FF68,\n"
" XF86XK_News: 0x1008FF69,\n"
" XF86XK_OfficeHome: 0x1008FF6A,\n"
" XF86XK_Open: 0x1008FF6B,\n"
" XF86XK_Option: 0x1008FF6C,\n"
" XF86XK_Paste: 0x1008FF6D,\n"
" XF86XK_Phone: 0x1008FF6E,\n"
" XF86XK_Q: 0x1008FF70,\n"
" XF86XK_Reply: 0x1008FF72,\n"
" XF86XK_Reload: 0x1008FF73,\n"
" XF86XK_RotateWindows: 0x1008FF74,\n"
" XF86XK_RotationPB: 0x1008FF75,\n"
" XF86XK_RotationKB: 0x1008FF76,\n"
" XF86XK_Save: 0x1008FF77,\n"
" XF86XK_ScrollUp: 0x1008FF78,\n"
" XF86XK_ScrollDown: 0x1008FF79,\n"
" XF86XK_ScrollClick: 0x1008FF7A,\n"
" XF86XK_Send: 0x1008FF7B,\n"
" XF86XK_Spell: 0x1008FF7C,\n"
" XF86XK_SplitScreen: 0x1008FF7D,\n"
" XF86XK_Support: 0x1008FF7E,\n"
" XF86XK_TaskPane: 0x1008FF7F,\n"
" XF86XK_Terminal: 0x1008FF80,\n"
" XF86XK_Tools: 0x1008FF81,\n"
" XF86XK_Travel: 0x1008FF82,\n"
" XF86XK_UserPB: 0x1008FF84,\n"
" XF86XK_User1KB: 0x1008FF85,\n"
" XF86XK_User2KB: 0x1008FF86,\n"
" XF86XK_Video: 0x1008FF87,\n"
" XF86XK_WheelButton: 0x1008FF88,\n"
" XF86XK_Word: 0x1008FF89,\n"
" XF86XK_Xfer: 0x1008FF8A,\n"
" XF86XK_ZoomIn: 0x1008FF8B,\n"
" XF86XK_ZoomOut: 0x1008FF8C,\n"
" XF86XK_Away: 0x1008FF8D,\n"
" XF86XK_Messenger: 0x1008FF8E,\n"
" XF86XK_WebCam: 0x1008FF8F,\n"
" XF86XK_MailForward: 0x1008FF90,\n"
" XF86XK_Pictures: 0x1008FF91,\n"
" XF86XK_Music: 0x1008FF92,\n"
" XF86XK_Battery: 0x1008FF93,\n"
" XF86XK_Bluetooth: 0x1008FF94,\n"
" XF86XK_WLAN: 0x1008FF95,\n"
" XF86XK_UWB: 0x1008FF96,\n"
" XF86XK_AudioForward: 0x1008FF97,\n"
" XF86XK_AudioRepeat: 0x1008FF98,\n"
" XF86XK_AudioRandomPlay: 0x1008FF99,\n"
" XF86XK_Subtitle: 0x1008FF9A,\n"
" XF86XK_AudioCycleTrack: 0x1008FF9B,\n"
" XF86XK_CycleAngle: 0x1008FF9C,\n"
" XF86XK_FrameBack: 0x1008FF9D,\n"
" XF86XK_FrameForward: 0x1008FF9E,\n"
" XF86XK_Time: 0x1008FF9F,\n"
" XF86XK_Select: 0x1008FFA0,\n"
" XF86XK_View: 0x1008FFA1,\n"
" XF86XK_TopMenu: 0x1008FFA2,\n"
" XF86XK_Red: 0x1008FFA3,\n"
" XF86XK_Green: 0x1008FFA4,\n"
" XF86XK_Yellow: 0x1008FFA5,\n"
" XF86XK_Blue: 0x1008FFA6,\n"
" XF86XK_Suspend: 0x1008FFA7,\n"
" XF86XK_Hibernate: 0x1008FFA8,\n"
" XF86XK_TouchpadToggle: 0x1008FFA9,\n"
" XF86XK_TouchpadOn: 0x1008FFB0,\n"
" XF86XK_TouchpadOff: 0x1008FFB1,\n"
" XF86XK_AudioMicMute: 0x1008FFB2,\n"
" XF86XK_Switch_VT_1: 0x1008FE01,\n"
" XF86XK_Switch_VT_2: 0x1008FE02,\n"
" XF86XK_Switch_VT_3: 0x1008FE03,\n"
" XF86XK_Switch_VT_4: 0x1008FE04,\n"
" XF86XK_Switch_VT_5: 0x1008FE05,\n"
" XF86XK_Switch_VT_6: 0x1008FE06,\n"
" XF86XK_Switch_VT_7: 0x1008FE07,\n"
" XF86XK_Switch_VT_8: 0x1008FE08,\n"
" XF86XK_Switch_VT_9: 0x1008FE09,\n"
" XF86XK_Switch_VT_10: 0x1008FE0A,\n"
" XF86XK_Switch_VT_11: 0x1008FE0B,\n"
" XF86XK_Switch_VT_12: 0x1008FE0C,\n"
" XF86XK_Ungrab: 0x1008FE20,\n"
" XF86XK_ClearGrab: 0x1008FE21,\n"
" XF86XK_Next_VMode: 0x1008FE22,\n"
" XF86XK_Prev_VMode: 0x1008FE23,\n"
" XF86XK_LogWindowTree: 0x1008FE24,\n"
" XF86XK_LogGrabInfo: 0x1008FE25,\n"
"// Create keysyms object for compatibility with util.js\n"
"window.keysyms = {\n"
" lookup: window.lookup\n"
"};\n"
;
if (strcmp(path, "/novnc/input/keysym.js") == 0) return novnc_input_keysym_js;
if (strcmp(path, "/novnc/input/keysymdef.js") == 0) return novnc_input_keysymdef_js;
const char *novnc_input_util_js =
"\n"
"// Get 'KeyboardEvent.code', handling legacy browsers\n"
......
......@@ -18,8 +18,8 @@
#include "html_pages/novnc_input_fixedkeys_js_page.h"
#include "html_pages/novnc_input_gesturehandler_js_page.h"
#include "html_pages/novnc_input_keyboard_js_page.h"
#include "html_pages/novnc_input_keysymdef_js_page.h"
#include "html_pages/novnc_input_keysym_js_page.h"
#include "html_pages/novnc_input_keysymdef_js_page.h"
#include "html_pages/novnc_input_util_js_page.h"
#include "html_pages/novnc_input_vkeys_js_page.h"
#include "html_pages/novnc_input_xtscancodes_js_page.h"
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -3,8 +3,8 @@
#include "html_pages/rdp_clipboard_js_page.h"
#include "html_pages/rdp_mstsc_js_page.h"
#include "html_pages/rdp_out_stream_js_page.h"
#include "html_pages/rdp_rdp_graphics_js_page.h"
#include "html_pages/rdp_rdp_wasm_js_page.h"
#include "html_pages/rdp_rdp_graphics_js_page.h"
#include "html_pages/rdp_reversed_layouts_js_page.h"
#include "html_pages/rdp_scancodes_js_page.h"
#include "html_pages/rdp_rdp_wasm_page.h"
......
......@@ -21,6 +21,7 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <openssl/err.h>
#include "ssl.h"
SSL_CTX *ssl_create_context(void) {
......@@ -43,6 +44,46 @@ SSL_CTX *ssl_create_context(void) {
return ctx;
}
SSL_CTX *create_ssl_context(void) {
SSL_CTX *ssl_ctx;
// Initialize SSL
SSL_library_init();
OpenSSL_add_all_algorithms();
SSL_load_error_strings();
ssl_ctx = SSL_CTX_new(TLS_client_method());
if (!ssl_ctx) {
ERR_print_errors_fp(stderr);
return NULL;
}
// Allow self-signed certificates
SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_NONE, NULL);
return ssl_ctx;
}
SSL *create_ssl_connection(SSL_CTX *ssl_ctx, int sock, int debug) {
SSL *ssl = SSL_new(ssl_ctx);
SSL_set_fd(ssl, sock);
if (debug) {
fprintf(stderr, "[DEBUG] Establishing SSL connection...\n");
}
if (SSL_connect(ssl) <= 0) {
ERR_print_errors_fp(stderr);
fprintf(stderr, "SSL connection failed\n");
SSL_free(ssl);
return NULL;
}
if (debug) {
fprintf(stderr, "[DEBUG] SSL connection established\n");
}
return ssl;
}
void ssl_cleanup(void) {
EVP_cleanup();
}
......
......@@ -31,4 +31,8 @@ void ssl_cleanup(void);
int ssl_load_certificates(SSL_CTX *ctx, const char *cert_file, const char *key_file);
int ssl_generate_self_signed_cert(const char *cert_file, const char *key_file);
// Client SSL functions (for web proxy)
SSL_CTX *create_ssl_context(void);
SSL *create_ssl_connection(SSL_CTX *ssl_ctx, int sock, int debug);
#endif /* SSL_H */
\ No newline at end of file
......@@ -30,9 +30,29 @@
#include <time.h>
#include <ctype.h>
#include <signal.h>
#include <netdb.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include "web_proxy.h"
#include "websocket.h"
#include "websocket_protocol.h"
#include "ssl.h"
// Service types for web proxy
typedef enum {
SERVICE_NONE = 0,
SERVICE_WEB,
SERVICE_HTTP,
SERVICE_HTTPS
} service_type_t;
// Structure to hold client and service info
typedef struct {
client_t *client;
service_type_t service_type;
char service_host[256];
int service_port;
} client_service_info_t;
// Global state for shutdown
static int server_socket = -1;
......@@ -53,12 +73,49 @@ static proxy_connection_t proxy_connections[MAX_PROXY_CONNECTIONS];
static int proxy_connections_count = 0;
static pthread_mutex_t proxy_mutex = PTHREAD_MUTEX_INITIALIZER;
// Active tunnels to client services
#define MAX_ACTIVE_TUNNELS 50
typedef struct {
char client_id[256];
char hostname[256];
service_type_t service_type;
char service_host[256];
int service_port;
int tunnel_fd; // Socket to client's service
SSL *ssl; // SSL connection for HTTPS
time_t last_used;
time_t created_at;
bool active;
pthread_mutex_t mutex;
} service_tunnel_t;
static service_tunnel_t active_tunnels[MAX_ACTIVE_TUNNELS];
static int active_tunnels_count = 0;
static pthread_mutex_t tunnels_mutex = PTHREAD_MUTEX_INITIALIZER;
// Thread arguments structure
typedef struct {
const wssshd_config_t *config;
wssshd_state_t *state;
} proxy_thread_args_t;
// Forward declarations
static void cleanup_expired_tunnels(void);
// Cleanup thread
static volatile int cleanup_running = 0;
static void *cleanup_thread(void *arg) {
(void)arg; // Unused
cleanup_running = 1;
while (cleanup_running) {
cleanup_expired_tunnels();
sleep(60); // Cleanup every minute
}
return NULL;
}
// Connection handler arguments
typedef struct {
int client_fd;
......@@ -69,8 +126,48 @@ typedef struct {
// Forward declaration for proxy connection handler
static void *proxy_connection_handler(void *arg);
// Find client by hostname (matching subdomain or client_id)
static client_t *find_client_by_hostname(const char *hostname, wssshd_state_t *state, const wssshd_config_t *config) {
// Parse service string to extract host and port
static int parse_service_info(const char *service_str, char *host, size_t host_size, int *port) {
// Service format: "web:host:port" or just "web"
char *colon1 = strchr(service_str, ':');
if (!colon1) {
// No host/port specified, use defaults
if (host) strncpy(host, "127.0.0.1", host_size);
if (port) *port = 80; // Default HTTP port
return 0;
}
char *colon2 = strchr(colon1 + 1, ':');
if (!colon2) {
// Only host specified
size_t host_len = colon1 - service_str;
if (host_len >= host_size) host_len = host_size - 1;
if (host) {
strncpy(host, service_str, host_len);
host[host_len] = '\0';
}
if (port) *port = 80; // Default HTTP port
return 0;
}
// Both host and port specified
size_t host_len = colon2 - colon1 - 1;
if (host_len >= host_size) host_len = host_size - 1;
if (host) {
strncpy(host, colon1 + 1, host_len);
host[host_len] = '\0';
}
if (port) *port = atoi(colon2 + 1);
return 0;
}
// Find client by hostname and determine which service to use
static client_service_info_t *find_client_service_by_hostname(const char *hostname, wssshd_state_t *state, const wssshd_config_t *config) {
static client_service_info_t result;
memset(&result, 0, sizeof(result));
if (!hostname || !state) return NULL;
pthread_mutex_lock(&state->client_mutex);
......@@ -79,28 +176,73 @@ static client_t *find_client_by_hostname(const char *hostname, wssshd_state_t *s
client_t *client = &state->clients[i];
if (!client->active) continue;
// Check if client has web service
if (strstr(client->services, "web") == NULL &&
strstr(client->services, "http") == NULL) {
continue;
}
// Try exact match with client_id
// Check hostname match
int hostname_match = 0;
if (strcasecmp(hostname, client->client_id) == 0) {
pthread_mutex_unlock(&state->client_mutex);
return client;
}
// Try subdomain match: hostname.client_id.domain
if (config && config->domain) {
hostname_match = 1;
} else if (config && config->domain) {
char expected_hostname[512];
snprintf(expected_hostname, sizeof(expected_hostname), "%s.%s",
client->client_id, config->domain);
if (strcasecmp(hostname, expected_hostname) == 0) {
pthread_mutex_unlock(&state->client_mutex);
return client;
hostname_match = 1;
}
}
if (!hostname_match) continue;
// Parse services and find the best one (web > http > https)
char *services_copy = strdup(client->services);
if (!services_copy) continue;
char *service_token = strtok(services_copy, ",");
service_type_t best_service = SERVICE_NONE;
char best_host[256] = "127.0.0.1";
int best_port = 80;
while (service_token) {
// Trim whitespace
while (*service_token == ' ' || *service_token == '\t') service_token++;
char *end = service_token + strlen(service_token) - 1;
while (end > service_token && (*end == ' ' || *end == '\t')) {
*end = '\0';
end--;
}
service_type_t current_type = SERVICE_NONE;
if (strncmp(service_token, "web", 3) == 0) {
current_type = SERVICE_WEB;
} else if (strncmp(service_token, "http", 4) == 0) {
current_type = SERVICE_HTTP;
} else if (strncmp(service_token, "https", 5) == 0) {
current_type = SERVICE_HTTPS;
}
if (current_type != SERVICE_NONE) {
// Check if this is better than current best
if (best_service == SERVICE_NONE ||
(current_type == SERVICE_WEB) ||
(current_type == SERVICE_HTTP && best_service != SERVICE_WEB) ||
(current_type == SERVICE_HTTPS && best_service != SERVICE_WEB && best_service != SERVICE_HTTP)) {
best_service = current_type;
parse_service_info(service_token, best_host, sizeof(best_host), &best_port);
}
}
service_token = strtok(NULL, ",");
}
free(services_copy);
if (best_service != SERVICE_NONE) {
result.client = client;
result.service_type = best_service;
strncpy(result.service_host, best_host, sizeof(result.service_host));
result.service_port = best_port;
pthread_mutex_unlock(&state->client_mutex);
return &result;
}
}
pthread_mutex_unlock(&state->client_mutex);
......@@ -138,6 +280,172 @@ static int parse_host_header(const char *request, char *hostname, size_t hostnam
return 0;
}
// Find existing tunnel for client service
static service_tunnel_t *find_service_tunnel(const char *client_id, const char *hostname, service_type_t service_type, const char *service_host, int service_port) {
pthread_mutex_lock(&tunnels_mutex);
for (int i = 0; i < active_tunnels_count; i++) {
service_tunnel_t *tunnel = &active_tunnels[i];
if (tunnel->active &&
strcmp(tunnel->client_id, client_id) == 0 &&
strcmp(tunnel->hostname, hostname) == 0 &&
tunnel->service_type == service_type &&
strcmp(tunnel->service_host, service_host) == 0 &&
tunnel->service_port == service_port) {
tunnel->last_used = time(NULL);
pthread_mutex_unlock(&tunnels_mutex);
return tunnel;
}
}
pthread_mutex_unlock(&tunnels_mutex);
return NULL;
}
// Create new tunnel to client service
static service_tunnel_t *create_service_tunnel(const char *client_id, const char *hostname, service_type_t service_type, const char *service_host, int service_port) {
pthread_mutex_lock(&tunnels_mutex);
// Find free slot
int slot = -1;
for (int i = 0; i < MAX_ACTIVE_TUNNELS; i++) {
if (!active_tunnels[i].active) {
slot = i;
break;
}
}
if (slot == -1 && active_tunnels_count < MAX_ACTIVE_TUNNELS) {
slot = active_tunnels_count++;
}
if (slot == -1) {
pthread_mutex_unlock(&tunnels_mutex);
return NULL;
}
service_tunnel_t *tunnel = &active_tunnels[slot];
memset(tunnel, 0, sizeof(service_tunnel_t));
strncpy(tunnel->client_id, client_id, sizeof(tunnel->client_id));
strncpy(tunnel->hostname, hostname, sizeof(tunnel->hostname));
tunnel->service_type = service_type;
strncpy(tunnel->service_host, service_host, sizeof(tunnel->service_host));
tunnel->service_port = service_port;
tunnel->created_at = time(NULL);
tunnel->last_used = time(NULL);
tunnel->active = true;
pthread_mutex_init(&tunnel->mutex, NULL);
pthread_mutex_unlock(&tunnels_mutex);
return tunnel;
}
// Establish connection to client service
static int establish_service_connection(service_tunnel_t *tunnel) {
pthread_mutex_lock(&tunnel->mutex);
if (tunnel->tunnel_fd >= 0) {
// Already connected
pthread_mutex_unlock(&tunnel->mutex);
return 0;
}
// Create socket
tunnel->tunnel_fd = socket(AF_INET, SOCK_STREAM, 0);
if (tunnel->tunnel_fd < 0) {
pthread_mutex_unlock(&tunnel->mutex);
return -1;
}
// Set non-blocking
fcntl(tunnel->tunnel_fd, F_SETFL, O_NONBLOCK);
// Resolve host
struct hostent *he = gethostbyname(tunnel->service_host);
if (!he) {
close(tunnel->tunnel_fd);
tunnel->tunnel_fd = -1;
pthread_mutex_unlock(&tunnel->mutex);
return -1;
}
// Connect
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(tunnel->service_port);
addr.sin_addr = *((struct in_addr *)he->h_addr);
if (connect(tunnel->tunnel_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
if (errno != EINPROGRESS) {
close(tunnel->tunnel_fd);
tunnel->tunnel_fd = -1;
pthread_mutex_unlock(&tunnel->mutex);
return -1;
}
}
// For HTTPS, establish SSL connection
if (tunnel->service_type == SERVICE_HTTPS) {
SSL_CTX *ctx = create_ssl_context();
if (!ctx) {
close(tunnel->tunnel_fd);
tunnel->tunnel_fd = -1;
pthread_mutex_unlock(&tunnel->mutex);
return -1;
}
tunnel->ssl = create_ssl_connection(ctx, tunnel->tunnel_fd, 0); // debug = 0
SSL_CTX_free(ctx);
if (!tunnel->ssl) {
close(tunnel->tunnel_fd);
tunnel->tunnel_fd = -1;
pthread_mutex_unlock(&tunnel->mutex);
return -1;
}
// Set to accept invalid certificates
SSL_set_verify(tunnel->ssl, SSL_VERIFY_NONE, NULL);
}
pthread_mutex_unlock(&tunnel->mutex);
return 0;
}
// Close tunnel
static void close_service_tunnel(service_tunnel_t *tunnel) {
pthread_mutex_lock(&tunnel->mutex);
if (tunnel->ssl) {
SSL_free(tunnel->ssl);
tunnel->ssl = NULL;
}
if (tunnel->tunnel_fd >= 0) {
close(tunnel->tunnel_fd);
tunnel->tunnel_fd = -1;
}
tunnel->active = false;
pthread_mutex_unlock(&tunnel->mutex);
}
// Cleanup expired tunnels (called periodically)
static void cleanup_expired_tunnels(void) {
time_t now = time(NULL);
const int timeout_seconds = 300; // 5 minutes
pthread_mutex_lock(&tunnels_mutex);
for (int i = 0; i < active_tunnels_count; i++) {
service_tunnel_t *tunnel = &active_tunnels[i];
if (tunnel->active && (now - tunnel->last_used) > timeout_seconds) {
printf("[WEB-PROXY] Closing expired tunnel for %s\n", tunnel->hostname);
close_service_tunnel(tunnel);
}
}
pthread_mutex_unlock(&tunnels_mutex);
}
// Send HTTP error response
static void send_http_error(int client_fd, int status_code, const char *status_text) {
const char *body_format = "<html><body><h1>%d %s</h1></body></html>";
......@@ -224,32 +532,123 @@ static int handle_proxy_request(int client_fd, wssshd_state_t *state, const wsss
printf("[WEB-PROXY] Received request for hostname: %s\n", hostname);
// Find client by hostname
client_t *client = find_client_by_hostname(hostname, state, config);
if (!client) {
printf("[WEB-PROXY] No client found for hostname: %s\n", hostname);
// Find client and service by hostname
client_service_info_t *service_info = find_client_service_by_hostname(hostname, state, config);
if (!service_info || !service_info->client) {
printf("[WEB-PROXY] No client/service found for hostname: %s\n", hostname);
send_http_error(client_fd, 404, "Not Found");
return -1;
}
printf("[WEB-PROXY] Found client: %s\n", client->client_id);
printf("[WEB-PROXY] Found client: %s, service: %s:%d\n",
service_info->client->client_id, service_info->service_host, service_info->service_port);
// Find or create tunnel
service_tunnel_t *tunnel = find_service_tunnel(service_info->client->client_id, hostname,
service_info->service_type,
service_info->service_host,
service_info->service_port);
if (!tunnel) {
tunnel = create_service_tunnel(service_info->client->client_id, hostname,
service_info->service_type,
service_info->service_host,
service_info->service_port);
if (!tunnel) {
printf("[WEB-PROXY] Failed to create tunnel for %s\n", hostname);
send_http_error(client_fd, 503, "Service Unavailable");
return -1;
}
}
// Establish connection if not already connected
if (establish_service_connection(tunnel) != 0) {
printf("[WEB-PROXY] Failed to establish connection to %s:%d\n",
service_info->service_host, service_info->service_port);
send_http_error(client_fd, 502, "Bad Gateway");
close_service_tunnel(tunnel);
return -1;
}
// For WEB service, try HTTP first, then HTTPS if it fails
if (service_info->service_type == SERVICE_WEB) {
// Try HTTP first
service_tunnel_t *http_tunnel = find_service_tunnel(service_info->client->client_id, hostname,
SERVICE_HTTP,
service_info->service_host,
80);
if (!http_tunnel) {
http_tunnel = create_service_tunnel(service_info->client->client_id, hostname,
SERVICE_HTTP,
service_info->service_host,
80);
}
// TODO: Establish tunnel to the client's web service
// For now, we'll return a simple response indicating the proxy is working
const char *response =
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/plain\r\n"
"Content-Length: 50\r\n"
"Connection: close\r\n"
"\r\n"
"Web proxy tunnel established for client: ";
if (http_tunnel && establish_service_connection(http_tunnel) == 0) {
tunnel = http_tunnel;
} else {
// Try HTTPS
service_tunnel_t *https_tunnel = find_service_tunnel(service_info->client->client_id, hostname,
SERVICE_HTTPS,
service_info->service_host,
443);
if (!https_tunnel) {
https_tunnel = create_service_tunnel(service_info->client->client_id, hostname,
SERVICE_HTTPS,
service_info->service_host,
443);
}
if (https_tunnel && establish_service_connection(https_tunnel) == 0) {
tunnel = https_tunnel;
} else {
printf("[WEB-PROXY] Failed to establish HTTP or HTTPS connection for WEB service\n");
send_http_error(client_fd, 502, "Bad Gateway");
return -1;
}
}
}
// Forward the request to the service
pthread_mutex_lock(&tunnel->mutex);
ssize_t sent;
if (tunnel->ssl) {
sent = SSL_write(tunnel->ssl, request, bytes_read);
} else {
sent = send(tunnel->tunnel_fd, request, bytes_read, 0);
}
if (sent != bytes_read) {
printf("[WEB-PROXY] Failed to forward request to service\n");
pthread_mutex_unlock(&tunnel->mutex);
send_http_error(client_fd, 502, "Bad Gateway");
return -1;
}
char response_body[512];
snprintf(response_body, sizeof(response_body), "%s%s", response, client->client_id);
// Read response from service and forward to client
char buffer[8192];
while (1) {
ssize_t response_bytes;
if (tunnel->ssl) {
response_bytes = SSL_read(tunnel->ssl, buffer, sizeof(buffer));
} else {
response_bytes = recv(tunnel->tunnel_fd, buffer, sizeof(buffer), 0);
}
send(client_fd, response_body, strlen(response_body), 0);
if (response_bytes <= 0) {
break;
}
// Close the connection for now (full tunnel implementation requires more work)
ssize_t client_sent = send(client_fd, buffer, response_bytes, 0);
if (client_sent != response_bytes) {
break;
}
}
pthread_mutex_unlock(&tunnel->mutex);
printf("[WEB-PROXY] Request handled for %s\n", hostname);
return 0;
}
......@@ -356,6 +755,14 @@ int web_proxy_start_server(const wssshd_config_t *config, wssshd_state_t *state)
return 0; // Web proxy not enabled
}
// Start cleanup thread
pthread_t cleanup_tid;
if (pthread_create(&cleanup_tid, NULL, cleanup_thread, NULL) != 0) {
perror("[WEB-PROXY] Failed to create cleanup thread");
return -1;
}
pthread_detach(cleanup_tid);
// Allocate thread arguments
proxy_thread_args_t *args = malloc(sizeof(proxy_thread_args_t));
if (!args) {
......@@ -379,6 +786,7 @@ int web_proxy_start_server(const wssshd_config_t *config, wssshd_state_t *state)
void web_proxy_stop_server(void) {
server_running = 0;
cleanup_running = 0;
// Close server socket to unblock accept()
if (server_socket >= 0) {
......@@ -399,5 +807,15 @@ void web_proxy_stop_server(void) {
proxy_connections_count = 0;
pthread_mutex_unlock(&proxy_mutex);
// Close all active tunnels
pthread_mutex_lock(&tunnels_mutex);
for (int i = 0; i < active_tunnels_count; i++) {
if (active_tunnels[i].active) {
close_service_tunnel(&active_tunnels[i]);
}
}
active_tunnels_count = 0;
pthread_mutex_unlock(&tunnels_mutex);
printf("[WEB-PROXY] Web proxy server stopping\n");
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment