--- sourceforge.net/trunk/rdesktop/xwin.c 2002/04/19 12:06:08 49 +++ sourceforge.net/trunk/rdesktop/xwin.c 2002/06/07 07:49:59 54 @@ -2,17 +2,17 @@ rdesktop: A Remote Desktop Protocol client. User interface services - X Window System 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. @@ -20,6 +20,7 @@ #include #include +#include #include #include #include "rdesktop.h" @@ -31,7 +32,8 @@ extern BOOL sendmotion; extern BOOL fullscreen; -static Display *display; +Display *display; +XkbDescPtr xkb; static int x_socket; static Window wnd; static GC gc; @@ -47,6 +49,23 @@ static BOOL ownbackstore; static Pixmap backstore; +/* needed to keep track of the modifiers */ +static unsigned int numlock_modifier_mask = 0; +static unsigned int key_down_state = 0; + + +#define DShift1Mask (1<<0) +#define DLockMask (1<<1) +#define DControl1Mask (1<<2) +#define DMod1Mask (1<<3) +#define DMod2Mask (1<<4) +#define DMod3Mask (1<<5) +#define DMod4Mask (1<<6) +#define DMod5Mask (1<<7) +#define DShift2Mask (1<<8) +#define DControl2Mask (1<<9) +#define DNumLockMask (1<<10) + #define FILL_RECTANGLE(x,y,cx,cy)\ { \ XFillRectangle(display, wnd, gc, x, y, cx, cy); \ @@ -86,6 +105,11 @@ #define SET_FUNCTION(rop2) { if (rop2 != ROP2_COPY) XSetFunction(display, gc, rop2_map[rop2]); } #define RESET_FUNCTION(rop2) { if (rop2 != ROP2_COPY) XSetFunction(display, gc, GXcopy); } +void xwin_get_numlock_mask(); +void xwin_mod_update(uint32 state, uint32 ev_time ); +void xwin_mod_release(uint32 state, uint32 ev_time, uint32 scancode); +void xwin_mod_press(uint32 state, uint32 ev_time, uint32 scancode); + static void translate8(uint8 *data, uint8 *out, uint8 *end) { @@ -191,8 +215,40 @@ Screen *screen; uint16 test; int i; + + int xkb_minor, xkb_major; + int xkb_event, xkb_error, xkb_reason; + + /* compare compiletime libs with runtime libs. */ + xkb_major = XkbMajorVersion; + xkb_minor = XkbMinorVersion; + if( XkbLibraryVersion( &xkb_major, &xkb_minor ) == False ) + { + error("please re-compile rdesktop\ncompile time version of xkb is not compatible with\nyour runtime version of the library\n"); + return False; + } + + + display = XkbOpenDisplay( NULL, &xkb_event, &xkb_error, &xkb_major, &xkb_minor, &xkb_reason ); + switch(xkb_reason) + { + case XkbOD_BadLibraryVersion: + error("XkbOD_BadLibraryVersion: XKB extensions in server and the library rdesktop is linked against aren't compatible with each other.\n"); + break; + case XkbOD_ConnectionRefused: + error("XkbOD_ConnectionRefused\n"); + break; + case XkbOD_BadServerVersion: + error("XkbOD_BadServerVersion\n"); + break; + case XkbOD_NonXkbServer: + error("XkbOD_NonXkbServer: XKB extension not present in server\nupdate your X server.\n"); + break; + case XkbOD_Success: + DEBUG("XkbOD_Success: Connection established with display\n"); + break; + } - display = XOpenDisplay(NULL); if (display == NULL) { error("Failed to open display\n"); @@ -203,7 +259,7 @@ screen = DefaultScreenOfDisplay(display); visual = DefaultVisualOfScreen(screen); depth = DefaultDepthOfScreen(screen); - + pfm = XListPixmapFormats(display, &i); if (pfm != NULL) { @@ -282,12 +338,11 @@ XFree(sizehints); } - xkeymap_init(display); - - input_mask = KeyPressMask | KeyReleaseMask - | ButtonPressMask | ButtonReleaseMask - | EnterWindowMask | LeaveWindowMask; + xkeymap_init(); + input_mask = KeyPressMask | KeyReleaseMask | + ButtonPressMask | ButtonReleaseMask | + EnterWindowMask | LeaveWindowMask; if (sendmotion) input_mask |= PointerMotionMask; @@ -301,12 +356,72 @@ backstore = XCreatePixmap(display, wnd, width, height, depth); XMapWindow(display, wnd); + + /* TODO: error texts... make them friendly. */ + xkb = XkbGetKeyboard(display, XkbAllComponentsMask, XkbUseCoreKbd); + if ((int)xkb == BadAlloc || xkb == NULL) + { + error( "XkbGetKeyboard failed.\n"); + exit(0); + } + + /* TODO: error texts... make them friendly. */ + if( XkbSelectEvents(display, xkb->device_spec, XkbAllEventsMask, XkbAllEventsMask) == False ) + { + error( "XkbSelectEvents failed.\n"); + exit(0); + } + + xwin_get_numlock_mask(); + return True; } void +xwin_get_numlock_mask() +{ + KeyCode numlockcode; + KeyCode* keycode; + XModifierKeymap *modmap; + int i,j; + + /* Find out if numlock is already defined as a modifier key, and if so where */ + numlockcode = XKeysymToKeycode(display, 0xFF7F); /* XF_Num_Lock = 0xFF7F */ + if (numlockcode) { + modmap = XGetModifierMapping(display); + if (modmap) { + keycode = modmap->modifiermap; + for (i = 0; i < 8; i++) + for (j = modmap->max_keypermod; j--;) { + if (*keycode == numlockcode) { + numlock_modifier_mask = (1 << i); + i = 8; + break; + } + keycode++; + } + if (!numlock_modifier_mask) { + modmap->modifiermap[7 * modmap->max_keypermod] = numlockcode; + if (XSetModifierMapping(display, modmap) == MappingSuccess) + numlock_modifier_mask = (1 << 7); + else + printf("XSetModifierMapping failed!\n"); + } + XFreeModifiermap(modmap); + } + } + + if (!numlock_modifier_mask) + printf("WARNING: Failed to get a numlock modifier mapping.\n"); + +} + +void ui_destroy_window() { + if( xkb != NULL ) + XkbFreeKeyboard(xkb, XkbAllControlsMask, True); + if (ownbackstore) XFreePixmap(display, backstore); @@ -319,74 +434,70 @@ static void xwin_process_events() { - XEvent event; + XEvent xevent; + KeySym keysym; uint8 scancode; - uint16 button; + uint16 button, flags; uint32 ev_time; + uint32 tmpmods; - if (display == NULL) - return; - - while (XCheckMaskEvent(display, ~0, &event)) + while (XCheckMaskEvent(display, ~0, &xevent)) { ev_time = time(NULL); + flags = 0; - switch (event.type) + switch (xevent.type) { + case KeyRelease: + flags = KBD_FLAG_DOWN | KBD_FLAG_UP; + /* fall through */ case KeyPress: - keysym = XKeycodeToKeysym(display, event.xkey.keycode, 0); - scancode = xkeymap_translate_key(keysym, event.xkey.keycode); - if (scancode == 0) + if( XkbTranslateKeyCode(xkb, xevent.xkey.keycode, xevent.xkey.state, &tmpmods, &keysym) == False ) break; + scancode = xkeymap_translate_key(keysym, xevent.xkey.keycode, &flags); - rdp_send_input(ev_time, RDP_INPUT_SCANCODE, 0, - scancode, 0); - break; - - case KeyRelease: - keysym = XKeycodeToKeysym(display, event.xkey.keycode, 0); - scancode = xkeymap_translate_key(keysym, event.xkey.keycode); - if (scancode == 0) + if (scancode == 0 ) break; - rdp_send_input(ev_time, RDP_INPUT_SCANCODE, - KBD_FLAG_DOWN | KBD_FLAG_UP, - scancode, 0); - break; + /* keep track of the modifiers -- needed for stickykeys... */ + if( xevent.type == KeyPress ) + xwin_mod_press( xevent.xkey.state, ev_time, scancode ); - case ButtonPress: - button = xkeymap_translate_button(event.xbutton.button); - if (button == 0) - break; + rdp_send_input(ev_time, RDP_INPUT_SCANCODE, flags, scancode, 0); + + if( xevent.type == KeyRelease ) + xwin_mod_release( xevent.xkey.state, ev_time, scancode ); - rdp_send_input(ev_time, RDP_INPUT_MOUSE, - button | MOUSE_FLAG_DOWN, - event.xbutton.x, - event.xbutton.y); break; + case ButtonPress: + flags = MOUSE_FLAG_DOWN; + /* fall through */ + case ButtonRelease: - button = xkeymap_translate_button(event.xbutton.button); + button = xkeymap_translate_button(xevent.xbutton.button); if (button == 0) break; rdp_send_input(ev_time, RDP_INPUT_MOUSE, - button, - event.xbutton.x, - event.xbutton.y); + flags | button, + xevent.xbutton.x, + xevent.xbutton.y); break; case MotionNotify: rdp_send_input(ev_time, RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE, - event.xmotion.x, - event.xmotion.y); + xevent.xmotion.x, + xevent.xmotion.y); break; case EnterNotify: XGrabKeyboard(display, wnd, True, GrabModeAsync, GrabModeAsync, CurrentTime); + + xwin_mod_update( xevent.xcrossing.state, ev_time ); break; case LeaveNotify: @@ -395,29 +506,183 @@ case Expose: XCopyArea(display, backstore, wnd, gc, - event.xexpose.x, event.xexpose.y, - event.xexpose.width, event.xexpose.height, - event.xexpose.x, event.xexpose.y); + xevent.xexpose.x, xevent.xexpose.y, + xevent.xexpose.width, xevent.xexpose.height, + xevent.xexpose.x, xevent.xexpose.y); break; } } } void +xwin_mod_update(uint32 state, uint32 ev_time ) +{ + xwin_mod_press(state, ev_time, 0); + xwin_mod_release(state, ev_time, 0); +} + +void +xwin_mod_release(uint32 state, uint32 ev_time, uint32 scancode) +{ + switch (scancode) { + case 0x2a: + key_down_state &= ~DShift1Mask; + break; + case 0x36: + key_down_state &= ~DShift2Mask; + break; + case 0x1d: + key_down_state &= ~DControl1Mask; + break; + case 0x9d: + key_down_state &= ~DControl2Mask; + break; + case 0x38: + key_down_state &= ~DMod1Mask; + break; + case 0xb8: + key_down_state &= ~DMod2Mask; + break; + } + + if( !(numlock_modifier_mask & state) && (key_down_state & DNumLockMask) ) + { + rdp_send_input(ev_time, RDP_INPUT_SCANCODE, 0, 0x45, 0); + rdp_send_input(ev_time, RDP_INPUT_SCANCODE, KBD_FLAG_DOWN | KBD_FLAG_UP, 0x45, 0); + key_down_state &= ~DNumLockMask; + } + + if( !(LockMask & state) && (key_down_state & DLockMask)) + { + rdp_send_input(ev_time, RDP_INPUT_SCANCODE, 0, 0x3a, 0); + rdp_send_input(ev_time, RDP_INPUT_SCANCODE, KBD_FLAG_DOWN | KBD_FLAG_UP, 0x3a, 0); + key_down_state &= ~DLockMask; + + } + + + if( !(ShiftMask & state) && (key_down_state & DShift1Mask)) + { + rdp_send_input(ev_time, RDP_INPUT_SCANCODE, KBD_FLAG_UP, 0x2a, 0); + key_down_state &= ~DShift1Mask; + + } + + if( !(ControlMask & state) && (key_down_state & DControl1Mask)) + { + rdp_send_input(ev_time, RDP_INPUT_SCANCODE, KBD_FLAG_UP, 0x1d, 0); + key_down_state &= ~DControl1Mask; + + } + + if( !(Mod1Mask & state) && (key_down_state & DMod1Mask)) + { + rdp_send_input(ev_time, RDP_INPUT_SCANCODE, KBD_FLAG_UP, 0x38, 0); + key_down_state &= ~DMod1Mask; + + } + + if( !(Mod2Mask & state) && (key_down_state & DMod2Mask)) + { + rdp_send_input(ev_time, RDP_INPUT_SCANCODE, KBD_FLAG_UP, 0xb8, 0); + key_down_state &= ~DMod2Mask; + } +} + + +void +xwin_mod_press(uint32 state, uint32 ev_time, uint32 scancode) +{ + + switch (scancode) { + case 0x2a: + key_down_state |= DShift1Mask; + break; + case 0x36: + key_down_state |= DShift2Mask; + break; + case 0x1d: + key_down_state |= DControl1Mask; + break; + case 0x9d: + key_down_state |= DControl2Mask; + break; + case 0x3a: + key_down_state ^= DLockMask; + break; + case 0x45: + key_down_state ^= DNumLockMask; + break; + case 0x38: + key_down_state |= DMod1Mask; + break; + case 0xb8: + key_down_state |= DMod2Mask; + break; + } + + if( (numlock_modifier_mask && state) && !(key_down_state & DNumLockMask) ) + { + rdp_send_input(ev_time, RDP_INPUT_SCANCODE, 0, 0x45, 0); + rdp_send_input(ev_time, RDP_INPUT_SCANCODE, KBD_FLAG_DOWN | KBD_FLAG_UP, 0x45, 0); + key_down_state |= DNumLockMask; + } + + if( (LockMask & state) && !(key_down_state & DLockMask)) + { + rdp_send_input(ev_time, RDP_INPUT_SCANCODE, 0, 0x3a, 0); + rdp_send_input(ev_time, RDP_INPUT_SCANCODE, KBD_FLAG_DOWN | KBD_FLAG_UP, 0x3a, 0); + key_down_state |= DLockMask; + + } + + + if( (ShiftMask & state) && !((key_down_state & DShift1Mask) || (key_down_state & DShift2Mask))) + { + rdp_send_input(ev_time, RDP_INPUT_SCANCODE, KBD_FLAG_DOWN, 0x2a, 0); + key_down_state |= DShift1Mask; + + } + + if( (ControlMask & state) && !((key_down_state & DControl1Mask) || (key_down_state & DControl2Mask))) + { + rdp_send_input(ev_time, RDP_INPUT_SCANCODE, KBD_FLAG_DOWN, 0x1d, 0); + key_down_state |= DControl1Mask; + + } + + if( (Mod1Mask & state) && !(key_down_state & DMod1Mask)) + { + rdp_send_input(ev_time, RDP_INPUT_SCANCODE, KBD_FLAG_DOWN, 0x38, 0); + key_down_state |= DMod1Mask; + + } + + if( (Mod2Mask & state) && !(key_down_state & DMod2Mask)) + { + rdp_send_input(ev_time, RDP_INPUT_SCANCODE, KBD_FLAG_DOWN, 0xb8, 0); + key_down_state |= DMod2Mask; + + } +} + +void ui_select(int rdp_socket) { int n = (rdp_socket > x_socket) ? rdp_socket+1 : x_socket+1; fd_set rfds; - XFlush(display); - FD_ZERO(&rfds); while (True) { FD_ZERO(&rfds); FD_SET(rdp_socket, &rfds); - FD_SET(x_socket, &rfds); + if (display != NULL) + { + FD_SET(x_socket, &rfds); + XFlush(display); + } switch (select(n, &rfds, NULL, NULL, NULL)) { @@ -937,7 +1202,7 @@ if (entry != NULL) { if ((((uint8 *) (entry->data))[1] == 0) && (!(flags & TEXT2_IMPLICIT_X))) { - if (flags & TEXT2_VERTICAL) + if (flags & TEXT2_VERTICAL) y += text[i + 2]; else x += text[i + 2]; @@ -946,7 +1211,7 @@ i += 3; else i += 2; - length -= i; + length -= i; /* this will move pointer from start to first character after FE command */ text = &(text[i]); i = 0;