livesplit_hotkey/linux/
x11_impl.rs

1use std::{
2    collections::HashMap,
3    mem::MaybeUninit,
4    os::raw::{c_int, c_uint},
5    ptr, thread,
6};
7
8use mio::{unix::SourceFd, Events, Interest, Poll, Token, Waker};
9use x11_dl::xlib::{
10    AnyKey, AnyModifier, ControlMask, Display, GrabModeAsync, KeyPress, LockMask, Mod1Mask,
11    Mod2Mask, Mod3Mask, Mod4Mask, ShiftMask, XErrorEvent, XKeyEvent, Xlib, _XDisplay,
12};
13
14use super::{Error, Hook, Message};
15use crate::{KeyCode, Modifiers, Result};
16
17unsafe fn ungrab_all(xlib: &Xlib, display: *mut Display) {
18    let screencount = (xlib.XScreenCount)(display);
19    for screen in 0..screencount {
20        let rootwindow = (xlib.XRootWindow)(display, screen);
21        (xlib.XUngrabKey)(display, AnyKey, AnyModifier, rootwindow);
22    }
23}
24
25const fn mask(x: c_uint) -> u8 {
26    if x < 256 {
27        x as u8
28    } else {
29        panic!()
30    }
31}
32
33const CAPS_LOCK: u8 = mask(LockMask);
34const NUM_LOCK: u8 = mask(Mod2Mask);
35const SCROLL_LOCK: u8 = mask(Mod3Mask);
36
37// X11 has no way of ignoring additional modifiers, so we have to register every
38// single combination of them. We are mostly only interested in the lock keys,
39// because they may be in the wrong state without you actively interacting with
40// them.
41const IGNORE_MASKS: [u8; 8] = [
42    0,
43    CAPS_LOCK,
44    NUM_LOCK,
45    NUM_LOCK | CAPS_LOCK,
46    SCROLL_LOCK,
47    SCROLL_LOCK | CAPS_LOCK,
48    SCROLL_LOCK | NUM_LOCK,
49    SCROLL_LOCK | NUM_LOCK | CAPS_LOCK,
50];
51
52unsafe fn grab_key(
53    xlib: &Xlib,
54    display: *mut Display,
55    code: c_uint,
56    modifiers: Modifiers,
57    ungrab: bool,
58) {
59    let screencount = (xlib.XScreenCount)(display);
60    for screen in 0..screencount {
61        let window = (xlib.XRootWindow)(display, screen);
62
63        let mut mod_mask = 0;
64        if modifiers.contains(Modifiers::SHIFT) {
65            mod_mask |= ShiftMask;
66        }
67        if modifiers.contains(Modifiers::CONTROL) {
68            mod_mask |= ControlMask;
69        }
70        if modifiers.contains(Modifiers::ALT) {
71            mod_mask |= Mod1Mask;
72        }
73        if modifiers.contains(Modifiers::META) {
74            mod_mask |= Mod4Mask;
75        }
76
77        for ignore_mask in IGNORE_MASKS {
78            if ungrab {
79                (xlib.XUngrabKey)(
80                    display,
81                    code as c_int,
82                    mod_mask | (ignore_mask as c_uint),
83                    window,
84                );
85            } else {
86                (xlib.XGrabKey)(
87                    display,
88                    code as c_int,
89                    mod_mask | (ignore_mask as c_uint),
90                    window,
91                    false as _,
92                    GrabModeAsync,
93                    GrabModeAsync,
94                );
95            }
96        }
97    }
98
99    // On some X11 connections it's crucial for the events to be flushed. They
100    // may otherwise stay buffered and the hotkeys don't actually work.
101    (xlib.XFlush)(display);
102}
103
104unsafe extern "C" fn handle_error(_: *mut Display, _: *mut XErrorEvent) -> c_int {
105    0
106}
107
108const fn code_for(key: KeyCode) -> Option<c_uint> {
109    match super::evdev_impl::code_for(key) {
110        Some(code) => Some(code.0 as c_uint + 8),
111        None => None,
112    }
113}
114
115const X_TOKEN: Token = Token(0);
116const PING_TOKEN: Token = Token(1);
117
118pub fn new() -> Result<Hook> {
119    unsafe {
120        let (sender, receiver) = crossbeam_channel::unbounded();
121
122        let xlib = Xlib::open().map_err(|_| Error::NoXLib)?;
123        (xlib.XSetErrorHandler)(Some(handle_error));
124
125        let display = (xlib.XOpenDisplay)(ptr::null());
126        if display.is_null() {
127            return Err(Error::OpenXServerConnection.into());
128        }
129
130        let fd = (xlib.XConnectionNumber)(display) as std::os::unix::io::RawFd;
131        let mut poll = Poll::new().map_err(|_| Error::EPoll)?;
132
133        let waker = Waker::new(poll.registry(), PING_TOKEN).map_err(|_| Error::EPoll)?;
134
135        poll.registry()
136            .register(
137                &mut SourceFd(&fd),
138                X_TOKEN,
139                Interest::READABLE | Interest::WRITABLE,
140            )
141            .map_err(|_| Error::EPoll)?;
142
143        struct XData(Xlib, *mut Display);
144        unsafe impl Send for XData {}
145        let xdata = XData(xlib, display);
146
147        let join_handle = thread::spawn(move || -> Result<()> {
148            // Force the whole XData to be moved.
149            let XData(xlib, display) = { xdata };
150
151            let mut result = Ok(());
152            let mut events = Events::with_capacity(1024);
153            let mut hotkeys = HashMap::new();
154
155            // For some reason we need to call this once for any KeyGrabs to
156            // actually do anything.
157            (xlib.XKeysymToKeycode)(display, 0);
158
159            'event_loop: loop {
160                if poll.poll(&mut events, None).is_err() {
161                    result = Err(Error::EPoll);
162                    break 'event_loop;
163                }
164
165                for mio_event in &events {
166                    if mio_event.token() == PING_TOKEN {
167                        for message in receiver.try_iter() {
168                            match message {
169                                Message::Register(key, callback, promise) => {
170                                    promise.set(if let Some(code) = code_for(key.key_code) {
171                                        if hotkeys.insert((code, key.modifiers), callback).is_some()
172                                        {
173                                            Err(crate::Error::AlreadyRegistered)
174                                        } else {
175                                            grab_key(&xlib, display, code, key.modifiers, false);
176                                            Ok(())
177                                        }
178                                    } else {
179                                        Ok(())
180                                    });
181                                }
182                                Message::Unregister(key, promise) => {
183                                    let res = if let Some(code) = code_for(key.key_code) {
184                                        let res = hotkeys
185                                            .remove(&(code, key.modifiers))
186                                            .map(drop)
187                                            .ok_or(crate::Error::NotRegistered);
188                                        if res.is_ok() {
189                                            grab_key(&xlib, display, code, key.modifiers, true);
190                                        }
191                                        res
192                                    } else {
193                                        Ok(())
194                                    };
195                                    promise.set(res);
196                                }
197                                Message::Resolve(key_code, promise) => {
198                                    promise.set(resolve(&xlib, display, key_code))
199                                }
200                                Message::End => {
201                                    break 'event_loop;
202                                }
203                            }
204                        }
205                    } else if mio_event.token() == X_TOKEN {
206                        while (xlib.XPending)(display) != 0 {
207                            let mut event = MaybeUninit::uninit();
208                            let err_code = (xlib.XNextEvent)(display, event.as_mut_ptr());
209                            if err_code == 0 {
210                                let event = event.assume_init();
211                                if event.get_type() == KeyPress {
212                                    let event: &XKeyEvent = event.as_ref();
213
214                                    let mut modifiers = Modifiers::empty();
215                                    if event.state & ShiftMask != 0 {
216                                        modifiers.insert(Modifiers::SHIFT);
217                                    }
218                                    if event.state & ControlMask != 0 {
219                                        modifiers.insert(Modifiers::CONTROL);
220                                    }
221                                    if event.state & Mod1Mask != 0 {
222                                        modifiers.insert(Modifiers::ALT);
223                                    }
224                                    if event.state & Mod4Mask != 0 {
225                                        modifiers.insert(Modifiers::META);
226                                    }
227
228                                    if let Some(callback) =
229                                        hotkeys.get_mut(&(event.keycode, modifiers))
230                                    {
231                                        callback();
232                                    }
233                                }
234                            }
235                        }
236                    }
237                }
238            }
239
240            ungrab_all(&xlib, display);
241
242            (xlib.XCloseDisplay)(display);
243
244            result.map_err(Into::into)
245        });
246
247        Ok(Hook {
248            sender,
249            waker,
250            join_handle: Some(join_handle),
251        })
252    }
253}
254
255pub(super) fn resolve(xlib: &Xlib, display: *mut _XDisplay, key_code: KeyCode) -> Option<char> {
256    let key_sym = unsafe { (xlib.XKeycodeToKeysym)(display, code_for(key_code)? as _, 0) };
257    if key_sym == 0 {
258        return None;
259    }
260    let code_point = keysym_to_utf32(key_sym as _);
261    if code_point == 0 {
262        return None;
263    }
264    char::from_u32(code_point)
265}
266
267// Based on this public domain code:
268// https://github.com/xkbcommon/libxkbcommon/blob/9af1f9f2cb3a7895f6ed7a130ffd3da1006dcc7b/src/keysym-utf.c
269fn keysym_to_utf32(keysym: u64) -> u32 {
270    const KP_SPACE: u64 = 0xff80;
271    const KP_TAB: u64 = 0xff89;
272    const KP_ENTER: u64 = 0xff8d;
273    const KP_EQUAL: u64 = 0xffbd;
274    const KP_MULTIPLY: u64 = 0xffaa;
275    const SPACE: u64 = 0x0020;
276    const BACKSPACE: u64 = 0xff08;
277    const CLEAR: u64 = 0xff0b;
278    const RETURN: u64 = 0xff0d;
279    const ESCAPE: u64 = 0xff1b;
280    const DELETE: u64 = 0xffff;
281    const KP_9: u64 = 0xffb9;
282
283    const NO_KEYSYM_UNICODE_CONVERSION: u32 = 0;
284
285    /// Offset to use when converting a Unicode code point to a keysym
286    const XKB_KEYSYM_UNICODE_OFFSET: u64 = 0x01000000;
287    /// Maximum Unicode keysym, correspoding to the maximum Unicode code point
288    const XKB_KEYSYM_UNICODE_MAX: u64 = 0x0110ffff;
289
290    // first check for Latin-1 characters (1:1 mapping)
291    if matches!(keysym, 0x0020..=0x007e | 0x00a0..=0x00ff) {
292        return keysym as u32;
293    }
294
295    // patch encoding botch
296    if keysym == KP_SPACE {
297        return (SPACE & 0x7f) as u32;
298    }
299
300    // special keysyms
301    if matches!(
302        keysym,
303        BACKSPACE..=CLEAR |
304        KP_MULTIPLY..=KP_9 |
305        RETURN | ESCAPE | DELETE | KP_TAB | KP_ENTER | KP_EQUAL
306    ) {
307        return (keysym & 0x7f) as u32;
308    }
309
310    // also check for directly encoded Unicode codepoints
311
312    // Exclude surrogates: they are invalid in UTF-32.
313    // See https://www.unicode.org/versions/Unicode15.0.0/ch03.pdf#G28875
314    // for further details.
315    if matches!(keysym, 0x0100d800..=0x0100dfff) {
316        return NO_KEYSYM_UNICODE_CONVERSION;
317    }
318
319    // In theory, this is supposed to start from 0x100100, such that the ASCII
320    // range, which is already covered by 0x00-0xff, can't be encoded in two
321    // ways. However, changing this after a couple of decades probably won't
322    // go well, so it stays as it is.
323    if matches!(keysym, XKB_KEYSYM_UNICODE_OFFSET..=XKB_KEYSYM_UNICODE_MAX) {
324        return (keysym - XKB_KEYSYM_UNICODE_OFFSET) as u32;
325    }
326
327    match keysym {
328        0x01a1 => 0x0104, // Aogonek Ą LATIN CAPITAL LETTER A WITH OGONEK
329        0x01a2 => 0x02d8, // breve ˘ BREVE
330        0x01a3 => 0x0141, // Lstroke Ł LATIN CAPITAL LETTER L WITH STROKE
331        0x01a5 => 0x013d, // Lcaron Ľ LATIN CAPITAL LETTER L WITH CARON
332        0x01a6 => 0x015a, // Sacute Ś LATIN CAPITAL LETTER S WITH ACUTE
333        0x01a9 => 0x0160, // Scaron Š LATIN CAPITAL LETTER S WITH CARON
334        0x01aa => 0x015e, // Scedilla Ş LATIN CAPITAL LETTER S WITH CEDILLA
335        0x01ab => 0x0164, // Tcaron Ť LATIN CAPITAL LETTER T WITH CARON
336        0x01ac => 0x0179, // Zacute Ź LATIN CAPITAL LETTER Z WITH ACUTE
337        0x01ae => 0x017d, // Zcaron Ž LATIN CAPITAL LETTER Z WITH CARON
338        0x01af => 0x017b, // Zabovedot Ż LATIN CAPITAL LETTER Z WITH DOT ABOVE
339        0x01b1 => 0x0105, // aogonek ą LATIN SMALL LETTER A WITH OGONEK
340        0x01b2 => 0x02db, // ogonek ˛ OGONEK
341        0x01b3 => 0x0142, // lstroke ł LATIN SMALL LETTER L WITH STROKE
342        0x01b5 => 0x013e, // lcaron ľ LATIN SMALL LETTER L WITH CARON
343        0x01b6 => 0x015b, // sacute ś LATIN SMALL LETTER S WITH ACUTE
344        0x01b7 => 0x02c7, // caron ˇ CARON
345        0x01b9 => 0x0161, // scaron š LATIN SMALL LETTER S WITH CARON
346        0x01ba => 0x015f, // scedilla ş LATIN SMALL LETTER S WITH CEDILLA
347        0x01bb => 0x0165, // tcaron ť LATIN SMALL LETTER T WITH CARON
348        0x01bc => 0x017a, // zacute ź LATIN SMALL LETTER Z WITH ACUTE
349        0x01bd => 0x02dd, // doubleacute ˝ DOUBLE ACUTE ACCENT
350        0x01be => 0x017e, // zcaron ž LATIN SMALL LETTER Z WITH CARON
351        0x01bf => 0x017c, // zabovedot ż LATIN SMALL LETTER Z WITH DOT ABOVE
352        0x01c0 => 0x0154, // Racute Ŕ LATIN CAPITAL LETTER R WITH ACUTE
353        0x01c3 => 0x0102, // Abreve Ă LATIN CAPITAL LETTER A WITH BREVE
354        0x01c5 => 0x0139, // Lacute Ĺ LATIN CAPITAL LETTER L WITH ACUTE
355        0x01c6 => 0x0106, // Cacute Ć LATIN CAPITAL LETTER C WITH ACUTE
356        0x01c8 => 0x010c, // Ccaron Č LATIN CAPITAL LETTER C WITH CARON
357        0x01ca => 0x0118, // Eogonek Ę LATIN CAPITAL LETTER E WITH OGONEK
358        0x01cc => 0x011a, // Ecaron Ě LATIN CAPITAL LETTER E WITH CARON
359        0x01cf => 0x010e, // Dcaron Ď LATIN CAPITAL LETTER D WITH CARON
360        0x01d0 => 0x0110, // Dstroke Đ LATIN CAPITAL LETTER D WITH STROKE
361        0x01d1 => 0x0143, // Nacute Ń LATIN CAPITAL LETTER N WITH ACUTE
362        0x01d2 => 0x0147, // Ncaron Ň LATIN CAPITAL LETTER N WITH CARON
363        0x01d5 => 0x0150, // Odoubleacute Ő LATIN CAPITAL LETTER O WITH DOUBLE ACUTE
364        0x01d8 => 0x0158, // Rcaron Ř LATIN CAPITAL LETTER R WITH CARON
365        0x01d9 => 0x016e, // Uring Ů LATIN CAPITAL LETTER U WITH RING ABOVE
366        0x01db => 0x0170, // Udoubleacute Ű LATIN CAPITAL LETTER U WITH DOUBLE ACUTE
367        0x01de => 0x0162, // Tcedilla Ţ LATIN CAPITAL LETTER T WITH CEDILLA
368        0x01e0 => 0x0155, // racute ŕ LATIN SMALL LETTER R WITH ACUTE
369        0x01e3 => 0x0103, // abreve ă LATIN SMALL LETTER A WITH BREVE
370        0x01e5 => 0x013a, // lacute ĺ LATIN SMALL LETTER L WITH ACUTE
371        0x01e6 => 0x0107, // cacute ć LATIN SMALL LETTER C WITH ACUTE
372        0x01e8 => 0x010d, // ccaron č LATIN SMALL LETTER C WITH CARON
373        0x01ea => 0x0119, // eogonek ę LATIN SMALL LETTER E WITH OGONEK
374        0x01ec => 0x011b, // ecaron ě LATIN SMALL LETTER E WITH CARON
375        0x01ef => 0x010f, // dcaron ď LATIN SMALL LETTER D WITH CARON
376        0x01f0 => 0x0111, // dstroke đ LATIN SMALL LETTER D WITH STROKE
377        0x01f1 => 0x0144, // nacute ń LATIN SMALL LETTER N WITH ACUTE
378        0x01f2 => 0x0148, // ncaron ň LATIN SMALL LETTER N WITH CARON
379        0x01f5 => 0x0151, // odoubleacute ő LATIN SMALL LETTER O WITH DOUBLE ACUTE
380        0x01f8 => 0x0159, // rcaron ř LATIN SMALL LETTER R WITH CARON
381        0x01f9 => 0x016f, // uring ů LATIN SMALL LETTER U WITH RING ABOVE
382        0x01fb => 0x0171, // udoubleacute ű LATIN SMALL LETTER U WITH DOUBLE ACUTE
383        0x01fe => 0x0163, // tcedilla ţ LATIN SMALL LETTER T WITH CEDILLA
384        0x01ff => 0x02d9, // abovedot ˙ DOT ABOVE
385        0x02a1 => 0x0126, // Hstroke Ħ LATIN CAPITAL LETTER H WITH STROKE
386        0x02a6 => 0x0124, // Hcircumflex Ĥ LATIN CAPITAL LETTER H WITH CIRCUMFLEX
387        0x02a9 => 0x0130, // Iabovedot İ LATIN CAPITAL LETTER I WITH DOT ABOVE
388        0x02ab => 0x011e, // Gbreve Ğ LATIN CAPITAL LETTER G WITH BREVE
389        0x02ac => 0x0134, // Jcircumflex Ĵ LATIN CAPITAL LETTER J WITH CIRCUMFLEX
390        0x02b1 => 0x0127, // hstroke ħ LATIN SMALL LETTER H WITH STROKE
391        0x02b6 => 0x0125, // hcircumflex ĥ LATIN SMALL LETTER H WITH CIRCUMFLEX
392        0x02b9 => 0x0131, // idotless ı LATIN SMALL LETTER DOTLESS I
393        0x02bb => 0x011f, // gbreve ğ LATIN SMALL LETTER G WITH BREVE
394        0x02bc => 0x0135, // jcircumflex ĵ LATIN SMALL LETTER J WITH CIRCUMFLEX
395        0x02c5 => 0x010a, // Cabovedot Ċ LATIN CAPITAL LETTER C WITH DOT ABOVE
396        0x02c6 => 0x0108, // Ccircumflex Ĉ LATIN CAPITAL LETTER C WITH CIRCUMFLEX
397        0x02d5 => 0x0120, // Gabovedot Ġ LATIN CAPITAL LETTER G WITH DOT ABOVE
398        0x02d8 => 0x011c, // Gcircumflex Ĝ LATIN CAPITAL LETTER G WITH CIRCUMFLEX
399        0x02dd => 0x016c, // Ubreve Ŭ LATIN CAPITAL LETTER U WITH BREVE
400        0x02de => 0x015c, // Scircumflex Ŝ LATIN CAPITAL LETTER S WITH CIRCUMFLEX
401        0x02e5 => 0x010b, // cabovedot ċ LATIN SMALL LETTER C WITH DOT ABOVE
402        0x02e6 => 0x0109, // ccircumflex ĉ LATIN SMALL LETTER C WITH CIRCUMFLEX
403        0x02f5 => 0x0121, // gabovedot ġ LATIN SMALL LETTER G WITH DOT ABOVE
404        0x02f8 => 0x011d, // gcircumflex ĝ LATIN SMALL LETTER G WITH CIRCUMFLEX
405        0x02fd => 0x016d, // ubreve ŭ LATIN SMALL LETTER U WITH BREVE
406        0x02fe => 0x015d, // scircumflex ŝ LATIN SMALL LETTER S WITH CIRCUMFLEX
407        0x03a2 => 0x0138, // kra ĸ LATIN SMALL LETTER KRA
408        0x03a3 => 0x0156, // Rcedilla Ŗ LATIN CAPITAL LETTER R WITH CEDILLA
409        0x03a5 => 0x0128, // Itilde Ĩ LATIN CAPITAL LETTER I WITH TILDE
410        0x03a6 => 0x013b, // Lcedilla Ļ LATIN CAPITAL LETTER L WITH CEDILLA
411        0x03aa => 0x0112, // Emacron Ē LATIN CAPITAL LETTER E WITH MACRON
412        0x03ab => 0x0122, // Gcedilla Ģ LATIN CAPITAL LETTER G WITH CEDILLA
413        0x03ac => 0x0166, // Tslash Ŧ LATIN CAPITAL LETTER T WITH STROKE
414        0x03b3 => 0x0157, // rcedilla ŗ LATIN SMALL LETTER R WITH CEDILLA
415        0x03b5 => 0x0129, // itilde ĩ LATIN SMALL LETTER I WITH TILDE
416        0x03b6 => 0x013c, // lcedilla ļ LATIN SMALL LETTER L WITH CEDILLA
417        0x03ba => 0x0113, // emacron ē LATIN SMALL LETTER E WITH MACRON
418        0x03bb => 0x0123, // gcedilla ģ LATIN SMALL LETTER G WITH CEDILLA
419        0x03bc => 0x0167, // tslash ŧ LATIN SMALL LETTER T WITH STROKE
420        0x03bd => 0x014a, // ENG Ŋ LATIN CAPITAL LETTER ENG
421        0x03bf => 0x014b, // eng ŋ LATIN SMALL LETTER ENG
422        0x03c0 => 0x0100, // Amacron Ā LATIN CAPITAL LETTER A WITH MACRON
423        0x03c7 => 0x012e, // Iogonek Į LATIN CAPITAL LETTER I WITH OGONEK
424        0x03cc => 0x0116, // Eabovedot Ė LATIN CAPITAL LETTER E WITH DOT ABOVE
425        0x03cf => 0x012a, // Imacron Ī LATIN CAPITAL LETTER I WITH MACRON
426        0x03d1 => 0x0145, // Ncedilla Ņ LATIN CAPITAL LETTER N WITH CEDILLA
427        0x03d2 => 0x014c, // Omacron Ō LATIN CAPITAL LETTER O WITH MACRON
428        0x03d3 => 0x0136, // Kcedilla Ķ LATIN CAPITAL LETTER K WITH CEDILLA
429        0x03d9 => 0x0172, // Uogonek Ų LATIN CAPITAL LETTER U WITH OGONEK
430        0x03dd => 0x0168, // Utilde Ũ LATIN CAPITAL LETTER U WITH TILDE
431        0x03de => 0x016a, // Umacron Ū LATIN CAPITAL LETTER U WITH MACRON
432        0x03e0 => 0x0101, // amacron ā LATIN SMALL LETTER A WITH MACRON
433        0x03e7 => 0x012f, // iogonek į LATIN SMALL LETTER I WITH OGONEK
434        0x03ec => 0x0117, // eabovedot ė LATIN SMALL LETTER E WITH DOT ABOVE
435        0x03ef => 0x012b, // imacron ī LATIN SMALL LETTER I WITH MACRON
436        0x03f1 => 0x0146, // ncedilla ņ LATIN SMALL LETTER N WITH CEDILLA
437        0x03f2 => 0x014d, // omacron ō LATIN SMALL LETTER O WITH MACRON
438        0x03f3 => 0x0137, // kcedilla ķ LATIN SMALL LETTER K WITH CEDILLA
439        0x03f9 => 0x0173, // uogonek ų LATIN SMALL LETTER U WITH OGONEK
440        0x03fd => 0x0169, // utilde ũ LATIN SMALL LETTER U WITH TILDE
441        0x03fe => 0x016b, // umacron ū LATIN SMALL LETTER U WITH MACRON
442        0x047e => 0x203e, // overline ‾ OVERLINE
443        0x04a1 => 0x3002, // kana_fullstop 。 IDEOGRAPHIC FULL STOP
444        0x04a2 => 0x300c, // kana_openingbracket 「 LEFT CORNER BRACKET
445        0x04a3 => 0x300d, // kana_closingbracket 」 RIGHT CORNER BRACKET
446        0x04a4 => 0x3001, // kana_comma 、 IDEOGRAPHIC COMMA
447        0x04a5 => 0x30fb, // kana_conjunctive ・ KATAKANA MIDDLE DOT
448        0x04a6 => 0x30f2, // kana_WO ヲ KATAKANA LETTER WO
449        0x04a7 => 0x30a1, // kana_a ァ KATAKANA LETTER SMALL A
450        0x04a8 => 0x30a3, // kana_i ィ KATAKANA LETTER SMALL I
451        0x04a9 => 0x30a5, // kana_u ゥ KATAKANA LETTER SMALL U
452        0x04aa => 0x30a7, // kana_e ェ KATAKANA LETTER SMALL E
453        0x04ab => 0x30a9, // kana_o ォ KATAKANA LETTER SMALL O
454        0x04ac => 0x30e3, // kana_ya ャ KATAKANA LETTER SMALL YA
455        0x04ad => 0x30e5, // kana_yu ュ KATAKANA LETTER SMALL YU
456        0x04ae => 0x30e7, // kana_yo ョ KATAKANA LETTER SMALL YO
457        0x04af => 0x30c3, // kana_tsu ッ KATAKANA LETTER SMALL TU
458        0x04b0 => 0x30fc, // prolongedsound ー KATAKANA-HIRAGANA PROLONGED SOUND MARK
459        0x04b1 => 0x30a2, // kana_A ア KATAKANA LETTER A
460        0x04b2 => 0x30a4, // kana_I イ KATAKANA LETTER I
461        0x04b3 => 0x30a6, // kana_U ウ KATAKANA LETTER U
462        0x04b4 => 0x30a8, // kana_E エ KATAKANA LETTER E
463        0x04b5 => 0x30aa, // kana_O オ KATAKANA LETTER O
464        0x04b6 => 0x30ab, // kana_KA カ KATAKANA LETTER KA
465        0x04b7 => 0x30ad, // kana_KI キ KATAKANA LETTER KI
466        0x04b8 => 0x30af, // kana_KU ク KATAKANA LETTER KU
467        0x04b9 => 0x30b1, // kana_KE ケ KATAKANA LETTER KE
468        0x04ba => 0x30b3, // kana_KO コ KATAKANA LETTER KO
469        0x04bb => 0x30b5, // kana_SA サ KATAKANA LETTER SA
470        0x04bc => 0x30b7, // kana_SHI シ KATAKANA LETTER SI
471        0x04bd => 0x30b9, // kana_SU ス KATAKANA LETTER SU
472        0x04be => 0x30bb, // kana_SE セ KATAKANA LETTER SE
473        0x04bf => 0x30bd, // kana_SO ソ KATAKANA LETTER SO
474        0x04c0 => 0x30bf, // kana_TA タ KATAKANA LETTER TA
475        0x04c1 => 0x30c1, // kana_CHI チ KATAKANA LETTER TI
476        0x04c2 => 0x30c4, // kana_TSU ツ KATAKANA LETTER TU
477        0x04c3 => 0x30c6, // kana_TE テ KATAKANA LETTER TE
478        0x04c4 => 0x30c8, // kana_TO ト KATAKANA LETTER TO
479        0x04c5 => 0x30ca, // kana_NA ナ KATAKANA LETTER NA
480        0x04c6 => 0x30cb, // kana_NI ニ KATAKANA LETTER NI
481        0x04c7 => 0x30cc, // kana_NU ヌ KATAKANA LETTER NU
482        0x04c8 => 0x30cd, // kana_NE ネ KATAKANA LETTER NE
483        0x04c9 => 0x30ce, // kana_NO ノ KATAKANA LETTER NO
484        0x04ca => 0x30cf, // kana_HA ハ KATAKANA LETTER HA
485        0x04cb => 0x30d2, // kana_HI ヒ KATAKANA LETTER HI
486        0x04cc => 0x30d5, // kana_FU フ KATAKANA LETTER HU
487        0x04cd => 0x30d8, // kana_HE ヘ KATAKANA LETTER HE
488        0x04ce => 0x30db, // kana_HO ホ KATAKANA LETTER HO
489        0x04cf => 0x30de, // kana_MA マ KATAKANA LETTER MA
490        0x04d0 => 0x30df, // kana_MI ミ KATAKANA LETTER MI
491        0x04d1 => 0x30e0, // kana_MU ム KATAKANA LETTER MU
492        0x04d2 => 0x30e1, // kana_ME メ KATAKANA LETTER ME
493        0x04d3 => 0x30e2, // kana_MO モ KATAKANA LETTER MO
494        0x04d4 => 0x30e4, // kana_YA ヤ KATAKANA LETTER YA
495        0x04d5 => 0x30e6, // kana_YU ユ KATAKANA LETTER YU
496        0x04d6 => 0x30e8, // kana_YO ヨ KATAKANA LETTER YO
497        0x04d7 => 0x30e9, // kana_RA ラ KATAKANA LETTER RA
498        0x04d8 => 0x30ea, // kana_RI リ KATAKANA LETTER RI
499        0x04d9 => 0x30eb, // kana_RU ル KATAKANA LETTER RU
500        0x04da => 0x30ec, // kana_RE レ KATAKANA LETTER RE
501        0x04db => 0x30ed, // kana_RO ロ KATAKANA LETTER RO
502        0x04dc => 0x30ef, // kana_WA ワ KATAKANA LETTER WA
503        0x04dd => 0x30f3, // kana_N ン KATAKANA LETTER N
504        0x04de => 0x309b, // voicedsound ゛ KATAKANA-HIRAGANA VOICED SOUND MARK
505        0x04df => 0x309c, // semivoicedsound ゜ KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK
506        0x05ac => 0x060c, // Arabic_comma ، ARABIC COMMA
507        0x05bb => 0x061b, // Arabic_semicolon ؛ ARABIC SEMICOLON
508        0x05bf => 0x061f, // Arabic_question_mark ؟ ARABIC QUESTION MARK
509        0x05c1 => 0x0621, // Arabic_hamza ء ARABIC LETTER HAMZA
510        0x05c2 => 0x0622, // Arabic_maddaonalef آ ARABIC LETTER ALEF WITH MADDA ABOVE
511        0x05c3 => 0x0623, // Arabic_hamzaonalef أ ARABIC LETTER ALEF WITH HAMZA ABOVE
512        0x05c4 => 0x0624, // Arabic_hamzaonwaw ؤ ARABIC LETTER WAW WITH HAMZA ABOVE
513        0x05c5 => 0x0625, // Arabic_hamzaunderalef إ ARABIC LETTER ALEF WITH HAMZA BELOW
514        0x05c6 => 0x0626, // Arabic_hamzaonyeh ئ ARABIC LETTER YEH WITH HAMZA ABOVE
515        0x05c7 => 0x0627, // Arabic_alef ا ARABIC LETTER ALEF
516        0x05c8 => 0x0628, // Arabic_beh ب ARABIC LETTER BEH
517        0x05c9 => 0x0629, // Arabic_tehmarbuta ة ARABIC LETTER TEH MARBUTA
518        0x05ca => 0x062a, // Arabic_teh ت ARABIC LETTER TEH
519        0x05cb => 0x062b, // Arabic_theh ث ARABIC LETTER THEH
520        0x05cc => 0x062c, // Arabic_jeem ج ARABIC LETTER JEEM
521        0x05cd => 0x062d, // Arabic_hah ح ARABIC LETTER HAH
522        0x05ce => 0x062e, // Arabic_khah خ ARABIC LETTER KHAH
523        0x05cf => 0x062f, // Arabic_dal د ARABIC LETTER DAL
524        0x05d0 => 0x0630, // Arabic_thal ذ ARABIC LETTER THAL
525        0x05d1 => 0x0631, // Arabic_ra ر ARABIC LETTER REH
526        0x05d2 => 0x0632, // Arabic_zain ز ARABIC LETTER ZAIN
527        0x05d3 => 0x0633, // Arabic_seen س ARABIC LETTER SEEN
528        0x05d4 => 0x0634, // Arabic_sheen ش ARABIC LETTER SHEEN
529        0x05d5 => 0x0635, // Arabic_sad ص ARABIC LETTER SAD
530        0x05d6 => 0x0636, // Arabic_dad ض ARABIC LETTER DAD
531        0x05d7 => 0x0637, // Arabic_tah ط ARABIC LETTER TAH
532        0x05d8 => 0x0638, // Arabic_zah ظ ARABIC LETTER ZAH
533        0x05d9 => 0x0639, // Arabic_ain ع ARABIC LETTER AIN
534        0x05da => 0x063a, // Arabic_ghain غ ARABIC LETTER GHAIN
535        0x05e0 => 0x0640, // Arabic_tatweel ـ ARABIC TATWEEL
536        0x05e1 => 0x0641, // Arabic_feh ف ARABIC LETTER FEH
537        0x05e2 => 0x0642, // Arabic_qaf ق ARABIC LETTER QAF
538        0x05e3 => 0x0643, // Arabic_kaf ك ARABIC LETTER KAF
539        0x05e4 => 0x0644, // Arabic_lam ل ARABIC LETTER LAM
540        0x05e5 => 0x0645, // Arabic_meem م ARABIC LETTER MEEM
541        0x05e6 => 0x0646, // Arabic_noon ن ARABIC LETTER NOON
542        0x05e7 => 0x0647, // Arabic_ha ه ARABIC LETTER HEH
543        0x05e8 => 0x0648, // Arabic_waw و ARABIC LETTER WAW
544        0x05e9 => 0x0649, // Arabic_alefmaksura ى ARABIC LETTER ALEF MAKSURA
545        0x05ea => 0x064a, // Arabic_yeh ي ARABIC LETTER YEH
546        0x05eb => 0x064b, // Arabic_fathatan ً ARABIC FATHATAN
547        0x05ec => 0x064c, // Arabic_dammatan ٌ ARABIC DAMMATAN
548        0x05ed => 0x064d, // Arabic_kasratan ٍ ARABIC KASRATAN
549        0x05ee => 0x064e, // Arabic_fatha َ ARABIC FATHA
550        0x05ef => 0x064f, // Arabic_damma ُ ARABIC DAMMA
551        0x05f0 => 0x0650, // Arabic_kasra ِ ARABIC KASRA
552        0x05f1 => 0x0651, // Arabic_shadda ّ ARABIC SHADDA
553        0x05f2 => 0x0652, // Arabic_sukun ْ ARABIC SUKUN
554        0x06a1 => 0x0452, // Serbian_dje ђ CYRILLIC SMALL LETTER DJE
555        0x06a2 => 0x0453, // Macedonia_gje ѓ CYRILLIC SMALL LETTER GJE
556        0x06a3 => 0x0451, // Cyrillic_io ё CYRILLIC SMALL LETTER IO
557        0x06a4 => 0x0454, // Ukrainian_ie є CYRILLIC SMALL LETTER UKRAINIAN IE
558        0x06a5 => 0x0455, // Macedonia_dse ѕ CYRILLIC SMALL LETTER DZE
559        0x06a6 => 0x0456, // Ukrainian_i і CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I
560        0x06a7 => 0x0457, // Ukrainian_yi ї CYRILLIC SMALL LETTER YI
561        0x06a8 => 0x0458, // Cyrillic_je ј CYRILLIC SMALL LETTER JE
562        0x06a9 => 0x0459, // Cyrillic_lje љ CYRILLIC SMALL LETTER LJE
563        0x06aa => 0x045a, // Cyrillic_nje њ CYRILLIC SMALL LETTER NJE
564        0x06ab => 0x045b, // Serbian_tshe ћ CYRILLIC SMALL LETTER TSHE
565        0x06ac => 0x045c, // Macedonia_kje ќ CYRILLIC SMALL LETTER KJE
566        0x06ad => 0x0491, // Ukrainian_ghe_with_upturn ґ CYRILLIC SMALL LETTER GHE WITH UPTURN
567        0x06ae => 0x045e, // Byelorussian_shortu ў CYRILLIC SMALL LETTER SHORT U
568        0x06af => 0x045f, // Cyrillic_dzhe џ CYRILLIC SMALL LETTER DZHE
569        0x06b0 => 0x2116, // numerosign № NUMERO SIGN
570        0x06b1 => 0x0402, // Serbian_DJE Ђ CYRILLIC CAPITAL LETTER DJE
571        0x06b2 => 0x0403, // Macedonia_GJE Ѓ CYRILLIC CAPITAL LETTER GJE
572        0x06b3 => 0x0401, // Cyrillic_IO Ё CYRILLIC CAPITAL LETTER IO
573        0x06b4 => 0x0404, // Ukrainian_IE Є CYRILLIC CAPITAL LETTER UKRAINIAN IE
574        0x06b5 => 0x0405, // Macedonia_DSE Ѕ CYRILLIC CAPITAL LETTER DZE
575        0x06b6 => 0x0406, // Ukrainian_I І CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I
576        0x06b7 => 0x0407, // Ukrainian_YI Ї CYRILLIC CAPITAL LETTER YI
577        0x06b8 => 0x0408, // Cyrillic_JE Ј CYRILLIC CAPITAL LETTER JE
578        0x06b9 => 0x0409, // Cyrillic_LJE Љ CYRILLIC CAPITAL LETTER LJE
579        0x06ba => 0x040a, // Cyrillic_NJE Њ CYRILLIC CAPITAL LETTER NJE
580        0x06bb => 0x040b, // Serbian_TSHE Ћ CYRILLIC CAPITAL LETTER TSHE
581        0x06bc => 0x040c, // Macedonia_KJE Ќ CYRILLIC CAPITAL LETTER KJE
582        0x06bd => 0x0490, // Ukrainian_GHE_WITH_UPTURN Ґ CYRILLIC CAPITAL LETTER GHE WITH UPTURN
583        0x06be => 0x040e, // Byelorussian_SHORTU Ў CYRILLIC CAPITAL LETTER SHORT U
584        0x06bf => 0x040f, // Cyrillic_DZHE Џ CYRILLIC CAPITAL LETTER DZHE
585        0x06c0 => 0x044e, // Cyrillic_yu ю CYRILLIC SMALL LETTER YU
586        0x06c1 => 0x0430, // Cyrillic_a а CYRILLIC SMALL LETTER A
587        0x06c2 => 0x0431, // Cyrillic_be б CYRILLIC SMALL LETTER BE
588        0x06c3 => 0x0446, // Cyrillic_tse ц CYRILLIC SMALL LETTER TSE
589        0x06c4 => 0x0434, // Cyrillic_de д CYRILLIC SMALL LETTER DE
590        0x06c5 => 0x0435, // Cyrillic_ie е CYRILLIC SMALL LETTER IE
591        0x06c6 => 0x0444, // Cyrillic_ef ф CYRILLIC SMALL LETTER EF
592        0x06c7 => 0x0433, // Cyrillic_ghe г CYRILLIC SMALL LETTER GHE
593        0x06c8 => 0x0445, // Cyrillic_ha х CYRILLIC SMALL LETTER HA
594        0x06c9 => 0x0438, // Cyrillic_i и CYRILLIC SMALL LETTER I
595        0x06ca => 0x0439, // Cyrillic_shorti й CYRILLIC SMALL LETTER SHORT I
596        0x06cb => 0x043a, // Cyrillic_ka к CYRILLIC SMALL LETTER KA
597        0x06cc => 0x043b, // Cyrillic_el л CYRILLIC SMALL LETTER EL
598        0x06cd => 0x043c, // Cyrillic_em м CYRILLIC SMALL LETTER EM
599        0x06ce => 0x043d, // Cyrillic_en н CYRILLIC SMALL LETTER EN
600        0x06cf => 0x043e, // Cyrillic_o о CYRILLIC SMALL LETTER O
601        0x06d0 => 0x043f, // Cyrillic_pe п CYRILLIC SMALL LETTER PE
602        0x06d1 => 0x044f, // Cyrillic_ya я CYRILLIC SMALL LETTER YA
603        0x06d2 => 0x0440, // Cyrillic_er р CYRILLIC SMALL LETTER ER
604        0x06d3 => 0x0441, // Cyrillic_es с CYRILLIC SMALL LETTER ES
605        0x06d4 => 0x0442, // Cyrillic_te т CYRILLIC SMALL LETTER TE
606        0x06d5 => 0x0443, // Cyrillic_u у CYRILLIC SMALL LETTER U
607        0x06d6 => 0x0436, // Cyrillic_zhe ж CYRILLIC SMALL LETTER ZHE
608        0x06d7 => 0x0432, // Cyrillic_ve в CYRILLIC SMALL LETTER VE
609        0x06d8 => 0x044c, // Cyrillic_softsign ь CYRILLIC SMALL LETTER SOFT SIGN
610        0x06d9 => 0x044b, // Cyrillic_yeru ы CYRILLIC SMALL LETTER YERU
611        0x06da => 0x0437, // Cyrillic_ze з CYRILLIC SMALL LETTER ZE
612        0x06db => 0x0448, // Cyrillic_sha ш CYRILLIC SMALL LETTER SHA
613        0x06dc => 0x044d, // Cyrillic_e э CYRILLIC SMALL LETTER E
614        0x06dd => 0x0449, // Cyrillic_shcha щ CYRILLIC SMALL LETTER SHCHA
615        0x06de => 0x0447, // Cyrillic_che ч CYRILLIC SMALL LETTER CHE
616        0x06df => 0x044a, // Cyrillic_hardsign ъ CYRILLIC SMALL LETTER HARD SIGN
617        0x06e0 => 0x042e, // Cyrillic_YU Ю CYRILLIC CAPITAL LETTER YU
618        0x06e1 => 0x0410, // Cyrillic_A А CYRILLIC CAPITAL LETTER A
619        0x06e2 => 0x0411, // Cyrillic_BE Б CYRILLIC CAPITAL LETTER BE
620        0x06e3 => 0x0426, // Cyrillic_TSE Ц CYRILLIC CAPITAL LETTER TSE
621        0x06e4 => 0x0414, // Cyrillic_DE Д CYRILLIC CAPITAL LETTER DE
622        0x06e5 => 0x0415, // Cyrillic_IE Е CYRILLIC CAPITAL LETTER IE
623        0x06e6 => 0x0424, // Cyrillic_EF Ф CYRILLIC CAPITAL LETTER EF
624        0x06e7 => 0x0413, // Cyrillic_GHE Г CYRILLIC CAPITAL LETTER GHE
625        0x06e8 => 0x0425, // Cyrillic_HA Х CYRILLIC CAPITAL LETTER HA
626        0x06e9 => 0x0418, // Cyrillic_I И CYRILLIC CAPITAL LETTER I
627        0x06ea => 0x0419, // Cyrillic_SHORTI Й CYRILLIC CAPITAL LETTER SHORT I
628        0x06eb => 0x041a, // Cyrillic_KA К CYRILLIC CAPITAL LETTER KA
629        0x06ec => 0x041b, // Cyrillic_EL Л CYRILLIC CAPITAL LETTER EL
630        0x06ed => 0x041c, // Cyrillic_EM М CYRILLIC CAPITAL LETTER EM
631        0x06ee => 0x041d, // Cyrillic_EN Н CYRILLIC CAPITAL LETTER EN
632        0x06ef => 0x041e, // Cyrillic_O О CYRILLIC CAPITAL LETTER O
633        0x06f0 => 0x041f, // Cyrillic_PE П CYRILLIC CAPITAL LETTER PE
634        0x06f1 => 0x042f, // Cyrillic_YA Я CYRILLIC CAPITAL LETTER YA
635        0x06f2 => 0x0420, // Cyrillic_ER Р CYRILLIC CAPITAL LETTER ER
636        0x06f3 => 0x0421, // Cyrillic_ES С CYRILLIC CAPITAL LETTER ES
637        0x06f4 => 0x0422, // Cyrillic_TE Т CYRILLIC CAPITAL LETTER TE
638        0x06f5 => 0x0423, // Cyrillic_U У CYRILLIC CAPITAL LETTER U
639        0x06f6 => 0x0416, // Cyrillic_ZHE Ж CYRILLIC CAPITAL LETTER ZHE
640        0x06f7 => 0x0412, // Cyrillic_VE В CYRILLIC CAPITAL LETTER VE
641        0x06f8 => 0x042c, // Cyrillic_SOFTSIGN Ь CYRILLIC CAPITAL LETTER SOFT SIGN
642        0x06f9 => 0x042b, // Cyrillic_YERU Ы CYRILLIC CAPITAL LETTER YERU
643        0x06fa => 0x0417, // Cyrillic_ZE З CYRILLIC CAPITAL LETTER ZE
644        0x06fb => 0x0428, // Cyrillic_SHA Ш CYRILLIC CAPITAL LETTER SHA
645        0x06fc => 0x042d, // Cyrillic_E Э CYRILLIC CAPITAL LETTER E
646        0x06fd => 0x0429, // Cyrillic_SHCHA Щ CYRILLIC CAPITAL LETTER SHCHA
647        0x06fe => 0x0427, // Cyrillic_CHE Ч CYRILLIC CAPITAL LETTER CHE
648        0x06ff => 0x042a, // Cyrillic_HARDSIGN Ъ CYRILLIC CAPITAL LETTER HARD SIGN
649        0x07a1 => 0x0386, // Greek_ALPHAaccent Ά GREEK CAPITAL LETTER ALPHA WITH TONOS
650        0x07a2 => 0x0388, // Greek_EPSILONaccent Έ GREEK CAPITAL LETTER EPSILON WITH TONOS
651        0x07a3 => 0x0389, // Greek_ETAaccent Ή GREEK CAPITAL LETTER ETA WITH TONOS
652        0x07a4 => 0x038a, // Greek_IOTAaccent Ί GREEK CAPITAL LETTER IOTA WITH TONOS
653        0x07a5 => 0x03aa, // Greek_IOTAdiaeresis Ϊ GREEK CAPITAL LETTER IOTA WITH DIALYTIKA
654        0x07a7 => 0x038c, // Greek_OMICRONaccent Ό GREEK CAPITAL LETTER OMICRON WITH TONOS
655        0x07a8 => 0x038e, // Greek_UPSILONaccent Ύ GREEK CAPITAL LETTER UPSILON WITH TONOS
656        0x07a9 => 0x03ab, // Greek_UPSILONdieresis Ϋ GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA
657        0x07ab => 0x038f, // Greek_OMEGAaccent Ώ GREEK CAPITAL LETTER OMEGA WITH TONOS
658        0x07ae => 0x0385, // Greek_accentdieresis ΅ GREEK DIALYTIKA TONOS
659        0x07af => 0x2015, // Greek_horizbar ― HORIZONTAL BAR
660        0x07b1 => 0x03ac, // Greek_alphaaccent ά GREEK SMALL LETTER ALPHA WITH TONOS
661        0x07b2 => 0x03ad, // Greek_epsilonaccent έ GREEK SMALL LETTER EPSILON WITH TONOS
662        0x07b3 => 0x03ae, // Greek_etaaccent ή GREEK SMALL LETTER ETA WITH TONOS
663        0x07b4 => 0x03af, // Greek_iotaaccent ί GREEK SMALL LETTER IOTA WITH TONOS
664        0x07b5 => 0x03ca, // Greek_iotadieresis ϊ GREEK SMALL LETTER IOTA WITH DIALYTIKA
665        0x07b6 => 0x0390, // Greek_iotaaccentdieresis ΐ GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS
666        0x07b7 => 0x03cc, // Greek_omicronaccent ό GREEK SMALL LETTER OMICRON WITH TONOS
667        0x07b8 => 0x03cd, // Greek_upsilonaccent ύ GREEK SMALL LETTER UPSILON WITH TONOS
668        0x07b9 => 0x03cb, // Greek_upsilondieresis ϋ GREEK SMALL LETTER UPSILON WITH DIALYTIKA
669        0x07ba => 0x03b0, // Greek_upsilonaccentdieresis ΰ GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS
670        0x07bb => 0x03ce, // Greek_omegaaccent ώ GREEK SMALL LETTER OMEGA WITH TONOS
671        0x07c1 => 0x0391, // Greek_ALPHA Α GREEK CAPITAL LETTER ALPHA
672        0x07c2 => 0x0392, // Greek_BETA Β GREEK CAPITAL LETTER BETA
673        0x07c3 => 0x0393, // Greek_GAMMA Γ GREEK CAPITAL LETTER GAMMA
674        0x07c4 => 0x0394, // Greek_DELTA Δ GREEK CAPITAL LETTER DELTA
675        0x07c5 => 0x0395, // Greek_EPSILON Ε GREEK CAPITAL LETTER EPSILON
676        0x07c6 => 0x0396, // Greek_ZETA Ζ GREEK CAPITAL LETTER ZETA
677        0x07c7 => 0x0397, // Greek_ETA Η GREEK CAPITAL LETTER ETA
678        0x07c8 => 0x0398, // Greek_THETA Θ GREEK CAPITAL LETTER THETA
679        0x07c9 => 0x0399, // Greek_IOTA Ι GREEK CAPITAL LETTER IOTA
680        0x07ca => 0x039a, // Greek_KAPPA Κ GREEK CAPITAL LETTER KAPPA
681        0x07cb => 0x039b, // Greek_LAMBDA Λ GREEK CAPITAL LETTER LAMDA
682        0x07cc => 0x039c, // Greek_MU Μ GREEK CAPITAL LETTER MU
683        0x07cd => 0x039d, // Greek_NU Ν GREEK CAPITAL LETTER NU
684        0x07ce => 0x039e, // Greek_XI Ξ GREEK CAPITAL LETTER XI
685        0x07cf => 0x039f, // Greek_OMICRON Ο GREEK CAPITAL LETTER OMICRON
686        0x07d0 => 0x03a0, // Greek_PI Π GREEK CAPITAL LETTER PI
687        0x07d1 => 0x03a1, // Greek_RHO Ρ GREEK CAPITAL LETTER RHO
688        0x07d2 => 0x03a3, // Greek_SIGMA Σ GREEK CAPITAL LETTER SIGMA
689        0x07d4 => 0x03a4, // Greek_TAU Τ GREEK CAPITAL LETTER TAU
690        0x07d5 => 0x03a5, // Greek_UPSILON Υ GREEK CAPITAL LETTER UPSILON
691        0x07d6 => 0x03a6, // Greek_PHI Φ GREEK CAPITAL LETTER PHI
692        0x07d7 => 0x03a7, // Greek_CHI Χ GREEK CAPITAL LETTER CHI
693        0x07d8 => 0x03a8, // Greek_PSI Ψ GREEK CAPITAL LETTER PSI
694        0x07d9 => 0x03a9, // Greek_OMEGA Ω GREEK CAPITAL LETTER OMEGA
695        0x07e1 => 0x03b1, // Greek_alpha α GREEK SMALL LETTER ALPHA
696        0x07e2 => 0x03b2, // Greek_beta β GREEK SMALL LETTER BETA
697        0x07e3 => 0x03b3, // Greek_gamma γ GREEK SMALL LETTER GAMMA
698        0x07e4 => 0x03b4, // Greek_delta δ GREEK SMALL LETTER DELTA
699        0x07e5 => 0x03b5, // Greek_epsilon ε GREEK SMALL LETTER EPSILON
700        0x07e6 => 0x03b6, // Greek_zeta ζ GREEK SMALL LETTER ZETA
701        0x07e7 => 0x03b7, // Greek_eta η GREEK SMALL LETTER ETA
702        0x07e8 => 0x03b8, // Greek_theta θ GREEK SMALL LETTER THETA
703        0x07e9 => 0x03b9, // Greek_iota ι GREEK SMALL LETTER IOTA
704        0x07ea => 0x03ba, // Greek_kappa κ GREEK SMALL LETTER KAPPA
705        0x07eb => 0x03bb, // Greek_lambda λ GREEK SMALL LETTER LAMDA
706        0x07ec => 0x03bc, // Greek_mu μ GREEK SMALL LETTER MU
707        0x07ed => 0x03bd, // Greek_nu ν GREEK SMALL LETTER NU
708        0x07ee => 0x03be, // Greek_xi ξ GREEK SMALL LETTER XI
709        0x07ef => 0x03bf, // Greek_omicron ο GREEK SMALL LETTER OMICRON
710        0x07f0 => 0x03c0, // Greek_pi π GREEK SMALL LETTER PI
711        0x07f1 => 0x03c1, // Greek_rho ρ GREEK SMALL LETTER RHO
712        0x07f2 => 0x03c3, // Greek_sigma σ GREEK SMALL LETTER SIGMA
713        0x07f3 => 0x03c2, // Greek_finalsmallsigma ς GREEK SMALL LETTER FINAL SIGMA
714        0x07f4 => 0x03c4, // Greek_tau τ GREEK SMALL LETTER TAU
715        0x07f5 => 0x03c5, // Greek_upsilon υ GREEK SMALL LETTER UPSILON
716        0x07f6 => 0x03c6, // Greek_phi φ GREEK SMALL LETTER PHI
717        0x07f7 => 0x03c7, // Greek_chi χ GREEK SMALL LETTER CHI
718        0x07f8 => 0x03c8, // Greek_psi ψ GREEK SMALL LETTER PSI
719        0x07f9 => 0x03c9, // Greek_omega ω GREEK SMALL LETTER OMEGA
720        0x08a1 => 0x23b7, // leftradical ⎷ ???
721        0x08a2 => 0x250c, // topleftradical ┌ BOX DRAWINGS LIGHT DOWN AND RIGHT
722        0x08a3 => 0x2500, // horizconnector ─ BOX DRAWINGS LIGHT HORIZONTAL
723        0x08a4 => 0x2320, // topintegral ⌠ TOP HALF INTEGRAL
724        0x08a5 => 0x2321, // botintegral ⌡ BOTTOM HALF INTEGRAL
725        0x08a6 => 0x2502, // vertconnector │ BOX DRAWINGS LIGHT VERTICAL
726        0x08a7 => 0x23a1, // topleftsqbracket ⎡ ???
727        0x08a8 => 0x23a3, // botleftsqbracket ⎣ ???
728        0x08a9 => 0x23a4, // toprightsqbracket ⎤ ???
729        0x08aa => 0x23a6, // botrightsqbracket ⎦ ???
730        0x08ab => 0x239b, // topleftparens ⎛ ???
731        0x08ac => 0x239d, // botleftparens ⎝ ???
732        0x08ad => 0x239e, // toprightparens ⎞ ???
733        0x08ae => 0x23a0, // botrightparens ⎠ ???
734        0x08af => 0x23a8, // leftmiddlecurlybrace ⎨ ???
735        0x08b0 => 0x23ac, // rightmiddlecurlybrace ⎬ ???
736        // 0x08b1 topleftsummation ? ???
737        // 0x08b2 botleftsummation ? ???
738        // 0x08b3 topvertsummationconnector ? ???
739        // 0x08b4 botvertsummationconnector ? ???
740        // 0x08b5 toprightsummation ? ???
741        // 0x08b6 botrightsummation ? ???
742        // 0x08b7 rightmiddlesummation ? ???
743        0x08bc => 0x2264, // lessthanequal ≤ LESS-THAN OR EQUAL TO
744        0x08bd => 0x2260, // notequal ≠ NOT EQUAL TO
745        0x08be => 0x2265, // greaterthanequal ≥ GREATER-THAN OR EQUAL TO
746        0x08bf => 0x222b, // integral ∫ INTEGRAL
747        0x08c0 => 0x2234, // therefore ∴ THEREFORE
748        0x08c1 => 0x221d, // variation ∝ PROPORTIONAL TO
749        0x08c2 => 0x221e, // infinity ∞ INFINITY
750        0x08c5 => 0x2207, // nabla ∇ NABLA
751        0x08c8 => 0x223c, // approximate ∼ TILDE OPERATOR
752        0x08c9 => 0x2243, // similarequal ≃ ASYMPTOTICALLY EQUAL TO
753        0x08cd => 0x21d4, // ifonlyif ⇔ LEFT RIGHT DOUBLE ARROW
754        0x08ce => 0x21d2, // implies ⇒ RIGHTWARDS DOUBLE ARROW
755        0x08cf => 0x2261, // identical ≡ IDENTICAL TO
756        0x08d6 => 0x221a, // radical √ SQUARE ROOT
757        0x08da => 0x2282, // includedin ⊂ SUBSET OF
758        0x08db => 0x2283, // includes ⊃ SUPERSET OF
759        0x08dc => 0x2229, // intersection ∩ INTERSECTION
760        0x08dd => 0x222a, // union ∪ UNION
761        0x08de => 0x2227, // logicaland ∧ LOGICAL AND
762        0x08df => 0x2228, // logicalor ∨ LOGICAL OR
763        0x08ef => 0x2202, // partialderivative ∂ PARTIAL DIFFERENTIAL
764        0x08f6 => 0x0192, // function ƒ LATIN SMALL LETTER F WITH HOOK
765        0x08fb => 0x2190, // leftarrow ← LEFTWARDS ARROW
766        0x08fc => 0x2191, // uparrow ↑ UPWARDS ARROW
767        0x08fd => 0x2192, // rightarrow → RIGHTWARDS ARROW
768        0x08fe => 0x2193, // downarrow ↓ DOWNWARDS ARROW
769        // 0x09df blank ? ???
770        0x09e0 => 0x25c6, // soliddiamond ◆ BLACK DIAMOND
771        0x09e1 => 0x2592, // checkerboard ▒ MEDIUM SHADE
772        0x09e2 => 0x2409, // ht ␉ SYMBOL FOR HORIZONTAL TABULATION
773        0x09e3 => 0x240c, // ff ␌ SYMBOL FOR FORM FEED
774        0x09e4 => 0x240d, // cr ␍ SYMBOL FOR CARRIAGE RETURN
775        0x09e5 => 0x240a, // lf ␊ SYMBOL FOR LINE FEED
776        0x09e8 => 0x2424, // nl ␤ SYMBOL FOR NEWLINE
777        0x09e9 => 0x240b, // vt ␋ SYMBOL FOR VERTICAL TABULATION
778        0x09ea => 0x2518, // lowrightcorner ┘ BOX DRAWINGS LIGHT UP AND LEFT
779        0x09eb => 0x2510, // uprightcorner ┐ BOX DRAWINGS LIGHT DOWN AND LEFT
780        0x09ec => 0x250c, // upleftcorner ┌ BOX DRAWINGS LIGHT DOWN AND RIGHT
781        0x09ed => 0x2514, // lowleftcorner └ BOX DRAWINGS LIGHT UP AND RIGHT
782        0x09ee => 0x253c, // crossinglines ┼ BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
783        0x09ef => 0x23ba, // horizlinescan1 ⎺ HORIZONTAL SCAN LINE-1 (Unicode 3.2 draft)
784        0x09f0 => 0x23bb, // horizlinescan3 ⎻ HORIZONTAL SCAN LINE-3 (Unicode 3.2 draft)
785        0x09f1 => 0x2500, // horizlinescan5 ─ BOX DRAWINGS LIGHT HORIZONTAL
786        0x09f2 => 0x23bc, // horizlinescan7 ⎼ HORIZONTAL SCAN LINE-7 (Unicode 3.2 draft)
787        0x09f3 => 0x23bd, // horizlinescan9 ⎽ HORIZONTAL SCAN LINE-9 (Unicode 3.2 draft)
788        0x09f4 => 0x251c, // leftt ├ BOX DRAWINGS LIGHT VERTICAL AND RIGHT
789        0x09f5 => 0x2524, // rightt ┤ BOX DRAWINGS LIGHT VERTICAL AND LEFT
790        0x09f6 => 0x2534, // bott ┴ BOX DRAWINGS LIGHT UP AND HORIZONTAL
791        0x09f7 => 0x252c, // topt ┬ BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
792        0x09f8 => 0x2502, // vertbar │ BOX DRAWINGS LIGHT VERTICAL
793        0x0aa1 => 0x2003, // emspace   EM SPACE
794        0x0aa2 => 0x2002, // enspace   EN SPACE
795        0x0aa3 => 0x2004, // em3space   THREE-PER-EM SPACE
796        0x0aa4 => 0x2005, // em4space   FOUR-PER-EM SPACE
797        0x0aa5 => 0x2007, // digitspace   FIGURE SPACE
798        0x0aa6 => 0x2008, // punctspace   PUNCTUATION SPACE
799        0x0aa7 => 0x2009, // thinspace   THIN SPACE
800        0x0aa8 => 0x200a, // hairspace   HAIR SPACE
801        0x0aa9 => 0x2014, // emdash — EM DASH
802        0x0aaa => 0x2013, // endash – EN DASH
803        0x0aac => 0x2423, // signifblank ␣ OPEN BOX
804        0x0aae => 0x2026, // ellipsis … HORIZONTAL ELLIPSIS
805        0x0aaf => 0x2025, // doubbaselinedot ‥ TWO DOT LEADER
806        0x0ab0 => 0x2153, // onethird ⅓ VULGAR FRACTION ONE THIRD
807        0x0ab1 => 0x2154, // twothirds ⅔ VULGAR FRACTION TWO THIRDS
808        0x0ab2 => 0x2155, // onefifth ⅕ VULGAR FRACTION ONE FIFTH
809        0x0ab3 => 0x2156, // twofifths ⅖ VULGAR FRACTION TWO FIFTHS
810        0x0ab4 => 0x2157, // threefifths ⅗ VULGAR FRACTION THREE FIFTHS
811        0x0ab5 => 0x2158, // fourfifths ⅘ VULGAR FRACTION FOUR FIFTHS
812        0x0ab6 => 0x2159, // onesixth ⅙ VULGAR FRACTION ONE SIXTH
813        0x0ab7 => 0x215a, // fivesixths ⅚ VULGAR FRACTION FIVE SIXTHS
814        0x0ab8 => 0x2105, // careof ℅ CARE OF
815        0x0abb => 0x2012, // figdash ‒ FIGURE DASH
816        0x0abc => 0x27e8, // leftanglebracket ⟨ MATHEMATICAL LEFT ANGLE BRACKET
817        0x0abd => 0x002e, // decimalpoint . FULL STOP
818        0x0abe => 0x27e9, // rightanglebracket ⟩ MATHEMATICAL RIGHT ANGLE BRACKET
819        // 0x0abf marker ? ???
820        0x0ac3 => 0x215b, // oneeighth ⅛ VULGAR FRACTION ONE EIGHTH
821        0x0ac4 => 0x215c, // threeeighths ⅜ VULGAR FRACTION THREE EIGHTHS
822        0x0ac5 => 0x215d, // fiveeighths ⅝ VULGAR FRACTION FIVE EIGHTHS
823        0x0ac6 => 0x215e, // seveneighths ⅞ VULGAR FRACTION SEVEN EIGHTHS
824        0x0ac9 => 0x2122, // trademark ™ TRADE MARK SIGN
825        0x0aca => 0x2613, // signaturemark ☓ SALTIRE
826        // 0x0acb trademarkincircle ? ???
827        0x0acc => 0x25c1, // leftopentriangle ◁ WHITE LEFT-POINTING TRIANGLE
828        0x0acd => 0x25b7, // rightopentriangle ▷ WHITE RIGHT-POINTING TRIANGLE
829        0x0ace => 0x25cb, // emopencircle ○ WHITE CIRCLE
830        0x0acf => 0x25af, // emopenrectangle ▯ WHITE VERTICAL RECTANGLE
831        0x0ad0 => 0x2018, // leftsinglequotemark ‘ LEFT SINGLE QUOTATION MARK
832        0x0ad1 => 0x2019, // rightsinglequotemark ’ RIGHT SINGLE QUOTATION MARK
833        0x0ad2 => 0x201c, // leftdoublequotemark “ LEFT DOUBLE QUOTATION MARK
834        0x0ad3 => 0x201d, // rightdoublequotemark ” RIGHT DOUBLE QUOTATION MARK
835        0x0ad4 => 0x211e, // prescription ℞ PRESCRIPTION TAKE
836        0x0ad5 => 0x2030, // permille ‰ PER MILLE SIGN
837        0x0ad6 => 0x2032, // minutes ′ PRIME
838        0x0ad7 => 0x2033, // seconds ″ DOUBLE PRIME
839        0x0ad9 => 0x271d, // latincross ✝ LATIN CROSS
840        // 0x0ada hexagram ? ???
841        0x0adb => 0x25ac, // filledrectbullet ▬ BLACK RECTANGLE
842        0x0adc => 0x25c0, // filledlefttribullet ◀ BLACK LEFT-POINTING TRIANGLE
843        0x0add => 0x25b6, // filledrighttribullet ▶ BLACK RIGHT-POINTING TRIANGLE
844        0x0ade => 0x25cf, // emfilledcircle ● BLACK CIRCLE
845        0x0adf => 0x25ae, // emfilledrect ▮ BLACK VERTICAL RECTANGLE
846        0x0ae0 => 0x25e6, // enopencircbullet ◦ WHITE BULLET
847        0x0ae1 => 0x25ab, // enopensquarebullet ▫ WHITE SMALL SQUARE
848        0x0ae2 => 0x25ad, // openrectbullet ▭ WHITE RECTANGLE
849        0x0ae3 => 0x25b3, // opentribulletup △ WHITE UP-POINTING TRIANGLE
850        0x0ae4 => 0x25bd, // opentribulletdown ▽ WHITE DOWN-POINTING TRIANGLE
851        0x0ae5 => 0x2606, // openstar ☆ WHITE STAR
852        0x0ae6 => 0x2022, // enfilledcircbullet • BULLET
853        0x0ae7 => 0x25aa, // enfilledsqbullet ▪ BLACK SMALL SQUARE
854        0x0ae8 => 0x25b2, // filledtribulletup ▲ BLACK UP-POINTING TRIANGLE
855        0x0ae9 => 0x25bc, // filledtribulletdown ▼ BLACK DOWN-POINTING TRIANGLE
856        0x0aea => 0x261c, // leftpointer ☜ WHITE LEFT POINTING INDEX
857        0x0aeb => 0x261e, // rightpointer ☞ WHITE RIGHT POINTING INDEX
858        0x0aec => 0x2663, // club ♣ BLACK CLUB SUIT
859        0x0aed => 0x2666, // diamond ♦ BLACK DIAMOND SUIT
860        0x0aee => 0x2665, // heart ♥ BLACK HEART SUIT
861        0x0af0 => 0x2720, // maltesecross ✠ MALTESE CROSS
862        0x0af1 => 0x2020, // dagger † DAGGER
863        0x0af2 => 0x2021, // doubledagger ‡ DOUBLE DAGGER
864        0x0af3 => 0x2713, // checkmark ✓ CHECK MARK
865        0x0af4 => 0x2717, // ballotcross ✗ BALLOT X
866        0x0af5 => 0x266f, // musicalsharp ♯ MUSIC SHARP SIGN
867        0x0af6 => 0x266d, // musicalflat ♭ MUSIC FLAT SIGN
868        0x0af7 => 0x2642, // malesymbol ♂ MALE SIGN
869        0x0af8 => 0x2640, // femalesymbol ♀ FEMALE SIGN
870        0x0af9 => 0x260e, // telephone ☎ BLACK TELEPHONE
871        0x0afa => 0x2315, // telephonerecorder ⌕ TELEPHONE RECORDER
872        0x0afb => 0x2117, // phonographcopyright ℗ SOUND RECORDING COPYRIGHT
873        0x0afc => 0x2038, // caret ‸ CARET
874        0x0afd => 0x201a, // singlelowquotemark ‚ SINGLE LOW-9 QUOTATION MARK
875        0x0afe => 0x201e, // doublelowquotemark „ DOUBLE LOW-9 QUOTATION MARK
876        // 0x0aff cursor ? ???
877        0x0ba3 => 0x003c, // leftcaret < LESS-THAN SIGN
878        0x0ba6 => 0x003e, // rightcaret > GREATER-THAN SIGN
879        0x0ba8 => 0x2228, // downcaret ∨ LOGICAL OR
880        0x0ba9 => 0x2227, // upcaret ∧ LOGICAL AND
881        0x0bc0 => 0x00af, // overbar ¯ MACRON
882        0x0bc2 => 0x22a4, // downtack ⊤ DOWN TACK
883        0x0bc3 => 0x2229, // upshoe ∩ INTERSECTION
884        0x0bc4 => 0x230a, // downstile ⌊ LEFT FLOOR
885        0x0bc6 => 0x005f, // underbar _ LOW LINE
886        0x0bca => 0x2218, // jot ∘ RING OPERATOR
887        0x0bcc => 0x2395, // quad ⎕ APL FUNCTIONAL SYMBOL QUAD (Unicode 3.0)
888        0x0bce => 0x22a5, // uptack ⊥ UP TACK
889        0x0bcf => 0x25cb, // circle ○ WHITE CIRCLE
890        0x0bd3 => 0x2308, // upstile ⌈ LEFT CEILING
891        0x0bd6 => 0x222a, // downshoe ∪ UNION
892        0x0bd8 => 0x2283, // rightshoe ⊃ SUPERSET OF
893        0x0bda => 0x2282, // leftshoe ⊂ SUBSET OF
894        0x0bdc => 0x22a3, // lefttack ⊣ LEFT TACK
895        0x0bfc => 0x22a2, // righttack ⊢ RIGHT TACK
896        0x0cdf => 0x2017, // hebrew_doublelowline ‗ DOUBLE LOW LINE
897        0x0ce0 => 0x05d0, // hebrew_aleph א HEBREW LETTER ALEF
898        0x0ce1 => 0x05d1, // hebrew_bet ב HEBREW LETTER BET
899        0x0ce2 => 0x05d2, // hebrew_gimel ג HEBREW LETTER GIMEL
900        0x0ce3 => 0x05d3, // hebrew_dalet ד HEBREW LETTER DALET
901        0x0ce4 => 0x05d4, // hebrew_he ה HEBREW LETTER HE
902        0x0ce5 => 0x05d5, // hebrew_waw ו HEBREW LETTER VAV
903        0x0ce6 => 0x05d6, // hebrew_zain ז HEBREW LETTER ZAYIN
904        0x0ce7 => 0x05d7, // hebrew_chet ח HEBREW LETTER HET
905        0x0ce8 => 0x05d8, // hebrew_tet ט HEBREW LETTER TET
906        0x0ce9 => 0x05d9, // hebrew_yod י HEBREW LETTER YOD
907        0x0cea => 0x05da, // hebrew_finalkaph ך HEBREW LETTER FINAL KAF
908        0x0ceb => 0x05db, // hebrew_kaph כ HEBREW LETTER KAF
909        0x0cec => 0x05dc, // hebrew_lamed ל HEBREW LETTER LAMED
910        0x0ced => 0x05dd, // hebrew_finalmem ם HEBREW LETTER FINAL MEM
911        0x0cee => 0x05de, // hebrew_mem מ HEBREW LETTER MEM
912        0x0cef => 0x05df, // hebrew_finalnun ן HEBREW LETTER FINAL NUN
913        0x0cf0 => 0x05e0, // hebrew_nun נ HEBREW LETTER NUN
914        0x0cf1 => 0x05e1, // hebrew_samech ס HEBREW LETTER SAMEKH
915        0x0cf2 => 0x05e2, // hebrew_ayin ע HEBREW LETTER AYIN
916        0x0cf3 => 0x05e3, // hebrew_finalpe ף HEBREW LETTER FINAL PE
917        0x0cf4 => 0x05e4, // hebrew_pe פ HEBREW LETTER PE
918        0x0cf5 => 0x05e5, // hebrew_finalzade ץ HEBREW LETTER FINAL TSADI
919        0x0cf6 => 0x05e6, // hebrew_zade צ HEBREW LETTER TSADI
920        0x0cf7 => 0x05e7, // hebrew_qoph ק HEBREW LETTER QOF
921        0x0cf8 => 0x05e8, // hebrew_resh ר HEBREW LETTER RESH
922        0x0cf9 => 0x05e9, // hebrew_shin ש HEBREW LETTER SHIN
923        0x0cfa => 0x05ea, // hebrew_taw ת HEBREW LETTER TAV
924        0x0da1 => 0x0e01, // Thai_kokai ก THAI CHARACTER KO KAI
925        0x0da2 => 0x0e02, // Thai_khokhai ข THAI CHARACTER KHO KHAI
926        0x0da3 => 0x0e03, // Thai_khokhuat ฃ THAI CHARACTER KHO KHUAT
927        0x0da4 => 0x0e04, // Thai_khokhwai ค THAI CHARACTER KHO KHWAI
928        0x0da5 => 0x0e05, // Thai_khokhon ฅ THAI CHARACTER KHO KHON
929        0x0da6 => 0x0e06, // Thai_khorakhang ฆ THAI CHARACTER KHO RAKHANG
930        0x0da7 => 0x0e07, // Thai_ngongu ง THAI CHARACTER NGO NGU
931        0x0da8 => 0x0e08, // Thai_chochan จ THAI CHARACTER CHO CHAN
932        0x0da9 => 0x0e09, // Thai_choching ฉ THAI CHARACTER CHO CHING
933        0x0daa => 0x0e0a, // Thai_chochang ช THAI CHARACTER CHO CHANG
934        0x0dab => 0x0e0b, // Thai_soso ซ THAI CHARACTER SO SO
935        0x0dac => 0x0e0c, // Thai_chochoe ฌ THAI CHARACTER CHO CHOE
936        0x0dad => 0x0e0d, // Thai_yoying ญ THAI CHARACTER YO YING
937        0x0dae => 0x0e0e, // Thai_dochada ฎ THAI CHARACTER DO CHADA
938        0x0daf => 0x0e0f, // Thai_topatak ฏ THAI CHARACTER TO PATAK
939        0x0db0 => 0x0e10, // Thai_thothan ฐ THAI CHARACTER THO THAN
940        0x0db1 => 0x0e11, // Thai_thonangmontho ฑ THAI CHARACTER THO NANGMONTHO
941        0x0db2 => 0x0e12, // Thai_thophuthao ฒ THAI CHARACTER THO PHUTHAO
942        0x0db3 => 0x0e13, // Thai_nonen ณ THAI CHARACTER NO NEN
943        0x0db4 => 0x0e14, // Thai_dodek ด THAI CHARACTER DO DEK
944        0x0db5 => 0x0e15, // Thai_totao ต THAI CHARACTER TO TAO
945        0x0db6 => 0x0e16, // Thai_thothung ถ THAI CHARACTER THO THUNG
946        0x0db7 => 0x0e17, // Thai_thothahan ท THAI CHARACTER THO THAHAN
947        0x0db8 => 0x0e18, // Thai_thothong ธ THAI CHARACTER THO THONG
948        0x0db9 => 0x0e19, // Thai_nonu น THAI CHARACTER NO NU
949        0x0dba => 0x0e1a, // Thai_bobaimai บ THAI CHARACTER BO BAIMAI
950        0x0dbb => 0x0e1b, // Thai_popla ป THAI CHARACTER PO PLA
951        0x0dbc => 0x0e1c, // Thai_phophung ผ THAI CHARACTER PHO PHUNG
952        0x0dbd => 0x0e1d, // Thai_fofa ฝ THAI CHARACTER FO FA
953        0x0dbe => 0x0e1e, // Thai_phophan พ THAI CHARACTER PHO PHAN
954        0x0dbf => 0x0e1f, // Thai_fofan ฟ THAI CHARACTER FO FAN
955        0x0dc0 => 0x0e20, // Thai_phosamphao ภ THAI CHARACTER PHO SAMPHAO
956        0x0dc1 => 0x0e21, // Thai_moma ม THAI CHARACTER MO MA
957        0x0dc2 => 0x0e22, // Thai_yoyak ย THAI CHARACTER YO YAK
958        0x0dc3 => 0x0e23, // Thai_rorua ร THAI CHARACTER RO RUA
959        0x0dc4 => 0x0e24, // Thai_ru ฤ THAI CHARACTER RU
960        0x0dc5 => 0x0e25, // Thai_loling ล THAI CHARACTER LO LING
961        0x0dc6 => 0x0e26, // Thai_lu ฦ THAI CHARACTER LU
962        0x0dc7 => 0x0e27, // Thai_wowaen ว THAI CHARACTER WO WAEN
963        0x0dc8 => 0x0e28, // Thai_sosala ศ THAI CHARACTER SO SALA
964        0x0dc9 => 0x0e29, // Thai_sorusi ษ THAI CHARACTER SO RUSI
965        0x0dca => 0x0e2a, // Thai_sosua ส THAI CHARACTER SO SUA
966        0x0dcb => 0x0e2b, // Thai_hohip ห THAI CHARACTER HO HIP
967        0x0dcc => 0x0e2c, // Thai_lochula ฬ THAI CHARACTER LO CHULA
968        0x0dcd => 0x0e2d, // Thai_oang อ THAI CHARACTER O ANG
969        0x0dce => 0x0e2e, // Thai_honokhuk ฮ THAI CHARACTER HO NOKHUK
970        0x0dcf => 0x0e2f, // Thai_paiyannoi ฯ THAI CHARACTER PAIYANNOI
971        0x0dd0 => 0x0e30, // Thai_saraa ะ THAI CHARACTER SARA A
972        0x0dd1 => 0x0e31, // Thai_maihanakat ั THAI CHARACTER MAI HAN-AKAT
973        0x0dd2 => 0x0e32, // Thai_saraaa า THAI CHARACTER SARA AA
974        0x0dd3 => 0x0e33, // Thai_saraam ำ THAI CHARACTER SARA AM
975        0x0dd4 => 0x0e34, // Thai_sarai ิ THAI CHARACTER SARA I
976        0x0dd5 => 0x0e35, // Thai_saraii ี THAI CHARACTER SARA II
977        0x0dd6 => 0x0e36, // Thai_saraue ึ THAI CHARACTER SARA UE
978        0x0dd7 => 0x0e37, // Thai_sarauee ื THAI CHARACTER SARA UEE
979        0x0dd8 => 0x0e38, // Thai_sarau ุ THAI CHARACTER SARA U
980        0x0dd9 => 0x0e39, // Thai_sarauu ู THAI CHARACTER SARA UU
981        0x0dda => 0x0e3a, // Thai_phinthu ฺ THAI CHARACTER PHINTHU
982        0x0dde => 0x0e3e, // Thai_maihanakat_maitho ฾ ???
983        0x0ddf => 0x0e3f, // Thai_baht ฿ THAI CURRENCY SYMBOL BAHT
984        0x0de0 => 0x0e40, // Thai_sarae เ THAI CHARACTER SARA E
985        0x0de1 => 0x0e41, // Thai_saraae แ THAI CHARACTER SARA AE
986        0x0de2 => 0x0e42, // Thai_sarao โ THAI CHARACTER SARA O
987        0x0de3 => 0x0e43, // Thai_saraaimaimuan ใ THAI CHARACTER SARA AI MAIMUAN
988        0x0de4 => 0x0e44, // Thai_saraaimaimalai ไ THAI CHARACTER SARA AI MAIMALAI
989        0x0de5 => 0x0e45, // Thai_lakkhangyao ๅ THAI CHARACTER LAKKHANGYAO
990        0x0de6 => 0x0e46, // Thai_maiyamok ๆ THAI CHARACTER MAIYAMOK
991        0x0de7 => 0x0e47, // Thai_maitaikhu ็ THAI CHARACTER MAITAIKHU
992        0x0de8 => 0x0e48, // Thai_maiek ่ THAI CHARACTER MAI EK
993        0x0de9 => 0x0e49, // Thai_maitho ้ THAI CHARACTER MAI THO
994        0x0dea => 0x0e4a, // Thai_maitri ๊ THAI CHARACTER MAI TRI
995        0x0deb => 0x0e4b, // Thai_maichattawa ๋ THAI CHARACTER MAI CHATTAWA
996        0x0dec => 0x0e4c, // Thai_thanthakhat ์ THAI CHARACTER THANTHAKHAT
997        0x0ded => 0x0e4d, // Thai_nikhahit ํ THAI CHARACTER NIKHAHIT
998        0x0df0 => 0x0e50, // Thai_leksun ๐ THAI DIGIT ZERO
999        0x0df1 => 0x0e51, // Thai_leknung ๑ THAI DIGIT ONE
1000        0x0df2 => 0x0e52, // Thai_leksong ๒ THAI DIGIT TWO
1001        0x0df3 => 0x0e53, // Thai_leksam ๓ THAI DIGIT THREE
1002        0x0df4 => 0x0e54, // Thai_leksi ๔ THAI DIGIT FOUR
1003        0x0df5 => 0x0e55, // Thai_lekha ๕ THAI DIGIT FIVE
1004        0x0df6 => 0x0e56, // Thai_lekhok ๖ THAI DIGIT SIX
1005        0x0df7 => 0x0e57, // Thai_lekchet ๗ THAI DIGIT SEVEN
1006        0x0df8 => 0x0e58, // Thai_lekpaet ๘ THAI DIGIT EIGHT
1007        0x0df9 => 0x0e59, // Thai_lekkao ๙ THAI DIGIT NINE
1008        0x0ea1 => 0x3131, // Hangul_Kiyeog ㄱ HANGUL LETTER KIYEOK
1009        0x0ea2 => 0x3132, // Hangul_SsangKiyeog ㄲ HANGUL LETTER SSANGKIYEOK
1010        0x0ea3 => 0x3133, // Hangul_KiyeogSios ㄳ HANGUL LETTER KIYEOK-SIOS
1011        0x0ea4 => 0x3134, // Hangul_Nieun ㄴ HANGUL LETTER NIEUN
1012        0x0ea5 => 0x3135, // Hangul_NieunJieuj ㄵ HANGUL LETTER NIEUN-CIEUC
1013        0x0ea6 => 0x3136, // Hangul_NieunHieuh ㄶ HANGUL LETTER NIEUN-HIEUH
1014        0x0ea7 => 0x3137, // Hangul_Dikeud ㄷ HANGUL LETTER TIKEUT
1015        0x0ea8 => 0x3138, // Hangul_SsangDikeud ㄸ HANGUL LETTER SSANGTIKEUT
1016        0x0ea9 => 0x3139, // Hangul_Rieul ㄹ HANGUL LETTER RIEUL
1017        0x0eaa => 0x313a, // Hangul_RieulKiyeog ㄺ HANGUL LETTER RIEUL-KIYEOK
1018        0x0eab => 0x313b, // Hangul_RieulMieum ㄻ HANGUL LETTER RIEUL-MIEUM
1019        0x0eac => 0x313c, // Hangul_RieulPieub ㄼ HANGUL LETTER RIEUL-PIEUP
1020        0x0ead => 0x313d, // Hangul_RieulSios ㄽ HANGUL LETTER RIEUL-SIOS
1021        0x0eae => 0x313e, // Hangul_RieulTieut ㄾ HANGUL LETTER RIEUL-THIEUTH
1022        0x0eaf => 0x313f, // Hangul_RieulPhieuf ㄿ HANGUL LETTER RIEUL-PHIEUPH
1023        0x0eb0 => 0x3140, // Hangul_RieulHieuh ㅀ HANGUL LETTER RIEUL-HIEUH
1024        0x0eb1 => 0x3141, // Hangul_Mieum ㅁ HANGUL LETTER MIEUM
1025        0x0eb2 => 0x3142, // Hangul_Pieub ㅂ HANGUL LETTER PIEUP
1026        0x0eb3 => 0x3143, // Hangul_SsangPieub ㅃ HANGUL LETTER SSANGPIEUP
1027        0x0eb4 => 0x3144, // Hangul_PieubSios ㅄ HANGUL LETTER PIEUP-SIOS
1028        0x0eb5 => 0x3145, // Hangul_Sios ㅅ HANGUL LETTER SIOS
1029        0x0eb6 => 0x3146, // Hangul_SsangSios ㅆ HANGUL LETTER SSANGSIOS
1030        0x0eb7 => 0x3147, // Hangul_Ieung ㅇ HANGUL LETTER IEUNG
1031        0x0eb8 => 0x3148, // Hangul_Jieuj ㅈ HANGUL LETTER CIEUC
1032        0x0eb9 => 0x3149, // Hangul_SsangJieuj ㅉ HANGUL LETTER SSANGCIEUC
1033        0x0eba => 0x314a, // Hangul_Cieuc ㅊ HANGUL LETTER CHIEUCH
1034        0x0ebb => 0x314b, // Hangul_Khieuq ㅋ HANGUL LETTER KHIEUKH
1035        0x0ebc => 0x314c, // Hangul_Tieut ㅌ HANGUL LETTER THIEUTH
1036        0x0ebd => 0x314d, // Hangul_Phieuf ㅍ HANGUL LETTER PHIEUPH
1037        0x0ebe => 0x314e, // Hangul_Hieuh ㅎ HANGUL LETTER HIEUH
1038        0x0ebf => 0x314f, // Hangul_A ㅏ HANGUL LETTER A
1039        0x0ec0 => 0x3150, // Hangul_AE ㅐ HANGUL LETTER AE
1040        0x0ec1 => 0x3151, // Hangul_YA ㅑ HANGUL LETTER YA
1041        0x0ec2 => 0x3152, // Hangul_YAE ㅒ HANGUL LETTER YAE
1042        0x0ec3 => 0x3153, // Hangul_EO ㅓ HANGUL LETTER EO
1043        0x0ec4 => 0x3154, // Hangul_E ㅔ HANGUL LETTER E
1044        0x0ec5 => 0x3155, // Hangul_YEO ㅕ HANGUL LETTER YEO
1045        0x0ec6 => 0x3156, // Hangul_YE ㅖ HANGUL LETTER YE
1046        0x0ec7 => 0x3157, // Hangul_O ㅗ HANGUL LETTER O
1047        0x0ec8 => 0x3158, // Hangul_WA ㅘ HANGUL LETTER WA
1048        0x0ec9 => 0x3159, // Hangul_WAE ㅙ HANGUL LETTER WAE
1049        0x0eca => 0x315a, // Hangul_OE ㅚ HANGUL LETTER OE
1050        0x0ecb => 0x315b, // Hangul_YO ㅛ HANGUL LETTER YO
1051        0x0ecc => 0x315c, // Hangul_U ㅜ HANGUL LETTER U
1052        0x0ecd => 0x315d, // Hangul_WEO ㅝ HANGUL LETTER WEO
1053        0x0ece => 0x315e, // Hangul_WE ㅞ HANGUL LETTER WE
1054        0x0ecf => 0x315f, // Hangul_WI ㅟ HANGUL LETTER WI
1055        0x0ed0 => 0x3160, // Hangul_YU ㅠ HANGUL LETTER YU
1056        0x0ed1 => 0x3161, // Hangul_EU ㅡ HANGUL LETTER EU
1057        0x0ed2 => 0x3162, // Hangul_YI ㅢ HANGUL LETTER YI
1058        0x0ed3 => 0x3163, // Hangul_I ㅣ HANGUL LETTER I
1059        0x0ed4 => 0x11a8, // Hangul_J_Kiyeog ᆨ HANGUL JONGSEONG KIYEOK
1060        0x0ed5 => 0x11a9, // Hangul_J_SsangKiyeog ᆩ HANGUL JONGSEONG SSANGKIYEOK
1061        0x0ed6 => 0x11aa, // Hangul_J_KiyeogSios ᆪ HANGUL JONGSEONG KIYEOK-SIOS
1062        0x0ed7 => 0x11ab, // Hangul_J_Nieun ᆫ HANGUL JONGSEONG NIEUN
1063        0x0ed8 => 0x11ac, // Hangul_J_NieunJieuj ᆬ HANGUL JONGSEONG NIEUN-CIEUC
1064        0x0ed9 => 0x11ad, // Hangul_J_NieunHieuh ᆭ HANGUL JONGSEONG NIEUN-HIEUH
1065        0x0eda => 0x11ae, // Hangul_J_Dikeud ᆮ HANGUL JONGSEONG TIKEUT
1066        0x0edb => 0x11af, // Hangul_J_Rieul ᆯ HANGUL JONGSEONG RIEUL
1067        0x0edc => 0x11b0, // Hangul_J_RieulKiyeog ᆰ HANGUL JONGSEONG RIEUL-KIYEOK
1068        0x0edd => 0x11b1, // Hangul_J_RieulMieum ᆱ HANGUL JONGSEONG RIEUL-MIEUM
1069        0x0ede => 0x11b2, // Hangul_J_RieulPieub ᆲ HANGUL JONGSEONG RIEUL-PIEUP
1070        0x0edf => 0x11b3, // Hangul_J_RieulSios ᆳ HANGUL JONGSEONG RIEUL-SIOS
1071        0x0ee0 => 0x11b4, // Hangul_J_RieulTieut ᆴ HANGUL JONGSEONG RIEUL-THIEUTH
1072        0x0ee1 => 0x11b5, // Hangul_J_RieulPhieuf ᆵ HANGUL JONGSEONG RIEUL-PHIEUPH
1073        0x0ee2 => 0x11b6, // Hangul_J_RieulHieuh ᆶ HANGUL JONGSEONG RIEUL-HIEUH
1074        0x0ee3 => 0x11b7, // Hangul_J_Mieum ᆷ HANGUL JONGSEONG MIEUM
1075        0x0ee4 => 0x11b8, // Hangul_J_Pieub ᆸ HANGUL JONGSEONG PIEUP
1076        0x0ee5 => 0x11b9, // Hangul_J_PieubSios ᆹ HANGUL JONGSEONG PIEUP-SIOS
1077        0x0ee6 => 0x11ba, // Hangul_J_Sios ᆺ HANGUL JONGSEONG SIOS
1078        0x0ee7 => 0x11bb, // Hangul_J_SsangSios ᆻ HANGUL JONGSEONG SSANGSIOS
1079        0x0ee8 => 0x11bc, // Hangul_J_Ieung ᆼ HANGUL JONGSEONG IEUNG
1080        0x0ee9 => 0x11bd, // Hangul_J_Jieuj ᆽ HANGUL JONGSEONG CIEUC
1081        0x0eea => 0x11be, // Hangul_J_Cieuc ᆾ HANGUL JONGSEONG CHIEUCH
1082        0x0eeb => 0x11bf, // Hangul_J_Khieuq ᆿ HANGUL JONGSEONG KHIEUKH
1083        0x0eec => 0x11c0, // Hangul_J_Tieut ᇀ HANGUL JONGSEONG THIEUTH
1084        0x0eed => 0x11c1, // Hangul_J_Phieuf ᇁ HANGUL JONGSEONG PHIEUPH
1085        0x0eee => 0x11c2, // Hangul_J_Hieuh ᇂ HANGUL JONGSEONG HIEUH
1086        0x0eef => 0x316d, // Hangul_RieulYeorinHieuh ㅭ HANGUL LETTER RIEUL-YEORINHIEUH
1087        0x0ef0 => 0x3171, // Hangul_SunkyeongeumMieum ㅱ HANGUL LETTER KAPYEOUNMIEUM
1088        0x0ef1 => 0x3178, // Hangul_SunkyeongeumPieub ㅸ HANGUL LETTER KAPYEOUNPIEUP
1089        0x0ef2 => 0x317f, // Hangul_PanSios ㅿ HANGUL LETTER PANSIOS
1090        0x0ef3 => 0x3181, // Hangul_KkogjiDalrinIeung ㆁ HANGUL LETTER YESIEUNG
1091        0x0ef4 => 0x3184, // Hangul_SunkyeongeumPhieuf ㆄ HANGUL LETTER KAPYEOUNPHIEUPH
1092        0x0ef5 => 0x3186, // Hangul_YeorinHieuh ㆆ HANGUL LETTER YEORINHIEUH
1093        0x0ef6 => 0x318d, // Hangul_AraeA ㆍ HANGUL LETTER ARAEA
1094        0x0ef7 => 0x318e, // Hangul_AraeAE ㆎ HANGUL LETTER ARAEAE
1095        0x0ef8 => 0x11eb, // Hangul_J_PanSios ᇫ HANGUL JONGSEONG PANSIOS
1096        0x0ef9 => 0x11f0, // Hangul_J_KkogjiDalrinIeung ᇰ HANGUL JONGSEONG YESIEUNG
1097        0x0efa => 0x11f9, // Hangul_J_YeorinHieuh ᇹ HANGUL JONGSEONG YEORINHIEUH
1098        0x0eff => 0x20a9, // Korean_Won ₩ WON SIGN
1099        0x13bc => 0x0152, // OE Œ LATIN CAPITAL LIGATURE OE
1100        0x13bd => 0x0153, // oe œ LATIN SMALL LIGATURE OE
1101        0x13be => 0x0178, // Ydiaeresis Ÿ LATIN CAPITAL LETTER Y WITH DIAERESIS
1102        0x20ac => 0x20ac, // EuroSign € EURO SIGN
1103        _ => 0,
1104    }
1105}