using XEvent instead of XkbEvent. better tracking of modifiers. ( TODO: 1. sync at start up, 2. fallback for missing or improperly configured xkb module. )

git-svn-id: svn://svn.code.sf.net/p/rdesktop/code/trunk/rdesktop@53 423420c4-83ab-492f-b58f-81f9feb106b5
This commit is contained in:
Peter Kallden 2002-06-07 07:49:59 +00:00
parent 09024cf458
commit 9ddcb7504a

187
xwin.c
View File

@ -50,15 +50,21 @@ static BOOL ownbackstore;
static Pixmap backstore; static Pixmap backstore;
/* needed to keep track of the modifiers */ /* needed to keep track of the modifiers */
static unsigned int key_modifier_state = 0; static unsigned int numlock_modifier_mask = 0;
static unsigned int key_down_state = 0; static unsigned int key_down_state = 0;
#define DShift1Mask (1<<0) #define DShift1Mask (1<<0)
#define DShift2Mask (1<<1) #define DLockMask (1<<1)
#define DControl1Mask (1<<2) #define DControl1Mask (1<<2)
#define DControl2Mask (1<<3) #define DMod1Mask (1<<3)
#define DMod1Mask (1<<4) #define DMod2Mask (1<<4)
#define DMod2Mask (1<<5) #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)\ #define FILL_RECTANGLE(x,y,cx,cy)\
{ \ { \
@ -99,8 +105,10 @@ static int rop2_map[] = {
#define SET_FUNCTION(rop2) { if (rop2 != ROP2_COPY) XSetFunction(display, gc, rop2_map[rop2]); } #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); } #define RESET_FUNCTION(rop2) { if (rop2 != ROP2_COPY) XSetFunction(display, gc, GXcopy); }
void xwin_release_modifiers(XKeyEvent* ev, uint32 ev_time, uint32 scancode); void xwin_get_numlock_mask();
void xwin_press_modifiers(XKeyEvent* ev, uint32 ev_time, uint32 scancode); 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 static void
translate8(uint8 *data, uint8 *out, uint8 *end) translate8(uint8 *data, uint8 *out, uint8 *end)
@ -221,10 +229,6 @@ ui_create_window(char *title)
} }
/* XKB is the 'new' keyboard handler in x.. ( the xkb code in Xfree86 originates from SGI, years 1993 and 1995 from what I could tell. )
* it makes it possible for people with disabilities to use rdesktop, stickykeys, bouncekeys etc. VERY MUCH useful.
* XFree86 has had support for it since it's earliest incarnation. I believe it is a reasonable dependency.
*/
display = XkbOpenDisplay( NULL, &xkb_event, &xkb_error, &xkb_major, &xkb_minor, &xkb_reason ); display = XkbOpenDisplay( NULL, &xkb_event, &xkb_error, &xkb_major, &xkb_minor, &xkb_reason );
switch(xkb_reason) switch(xkb_reason)
{ {
@ -338,7 +342,7 @@ ui_create_window(char *title)
input_mask = KeyPressMask | KeyReleaseMask | input_mask = KeyPressMask | KeyReleaseMask |
ButtonPressMask | ButtonReleaseMask | ButtonPressMask | ButtonReleaseMask |
EnterWindowMask | LeaveWindowMask | KeymapStateMask; EnterWindowMask | LeaveWindowMask;
if (sendmotion) if (sendmotion)
input_mask |= PointerMotionMask; input_mask |= PointerMotionMask;
@ -367,10 +371,51 @@ ui_create_window(char *title)
error( "XkbSelectEvents failed.\n"); error( "XkbSelectEvents failed.\n");
exit(0); exit(0);
} }
xwin_get_numlock_mask();
return True; 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 void
ui_destroy_window() ui_destroy_window()
{ {
@ -389,50 +434,40 @@ ui_destroy_window()
static void static void
xwin_process_events() xwin_process_events()
{ {
XkbEvent xkbevent; XEvent xevent;
KeySym keysym; KeySym keysym;
uint8 scancode; uint8 scancode;
uint16 button, flags; uint16 button, flags;
uint32 ev_time; uint32 ev_time;
uint32 tmpmods; uint32 tmpmods;
while (XCheckMaskEvent(display, ~0, &xkbevent.core)) while (XCheckMaskEvent(display, ~0, &xevent))
{ {
ev_time = time(NULL); ev_time = time(NULL);
flags = 0; flags = 0;
switch (xkbevent.type) switch (xevent.type)
{ {
case KeymapNotify:
/* TODO:
* read modifier status at focus in, and update the local masks, and the other end as well..
* if not, we may get out of sync.
* xkbevent.core.xkeymap.key_vector
* char key_vector[32];
*/
break;
case KeyRelease: case KeyRelease:
flags = KBD_FLAG_DOWN | KBD_FLAG_UP; flags = KBD_FLAG_DOWN | KBD_FLAG_UP;
/* fall through */ /* fall through */
case KeyPress: case KeyPress:
if( XkbTranslateKeyCode(xkb, xkbevent.core.xkey.keycode, xkbevent.core.xkey.state, &tmpmods, &keysym) == False ) if( XkbTranslateKeyCode(xkb, xevent.xkey.keycode, xevent.xkey.state, &tmpmods, &keysym) == False )
break; break;
scancode = xkeymap_translate_key(keysym, xkbevent.core.xkey.keycode, &flags); scancode = xkeymap_translate_key(keysym, xevent.xkey.keycode, &flags);
if (scancode == 0 ) if (scancode == 0 )
break; break;
/* keep track of the modifiers -- needed for stickykeys... */ /* keep track of the modifiers -- needed for stickykeys... */
if( xkbevent.type == KeyPress ) if( xevent.type == KeyPress )
xwin_press_modifiers( &xkbevent.core.xkey, ev_time, scancode ); xwin_mod_press( xevent.xkey.state, ev_time, scancode );
rdp_send_input(ev_time, RDP_INPUT_SCANCODE, flags, scancode, 0); rdp_send_input(ev_time, RDP_INPUT_SCANCODE, flags, scancode, 0);
if( xkbevent.type == KeyRelease ) if( xevent.type == KeyRelease )
xwin_release_modifiers( &xkbevent.core.xkey, ev_time, scancode ); xwin_mod_release( xevent.xkey.state, ev_time, scancode );
break; break;
@ -441,26 +476,28 @@ xwin_process_events()
/* fall through */ /* fall through */
case ButtonRelease: case ButtonRelease:
button = xkeymap_translate_button(xkbevent.core.xbutton.button); button = xkeymap_translate_button(xevent.xbutton.button);
if (button == 0) if (button == 0)
break; break;
rdp_send_input(ev_time, RDP_INPUT_MOUSE, rdp_send_input(ev_time, RDP_INPUT_MOUSE,
flags | button, flags | button,
xkbevent.core.xbutton.x, xevent.xbutton.x,
xkbevent.core.xbutton.y); xevent.xbutton.y);
break; break;
case MotionNotify: case MotionNotify:
rdp_send_input(ev_time, RDP_INPUT_MOUSE, rdp_send_input(ev_time, RDP_INPUT_MOUSE,
MOUSE_FLAG_MOVE, MOUSE_FLAG_MOVE,
xkbevent.core.xmotion.x, xevent.xmotion.x,
xkbevent.core.xmotion.y); xevent.xmotion.y);
break; break;
case EnterNotify: case EnterNotify:
XGrabKeyboard(display, wnd, True, GrabModeAsync, XGrabKeyboard(display, wnd, True, GrabModeAsync,
GrabModeAsync, CurrentTime); GrabModeAsync, CurrentTime);
xwin_mod_update( xevent.xcrossing.state, ev_time );
break; break;
case LeaveNotify: case LeaveNotify:
@ -469,16 +506,23 @@ xwin_process_events()
case Expose: case Expose:
XCopyArea(display, backstore, wnd, gc, XCopyArea(display, backstore, wnd, gc,
xkbevent.core.xexpose.x, xkbevent.core.xexpose.y, xevent.xexpose.x, xevent.xexpose.y,
xkbevent.core.xexpose.width, xkbevent.core.xexpose.height, xevent.xexpose.width, xevent.xexpose.height,
xkbevent.core.xexpose.x, xkbevent.core.xexpose.y); xevent.xexpose.x, xevent.xexpose.y);
break; break;
} }
} }
} }
void void
xwin_release_modifiers(XKeyEvent* ev, uint32 ev_time, uint32 scancode) 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) { switch (scancode) {
case 0x2a: case 0x2a:
@ -501,28 +545,44 @@ xwin_release_modifiers(XKeyEvent* ev, uint32 ev_time, uint32 scancode)
break; break;
} }
if( !(ShiftMask & ev->state) && (key_down_state & DShift1Mask)) 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); rdp_send_input(ev_time, RDP_INPUT_SCANCODE, KBD_FLAG_UP, 0x2a, 0);
key_down_state &= ~DShift1Mask; key_down_state &= ~DShift1Mask;
} }
if( !(ControlMask & ev->state) && (key_down_state & DControl1Mask)) if( !(ControlMask & state) && (key_down_state & DControl1Mask))
{ {
rdp_send_input(ev_time, RDP_INPUT_SCANCODE, KBD_FLAG_UP, 0x1d, 0); rdp_send_input(ev_time, RDP_INPUT_SCANCODE, KBD_FLAG_UP, 0x1d, 0);
key_down_state &= ~DControl1Mask; key_down_state &= ~DControl1Mask;
} }
if( !(Mod1Mask & ev->state) && (key_down_state & DMod1Mask)) if( !(Mod1Mask & state) && (key_down_state & DMod1Mask))
{ {
rdp_send_input(ev_time, RDP_INPUT_SCANCODE, KBD_FLAG_UP, 0x38, 0); rdp_send_input(ev_time, RDP_INPUT_SCANCODE, KBD_FLAG_UP, 0x38, 0);
key_down_state &= ~DMod1Mask; key_down_state &= ~DMod1Mask;
} }
if( !(Mod2Mask & ev->state) && (key_down_state & DMod2Mask)) if( !(Mod2Mask & state) && (key_down_state & DMod2Mask))
{ {
rdp_send_input(ev_time, RDP_INPUT_SCANCODE, KBD_FLAG_UP, 0xb8, 0); rdp_send_input(ev_time, RDP_INPUT_SCANCODE, KBD_FLAG_UP, 0xb8, 0);
key_down_state &= ~DMod2Mask; key_down_state &= ~DMod2Mask;
@ -531,9 +591,8 @@ xwin_release_modifiers(XKeyEvent* ev, uint32 ev_time, uint32 scancode)
void void
xwin_press_modifiers(XKeyEvent* ev, uint32 ev_time, uint32 scancode) xwin_mod_press(uint32 state, uint32 ev_time, uint32 scancode)
{ {
key_modifier_state = ev->state;
switch (scancode) { switch (scancode) {
case 0x2a: case 0x2a:
@ -548,6 +607,12 @@ xwin_press_modifiers(XKeyEvent* ev, uint32 ev_time, uint32 scancode)
case 0x9d: case 0x9d:
key_down_state |= DControl2Mask; key_down_state |= DControl2Mask;
break; break;
case 0x3a:
key_down_state ^= DLockMask;
break;
case 0x45:
key_down_state ^= DNumLockMask;
break;
case 0x38: case 0x38:
key_down_state |= DMod1Mask; key_down_state |= DMod1Mask;
break; break;
@ -556,28 +621,44 @@ xwin_press_modifiers(XKeyEvent* ev, uint32 ev_time, uint32 scancode)
break; break;
} }
if( (ShiftMask & ev->state) && !((key_down_state & DShift1Mask) || (key_down_state & DShift2Mask))) 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); rdp_send_input(ev_time, RDP_INPUT_SCANCODE, KBD_FLAG_DOWN, 0x2a, 0);
key_down_state |= DShift1Mask; key_down_state |= DShift1Mask;
} }
if( (ControlMask & ev->state) && !((key_down_state & DControl1Mask) || (key_down_state & DControl2Mask))) if( (ControlMask & state) && !((key_down_state & DControl1Mask) || (key_down_state & DControl2Mask)))
{ {
rdp_send_input(ev_time, RDP_INPUT_SCANCODE, KBD_FLAG_DOWN, 0x1d, 0); rdp_send_input(ev_time, RDP_INPUT_SCANCODE, KBD_FLAG_DOWN, 0x1d, 0);
key_down_state |= DControl1Mask; key_down_state |= DControl1Mask;
} }
if( (Mod1Mask & ev->state) && !(key_down_state & DMod1Mask)) if( (Mod1Mask & state) && !(key_down_state & DMod1Mask))
{ {
rdp_send_input(ev_time, RDP_INPUT_SCANCODE, KBD_FLAG_DOWN, 0x38, 0); rdp_send_input(ev_time, RDP_INPUT_SCANCODE, KBD_FLAG_DOWN, 0x38, 0);
key_down_state |= DMod1Mask; key_down_state |= DMod1Mask;
} }
if( (Mod2Mask & ev->state) && !(key_down_state & DMod2Mask)) if( (Mod2Mask & state) && !(key_down_state & DMod2Mask))
{ {
rdp_send_input(ev_time, RDP_INPUT_SCANCODE, KBD_FLAG_DOWN, 0xb8, 0); rdp_send_input(ev_time, RDP_INPUT_SCANCODE, KBD_FLAG_DOWN, 0xb8, 0);
key_down_state |= DMod2Mask; key_down_state |= DMod2Mask;