diff options
author | Jon Turney <jon.turney@dronecode.org.uk> | 2017-01-27 17:30:07 +0000 |
---|---|---|
committer | Jon Turney <jon.turney@dronecode.org.uk> | 2017-04-18 17:17:09 +0100 |
commit | 9def9569431d5e376f8fc63c913f21dda3ff9cec (patch) | |
tree | d3235e71ec082d1bf8ca5ab51540b805376ecb6f | |
parent | cbe408a1c2eb547525d81baa99a6dc0156b3ad0f (diff) |
Fallback to generating a modmap from Windows keyboard layoutwinlayout-to-xmodmap-2
If we can't find a matching XKB keyboard layout, generate a modmap from the
information Windows provides about it's keyboard layout.
Loosely based on equivalent functionality in XQuartz.
v2: Include deadkey handling
-rw-r--r-- | hw/xwin/Makefile.am | 2 | ||||
-rw-r--r-- | hw/xwin/keysym2ucs.c | 911 | ||||
-rw-r--r-- | hw/xwin/keysym2ucs.h | 38 | ||||
-rw-r--r-- | hw/xwin/man/XWin.man | 4 | ||||
-rw-r--r-- | hw/xwin/winconfig.c | 3 | ||||
-rw-r--r-- | hw/xwin/winconfig.h | 1 | ||||
-rw-r--r-- | hw/xwin/winkeybd.c | 444 |
7 files changed, 1372 insertions, 31 deletions
diff --git a/hw/xwin/Makefile.am b/hw/xwin/Makefile.am index 818e250d0..f100a2d89 100644 --- a/hw/xwin/Makefile.am +++ b/hw/xwin/Makefile.am @@ -50,6 +50,8 @@ endif SRCS = InitInput.c \ InitOutput.c \ + keysym2ucs.c \ + keysym2ucs.h \ winallpriv.c \ winauth.c \ winblock.c \ diff --git a/hw/xwin/keysym2ucs.c b/hw/xwin/keysym2ucs.c new file mode 100644 index 000000000..934b57756 --- /dev/null +++ b/hw/xwin/keysym2ucs.c @@ -0,0 +1,911 @@ +/* + * + * This module converts keysym values into the corresponding ISO 10646 + * (UCS, Unicode) values. + * + * The array keysymtab[] contains pairs of X11 keysym values for graphical + * characters and the corresponding Unicode value. The function + * keysym2ucs() maps a keysym onto a Unicode value using a binary search, + * therefore keysymtab[] must remain SORTED by keysym value. + * + * The keysym -> UTF-8 conversion will hopefully one day be provided + * by Xlib via XmbLookupString() and should ideally not have to be + * done in X applications. But we are not there yet. + * + * We allow to represent any UCS character in the range U-00000000 to + * U-00FFFFFF by a keysym value in the range 0x01000000 to 0x01ffffff. + * This admittedly does not cover the entire 31-bit space of UCS, but + * it does cover all of the characters up to U-10FFFF, which can be + * represented by UTF-16, and more, and it is very unlikely that higher + * UCS codes will ever be assigned by ISO. So to get Unicode character + * U+ABCD you can directly use keysym 0x0100abcd. + * + * NOTE: The comments in the table below contain the actual character + * encoded in UTF-8, so for viewing and editing best use an editor in + * UTF-8 mode. + * + * Author: Markus G. Kuhn <mkuhn@acm.org>, University of Cambridge, April 2001 + * + * Special thanks to Richard Verhoeven <river@win.tue.nl> for preparing + * an initial draft of the mapping table. + * + * This software is in the public domain. Share and enjoy! + * + * AUTOMATICALLY GENERATED FILE, DO NOT EDIT !!! (unicode/convmap.pl) + */ + +#include "keysym2ucs.h" + +#include <stdlib.h> +#include <string.h> + +struct codepair { + unsigned short keysym; + unsigned short ucs; +}; + +const static struct codepair keysymtab[] = { + { 0x01a1, 0x0104 }, + { 0x01a2, 0x02d8 }, + { 0x01a3, 0x0141 }, + { 0x01a5, 0x013d }, + { 0x01a6, 0x015a }, + { 0x01a9, 0x0160 }, + { 0x01aa, 0x015e }, + { 0x01ab, 0x0164 }, + { 0x01ac, 0x0179 }, + { 0x01ae, 0x017d }, + { 0x01af, 0x017b }, + { 0x01b1, 0x0105 }, + { 0x01b2, 0x02db }, + { 0x01b3, 0x0142 }, + { 0x01b5, 0x013e }, + { 0x01b6, 0x015b }, + { 0x01b7, 0x02c7 }, + { 0x01b9, 0x0161 }, + { 0x01ba, 0x015f }, + { 0x01bb, 0x0165 }, + { 0x01bc, 0x017a }, + { 0x01bd, 0x02dd }, + { 0x01be, 0x017e }, + { 0x01bf, 0x017c }, + { 0x01c0, 0x0154 }, + { 0x01c3, 0x0102 }, + { 0x01c5, 0x0139 }, + { 0x01c6, 0x0106 }, + { 0x01c8, 0x010c }, + { 0x01ca, 0x0118 }, + { 0x01cc, 0x011a }, + { 0x01cf, 0x010e }, + { 0x01d0, 0x0110 }, + { 0x01d1, 0x0143 }, + { 0x01d2, 0x0147 }, + { 0x01d5, 0x0150 }, + { 0x01d8, 0x0158 }, + { 0x01d9, 0x016e }, + { 0x01db, 0x0170 }, + { 0x01de, 0x0162 }, + { 0x01e0, 0x0155 }, + { 0x01e3, 0x0103 }, + { 0x01e5, 0x013a }, + { 0x01e6, 0x0107 }, + { 0x01e8, 0x010d }, + { 0x01ea, 0x0119 }, + { 0x01ec, 0x011b }, + { 0x01ef, 0x010f }, + { 0x01f0, 0x0111 }, + { 0x01f1, 0x0144 }, + { 0x01f2, 0x0148 }, + { 0x01f5, 0x0151 }, + { 0x01f8, 0x0159 }, + { 0x01f9, 0x016f }, + { 0x01fb, 0x0171 }, + { 0x01fe, 0x0163 }, + { 0x01ff, 0x02d9 }, + { 0x02a1, 0x0126 }, + { 0x02a6, 0x0124 }, + { 0x02a9, 0x0130 }, + { 0x02ab, 0x011e }, + { 0x02ac, 0x0134 }, + { 0x02b1, 0x0127 }, + { 0x02b6, 0x0125 }, + { 0x02b9, 0x0131 }, + { 0x02bb, 0x011f }, + { 0x02bc, 0x0135 }, + { 0x02c5, 0x010a }, + { 0x02c6, 0x0108 }, + { 0x02d5, 0x0120 }, + { 0x02d8, 0x011c }, + { 0x02dd, 0x016c }, + { 0x02de, 0x015c }, + { 0x02e5, 0x010b }, + { 0x02e6, 0x0109 }, + { 0x02f5, 0x0121 }, + { 0x02f8, 0x011d }, + { 0x02fd, 0x016d }, + { 0x02fe, 0x015d }, + { 0x03a2, 0x0138 }, + { 0x03a3, 0x0156 }, + { 0x03a5, 0x0128 }, + { 0x03a6, 0x013b }, + { 0x03aa, 0x0112 }, + { 0x03ab, 0x0122 }, + { 0x03ac, 0x0166 }, + { 0x03b3, 0x0157 }, + { 0x03b5, 0x0129 }, + { 0x03b6, 0x013c }, + { 0x03ba, 0x0113 }, + { 0x03bb, 0x0123 }, + { 0x03bc, 0x0167 }, + { 0x03bd, 0x014a }, + { 0x03bf, 0x014b }, + { 0x03c0, 0x0100 }, + { 0x03c7, 0x012e }, + { 0x03cc, 0x0116 }, + { 0x03cf, 0x012a }, + { 0x03d1, 0x0145 }, + { 0x03d2, 0x014c }, + { 0x03d3, 0x0136 }, + { 0x03d9, 0x0172 }, + { 0x03dd, 0x0168 }, + { 0x03de, 0x016a }, + { 0x03e0, 0x0101 }, + { 0x03e7, 0x012f }, + { 0x03ec, 0x0117 }, + { 0x03ef, 0x012b }, + { 0x03f1, 0x0146 }, + { 0x03f2, 0x014d }, + { 0x03f3, 0x0137 }, + { 0x03f9, 0x0173 }, + { 0x03fd, 0x0169 }, + { 0x03fe, 0x016b }, + { 0x047e, 0x203e }, + { 0x04a1, 0x3002 }, + { 0x04a2, 0x300c }, + { 0x04a3, 0x300d }, + { 0x04a4, 0x3001 }, + { 0x04a5, 0x30fb }, + { 0x04a6, 0x30f2 }, + { 0x04a7, 0x30a1 }, + { 0x04a8, 0x30a3 }, + { 0x04a9, 0x30a5 }, + { 0x04aa, 0x30a7 }, + { 0x04ab, 0x30a9 }, + { 0x04ac, 0x30e3 }, + { 0x04ad, 0x30e5 }, + { 0x04ae, 0x30e7 }, + { 0x04af, 0x30c3 }, + { 0x04b0, 0x30fc }, + { 0x04b1, 0x30a2 }, + { 0x04b2, 0x30a4 }, + { 0x04b3, 0x30a6 }, + { 0x04b4, 0x30a8 }, + { 0x04b5, 0x30aa }, + { 0x04b6, 0x30ab }, + { 0x04b7, 0x30ad }, + { 0x04b8, 0x30af }, + { 0x04b9, 0x30b1 }, + { 0x04ba, 0x30b3 }, + { 0x04bb, 0x30b5 }, + { 0x04bc, 0x30b7 }, + { 0x04bd, 0x30b9 }, + { 0x04be, 0x30bb }, + { 0x04bf, 0x30bd }, + { 0x04c0, 0x30bf }, + { 0x04c1, 0x30c1 }, + { 0x04c2, 0x30c4 }, + { 0x04c3, 0x30c6 }, + { 0x04c4, 0x30c8 }, + { 0x04c5, 0x30ca }, + { 0x04c6, 0x30cb }, + { 0x04c7, 0x30cc }, + { 0x04c8, 0x30cd }, + { 0x04c9, 0x30ce }, + { 0x04ca, 0x30cf }, + { 0x04cb, 0x30d2 }, + { 0x04cc, 0x30d5 }, + { 0x04cd, 0x30d8 }, + { 0x04ce, 0x30db }, + { 0x04cf, 0x30de }, + { 0x04d0, 0x30df }, + { 0x04d1, 0x30e0 }, + { 0x04d2, 0x30e1 }, + { 0x04d3, 0x30e2 }, + { 0x04d4, 0x30e4 }, + { 0x04d5, 0x30e6 }, + { 0x04d6, 0x30e8 }, + { 0x04d7, 0x30e9 }, + { 0x04d8, 0x30ea }, + { 0x04d9, 0x30eb }, + { 0x04da, 0x30ec }, + { 0x04db, 0x30ed }, + { 0x04dc, 0x30ef }, + { 0x04dd, 0x30f3 }, + { 0x04de, 0x309b }, + { 0x04df, 0x309c }, + { 0x05ac, 0x060c }, + { 0x05bb, 0x061b }, + { 0x05bf, 0x061f }, + { 0x05c1, 0x0621 }, + { 0x05c2, 0x0622 }, + { 0x05c3, 0x0623 }, + { 0x05c4, 0x0624 }, + { 0x05c5, 0x0625 }, + { 0x05c6, 0x0626 }, + { 0x05c7, 0x0627 }, + { 0x05c8, 0x0628 }, + { 0x05c9, 0x0629 }, + { 0x05ca, 0x062a }, + { 0x05cb, 0x062b }, + { 0x05cc, 0x062c }, + { 0x05cd, 0x062d }, + { 0x05ce, 0x062e }, + { 0x05cf, 0x062f }, + { 0x05d0, 0x0630 }, + { 0x05d1, 0x0631 }, + { 0x05d2, 0x0632 }, + { 0x05d3, 0x0633 }, + { 0x05d4, 0x0634 }, + { 0x05d5, 0x0635 }, + { 0x05d6, 0x0636 }, + { 0x05d7, 0x0637 }, + { 0x05d8, 0x0638 }, + { 0x05d9, 0x0639 }, + { 0x05da, 0x063a }, + { 0x05e0, 0x0640 }, + { 0x05e1, 0x0641 }, + { 0x05e2, 0x0642 }, + { 0x05e3, 0x0643 }, + { 0x05e4, 0x0644 }, + { 0x05e5, 0x0645 }, + { 0x05e6, 0x0646 }, + { 0x05e7, 0x0647 }, + { 0x05e8, 0x0648 }, + { 0x05e9, 0x0649 }, + { 0x05ea, 0x064a }, + { 0x05eb, 0x064b }, + { 0x05ec, 0x064c }, + { 0x05ed, 0x064d }, + { 0x05ee, 0x064e }, + { 0x05ef, 0x064f }, + { 0x05f0, 0x0650 }, + { 0x05f1, 0x0651 }, + { 0x05f2, 0x0652 }, + { 0x06a1, 0x0452 }, + { 0x06a2, 0x0453 }, + { 0x06a3, 0x0451 }, + { 0x06a4, 0x0454 }, + { 0x06a5, 0x0455 }, + { 0x06a6, 0x0456 }, + { 0x06a7, 0x0457 }, + { 0x06a8, 0x0458 }, + { 0x06a9, 0x0459 }, + { 0x06aa, 0x045a }, + { 0x06ab, 0x045b }, + { 0x06ac, 0x045c }, + { 0x06ae, 0x045e }, + { 0x06af, 0x045f }, + { 0x06b0, 0x2116 }, + { 0x06b1, 0x0402 }, + { 0x06b2, 0x0403 }, + { 0x06b3, 0x0401 }, + { 0x06b4, 0x0404 }, + { 0x06b5, 0x0405 }, + { 0x06b6, 0x0406 }, + { 0x06b7, 0x0407 }, + { 0x06b8, 0x0408 }, + { 0x06b9, 0x0409 }, + { 0x06ba, 0x040a }, + { 0x06bb, 0x040b }, + { 0x06bc, 0x040c }, + { 0x06be, 0x040e }, + { 0x06bf, 0x040f }, + { 0x06c0, 0x044e }, + { 0x06c1, 0x0430 }, + { 0x06c2, 0x0431 }, + { 0x06c3, 0x0446 }, + { 0x06c4, 0x0434 }, + { 0x06c5, 0x0435 }, + { 0x06c6, 0x0444 }, + { 0x06c7, 0x0433 }, + { 0x06c8, 0x0445 }, + { 0x06c9, 0x0438 }, + { 0x06ca, 0x0439 }, + { 0x06cb, 0x043a }, + { 0x06cc, 0x043b }, + { 0x06cd, 0x043c }, + { 0x06ce, 0x043d }, + { 0x06cf, 0x043e }, + { 0x06d0, 0x043f }, + { 0x06d1, 0x044f }, + { 0x06d2, 0x0440 }, + { 0x06d3, 0x0441 }, + { 0x06d4, 0x0442 }, + { 0x06d5, 0x0443 }, + { 0x06d6, 0x0436 }, + { 0x06d7, 0x0432 }, + { 0x06d8, 0x044c }, + { 0x06d9, 0x044b }, + { 0x06da, 0x0437 }, + { 0x06db, 0x0448 }, + { 0x06dc, 0x044d }, + { 0x06dd, 0x0449 }, + { 0x06de, 0x0447 }, + { 0x06df, 0x044a }, + { 0x06e0, 0x042e }, + { 0x06e1, 0x0410 }, + { 0x06e2, 0x0411 }, + { 0x06e3, 0x0426 }, + { 0x06e4, 0x0414 }, + { 0x06e5, 0x0415 }, + { 0x06e6, 0x0424 }, + { 0x06e7, 0x0413 }, + { 0x06e8, 0x0425 }, + { 0x06e9, 0x0418 }, + { 0x06ea, 0x0419 }, + { 0x06eb, 0x041a }, + { 0x06ec, 0x041b }, + { 0x06ed, 0x041c }, + { 0x06ee, 0x041d }, + { 0x06ef, 0x041e }, + { 0x06f0, 0x041f }, + { 0x06f1, 0x042f }, + { 0x06f2, 0x0420 }, + { 0x06f3, 0x0421 }, + { 0x06f4, 0x0422 }, + { 0x06f5, 0x0423 }, + { 0x06f6, 0x0416 }, + { 0x06f7, 0x0412 }, + { 0x06f8, 0x042c }, + { 0x06f9, 0x042b }, + { 0x06fa, 0x0417 }, + { 0x06fb, 0x0428 }, + { 0x06fc, 0x042d }, + { 0x06fd, 0x0429 }, + { 0x06fe, 0x0427 }, + { 0x06ff, 0x042a }, + { 0x07a1, 0x0386 }, + { 0x07a2, 0x0388 }, + { 0x07a3, 0x0389 }, + { 0x07a4, 0x038a }, + { 0x07a5, 0x03aa }, + { 0x07a7, 0x038c }, + { 0x07a8, 0x038e }, + { 0x07a9, 0x03ab }, + { 0x07ab, 0x038f }, + { 0x07ae, 0x0385 }, + { 0x07af, 0x2015 }, + { 0x07b1, 0x03ac }, + { 0x07b2, 0x03ad }, + { 0x07b3, 0x03ae }, + { 0x07b4, 0x03af }, + { 0x07b5, 0x03ca }, + { 0x07b6, 0x0390 }, + { 0x07b7, 0x03cc }, + { 0x07b8, 0x03cd }, + { 0x07b9, 0x03cb }, + { 0x07ba, 0x03b0 }, + { 0x07bb, 0x03ce }, + { 0x07c1, 0x0391 }, + { 0x07c2, 0x0392 }, + { 0x07c3, 0x0393 }, + { 0x07c4, 0x0394 }, + { 0x07c5, 0x0395 }, + { 0x07c6, 0x0396 }, + { 0x07c7, 0x0397 }, + { 0x07c8, 0x0398 }, + { 0x07c9, 0x0399 }, + { 0x07ca, 0x039a }, + { 0x07cb, 0x039b }, + { 0x07cc, 0x039c }, + { 0x07cd, 0x039d }, + { 0x07ce, 0x039e }, + { 0x07cf, 0x039f }, + { 0x07d0, 0x03a0 }, + { 0x07d1, 0x03a1 }, + { 0x07d2, 0x03a3 }, + { 0x07d4, 0x03a4 }, + { 0x07d5, 0x03a5 }, + { 0x07d6, 0x03a6 }, + { 0x07d7, 0x03a7 }, + { 0x07d8, 0x03a8 }, + { 0x07d9, 0x03a9 }, + { 0x07e1, 0x03b1 }, + { 0x07e2, 0x03b2 }, + { 0x07e3, 0x03b3 }, + { 0x07e4, 0x03b4 }, + { 0x07e5, 0x03b5 }, + { 0x07e6, 0x03b6 }, + { 0x07e7, 0x03b7 }, + { 0x07e8, 0x03b8 }, + { 0x07e9, 0x03b9 }, + { 0x07ea, 0x03ba }, + { 0x07eb, 0x03bb }, + { 0x07ec, 0x03bc }, + { 0x07ed, 0x03bd }, + { 0x07ee, 0x03be }, + { 0x07ef, 0x03bf }, + { 0x07f0, 0x03c0 }, + { 0x07f1, 0x03c1 }, + { 0x07f2, 0x03c3 }, + { 0x07f3, 0x03c2 }, + { 0x07f4, 0x03c4 }, + { 0x07f5, 0x03c5 }, + { 0x07f6, 0x03c6 }, + { 0x07f7, 0x03c7 }, + { 0x07f8, 0x03c8 }, + { 0x07f9, 0x03c9 }, + { 0x08a1, 0x23b7 }, + { 0x08a2, 0x250c }, + { 0x08a3, 0x2500 }, + { 0x08a4, 0x2320 }, + { 0x08a5, 0x2321 }, + { 0x08a6, 0x2502 }, + { 0x08a7, 0x23a1 }, + { 0x08a8, 0x23a3 }, + { 0x08a9, 0x23a4 }, + { 0x08aa, 0x23a6 }, + { 0x08ab, 0x239b }, + { 0x08ac, 0x239d }, + { 0x08ad, 0x239e }, + { 0x08ae, 0x23a0 }, + { 0x08af, 0x23a8 }, + { 0x08b0, 0x23ac }, + { 0x08bc, 0x2264 }, + { 0x08bd, 0x2260 }, + { 0x08be, 0x2265 }, + { 0x08bf, 0x222b }, + { 0x08c0, 0x2234 }, + { 0x08c1, 0x221d }, + { 0x08c2, 0x221e }, + { 0x08c5, 0x2207 }, + { 0x08c8, 0x223c }, + { 0x08c9, 0x2243 }, + { 0x08cd, 0x21d4 }, + { 0x08ce, 0x21d2 }, + { 0x08cf, 0x2261 }, + { 0x08d6, 0x221a }, + { 0x08da, 0x2282 }, + { 0x08db, 0x2283 }, + { 0x08dc, 0x2229 }, + { 0x08dd, 0x222a }, + { 0x08de, 0x2227 }, + { 0x08df, 0x2228 }, + { 0x08ef, 0x2202 }, + { 0x08f6, 0x0192 }, + { 0x08fb, 0x2190 }, + { 0x08fc, 0x2191 }, + { 0x08fd, 0x2192 }, + { 0x08fe, 0x2193 }, + { 0x09e0, 0x25c6 }, + { 0x09e1, 0x2592 }, + { 0x09e2, 0x2409 }, + { 0x09e3, 0x240c }, + { 0x09e4, 0x240d }, + { 0x09e5, 0x240a }, + { 0x09e8, 0x2424 }, + { 0x09e9, 0x240b }, + { 0x09ea, 0x2518 }, + { 0x09eb, 0x2510 }, + { 0x09ec, 0x250c }, + { 0x09ed, 0x2514 }, + { 0x09ee, 0x253c }, + { 0x09ef, 0x23ba }, + { 0x09f0, 0x23bb }, + { 0x09f1, 0x2500 }, + { 0x09f2, 0x23bc }, + { 0x09f3, 0x23bd }, + { 0x09f4, 0x251c }, + { 0x09f5, 0x2524 }, + { 0x09f6, 0x2534 }, + { 0x09f7, 0x252c }, + { 0x09f8, 0x2502 }, + { 0x0aa1, 0x2003 }, + { 0x0aa2, 0x2002 }, + { 0x0aa3, 0x2004 }, + { 0x0aa4, 0x2005 }, + { 0x0aa5, 0x2007 }, + { 0x0aa6, 0x2008 }, + { 0x0aa7, 0x2009 }, + { 0x0aa8, 0x200a }, + { 0x0aa9, 0x2014 }, + { 0x0aaa, 0x2013 }, + { 0x0aae, 0x2026 }, + { 0x0aaf, 0x2025 }, + { 0x0ab0, 0x2153 }, + { 0x0ab1, 0x2154 }, + { 0x0ab2, 0x2155 }, + { 0x0ab3, 0x2156 }, + { 0x0ab4, 0x2157 }, + { 0x0ab5, 0x2158 }, + { 0x0ab6, 0x2159 }, + { 0x0ab7, 0x215a }, + { 0x0ab8, 0x2105 }, + { 0x0abb, 0x2012 }, + { 0x0abc, 0x2329 }, + { 0x0abe, 0x232a }, + { 0x0ac3, 0x215b }, + { 0x0ac4, 0x215c }, + { 0x0ac5, 0x215d }, + { 0x0ac6, 0x215e }, + { 0x0ac9, 0x2122 }, + { 0x0aca, 0x2613 }, + { 0x0acc, 0x25c1 }, + { 0x0acd, 0x25b7 }, + { 0x0ace, 0x25cb }, + { 0x0acf, 0x25af }, + { 0x0ad0, 0x2018 }, + { 0x0ad1, 0x2019 }, + { 0x0ad2, 0x201c }, + { 0x0ad3, 0x201d }, + { 0x0ad4, 0x211e }, + { 0x0ad6, 0x2032 }, + { 0x0ad7, 0x2033 }, + { 0x0ad9, 0x271d }, + { 0x0adb, 0x25ac }, + { 0x0adc, 0x25c0 }, + { 0x0add, 0x25b6 }, + { 0x0ade, 0x25cf }, + { 0x0adf, 0x25ae }, + { 0x0ae0, 0x25e6 }, + { 0x0ae1, 0x25ab }, + { 0x0ae2, 0x25ad }, + { 0x0ae3, 0x25b3 }, + { 0x0ae4, 0x25bd }, + { 0x0ae5, 0x2606 }, + { 0x0ae6, 0x2022 }, + { 0x0ae7, 0x25aa }, + { 0x0ae8, 0x25b2 }, + { 0x0ae9, 0x25bc }, + { 0x0aea, 0x261c }, + { 0x0aeb, 0x261e }, + { 0x0aec, 0x2663 }, + { 0x0aed, 0x2666 }, + { 0x0aee, 0x2665 }, + { 0x0af0, 0x2720 }, + { 0x0af1, 0x2020 }, + { 0x0af2, 0x2021 }, + { 0x0af3, 0x2713 }, + { 0x0af4, 0x2717 }, + { 0x0af5, 0x266f }, + { 0x0af6, 0x266d }, + { 0x0af7, 0x2642 }, + { 0x0af8, 0x2640 }, + { 0x0af9, 0x260e }, + { 0x0afa, 0x2315 }, + { 0x0afb, 0x2117 }, + { 0x0afc, 0x2038 }, + { 0x0afd, 0x201a }, + { 0x0afe, 0x201e }, + { 0x0ba3, 0x003c }, + { 0x0ba6, 0x003e }, + { 0x0ba8, 0x2228 }, + { 0x0ba9, 0x2227 }, + { 0x0bc0, 0x00af }, + { 0x0bc2, 0x22a5 }, + { 0x0bc3, 0x2229 }, + { 0x0bc4, 0x230a }, + { 0x0bc6, 0x005f }, + { 0x0bca, 0x2218 }, + { 0x0bcc, 0x2395 }, + { 0x0bce, 0x22a4 }, + { 0x0bcf, 0x25cb }, + { 0x0bd3, 0x2308 }, + { 0x0bd6, 0x222a }, + { 0x0bd8, 0x2283 }, + { 0x0bda, 0x2282 }, + { 0x0bdc, 0x22a2 }, + { 0x0bfc, 0x22a3 }, + { 0x0cdf, 0x2017 }, + { 0x0ce0, 0x05d0 }, + { 0x0ce1, 0x05d1 }, + { 0x0ce2, 0x05d2 }, + { 0x0ce3, 0x05d3 }, + { 0x0ce4, 0x05d4 }, + { 0x0ce5, 0x05d5 }, + { 0x0ce6, 0x05d6 }, + { 0x0ce7, 0x05d7 }, + { 0x0ce8, 0x05d8 }, + { 0x0ce9, 0x05d9 }, + { 0x0cea, 0x05da }, + { 0x0ceb, 0x05db }, + { 0x0cec, 0x05dc }, + { 0x0ced, 0x05dd }, + { 0x0cee, 0x05de }, + { 0x0cef, 0x05df }, + { 0x0cf0, 0x05e0 }, + { 0x0cf1, 0x05e1 }, + { 0x0cf2, 0x05e2 }, + { 0x0cf3, 0x05e3 }, + { 0x0cf4, 0x05e4 }, + { 0x0cf5, 0x05e5 }, + { 0x0cf6, 0x05e6 }, + { 0x0cf7, 0x05e7 }, + { 0x0cf8, 0x05e8 }, + { 0x0cf9, 0x05e9 }, + { 0x0cfa, 0x05ea }, + { 0x0da1, 0x0e01 }, + { 0x0da2, 0x0e02 }, + { 0x0da3, 0x0e03 }, + { 0x0da4, 0x0e04 }, + { 0x0da5, 0x0e05 }, + { 0x0da6, 0x0e06 }, + { 0x0da7, 0x0e07 }, + { 0x0da8, 0x0e08 }, + { 0x0da9, 0x0e09 }, + { 0x0daa, 0x0e0a }, + { 0x0dab, 0x0e0b }, + { 0x0dac, 0x0e0c }, + { 0x0dad, 0x0e0d }, + { 0x0dae, 0x0e0e }, + { 0x0daf, 0x0e0f }, + { 0x0db0, 0x0e10 }, + { 0x0db1, 0x0e11 }, + { 0x0db2, 0x0e12 }, + { 0x0db3, 0x0e13 }, + { 0x0db4, 0x0e14 }, + { 0x0db5, 0x0e15 }, + { 0x0db6, 0x0e16 }, + { 0x0db7, 0x0e17 }, + { 0x0db8, 0x0e18 }, + { 0x0db9, 0x0e19 }, + { 0x0dba, 0x0e1a }, + { 0x0dbb, 0x0e1b }, + { 0x0dbc, 0x0e1c }, + { 0x0dbd, 0x0e1d }, + { 0x0dbe, 0x0e1e }, + { 0x0dbf, 0x0e1f }, + { 0x0dc0, 0x0e20 }, + { 0x0dc1, 0x0e21 }, + { 0x0dc2, 0x0e22 }, + { 0x0dc3, 0x0e23 }, + { 0x0dc4, 0x0e24 }, + { 0x0dc5, 0x0e25 }, + { 0x0dc6, 0x0e26 }, + { 0x0dc7, 0x0e27 }, + { 0x0dc8, 0x0e28 }, + { 0x0dc9, 0x0e29 }, + { 0x0dca, 0x0e2a }, + { 0x0dcb, 0x0e2b }, + { 0x0dcc, 0x0e2c }, + { 0x0dcd, 0x0e2d }, + { 0x0dce, 0x0e2e }, + { 0x0dcf, 0x0e2f }, + { 0x0dd0, 0x0e30 }, + { 0x0dd1, 0x0e31 }, + { 0x0dd2, 0x0e32 }, + { 0x0dd3, 0x0e33 }, + { 0x0dd4, 0x0e34 }, + { 0x0dd5, 0x0e35 }, + { 0x0dd6, 0x0e36 }, + { 0x0dd7, 0x0e37 }, + { 0x0dd8, 0x0e38 }, + { 0x0dd9, 0x0e39 }, + { 0x0dda, 0x0e3a }, + { 0x0ddf, 0x0e3f }, + { 0x0de0, 0x0e40 }, + { 0x0de1, 0x0e41 }, + { 0x0de2, 0x0e42 }, + { 0x0de3, 0x0e43 }, + { 0x0de4, 0x0e44 }, + { 0x0de5, 0x0e45 }, + { 0x0de6, 0x0e46 }, + { 0x0de7, 0x0e47 }, + { 0x0de8, 0x0e48 }, + { 0x0de9, 0x0e49 }, + { 0x0dea, 0x0e4a }, + { 0x0deb, 0x0e4b }, + { 0x0dec, 0x0e4c }, + { 0x0ded, 0x0e4d }, + { 0x0df0, 0x0e50 }, + { 0x0df1, 0x0e51 }, + { 0x0df2, 0x0e52 }, + { 0x0df3, 0x0e53 }, + { 0x0df4, 0x0e54 }, + { 0x0df5, 0x0e55 }, + { 0x0df6, 0x0e56 }, + { 0x0df7, 0x0e57 }, + { 0x0df8, 0x0e58 }, + { 0x0df9, 0x0e59 }, + { 0x0ea1, 0x3131 }, + { 0x0ea2, 0x3132 }, + { 0x0ea3, 0x3133 }, + { 0x0ea4, 0x3134 }, + { 0x0ea5, 0x3135 }, + { 0x0ea6, 0x3136 }, + { 0x0ea7, 0x3137 }, + { 0x0ea8, 0x3138 }, + { 0x0ea9, 0x3139 }, + { 0x0eaa, 0x313a }, + { 0x0eab, 0x313b }, + { 0x0eac, 0x313c }, + { 0x0ead, 0x313d }, + { 0x0eae, 0x313e }, + { 0x0eaf, 0x313f }, + { 0x0eb0, 0x3140 }, + { 0x0eb1, 0x3141 }, + { 0x0eb2, 0x3142 }, + { 0x0eb3, 0x3143 }, + { 0x0eb4, 0x3144 }, + { 0x0eb5, 0x3145 }, + { 0x0eb6, 0x3146 }, + { 0x0eb7, 0x3147 }, + { 0x0eb8, 0x3148 }, + { 0x0eb9, 0x3149 }, + { 0x0eba, 0x314a }, + { 0x0ebb, 0x314b }, + { 0x0ebc, 0x314c }, + { 0x0ebd, 0x314d }, + { 0x0ebe, 0x314e }, + { 0x0ebf, 0x314f }, + { 0x0ec0, 0x3150 }, + { 0x0ec1, 0x3151 }, + { 0x0ec2, 0x3152 }, + { 0x0ec3, 0x3153 }, + { 0x0ec4, 0x3154 }, + { 0x0ec5, 0x3155 }, + { 0x0ec6, 0x3156 }, + { 0x0ec7, 0x3157 }, + { 0x0ec8, 0x3158 }, + { 0x0ec9, 0x3159 }, + { 0x0eca, 0x315a }, + { 0x0ecb, 0x315b }, + { 0x0ecc, 0x315c }, + { 0x0ecd, 0x315d }, + { 0x0ece, 0x315e }, + { 0x0ecf, 0x315f }, + { 0x0ed0, 0x3160 }, + { 0x0ed1, 0x3161 }, + { 0x0ed2, 0x3162 }, + { 0x0ed3, 0x3163 }, + { 0x0ed4, 0x11a8 }, + { 0x0ed5, 0x11a9 }, + { 0x0ed6, 0x11aa }, + { 0x0ed7, 0x11ab }, + { 0x0ed8, 0x11ac }, + { 0x0ed9, 0x11ad }, + { 0x0eda, 0x11ae }, + { 0x0edb, 0x11af }, + { 0x0edc, 0x11b0 }, + { 0x0edd, 0x11b1 }, + { 0x0ede, 0x11b2 }, + { 0x0edf, 0x11b3 }, + { 0x0ee0, 0x11b4 }, + { 0x0ee1, 0x11b5 }, + { 0x0ee2, 0x11b6 }, + { 0x0ee3, 0x11b7 }, + { 0x0ee4, 0x11b8 }, + { 0x0ee5, 0x11b9 }, + { 0x0ee6, 0x11ba }, + { 0x0ee7, 0x11bb }, + { 0x0ee8, 0x11bc }, + { 0x0ee9, 0x11bd }, + { 0x0eea, 0x11be }, + { 0x0eeb, 0x11bf }, + { 0x0eec, 0x11c0 }, + { 0x0eed, 0x11c1 }, + { 0x0eee, 0x11c2 }, + { 0x0eef, 0x316d }, + { 0x0ef0, 0x3171 }, + { 0x0ef1, 0x3178 }, + { 0x0ef2, 0x317f }, + { 0x0ef3, 0x3181 }, + { 0x0ef4, 0x3184 }, + { 0x0ef5, 0x3186 }, + { 0x0ef6, 0x318d }, + { 0x0ef7, 0x318e }, + { 0x0ef8, 0x11eb }, + { 0x0ef9, 0x11f0 }, + { 0x0efa, 0x11f9 }, + { 0x0eff, 0x20a9 }, +#if 0 + /* FIXME: there is no keysym 0x13a4? But 0x20ac is EuroSign in both + keysym and Unicode */ + { 0x13a4, 0x20ac }, +#endif + { 0x13bc, 0x0152 }, + { 0x13bd, 0x0153 }, + { 0x13be, 0x0178 }, + { 0x20ac, 0x20ac }, + + /* Special function keys. */ + + { 0xff08, 0x0008 }, /* XK_BackSpace */ + { 0xff09, 0x0009 }, /* XK_Tab */ + { 0xff0a, 0x000a }, /* XK_Linefeed */ + { 0xff0d, 0x000d }, /* XK_Return */ + { 0xff13, 0x0013 }, /* XK_Pause */ + { 0xff1b, 0x001b }, /* XK_Escape */ + { 0xff50, 0x0001 }, /* XK_Home */ + { 0xff51, 0x001c }, /* XK_Left */ + { 0xff52, 0x001e }, /* XK_Up */ + { 0xff53, 0x001d }, /* XK_Right */ + { 0xff54, 0x001f }, /* XK_Down */ + { 0xff55, 0x000b }, /* XK_Prior */ + { 0xff56, 0x000c }, /* XK_Next */ + { 0xff57, 0x0004 }, /* XK_End */ + { 0xff6a, 0x0005 }, /* XK_Help */ + { 0xffff, 0x007f }, /* XK_Delete */ +}; + +long +keysym2ucs(int keysym) +{ + int min = 0; + int max = sizeof(keysymtab) / sizeof(struct codepair) - 1; + int mid; + + /* first check for Latin-1 characters (1:1 mapping) */ + if ((keysym >= 0x0020 && keysym <= 0x007e) || + (keysym >= 0x00a0 && keysym <= 0x00ff)) + return keysym; + + /* also check for directly encoded 24-bit UCS characters */ + if ((keysym & 0xff000000) == 0x01000000) + return keysym & 0x00ffffff; + + /* binary search in table */ + while (max >= min) { + mid = (min + max) / 2; + if (keysymtab[mid].keysym < keysym) + min = mid + 1; + else if (keysymtab[mid].keysym > keysym) + max = mid - 1; + else { + /* found it */ + return keysymtab[mid].ucs; + } + } + + /* no matching Unicode value found */ + return -1; +} + +static int +reverse_compare(const void *a, const void *b) +{ + const struct codepair *ca = a, *cb = b; + + return ca->ucs - cb->ucs; +} + +int +ucs2keysym(long ucs) +{ + static struct codepair *reverse_keysymtab; + + int min = 0; + int max = sizeof(keysymtab) / sizeof(struct codepair) - 1; + int mid; + + if (reverse_keysymtab == NULL) { + reverse_keysymtab = malloc(sizeof(keysymtab)); + memcpy(reverse_keysymtab, keysymtab, sizeof(keysymtab)); + + qsort(reverse_keysymtab, + sizeof(keysymtab) / sizeof(struct codepair), + sizeof(struct codepair), + reverse_compare); + } + + /* first check for Latin-1 characters (1:1 mapping) */ + if ((ucs >= 0x0020 && ucs <= 0x007e) || + (ucs >= 0x00a0 && ucs <= 0x00ff)) + return ucs; + + /* binary search in table */ + while (max >= min) { + mid = (min + max) / 2; + if (reverse_keysymtab[mid].ucs < ucs) + min = mid + 1; + else if (reverse_keysymtab[mid].ucs > ucs) + max = mid - 1; + else { + /* found it */ + return reverse_keysymtab[mid].keysym; + } + } + + /* finally, assume a directly encoded 24-bit UCS character */ + return ucs | 0x01000000; +} diff --git a/hw/xwin/keysym2ucs.h b/hw/xwin/keysym2ucs.h new file mode 100644 index 000000000..01af0371d --- /dev/null +++ b/hw/xwin/keysym2ucs.h @@ -0,0 +1,38 @@ +/* + * This module converts keysym values into the corresponding ISO 10646 + * (UCS, Unicode) values. + * + * The array keysymtab[] contains pairs of X11 keysym values for graphical + * characters and the corresponding Unicode value. The function + * keysym2ucs() maps a keysym onto a Unicode value using a binary search, + * therefore keysymtab[] must remain SORTED by keysym value. + * + * The keysym -> UTF-8 conversion will hopefully one day be provided + * by Xlib via XmbLookupString() and should ideally not have to be + * done in X applications. But we are not there yet. + * + * We allow to represent any UCS character in the range U-00000000 to + * U-00FFFFFF by a keysym value in the range 0x01000000 to 0x01ffffff. + * This admittedly does not cover the entire 31-bit space of UCS, but + * it does cover all of the characters up to U-10FFFF, which can be + * represented by UTF-16, and more, and it is very unlikely that higher + * UCS codes will ever be assigned by ISO. So to get Unicode character + * U+ABCD you can directly use keysym 0x0100abcd. + * + * Author: Markus G. Kuhn <mkuhn@acm.org>, University of Cambridge, April 2001 + * + * Special thanks to Richard Verhoeven <river@win.tue.nl> for preparing + * an initial draft of the mapping table. + * + * This software is in the public domain. Share and enjoy! + */ + +#ifndef KEYSYM2UCS_H +#define KEYSYM2UCS_H 1 + +extern long +keysym2ucs(int keysym); +extern int +ucs2keysym(long ucs); + +#endif /* KEYSYM2UCS_H */ diff --git a/hw/xwin/man/XWin.man b/hw/xwin/man/XWin.man index a6e452d67..7303bb68b 100644 --- a/hw/xwin/man/XWin.man +++ b/hw/xwin/man/XWin.man @@ -336,6 +336,10 @@ The RMLVO components of this configuration are then overridden by any \fB\-xkbrules\fP, \fB\-xkbmodel\fP, etc. keyboard configuration options specified. +If no matching keyboard configuration is known, and no keyboard configuration +options are specified, the \fIWindows\fP keyboard layout is converted to a +\fIxmodmap\fP(1) layout. + You can also use the \fIsetxkbmap\fP(1) or \fIxmodmap\fP(1) programs while \fIXWin\fP is running to change the keyboard layout. diff --git a/hw/xwin/winconfig.c b/hw/xwin/winconfig.c index 5cba2c360..42342f9ec 100644 --- a/hw/xwin/winconfig.c +++ b/hw/xwin/winconfig.c @@ -25,7 +25,7 @@ *or other dealings in this Software without prior written authorization *from the XFree86 Project. * - * Authors: Alexander Gottwald + * Authors: Alexander Gottwald */ #ifdef HAVE_XWIN_CONFIG_H @@ -98,6 +98,7 @@ winInfoRec g_winInfo = { NULL, /* options */ } , + TRUE, /* rmlvo */ { FALSE, 50} diff --git a/hw/xwin/winconfig.h b/hw/xwin/winconfig.h index 6585a3369..d631187f0 100644 --- a/hw/xwin/winconfig.h +++ b/hw/xwin/winconfig.h @@ -254,6 +254,7 @@ typedef struct { long rate; } keyboard; XkbRMLVOSet xkb; + Bool rmlvoNotModmap; struct { Bool emulate3Buttons; long emulate3Timeout; diff --git a/hw/xwin/winkeybd.c b/hw/xwin/winkeybd.c index bce2c5298..7b1708444 100644 --- a/hw/xwin/winkeybd.c +++ b/hw/xwin/winkeybd.c @@ -31,6 +31,8 @@ * Harold L Hunt II */ +#define WINVER 0x0600 + #ifdef HAVE_XWIN_CONFIG_H #include <xwin-config.h> #endif @@ -44,6 +46,7 @@ #include "xkbsrv.h" #include "dixgrabs.h" +#include "keysym2ucs.h" /* C does not have a logical XOR operator, so we use a macro instead */ #define LOGICAL_XOR(a,b) ((!(a) && (b)) || ((a) && !(b))) @@ -88,6 +91,358 @@ winKeybdCtrl(DeviceIntPtr pDevice, KeybdCtrl * pCtrl) { } +/* + + */ + +/* + Each key can generate 4 glyphs. They are, in order: + unshifted, shifted, modeswitch unshifted, modeswitch shifted +*/ +#define GLYPHS_PER_KEY 4 +#define NUM_KEYCODES 248 +#define MIN_KEYCODE XkbMinLegalKeyCode /* unfortunately, this isn't 0... */ +#define MAX_KEYCODE NUM_KEYCODES + MIN_KEYCODE - 1 + +typedef struct winKeyboardInfo_struct { + CARD8 modMap[MAP_LENGTH]; + KeySym keyMap[MAP_LENGTH * GLYPHS_PER_KEY]; +} winKeyboardInfo; + +winKeyboardInfo keyInfo; + +/* + * BuildModifierMaps + * + * Populate modMap assigning modifier-type keys which are present in the + * keymap to specific modifiers. + * + */ +static void +BuildModifierMaps(winKeyboardInfo *info) +{ + int i; + KeySym *k; + + memset(info->modMap, NoSymbol, sizeof(info->modMap)); + + for (i = 0; i < NUM_KEYCODES; i++) { + k = info->keyMap + i * GLYPHS_PER_KEY; + + switch (*k) { + case XK_Shift_L: + info->modMap[MIN_KEYCODE + i] = ShiftMask; + break; + + case XK_Shift_R: + info->modMap[MIN_KEYCODE + i] = ShiftMask; + break; + + case XK_Control_L: + info->modMap[MIN_KEYCODE + i] = ControlMask; + break; + + case XK_Control_R: + info->modMap[MIN_KEYCODE + i] = ControlMask; + break; + + case XK_Caps_Lock: + info->modMap[MIN_KEYCODE + i] = LockMask; + break; + + case XK_Alt_L: + info->modMap[MIN_KEYCODE + i] = Mod1Mask; + break; + + case XK_Alt_R: + info->modMap[MIN_KEYCODE + i] = Mod1Mask; + break; + + case XK_Meta_L: + info->modMap[MIN_KEYCODE + i] = Mod1Mask; + break; + + case XK_Meta_R: + info->modMap[MIN_KEYCODE + i] = Mod1Mask; + break; + + case XK_Num_Lock: + info->modMap[MIN_KEYCODE + i] = Mod2Mask; + break; + + case XK_Mode_switch: + info->modMap[MIN_KEYCODE + i] = Mod5Mask; + break; + + case XK_ISO_Level3_Shift: + info->modMap[MIN_KEYCODE + i] = Mod5Mask; + break; + } + } +} + +/* Table of virtualkey->keysym mappings for keys that are not Unicode characters */ +const static struct { + int vk; + KeySym ks[GLYPHS_PER_KEY]; +} knownVKs[] = { + { VK_BACK , {XK_BackSpace, XK_BackSpace, XK_BackSpace, XK_BackSpace} }, + { VK_ESCAPE , {XK_Escape, XK_Escape, XK_Escape, XK_Escape} }, + { VK_RETURN , {XK_Return, XK_Return, XK_Return, XK_Return} }, + { VK_TAB , {XK_Tab, XK_Tab, XK_Tab, XK_Tab} }, + + /* Modifier keys */ + { VK_CONTROL , { XK_Control_L, XK_Control_L, XK_Control_L, XK_Control_L} }, + { VK_LCONTROL, { XK_Control_L, XK_Control_L, XK_Control_L, XK_Control_L} }, + { VK_RCONTROL, { XK_Control_R, XK_Control_R, XK_Control_R, XK_Control_R} }, + { VK_SHIFT , { XK_Shift_L, XK_Shift_L, XK_Shift_L, XK_Shift_L} }, + { VK_LSHIFT , { XK_Shift_L, XK_Shift_L, XK_Shift_L, XK_Shift_L} }, + { VK_RSHIFT , { XK_Shift_R, XK_Shift_R, XK_Shift_R, XK_Shift_R} }, + { VK_MENU , { XK_Alt_L, XK_Alt_L, XK_Alt_L, XK_Alt_L} }, + { VK_LMENU , { XK_Alt_L, XK_Alt_L, XK_Alt_L, XK_Alt_L} }, + /* VK_RMENU ties up with the keyboard state used for modeswitched states */ + { VK_RMENU , { XK_ISO_Level3_Shift, XK_ISO_Level3_Shift, XK_ISO_Level3_Shift, XK_ISO_Level3_Shift} }, + { VK_CAPITAL , { XK_Caps_Lock, XK_Caps_Lock, XK_Caps_Lock, XK_Caps_Lock} }, + { VK_LWIN , { XK_Super_L, XK_Super_L, XK_Super_L, XK_Super_L} }, + { VK_RWIN , { XK_Super_R, XK_Super_R, XK_Super_R, XK_Super_R} }, + + /* */ + { VK_CANCEL , { XK_Break, XK_Break, XK_Break, XK_Break} }, + { VK_PAUSE , { XK_Pause, XK_Pause, XK_Pause, XK_Pause} }, + { VK_SCROLL , { XK_Scroll_Lock, XK_Scroll_Lock, XK_Scroll_Lock, XK_Scroll_Lock} }, + { VK_SNAPSHOT, { XK_Sys_Req, XK_Sys_Req, XK_Sys_Req, XK_Sys_Req} }, + { VK_APPS , { XK_Menu, XK_Menu, XK_Menu, XK_Menu } }, + + /* function keys */ + { VK_F1 , { XK_F1, XK_F1, XK_F1, XK_F1 } }, + { VK_F2 , { XK_F2, XK_F2, XK_F2, XK_F2 } }, + { VK_F3 , { XK_F3, XK_F3, XK_F3, XK_F3 } }, + { VK_F4 , { XK_F4, XK_F4, XK_F4, XK_F4 } }, + { VK_F5 , { XK_F5, XK_F5, XK_F5, XK_F5 } }, + { VK_F6 , { XK_F6, XK_F6, XK_F6, XK_F6 } }, + { VK_F7 , { XK_F7, XK_F7, XK_F7, XK_F7 } }, + { VK_F8 , { XK_F8, XK_F8, XK_F8, XK_F8 } }, + { VK_F9 , { XK_F9, XK_F9, XK_F9, XK_F9 } }, + { VK_F10 , { XK_F10, XK_F10, XK_F10, XK_F10 } }, + { VK_F11 , { XK_F11, XK_F11, XK_F11, XK_F11 } }, + { VK_F12 , { XK_F12, XK_F12, XK_F12, XK_F12 } }, + + /* numpad */ + { VK_NUMLOCK , { XK_Num_Lock, XK_Num_Lock, XK_Num_Lock, XK_Num_Lock } }, + { VK_ADD , { XK_KP_Add, XK_KP_Add, XK_KP_Add, XK_KP_Add } }, + { VK_DIVIDE , { XK_KP_Divide, XK_KP_Divide, XK_KP_Divide, XK_KP_Divide } }, + { VK_MULTIPLY, { XK_KP_Multiply, XK_KP_Multiply, XK_KP_Multiply, XK_KP_Multiply } }, + { VK_SUBTRACT, { XK_KP_Subtract, XK_KP_Subtract, XK_KP_Subtract, XK_KP_Subtract } }, + { VK_DECIMAL , { XK_KP_Delete, XK_KP_Decimal, XK_KP_Delete, XK_KP_Decimal } }, + { VK_NUMPAD0 , { XK_KP_Insert, XK_KP_0, XK_KP_Insert, XK_KP_0 } }, + { VK_NUMPAD1 , { XK_KP_End, XK_KP_1, XK_KP_End, XK_KP_1 } }, + { VK_NUMPAD2 , { XK_KP_Down, XK_KP_2, XK_KP_Down, XK_KP_2 } }, + { VK_NUMPAD3 , { XK_KP_Next, XK_KP_3, XK_KP_Next, XK_KP_3 } }, + { VK_NUMPAD4 , { XK_KP_Left, XK_KP_4, XK_KP_Left, XK_KP_4 } }, + { VK_NUMPAD5 , { XK_KP_Begin, XK_KP_5, XK_KP_Begin, XK_KP_5 } }, + { VK_NUMPAD6 , { XK_KP_Right, XK_KP_6, XK_KP_Right, XK_KP_6 } }, + { VK_NUMPAD7 , { XK_KP_Home, XK_KP_7, XK_KP_Home, XK_KP_7 } }, + { VK_NUMPAD8 , { XK_KP_Up, XK_KP_8, XK_KP_Up, XK_KP_8 } }, + { VK_NUMPAD9 , { XK_KP_Prior, XK_KP_9, XK_KP_Prior, XK_KP_9 } }, + + /* cursor motion */ + { VK_DELETE , { XK_Delete, XK_Delete, XK_Delete, XK_Delete } }, + { VK_DOWN , { XK_Down, XK_Down, XK_Down, XK_Down } }, + { VK_END , { XK_End, XK_End, XK_End, XK_End } }, + { VK_HOME , { XK_Home, XK_Home, XK_Home, XK_Home } }, + { VK_INSERT , { XK_Insert, XK_Insert, XK_Insert, XK_Insert } }, + { VK_LEFT , { XK_Left, XK_Left, XK_Left, XK_Left } }, + { VK_NEXT , { XK_Page_Down, XK_Page_Down, XK_Page_Down, XK_Page_Down } }, + { VK_PRIOR , { XK_Page_Up, XK_Page_Up, XK_Page_Up, XK_Page_Up } }, + { VK_RIGHT , { XK_Right, XK_Right, XK_Right, XK_Right } }, + { VK_UP , { XK_Up, XK_Up, XK_Up, XK_Up } }, +}; + +static KeySym +VKToKeySym(UINT vk, int state) +{ + int i; + + for (i = 0; i < sizeof(knownVKs) / sizeof(knownVKs[0]); i++) + if (knownVKs[i].vk == vk) return knownVKs[i].ks[state]; + + return 0; +} + +const static struct { + WCHAR diacritic; + KeySym dead; +} dead_keys[] = { + /* This table is sorted by KeySym value */ + { L'`', XK_dead_grave }, /* U+0060 GRAVE ACCENT */ + { L'\'', XK_dead_acute }, /* U+0027 APOSTROPHE */ + { L'´', XK_dead_acute }, /* U+00B4 ACUTE ACCENT */ + { L'^', XK_dead_circumflex }, /* U+005E CIRCUMFLEX ACCENT */ + { L'~', XK_dead_tilde }, /* U+007E TILDE */ + { L'¯', XK_dead_macron }, /* U+00AF MARK */ + { L'˘', XK_dead_breve }, /* U+02D8 BREVE */ + { L'˙', XK_dead_abovedot }, /* U+02D9 DOT ABOVE */ + { L'¨', XK_dead_diaeresis }, /* U+00A8 DIAERESIS */ + { L'"', XK_dead_diaeresis }, /* U+0022 QUOTATION MARK */ + { L'°', XK_dead_abovering }, /* U+00B0 DEGREE SIGN */ + { L'˝', XK_dead_doubleacute }, /* U+02DD DOUBLE ACUTE ACCENT */ + { L'ˇ', XK_dead_caron }, /* U+02C7 CARON */ + { L'¸', XK_dead_cedilla }, /* U+00B8 CEDILLA */ + { L'˛', XK_dead_ogonek }, /* U+02DB OGONEK */ + /* This table is incomplete ... */ +}; + +/* Map the spacing form of a diacritic glyph to a deadkey KeySym */ +static KeySym +make_dead_key(WCHAR in) +{ + int i; + + for (i = 0; i < sizeof(dead_keys) / sizeof(dead_keys[0]); i++) + if (dead_keys[i].diacritic == in) return dead_keys[i].dead; + + return 0; +} + +static bool +winKeybdModmapLayout(void) +{ + UINT vk; + int j; + memset(keyInfo.modMap, 0, MAP_LENGTH); + memset(keyInfo.keyMap, 0, MAP_LENGTH * GLYPHS_PER_KEY * sizeof(KeySym)); + + /* + For all scancodes, in the four shift states + + If it produces a VirtualKey code for which we know the + corresponding KeySym, use that. + + If it produces a Unicode character, convert that to an X11 KeySym + (which may just be a unicode Keysym, if there isn't a better one) + */ + for (j = 0; j < 4; j++) { + /* Setup the modifier key state */ + BYTE state[256]; + memset(state, 0, 256); + if ((j % 2) == 1) + state[VK_SHIFT] = 0x80; + if (j >= 2) { + /* VK_RMENU is mapped to XK_ISO_Level3_Shift + AltGR = Alt + Control + (what to use here might depend on layout?) */ + state[VK_CONTROL] = 0x80; + state[VK_MENU] = 0x80; + } + + winDebug("Examining %s%s layout\n", (j % 2) ? "shift " : "", + (j >= 2) ? "altgr" : ""); + + for (vk = 0; vk < 0xff; vk++) { + int sc; + KeySym ks; + char keyName[64]; + + /* Translate Virtual Key code to extended scan code */ + sc = MapVirtualKey(vk, MAPVK_VK_TO_VSC_EX); + if (sc == 0) + continue; + + /* Workaround what appear to be bugs in MAPVK_VK_TO_VSC_EX */ + if (((vk >= VK_PRIOR) && (vk <= VK_DOWN)) || + (vk == VK_INSERT) || (vk == VK_DELETE)) { + /* cursor keys are extended keys */ + sc = sc | 0xe000; + } + + /* Munge as we do actual key events, to translate extended + scancodes into the server generated ones */ + { + int tsc; + tsc = winTranslateKey(vk, + ((sc & 0xff) | (sc & 0xe000 ? 0x100 : 0)) << 16); + + if (tsc != sc) { + winDebug("scan code munged %x -> %x\n", sc, tsc); + sc = tsc; + } + } + + GetKeyNameText(sc << 16, keyName, sizeof(keyName)); + + /* Is the KeySym for the VK_ known ?*/ + ks = VKToKeySym(vk, j); + if (ks) { + winDebug("scan code %x (%s), VK %x -> keysym %x\n", sc, keyName, vk, ks); + } else { + /* What unicode characters are output by that key in + this modifier state */ + int result; + WCHAR out[8]; + char outAsUtf8[8]; + memset(outAsUtf8, 0, 8); + + result = ToUnicode(vk, sc, state, &out[0], 8, 0); + + if (result != 0) { + int len = WideCharToMultiByte(CP_UTF8, 0, out, 1, outAsUtf8, 8, NULL, NULL); + outAsUtf8[len] = '\0'; + } + + switch (result) { + case -1: /* dead-key */ + ks = make_dead_key(out[0]); + if (ks) + winDebug("scan code %x (%s), VK %x -> deadkey %x ('%s') -> keysym %x\n", sc, keyName, vk, out[0], outAsUtf8, ks); + else + ErrorF("scan code %x (%s), VK %x -> deadkey %x ('%s') -> unknown keysym\n", sc, keyName, vk, out[0], outAsUtf8); + + /* Force the partially-composed state to be discarded, so it + doesn't effect the next call to ToUnicode() */ + ToUnicode(vk, sc, state, &out[0], 8, 0); + + break; + case 0: /* nothing */ + winDebug("scan code %x (%s), VK %x -> nothing\n", sc, keyName, vk); + break; + case 1: /* something */ + ks = ucs2keysym(out[0]); + winDebug("scan code %x (%s), VK %x -> unicode %x ('%s') -> keysym %x\n", sc, keyName, vk, out[0], outAsUtf8, ks); + break; + default: + case 2: /* too much */ + ErrorF("scan code %x (%s), VK %x produced %d unicode characters ('%s')\n", sc, keyName, vk, result, outAsUtf8); + break; + } + } + + if (ks) { + KeySym *k; + k = keyInfo.keyMap + (sc & 0xff) * GLYPHS_PER_KEY; + if ((k[j]) && (k[j] != ks)) + ErrorF("X KeyCode %d state %d KeySym collision %d and %d\n", sc, j, k[j], ks); + k[j] = ks; + } + } + + /* keypad_enter doesn't have a separate VK code, so we need to + add it ourselves */ + { + int sc; + KeySym *k; + + sc = KEY_KP_Enter; + k = keyInfo.keyMap + (sc & 0xff) * GLYPHS_PER_KEY; + k[j] = XK_KP_Enter; + } + } + + /* Build the modmap */ + BuildModifierMaps(&keyInfo); + + return TRUE; +} + /* Find the XKB layout corresponding to the current Windows keyboard layout */ void winKeybdLayoutFind(void) @@ -97,14 +452,16 @@ winKeybdLayoutFind(void) unsigned int layoutNum = 0; unsigned int deviceIdentifier = 0; int keyboardType; + Bool bfound = FALSE; /* Setup defaults */ XkbGetRulesDflts(&g_winInfo.xkb); + g_winInfo.rmlvoNotModmap = TRUE; + keyboardType = GetKeyboardType(0); if (keyboardType > 0 && GetKeyboardLayoutName(layoutName)) { WinKBLayoutPtr pLayout; - Bool bfound = FALSE; int pass; layoutNum = strtoul(layoutName, (char **) NULL, 16); @@ -189,51 +546,78 @@ winKeybdLayoutFind(void) if (bfound) break; } + } - if (!bfound) { - winMsg(X_ERROR, - "Keyboardlayout \"%s\" (%s) is unknown, using X server default layout\n", - layoutFriendlyName, layoutName); + /* If that fails, try converting the Windows layout to a modmap */ + if (!bfound) { + winMsg(X_ERROR, + "Keyboardlayout \"%s\" (%s) is unknown\n", layoutFriendlyName, layoutName); + + bfound = winKeybdModmapLayout(); + + if (bfound) { + winMsg(X_INFO, "Converted to modmap\n"); + g_winInfo.rmlvoNotModmap = FALSE; + } else { + winMsg(X_INFO, "Conversion to modmap failed\n"); } } + + if (!bfound) { + winMsg(X_ERROR, "using X server default layout\n"); + } } void winKeybdLayoutChange(void) { - pthread_t t; - static char cmd[256]; - /* Ignore layout changes if static layout was requested */ if (g_cmdline.xkbStatic) return; winKeybdLayoutFind(); - /* Compile rmlvo keymap and apply it */ - sprintf(cmd, "/usr/bin/setxkbmap %s%s %s%s %s%s %s%s %s%s", - g_winInfo.xkb.rules ? "-rules " : "", - g_winInfo.xkb.rules ? g_winInfo.xkb.rules : "", - g_winInfo.xkb.model ? "-model " : "", - g_winInfo.xkb.model ? g_winInfo.xkb.model : "", - g_winInfo.xkb.layout ? "-layout " : "", - g_winInfo.xkb.layout ? g_winInfo.xkb.layout : "", - g_winInfo.xkb.variant ? "-variant " : "", - g_winInfo.xkb.variant ? g_winInfo.xkb.variant : "", - g_winInfo.xkb.options ? "-option " : "", - g_winInfo.xkb.options ? g_winInfo.xkb.options : ""); + if (g_winInfo.rmlvoNotModmap) { + pthread_t t; + static char cmd[256]; + + /* Compile rmlvo keymap and apply it */ + sprintf(cmd, "/usr/bin/setxkbmap %s%s %s%s %s%s %s%s %s%s", + g_winInfo.xkb.rules ? "-rules " : "", + g_winInfo.xkb.rules ? g_winInfo.xkb.rules : "", + g_winInfo.xkb.model ? "-model " : "", + g_winInfo.xkb.model ? g_winInfo.xkb.model : "", + g_winInfo.xkb.layout ? "-layout " : "", + g_winInfo.xkb.layout ? g_winInfo.xkb.layout : "", + g_winInfo.xkb.variant ? "-variant " : "", + g_winInfo.xkb.variant ? g_winInfo.xkb.variant : "", + g_winInfo.xkb.options ? "-option " : "", + g_winInfo.xkb.options ? g_winInfo.xkb.options : ""); - /* - Really keymap should be updated synchronously in WM_INPUTLANGCHANGE, so - that any subsequent WM_KEY(UP|DOWN) are interpreted correctly. But this - is currently impossible as message pump is run in the server thread, so - we create a separate thread to do this work... - */ + /* + Really keymap should be updated synchronously in WM_INPUTLANGCHANGE, + so that any subsequent WM_KEY(UP|DOWN) are interpreted correctly. But + this is currently impossible as message pump is run in the server + thread, so we create a separate thread to do this work... + */ + + if (!pthread_create(&t, NULL, ExecAndLogThread, cmd)) + pthread_detach(t); + else + ErrorF("Creating setxkbmap failed\n"); + } else { + KeySymsRec keySyms; + keySyms.map = keyInfo.keyMap; + keySyms.mapWidth = GLYPHS_PER_KEY; + keySyms.minKeyCode = MIN_KEYCODE; + keySyms.maxKeyCode = MAX_KEYCODE; + + /* TODO: We should build the entire XkbDescRec and use XkbCopyKeymap */ + XkbApplyMappingChange(g_pwinKeyboard, &keySyms, keySyms.minKeyCode, + keySyms.maxKeyCode - keySyms.minKeyCode + 1, + keyInfo.modMap, serverClient); - if (!pthread_create(&t, NULL, ExecAndLogThread, cmd)) - pthread_detach(t); - else - ErrorF("Creating setxkbmap failed\n"); + } } /* |