diff --git a/Makefile b/Makefile index b83981a..b30dcfd 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ # Configuration defaults CC = cc -CFLAGS = -O2 +CFLAGS = -O2 -DKEYMAP_PATH=\"$(KEYMAP_PATH)\" INCLUDES = -I/usr/X11R6/include LDLIBS = -L/usr/X11R6/lib -lX11 @@ -15,8 +15,11 @@ PREFIX = /usr/local EPREFIX = $(PREFIX) BINDIR = $(EPREFIX)/bin MANDIR = $(PREFIX)/man +SHAREDIR = $(PREFIX)/share/rdesktop -RDPOBJ = rdesktop.o tcp.o iso.o mcs.o secure.o licence.o rdp.o orders.o bitmap.o cache.o xwin.o +KEYMAP_PATH = $(SHAREDIR)/keymaps/ + +RDPOBJ = rdesktop.o tcp.o iso.o mcs.o secure.o licence.o rdp.o orders.o bitmap.o cache.o xwin.o xkeymap.o CRYPTOBJ = crypto/rc4_enc.o crypto/rc4_skey.o crypto/md5_dgst.o crypto/sha1dgst.o crypto/bn_exp.o crypto/bn_mul.o crypto/bn_div.o crypto/bn_sqr.o crypto/bn_add.o crypto/bn_shift.o crypto/bn_asm.o crypto/bn_ctx.o crypto/bn_lib.o include Makeconf # local configuration @@ -28,7 +31,7 @@ rdesktop: $(RDPOBJ) $(CRYPTOBJ) Makeconf: ./configure -install: installbin +install: installbin installkeymaps installbin: rdesktop mkdir -p $(BINDIR) @@ -41,6 +44,11 @@ installman: rdesktop.1 cp rdesktop.1 $(MANDIR)/man1 chmod 755 $(MANDIR)/man1/rdesktop.1 +installkeymaps: + mkdir -p $(KEYMAP_PATH) + cp keymaps/* $(KEYMAP_PATH) + chmod 644 $(KEYMAP_PATH)/* + proto: cproto -DMAKE_PROTO -o proto.h *.c diff --git a/keymaps/common b/keymaps/common new file mode 100644 index 0000000..1c5273f --- /dev/null +++ b/keymaps/common @@ -0,0 +1,52 @@ +01 Escape +0e BackSpace +0f Tab ISO_Left_Tab +1c Return +1d Control_L +2a Shift_L +36 Shift_R +37 KP_Multiply +38 Alt_L +39 space +3a Caps_Lock +3b F1 +3c F2 +3d F3 +3e F4 +3f F5 +40 F6 +41 F7 +42 F8 +43 F9 +44 F10 +45 Num_Lock +46 Scroll_Lock +47 KP_Home KP_7 +48 KP_Up KP_8 +49 KP_Prior KP_9 +4a KP_Subtract +4b KP_Left KP_4 +4c KP_Begin KP_5 +4d KP_Right KP_6 +4e KP_Add +4f KP_End KP_1 +50 KP_Down KP_2 +51 KP_Next KP_3 +52 KP_Insert KP_0 +53 KP_Delete KP_Decimal +54 Print +57 F11 +58 F12 +9c KP_Enter +9d Control_R +b8 Alt_R +c7 Home +c8 Up +c9 Prior +cb Left +cd Right +cf End +d0 Down +d1 Next +d2 Insert +d3 Delete diff --git a/keymaps/de b/keymaps/de new file mode 100644 index 0000000..5e52eae --- /dev/null +++ b/keymaps/de @@ -0,0 +1,50 @@ +include common +map 407 de +02 1 exclam +03 2 quotedbl twosuperior +04 3 section threesuperior +05 4 dollar +06 5 percent +07 6 ampersand +08 7 slash braceleft +09 8 parenleft bracketleft +0a 9 parenright bracketright +0b 0 equal braceright +0c ssharp question backslash +0d apostrophe +10 q Q at +11 w W +12 e E +13 r R +14 t T +15 z Z +16 u U +17 i I +18 o O +19 p P +1a udiaeresis Udiaeresis +1b plus asterisk asciitilde +1e a A +1f s S +20 d D +21 f F +22 g G +23 h H +24 j J +25 k K +26 l L +27 odiaeresis Odiaeresis +28 adiaeresis Adiaeresis +29 asciicircum degree +2b numbersign acute +2c y Y +2d x X +2e c C +2f v V +30 b B +31 n N +32 m M mu +33 comma semicolon +34 period colon +35 minus underscore +56 less greater bar diff --git a/keymaps/fr b/keymaps/fr new file mode 100644 index 0000000..99a7bca --- /dev/null +++ b/keymaps/fr @@ -0,0 +1,49 @@ +include common +map 40c fr +02 ampersand 1 +03 eacute 2 asciitilde +04 quotedbl 3 numbersign +05 apostrophe 4 braceleft +06 parenleft 5 bracketleft +07 minus 6 bar +08 egrave 7 grave +09 underscore 8 backslash +0a ccedilla 9 asciicircum +0b agrave 0 at +0c parenright degree bracketright +0d equal plus braceright +10 a A +11 z Z +12 e E +13 r R +14 t T +15 y Y +16 u U +17 i I +18 o O +19 p P +1a diaeresis +1b dollar sterling currency +1e q Q +1f s S ssharp +20 d D +21 f F +22 g G +23 h H +24 j J +25 k K +26 l L +27 m M +28 ugrave percent +29 asterisk mu +2c w W +2d x X +2e c C +2f v V +30 b B +31 n N +32 comma question +33 semicolon period +34 colon slash +35 exclam section +56 less greater diff --git a/keymaps/uk b/keymaps/uk new file mode 100644 index 0000000..b255f5b --- /dev/null +++ b/keymaps/uk @@ -0,0 +1,7 @@ +include us +map 809 uk +03 2 quotedbl +04 3 sterling +28 apostrophe at +2b numbersign asciitilde +56 backslash bar diff --git a/keymaps/us b/keymaps/us new file mode 100644 index 0000000..d0d29dc --- /dev/null +++ b/keymaps/us @@ -0,0 +1,49 @@ +include common +map 409 us +02 1 exclam +03 2 at +04 3 numbersign +05 4 dollar +06 5 percent +07 6 asciicircum +08 7 ampersand +09 8 asterisk +0a 9 parenleft +0b 0 parenright +0c minus underscore +0d equal plus +10 q Q +11 w W +12 e E +13 r R +14 t T +15 y Y +16 u U +17 i I +18 o O +19 p P +1a bracketleft braceleft +1b bracketright braceright +1e a A +1f s S +20 d D +21 f F +22 g G +23 h H +24 j J +25 k K +26 l L +27 semicolon colon +28 apostrophe quotedbl +29 grave asciitilde +2b backslash bar +2c z Z +2d x X +2e c C +2f v V +30 b B +31 n N +32 m M +33 comma less +34 period greater +35 slash question diff --git a/rdesktop.c b/rdesktop.c index 6604c7a..df86bb1 100644 --- a/rdesktop.c +++ b/rdesktop.c @@ -30,9 +30,10 @@ char username[16]; char hostname[16]; +char keymapname[16]; +int keylayout; int width; int height; -int keylayout = 0x409; BOOL bitmap_compression = True; BOOL sendmotion = True; BOOL orders = True; @@ -52,7 +53,7 @@ usage(char *program) printf(" -c: working directory\n"); printf(" -p: password (autologon)\n"); printf(" -n: client hostname\n"); - printf(" -k: keyboard layout (hex)\n"); + printf(" -k: keyboard layout\n"); printf(" -g: desktop geometry (WxH)\n"); printf(" -f: full-screen mode\n"); printf(" -b: force bitmap updates\n"); @@ -82,6 +83,7 @@ main(int argc, char *argv[]) flags = RDP_LOGON_NORMAL; domain[0] = password[0] = shell[0] = directory[0] = 0; + strcpy(keymapname, "us"); while ((c = getopt(argc, argv, "u:d:s:c:p:n:k:g:fbemlh?")) != -1) { @@ -113,12 +115,7 @@ main(int argc, char *argv[]) break; case 'k': - keylayout = strtol(optarg, NULL, 16); - if (keylayout == 0) - { - error("invalid keyboard layout\n"); - return 1; - } + STRNCPY(keymapname, optarg, sizeof(keymapname)); break; case 'g': @@ -226,9 +223,9 @@ main(int argc, char *argv[]) rdp_main_loop(); printf("Disconnecting...\n"); ui_destroy_window(); + rdp_disconnect(); } - rdp_disconnect(); return 0; } diff --git a/xkeymap.c b/xkeymap.c new file mode 100644 index 0000000..065b5b0 --- /dev/null +++ b/xkeymap.c @@ -0,0 +1,181 @@ +/* + rdesktop: A Remote Desktop Protocol client. + User interface services - X keyboard mapping + Copyright (C) Matthew Chapman 1999-2001 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include "rdesktop.h" + +#define KEYMAP_SIZE 4096 +#define KEYMAP_MASK (KEYMAP_SIZE - 1) + +extern char keymapname[16]; +extern int keylayout; + +static uint8 keymap[KEYMAP_SIZE]; +static unsigned int min_keycode; + +static BOOL xkeymap_read(char *mapname) +{ + FILE *fp; + char line[256], path[256]; + char *keyname, *p; + KeySym keysym; + unsigned char keycode; + unsigned int mapcode = 0; + + strcpy(path, KEYMAP_PATH); + strncat(path, mapname, sizeof(path) - sizeof(KEYMAP_PATH)); + + fp = fopen(path, "r"); + if (fp == NULL) + { + error("Failed to open keymap %s\n", path); + return False; + } + + while (fgets(line, sizeof(line), fp) != NULL) + { + p = strchr(line, '\n'); + if (p != NULL) + *p = 0; + + keycode = strtol(line, &keyname, 16); + if ((keycode != 0) && (*keyname == ' ')) + { + do + { + keyname++; + p = strchr(keyname, ' '); + if (p != NULL) + *p = 0; + + keysym = XStringToKeysym(keyname); + if (keysym == NoSymbol) + error("Bad keysym %s in keymap %s\n", keyname, mapname); + + keymap[keysym & KEYMAP_MASK] = keycode; + keyname = p; + + } while (keyname != NULL); + } + else if (strncmp(line, "include ", 8) == 0) + { + if (!xkeymap_read(line+8)) + return False; + } + else if (strncmp(line, "map ", 4) == 0) + { + keylayout = strtol(line+4, NULL, 16); + } + else if (line[0] != '#') + { + error("Malformed line in keymap %s\n", mapname); + } + } + + fclose(fp); + return True; +} + +void xkeymap_init(Display *display) +{ + unsigned int max_keycode; + + XDisplayKeycodes(display, &min_keycode, &max_keycode); + + if (strcmp(keymapname, "none")) + xkeymap_read(keymapname); +} + +uint8 xkeymap_translate_key(KeySym keysym, unsigned int keycode) +{ + uint8 scancode; + + scancode = keymap[keysym & KEYMAP_MASK]; + if (scancode != 0) + return scancode; + + /* not in keymap, try to interpret the raw scancode */ + + if ((keycode >= min_keycode) && (keycode <= 0x60)) + return (uint8)(keycode - min_keycode); + + switch (keycode) + { + case 0x61: /* home */ + return 0x47 | 0x80; + case 0x62: /* up arrow */ + return 0x48 | 0x80; + case 0x63: /* page up */ + return 0x49 | 0x80; + case 0x64: /* left arrow */ + return 0x4b | 0x80; + case 0x66: /* right arrow */ + return 0x4d | 0x80; + case 0x67: /* end */ + return 0x4f | 0x80; + case 0x68: /* down arrow */ + return 0x50 | 0x80; + case 0x69: /* page down */ + return 0x51 | 0x80; + case 0x6a: /* insert */ + return 0x52 | 0x80; + case 0x6b: /* delete */ + return 0x53 | 0x80; + case 0x6c: /* keypad enter */ + return 0x1c | 0x80; + case 0x6d: /* right ctrl */ + return 0x1d | 0x80; + case 0x6f: /* ctrl - print screen */ + return 0x37 | 0x80; + case 0x70: /* keypad '/' */ + return 0x35 | 0x80; + case 0x71: /* right alt */ + return 0x38 | 0x80; + case 0x72: /* ctrl break */ + return 0x46 | 0x80; + case 0x73: /* left window key */ + return 0x5b | 0x80; + case 0x74: /* right window key */ + return 0x5c | 0x80; + case 0x75: /* menu key */ + return 0x5d | 0x80; + } + + return 0; +} + +uint16 xkeymap_translate_button(unsigned int button) +{ + switch (button) + { + case Button1: /* left */ + return MOUSE_FLAG_BUTTON1; + case Button2: /* middle */ + return MOUSE_FLAG_BUTTON3; + case Button3: /* right */ + return MOUSE_FLAG_BUTTON2; + } + + return 0; +} diff --git a/xwin.c b/xwin.c index eee1d7f..11b9dc8 100644 --- a/xwin.c +++ b/xwin.c @@ -1,6 +1,6 @@ /* rdesktop: A Remote Desktop Protocol client. - User interface services - X-Windows + User interface services - X Window System Copyright (C) Matthew Chapman 1999-2001 This program is free software; you can redistribute it and/or modify @@ -24,6 +24,8 @@ #include #include "rdesktop.h" +extern char keymapname[16]; +extern int keylayout; extern int width; extern int height; extern BOOL sendmotion; @@ -280,6 +282,8 @@ ui_create_window(char *title) XFree(sizehints); } + xkeymap_init(display); + input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask; @@ -312,79 +316,11 @@ ui_destroy_window() display = NULL; } -static uint8 -xwin_translate_key(unsigned long key) -{ - DEBUG(("KEY(code=0x%lx)\n", key)); - - if ((key > 8) && (key <= 0x60)) - return (key - 8); - - switch (key) - { - case 0x61: /* home */ - return 0x47 | 0x80; - case 0x62: /* up arrow */ - return 0x48 | 0x80; - case 0x63: /* page up */ - return 0x49 | 0x80; - case 0x64: /* left arrow */ - return 0x4b | 0x80; - case 0x66: /* right arrow */ - return 0x4d | 0x80; - case 0x67: /* end */ - return 0x4f | 0x80; - case 0x68: /* down arrow */ - return 0x50 | 0x80; - case 0x69: /* page down */ - return 0x51 | 0x80; - case 0x6a: /* insert */ - return 0x52 | 0x80; - case 0x6b: /* delete */ - return 0x53 | 0x80; - case 0x6c: /* keypad enter */ - return 0x1c | 0x80; - case 0x6d: /* right ctrl */ - return 0x1d | 0x80; - case 0x6f: /* ctrl - print screen */ - return 0x37 | 0x80; - case 0x70: /* keypad '/' */ - return 0x35 | 0x80; - case 0x71: /* right alt */ - return 0x38 | 0x80; - case 0x72: /* ctrl break */ - return 0x46 | 0x80; - case 0x73: /* left window key */ - return 0xff; /* real scancode is 5b */ - case 0x74: /* right window key */ - return 0xff; /* real scancode is 5c */ - case 0x75: /* menu key */ - return 0x5d | 0x80; - } - - return 0; -} - -static uint16 -xwin_translate_mouse(unsigned long button) -{ - switch (button) - { - case Button1: /* left */ - return MOUSE_FLAG_BUTTON1; - case Button2: /* middle */ - return MOUSE_FLAG_BUTTON3; - case Button3: /* right */ - return MOUSE_FLAG_BUTTON2; - } - - return 0; -} - static void xwin_process_events() { XEvent event; + KeySym keysym; uint8 scancode; uint16 button; uint32 ev_time; @@ -399,7 +335,8 @@ xwin_process_events() switch (event.type) { case KeyPress: - scancode = xwin_translate_key(event.xkey.keycode); + keysym = XKeycodeToKeysym(display, event.xkey.keycode, 0); + scancode = xkeymap_translate_key(keysym, event.xkey.keycode); if (scancode == 0) break; @@ -408,7 +345,8 @@ xwin_process_events() break; case KeyRelease: - scancode = xwin_translate_key(event.xkey.keycode); + keysym = XKeycodeToKeysym(display, event.xkey.keycode, 0); + scancode = xkeymap_translate_key(keysym, event.xkey.keycode); if (scancode == 0) break; @@ -418,7 +356,7 @@ xwin_process_events() break; case ButtonPress: - button = xwin_translate_mouse(event.xbutton.button); + button = xkeymap_translate_button(event.xbutton.button); if (button == 0) break; @@ -429,7 +367,7 @@ xwin_process_events() break; case ButtonRelease: - button = xwin_translate_mouse(event.xbutton.button); + button = xkeymap_translate_button(event.xbutton.button); if (button == 0) break;