diff --git a/hw/kdrive/ephyr/ephyr.c b/hw/kdrive/ephyr/ephyr.c index 95670eb24..ad8dab1a9 100644 --- a/hw/kdrive/ephyr/ephyr.c +++ b/hw/kdrive/ephyr/ephyr.c @@ -38,7 +38,10 @@ #endif #include "ephyr.h" +#include "inputstr.h" + extern int KdTsPhyScreen; +extern DeviceIntPtr pKdKeyboard; static int mouseState = 0; @@ -564,6 +567,65 @@ ephyrScreenFini (KdScreenInfo *screen) { } +/* + * Port of Mark McLoughlin's Xnest fix for focus in + modifier bug. + * See https://bugs.freedesktop.org/show_bug.cgi?id=3030 + */ +void +ephyrUpdateModifierState(unsigned int state) +{ + DeviceIntPtr pkeydev; + KeyClassPtr keyc; + int i; + CARD8 mask; + + pkeydev = LookupKeyboardDevice(); + + if (!pkeydev) + return; + + keyc = pkeydev->key; + + if (keyc->state == state) + return; + + for (i = 0, mask = 1; i < 8; i++, mask <<= 1) + { + int key; + + /* Modifier is down, but shouldn't be */ + if ((keyc->state & mask) && !(state & mask)) + { + int count = keyc->modifierKeyCount[i]; + + for (key = 0; key < MAP_LENGTH; key++) + if (keyc->modifierMap[key] & mask) + { + int bit; + BYTE *kptr; + + kptr = &keyc->down[key >> 3]; + bit = 1 << (key & 7); + + if (*kptr & bit) + KdEnqueueKeyboardEvent(key, TRUE); /* release */ + + if (--count == 0) + break; + } + } + + /* Modifier shoud be down, but isn't */ + if (!(keyc->state & mask) && (state & mask)) + for (key = 0; key < MAP_LENGTH; key++) + if (keyc->modifierMap[key] & mask) + { + KdEnqueueKeyboardEvent(key, FALSE); /* press */ + break; + } + } +} + void ephyrPoll(void) { @@ -592,12 +654,12 @@ ephyrPoll(void) break; case EPHYR_EV_KEY_PRESS: - + ephyrUpdateModifierState(ev.data.key_down.state); KdEnqueueKeyboardEvent (ev.data.key_down.scancode, FALSE); break; case EPHYR_EV_KEY_RELEASE: - + ephyrUpdateModifierState(ev.data.key_up.state); KdEnqueueKeyboardEvent (ev.data.key_up.scancode, TRUE); break; diff --git a/hw/kdrive/ephyr/ephyr.h b/hw/kdrive/ephyr/ephyr.h index d7c9ecdb4..0e84cdbc3 100644 --- a/hw/kdrive/ephyr/ephyr.h +++ b/hw/kdrive/ephyr/ephyr.h @@ -142,6 +142,9 @@ ephyrShadowUpdate (ScreenPtr pScreen, shadowBufPtr pBuf); #endif +void +ephyrUpdateModifierState(unsigned int state); + extern KdMouseFuncs EphyrMouseFuncs; extern KdKeyboardFuncs EphyrKeyboardFuncs; diff --git a/hw/kdrive/ephyr/hostx.c b/hw/kdrive/ephyr/hostx.c index 301b3e26b..3454f2785 100644 --- a/hw/kdrive/ephyr/hostx.c +++ b/hw/kdrive/ephyr/hostx.c @@ -29,11 +29,11 @@ #include #include #include /* for memset */ +#include #include #include #include -#include #include #include @@ -733,7 +733,8 @@ hostx_get_event(EphyrHostXEvent *ev) case KeyPress: { - ev->type = EPHYR_EV_KEY_PRESS; + ev->type = EPHYR_EV_KEY_PRESS; + ev->data.key_down.state = xev.xkey.state; ev->data.key_down.scancode = xev.xkey.keycode; return 1; } @@ -779,6 +780,7 @@ hostx_get_event(EphyrHostXEvent *ev) * kdrive all togeather. */ ev->type = EPHYR_EV_KEY_RELEASE; + ev->data.key_up.state = xev.xkey.state; ev->data.key_up.scancode = xev.xkey.keycode; return 1; diff --git a/hw/kdrive/ephyr/hostx.h b/hw/kdrive/ephyr/hostx.h index 73e7e04a1..08ed036d4 100644 --- a/hw/kdrive/ephyr/hostx.h +++ b/hw/kdrive/ephyr/hostx.h @@ -69,10 +69,12 @@ struct EphyrHostXEvent struct key_up { int scancode; + int state; } key_up; struct key_down { int scancode; + int state; } key_down; } data;