2003-11-14 16:54:54 +01:00
|
|
|
/************************************************************
|
|
|
|
Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc.
|
|
|
|
|
|
|
|
Permission to use, copy, modify, and distribute this
|
|
|
|
software and its documentation for any purpose and without
|
|
|
|
fee is hereby granted, provided that the above copyright
|
|
|
|
notice appear in all copies and that both that copyright
|
|
|
|
notice and this permission notice appear in supporting
|
|
|
|
documentation, and that the name of Silicon Graphics not be
|
|
|
|
used in advertising or publicity pertaining to distribution
|
|
|
|
of the software without specific prior written permission.
|
|
|
|
Silicon Graphics makes no representation about the suitability
|
|
|
|
of this software for any purpose. It is provided "as is"
|
|
|
|
without any express or implied warranty.
|
|
|
|
|
|
|
|
SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
|
|
|
|
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
|
|
AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
|
|
|
|
GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
|
|
|
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
|
|
|
DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
|
|
|
OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH
|
|
|
|
THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
|
|
|
|
********************************************************/
|
|
|
|
|
2005-07-03 09:02:09 +02:00
|
|
|
#ifdef HAVE_DIX_CONFIG_H
|
|
|
|
#include <dix-config.h>
|
|
|
|
#endif
|
|
|
|
|
2003-11-14 16:54:54 +01:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <math.h>
|
|
|
|
#include <X11/X.h>
|
|
|
|
#include <X11/Xproto.h>
|
|
|
|
#include <X11/keysym.h>
|
2005-07-03 10:53:54 +02:00
|
|
|
#include "misc.h"
|
2003-11-14 16:54:54 +01:00
|
|
|
#include "inputstr.h"
|
2007-10-27 20:31:39 +02:00
|
|
|
#include "exevents.h"
|
2009-07-27 08:54:33 +02:00
|
|
|
#include "eventstr.h"
|
2007-03-18 21:31:19 +01:00
|
|
|
#include <xkbsrv.h>
|
2003-11-25 20:29:01 +01:00
|
|
|
#include "xkb.h"
|
2003-11-14 16:54:54 +01:00
|
|
|
#include <ctype.h>
|
2010-04-14 02:54:29 +02:00
|
|
|
#include "mi.h"
|
2010-06-04 04:00:54 +02:00
|
|
|
#include "mipointer.h"
|
2010-10-19 05:37:46 +02:00
|
|
|
#include "inpututils.h"
|
2007-09-06 11:19:57 +02:00
|
|
|
#define EXTENSION_EVENT_BASE 64
|
2003-11-14 16:54:54 +01:00
|
|
|
|
2010-04-27 02:22:21 +02:00
|
|
|
DevPrivateKeyRec xkbDevicePrivateKeyRec;
|
2005-05-22 03:12:49 +02:00
|
|
|
|
2012-03-21 20:55:09 +01:00
|
|
|
static void XkbFakePointerMotion(DeviceIntPtr dev, unsigned flags, int x,
|
|
|
|
int y);
|
2010-04-14 02:54:29 +02:00
|
|
|
|
Rework symbol visibility for easier maintenance
Save in a few special cases, _X_EXPORT should not be used in C source
files. Instead, it should be used in headers, and the proper C source
include that header. Some special cases are symbols that need to be
shared between modules, but not expected to be used by external drivers,
and symbols that are accessible via LoaderSymbol/dlopen.
This patch also adds conditionally some new sdk header files, depending
on extensions enabled. These files were added to match pattern for
other extensions/modules, that is, have the headers "deciding" symbol
visibility in the sdk. These headers are:
o Xext/panoramiXsrv.h, Xext/panoramiX.h
o fbpict.h (unconditionally)
o vidmodeproc.h
o mioverlay.h (unconditionally, used only by xaa)
o xfixes.h (unconditionally, symbols required by dri2)
LoaderSymbol and similar functions now don't have different prototypes,
in loaderProcs.h and xf86Module.h, so that both headers can be included,
without the need of defining IN_LOADER.
xf86NewInputDevice() device prototype readded to xf86Xinput.h, but
not exported (and with a comment about it).
2008-12-03 08:43:34 +01:00
|
|
|
void
|
2013-12-15 10:05:51 +01:00
|
|
|
xkbUnwrapProc(DeviceIntPtr device, DeviceHandleProc proc, void *data)
|
2005-05-22 03:12:49 +02:00
|
|
|
{
|
|
|
|
xkbDeviceInfoPtr xkbPrivPtr = XKBDEVICEINFO(device);
|
2008-04-01 14:27:06 +02:00
|
|
|
ProcessInputProc backupproc;
|
2005-05-22 03:12:49 +02:00
|
|
|
|
2012-03-21 20:55:09 +01:00
|
|
|
if (xkbPrivPtr->unwrapProc)
|
|
|
|
xkbPrivPtr->unwrapProc = NULL;
|
|
|
|
|
|
|
|
UNWRAP_PROCESS_INPUT_PROC(device, xkbPrivPtr, backupproc);
|
|
|
|
proc(device, data);
|
|
|
|
COND_WRAP_PROCESS_INPUT_PROC(device, xkbPrivPtr, backupproc, xkbUnwrapProc);
|
2005-05-22 03:12:49 +02:00
|
|
|
}
|
|
|
|
|
2010-06-07 05:45:53 +02:00
|
|
|
Bool
|
|
|
|
XkbInitPrivates(void)
|
|
|
|
{
|
2012-03-21 20:55:09 +01:00
|
|
|
return dixRegisterPrivateKey(&xkbDevicePrivateKeyRec, PRIVATE_DEVICE,
|
|
|
|
sizeof(xkbDeviceInfoRec));
|
2010-06-07 05:45:53 +02:00
|
|
|
}
|
2005-05-22 03:12:49 +02:00
|
|
|
|
Rework symbol visibility for easier maintenance
Save in a few special cases, _X_EXPORT should not be used in C source
files. Instead, it should be used in headers, and the proper C source
include that header. Some special cases are symbols that need to be
shared between modules, but not expected to be used by external drivers,
and symbols that are accessible via LoaderSymbol/dlopen.
This patch also adds conditionally some new sdk header files, depending
on extensions enabled. These files were added to match pattern for
other extensions/modules, that is, have the headers "deciding" symbol
visibility in the sdk. These headers are:
o Xext/panoramiXsrv.h, Xext/panoramiX.h
o fbpict.h (unconditionally)
o vidmodeproc.h
o mioverlay.h (unconditionally, used only by xaa)
o xfixes.h (unconditionally, symbols required by dri2)
LoaderSymbol and similar functions now don't have different prototypes,
in loaderProcs.h and xf86Module.h, so that both headers can be included,
without the need of defining IN_LOADER.
xf86NewInputDevice() device prototype readded to xf86Xinput.h, but
not exported (and with a comment about it).
2008-12-03 08:43:34 +01:00
|
|
|
void
|
2005-05-22 03:12:49 +02:00
|
|
|
XkbSetExtension(DeviceIntPtr device, ProcessInputProc proc)
|
|
|
|
{
|
2011-03-04 16:55:31 +01:00
|
|
|
xkbDeviceInfoPtr xkbPrivPtr = XKBDEVICEINFO(device);
|
2012-03-21 20:55:09 +01:00
|
|
|
|
2007-10-27 20:31:39 +02:00
|
|
|
WRAP_PROCESS_INPUT_PROC(device, xkbPrivPtr, proc, xkbUnwrapProc);
|
2005-05-22 03:12:49 +02:00
|
|
|
}
|
|
|
|
|
2003-11-14 16:54:54 +01:00
|
|
|
/***====================================================================***/
|
|
|
|
|
|
|
|
static XkbAction
|
2012-03-21 20:55:09 +01:00
|
|
|
_FixUpAction(XkbDescPtr xkb, XkbAction *act)
|
2003-11-14 16:54:54 +01:00
|
|
|
{
|
2012-03-21 20:55:09 +01:00
|
|
|
static XkbAction fake;
|
2003-11-14 16:54:54 +01:00
|
|
|
|
2012-03-21 20:55:09 +01:00
|
|
|
if (XkbIsPtrAction(act) &&
|
|
|
|
(!(xkb->ctrls->enabled_ctrls & XkbMouseKeysMask))) {
|
|
|
|
fake.type = XkbSA_NoAction;
|
|
|
|
return fake;
|
2003-11-14 16:54:54 +01:00
|
|
|
}
|
2012-03-21 20:55:09 +01:00
|
|
|
if (xkb->ctrls->enabled_ctrls & XkbStickyKeysMask) {
|
|
|
|
if (act->any.type == XkbSA_SetMods) {
|
|
|
|
fake.mods.type = XkbSA_LatchMods;
|
|
|
|
fake.mods.mask = act->mods.mask;
|
|
|
|
if (XkbAX_NeedOption(xkb->ctrls, XkbAX_LatchToLockMask))
|
|
|
|
fake.mods.flags = XkbSA_ClearLocks | XkbSA_LatchToLock;
|
|
|
|
else
|
|
|
|
fake.mods.flags = XkbSA_ClearLocks;
|
|
|
|
return fake;
|
|
|
|
}
|
|
|
|
if (act->any.type == XkbSA_SetGroup) {
|
|
|
|
fake.group.type = XkbSA_LatchGroup;
|
|
|
|
if (XkbAX_NeedOption(xkb->ctrls, XkbAX_LatchToLockMask))
|
|
|
|
fake.group.flags = XkbSA_ClearLocks | XkbSA_LatchToLock;
|
|
|
|
else
|
|
|
|
fake.group.flags = XkbSA_ClearLocks;
|
|
|
|
XkbSASetGroup(&fake.group, XkbSAGroup(&act->group));
|
|
|
|
return fake;
|
|
|
|
}
|
2003-11-14 16:54:54 +01:00
|
|
|
}
|
|
|
|
return *act;
|
|
|
|
}
|
|
|
|
|
|
|
|
static XkbAction
|
2012-03-21 20:55:09 +01:00
|
|
|
XkbGetKeyAction(XkbSrvInfoPtr xkbi, XkbStatePtr xkbState, CARD8 key)
|
2003-11-14 16:54:54 +01:00
|
|
|
{
|
2012-03-21 20:55:09 +01:00
|
|
|
int effectiveGroup;
|
|
|
|
int col;
|
|
|
|
XkbDescPtr xkb;
|
|
|
|
XkbKeyTypePtr type;
|
|
|
|
XkbAction *pActs;
|
|
|
|
static XkbAction fake;
|
|
|
|
|
|
|
|
xkb = xkbi->desc;
|
|
|
|
if (!XkbKeyHasActions(xkb, key) || !XkbKeycodeInRange(xkb, key)) {
|
|
|
|
fake.type = XkbSA_NoAction;
|
|
|
|
return fake;
|
2003-11-14 16:54:54 +01:00
|
|
|
}
|
2012-03-21 20:55:09 +01:00
|
|
|
pActs = XkbKeyActionsPtr(xkb, key);
|
|
|
|
col = 0;
|
2009-09-08 08:30:36 +02:00
|
|
|
|
|
|
|
effectiveGroup = XkbGetEffectiveGroup(xkbi, xkbState, key);
|
|
|
|
if (effectiveGroup != XkbGroup1Index)
|
|
|
|
col += (effectiveGroup * XkbKeyGroupsWidth(xkb, key));
|
|
|
|
|
2012-03-21 20:55:09 +01:00
|
|
|
type = XkbKeyKeyType(xkb, key, effectiveGroup);
|
|
|
|
if (type->map != NULL) {
|
|
|
|
register unsigned i, mods;
|
|
|
|
register XkbKTMapEntryPtr entry;
|
|
|
|
|
|
|
|
mods = xkbState->mods & type->mods.mask;
|
|
|
|
for (entry = type->map, i = 0; i < type->map_count; i++, entry++) {
|
|
|
|
if ((entry->active) && (entry->mods.mask == mods)) {
|
|
|
|
col += entry->level;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2003-11-14 16:54:54 +01:00
|
|
|
}
|
2012-03-21 20:55:09 +01:00
|
|
|
if (pActs[col].any.type == XkbSA_NoAction)
|
|
|
|
return pActs[col];
|
|
|
|
fake = _FixUpAction(xkb, &pActs[col]);
|
2003-11-14 16:54:54 +01:00
|
|
|
return fake;
|
|
|
|
}
|
|
|
|
|
2007-03-18 21:31:19 +01:00
|
|
|
static XkbAction
|
2012-03-21 20:55:09 +01:00
|
|
|
XkbGetButtonAction(DeviceIntPtr kbd, DeviceIntPtr dev, int button)
|
2003-11-14 16:54:54 +01:00
|
|
|
{
|
2012-03-21 20:55:09 +01:00
|
|
|
XkbAction fake;
|
|
|
|
|
|
|
|
if ((dev->button) && (dev->button->xkb_acts)) {
|
|
|
|
if (dev->button->xkb_acts[button - 1].any.type != XkbSA_NoAction) {
|
|
|
|
fake = _FixUpAction(kbd->key->xkbInfo->desc,
|
|
|
|
&dev->button->xkb_acts[button - 1]);
|
|
|
|
return fake;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fake.any.type = XkbSA_NoAction;
|
|
|
|
return fake;
|
2003-11-14 16:54:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/***====================================================================***/
|
|
|
|
|
|
|
|
#define SYNTHETIC_KEYCODE 1
|
|
|
|
#define BTN_ACT_FLAG 0x100
|
|
|
|
|
|
|
|
static int
|
2012-03-21 20:55:09 +01:00
|
|
|
_XkbFilterSetState(XkbSrvInfoPtr xkbi,
|
|
|
|
XkbFilterPtr filter, unsigned keycode, XkbAction *pAction)
|
2003-11-14 16:54:54 +01:00
|
|
|
{
|
2012-03-21 20:55:09 +01:00
|
|
|
if (filter->keycode == 0) { /* initial press */
|
|
|
|
filter->keycode = keycode;
|
|
|
|
filter->active = 1;
|
|
|
|
filter->filterOthers = ((pAction->mods.mask & XkbSA_ClearLocks) != 0);
|
|
|
|
filter->priv = 0;
|
|
|
|
filter->filter = _XkbFilterSetState;
|
|
|
|
if (pAction->type == XkbSA_SetMods) {
|
|
|
|
filter->upAction = *pAction;
|
|
|
|
xkbi->setMods = pAction->mods.mask;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
xkbi->groupChange = XkbSAGroup(&pAction->group);
|
|
|
|
if (pAction->group.flags & XkbSA_GroupAbsolute)
|
|
|
|
xkbi->groupChange -= xkbi->state.base_group;
|
|
|
|
filter->upAction = *pAction;
|
|
|
|
XkbSASetGroup(&filter->upAction.group, xkbi->groupChange);
|
|
|
|
}
|
2003-11-14 16:54:54 +01:00
|
|
|
}
|
2012-03-21 20:55:09 +01:00
|
|
|
else if (filter->keycode == keycode) {
|
|
|
|
if (filter->upAction.type == XkbSA_SetMods) {
|
|
|
|
xkbi->clearMods = filter->upAction.mods.mask;
|
|
|
|
if (filter->upAction.mods.flags & XkbSA_ClearLocks) {
|
|
|
|
xkbi->state.locked_mods &= ~filter->upAction.mods.mask;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (filter->upAction.group.flags & XkbSA_ClearLocks) {
|
|
|
|
xkbi->state.locked_group = 0;
|
|
|
|
}
|
|
|
|
xkbi->groupChange = -XkbSAGroup(&filter->upAction.group);
|
|
|
|
}
|
|
|
|
filter->active = 0;
|
2003-11-14 16:54:54 +01:00
|
|
|
}
|
|
|
|
else {
|
2012-03-21 20:55:09 +01:00
|
|
|
filter->upAction.mods.flags &= ~XkbSA_ClearLocks;
|
|
|
|
filter->filterOthers = 0;
|
2003-11-14 16:54:54 +01:00
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define LATCH_KEY_DOWN 1
|
|
|
|
#define LATCH_PENDING 2
|
|
|
|
|
|
|
|
static int
|
2012-03-21 20:55:09 +01:00
|
|
|
_XkbFilterLatchState(XkbSrvInfoPtr xkbi,
|
|
|
|
XkbFilterPtr filter, unsigned keycode, XkbAction *pAction)
|
2003-11-14 16:54:54 +01:00
|
|
|
{
|
|
|
|
|
2012-03-21 20:55:09 +01:00
|
|
|
if (filter->keycode == 0) { /* initial press */
|
xkb: Fixes to LatchMods/LatchGroup
The main problem this patch addresses is that if a latch is put on
multi-level key with a Latch/Lock/Set, it is possible that after all
keys are released, still base modifiers are set, which typically will
make the keyboard unusable. To see how it happens (without the patch),
assume that key AltGr sets Mod5 when pressed by itself, and latches Mod3
when pressed together with Shift. Now press Shift, then AltGr and
release both keys in reverse order. Mod3 is now latched, and the
LatchMods filter remains active as the second filter. Now press AltGr;
Mod5 base modifier gets set, and the SetMods filter will become active
as the first filter. Release AltGr: First, the SetMods filter will set
clearMods to Mod5, then the LatchMods filter will overwrite clearMods
with Mod3. Result: the Mod5 base modifier will remain set. This
example becomes practically relevant for the revised German standard
layout (DIN 2137-1:2012-06).
Other changes implement the latch behaviour more accurately according to
the specification. For example, releasing a modifier latching key can
at the same time clear a locked modifier, promote another modifier that
is latched to locked, and latch a third modifier. Overall, what the
code does should be straightforward to compare what the XKB protocol
specification demands, see the table in section 6.3.
Finally, releasing a key no longer cancels a latch that has not become
pending yet. In my opinion, the specification is not clear; it speaks
of "operating" a key, which the patch effectivly interprets as "press"
rather than "press or release". From my experience, using the latter
interpretation makes latches on higher levels practically unusable. In
the example given above, one would have to release AltGr always before
Shift to get the Mod3-Latch. The practical relevance of latches on
higher levels is once more given by the revised German standard layout.
Signed-off-by: Andreas Wettstein <wettstein509@solnet.ch>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2013-03-03 20:25:44 +01:00
|
|
|
AccessXCancelRepeatKey(xkbi,keycode);
|
2012-03-21 20:55:09 +01:00
|
|
|
filter->keycode = keycode;
|
|
|
|
filter->active = 1;
|
|
|
|
filter->filterOthers = 1;
|
|
|
|
filter->priv = LATCH_KEY_DOWN;
|
|
|
|
filter->filter = _XkbFilterLatchState;
|
|
|
|
if (pAction->type == XkbSA_LatchMods) {
|
|
|
|
filter->upAction = *pAction;
|
|
|
|
xkbi->setMods = pAction->mods.mask;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
xkbi->groupChange = XkbSAGroup(&pAction->group);
|
|
|
|
if (pAction->group.flags & XkbSA_GroupAbsolute)
|
|
|
|
xkbi->groupChange -= xkbi->state.base_group;
|
|
|
|
filter->upAction = *pAction;
|
|
|
|
XkbSASetGroup(&filter->upAction.group, xkbi->groupChange);
|
|
|
|
}
|
2003-11-14 16:54:54 +01:00
|
|
|
}
|
2012-03-21 20:55:09 +01:00
|
|
|
else if (pAction && (filter->priv == LATCH_PENDING)) {
|
|
|
|
if (((1 << pAction->type) & XkbSA_BreakLatch) != 0) {
|
|
|
|
filter->active = 0;
|
xkb: Fixes to LatchMods/LatchGroup
The main problem this patch addresses is that if a latch is put on
multi-level key with a Latch/Lock/Set, it is possible that after all
keys are released, still base modifiers are set, which typically will
make the keyboard unusable. To see how it happens (without the patch),
assume that key AltGr sets Mod5 when pressed by itself, and latches Mod3
when pressed together with Shift. Now press Shift, then AltGr and
release both keys in reverse order. Mod3 is now latched, and the
LatchMods filter remains active as the second filter. Now press AltGr;
Mod5 base modifier gets set, and the SetMods filter will become active
as the first filter. Release AltGr: First, the SetMods filter will set
clearMods to Mod5, then the LatchMods filter will overwrite clearMods
with Mod3. Result: the Mod5 base modifier will remain set. This
example becomes practically relevant for the revised German standard
layout (DIN 2137-1:2012-06).
Other changes implement the latch behaviour more accurately according to
the specification. For example, releasing a modifier latching key can
at the same time clear a locked modifier, promote another modifier that
is latched to locked, and latch a third modifier. Overall, what the
code does should be straightforward to compare what the XKB protocol
specification demands, see the table in section 6.3.
Finally, releasing a key no longer cancels a latch that has not become
pending yet. In my opinion, the specification is not clear; it speaks
of "operating" a key, which the patch effectivly interprets as "press"
rather than "press or release". From my experience, using the latter
interpretation makes latches on higher levels practically unusable. In
the example given above, one would have to release AltGr always before
Shift to get the Mod3-Latch. The practical relevance of latches on
higher levels is once more given by the revised German standard layout.
Signed-off-by: Andreas Wettstein <wettstein509@solnet.ch>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2013-03-03 20:25:44 +01:00
|
|
|
/* If one latch is broken, all latches are broken, so it's no use
|
|
|
|
to find out which particular latch this filter tracks. */
|
|
|
|
xkbi->state.latched_mods = 0;
|
|
|
|
xkbi->state.latched_group = 0;
|
2012-03-21 20:55:09 +01:00
|
|
|
}
|
2003-11-14 16:54:54 +01:00
|
|
|
}
|
xkb: Fixes to LatchMods/LatchGroup
The main problem this patch addresses is that if a latch is put on
multi-level key with a Latch/Lock/Set, it is possible that after all
keys are released, still base modifiers are set, which typically will
make the keyboard unusable. To see how it happens (without the patch),
assume that key AltGr sets Mod5 when pressed by itself, and latches Mod3
when pressed together with Shift. Now press Shift, then AltGr and
release both keys in reverse order. Mod3 is now latched, and the
LatchMods filter remains active as the second filter. Now press AltGr;
Mod5 base modifier gets set, and the SetMods filter will become active
as the first filter. Release AltGr: First, the SetMods filter will set
clearMods to Mod5, then the LatchMods filter will overwrite clearMods
with Mod3. Result: the Mod5 base modifier will remain set. This
example becomes practically relevant for the revised German standard
layout (DIN 2137-1:2012-06).
Other changes implement the latch behaviour more accurately according to
the specification. For example, releasing a modifier latching key can
at the same time clear a locked modifier, promote another modifier that
is latched to locked, and latch a third modifier. Overall, what the
code does should be straightforward to compare what the XKB protocol
specification demands, see the table in section 6.3.
Finally, releasing a key no longer cancels a latch that has not become
pending yet. In my opinion, the specification is not clear; it speaks
of "operating" a key, which the patch effectivly interprets as "press"
rather than "press or release". From my experience, using the latter
interpretation makes latches on higher levels practically unusable. In
the example given above, one would have to release AltGr always before
Shift to get the Mod3-Latch. The practical relevance of latches on
higher levels is once more given by the revised German standard layout.
Signed-off-by: Andreas Wettstein <wettstein509@solnet.ch>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2013-03-03 20:25:44 +01:00
|
|
|
else if (filter->keycode == keycode && filter->priv != LATCH_PENDING){
|
|
|
|
/* The test above for LATCH_PENDING skips subsequent releases of the
|
|
|
|
key after it has been released first time and the latch became
|
|
|
|
pending. */
|
2012-03-21 20:55:09 +01:00
|
|
|
XkbControlsPtr ctrls = xkbi->desc->ctrls;
|
xkb: Fixes to LatchMods/LatchGroup
The main problem this patch addresses is that if a latch is put on
multi-level key with a Latch/Lock/Set, it is possible that after all
keys are released, still base modifiers are set, which typically will
make the keyboard unusable. To see how it happens (without the patch),
assume that key AltGr sets Mod5 when pressed by itself, and latches Mod3
when pressed together with Shift. Now press Shift, then AltGr and
release both keys in reverse order. Mod3 is now latched, and the
LatchMods filter remains active as the second filter. Now press AltGr;
Mod5 base modifier gets set, and the SetMods filter will become active
as the first filter. Release AltGr: First, the SetMods filter will set
clearMods to Mod5, then the LatchMods filter will overwrite clearMods
with Mod3. Result: the Mod5 base modifier will remain set. This
example becomes practically relevant for the revised German standard
layout (DIN 2137-1:2012-06).
Other changes implement the latch behaviour more accurately according to
the specification. For example, releasing a modifier latching key can
at the same time clear a locked modifier, promote another modifier that
is latched to locked, and latch a third modifier. Overall, what the
code does should be straightforward to compare what the XKB protocol
specification demands, see the table in section 6.3.
Finally, releasing a key no longer cancels a latch that has not become
pending yet. In my opinion, the specification is not clear; it speaks
of "operating" a key, which the patch effectivly interprets as "press"
rather than "press or release". From my experience, using the latter
interpretation makes latches on higher levels practically unusable. In
the example given above, one would have to release AltGr always before
Shift to get the Mod3-Latch. The practical relevance of latches on
higher levels is once more given by the revised German standard layout.
Signed-off-by: Andreas Wettstein <wettstein509@solnet.ch>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2013-03-03 20:25:44 +01:00
|
|
|
int needBeep = ((ctrls->enabled_ctrls & XkbStickyKeysMask) &&
|
|
|
|
XkbAX_NeedFeedback(ctrls, XkbAX_StickyKeysFBMask));
|
2012-03-21 20:55:09 +01:00
|
|
|
|
|
|
|
if (filter->upAction.type == XkbSA_LatchMods) {
|
xkb: Fixes to LatchMods/LatchGroup
The main problem this patch addresses is that if a latch is put on
multi-level key with a Latch/Lock/Set, it is possible that after all
keys are released, still base modifiers are set, which typically will
make the keyboard unusable. To see how it happens (without the patch),
assume that key AltGr sets Mod5 when pressed by itself, and latches Mod3
when pressed together with Shift. Now press Shift, then AltGr and
release both keys in reverse order. Mod3 is now latched, and the
LatchMods filter remains active as the second filter. Now press AltGr;
Mod5 base modifier gets set, and the SetMods filter will become active
as the first filter. Release AltGr: First, the SetMods filter will set
clearMods to Mod5, then the LatchMods filter will overwrite clearMods
with Mod3. Result: the Mod5 base modifier will remain set. This
example becomes practically relevant for the revised German standard
layout (DIN 2137-1:2012-06).
Other changes implement the latch behaviour more accurately according to
the specification. For example, releasing a modifier latching key can
at the same time clear a locked modifier, promote another modifier that
is latched to locked, and latch a third modifier. Overall, what the
code does should be straightforward to compare what the XKB protocol
specification demands, see the table in section 6.3.
Finally, releasing a key no longer cancels a latch that has not become
pending yet. In my opinion, the specification is not clear; it speaks
of "operating" a key, which the patch effectivly interprets as "press"
rather than "press or release". From my experience, using the latter
interpretation makes latches on higher levels practically unusable. In
the example given above, one would have to release AltGr always before
Shift to get the Mod3-Latch. The practical relevance of latches on
higher levels is once more given by the revised German standard layout.
Signed-off-by: Andreas Wettstein <wettstein509@solnet.ch>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2013-03-03 20:25:44 +01:00
|
|
|
unsigned char mask = filter->upAction.mods.mask;
|
|
|
|
unsigned char common;
|
|
|
|
|
|
|
|
xkbi->clearMods = mask;
|
|
|
|
|
|
|
|
/* ClearLocks */
|
|
|
|
common = mask & xkbi->state.locked_mods;
|
|
|
|
if ((filter->upAction.mods.flags & XkbSA_ClearLocks) && common) {
|
|
|
|
mask &= ~common;
|
|
|
|
xkbi->state.locked_mods &= ~common;
|
|
|
|
if (needBeep)
|
|
|
|
XkbDDXAccessXBeep(xkbi->device, _BEEP_STICKY_UNLOCK,
|
|
|
|
XkbStickyKeysMask);
|
|
|
|
}
|
|
|
|
/* LatchToLock */
|
|
|
|
common = mask & xkbi->state.latched_mods;
|
|
|
|
if ((filter->upAction.mods.flags & XkbSA_LatchToLock) && common) {
|
|
|
|
unsigned char newlocked;
|
|
|
|
|
|
|
|
mask &= ~common;
|
|
|
|
newlocked = common & ~xkbi->state.locked_mods;
|
|
|
|
if(newlocked){
|
|
|
|
xkbi->state.locked_mods |= newlocked;
|
|
|
|
if (needBeep)
|
|
|
|
XkbDDXAccessXBeep(xkbi->device, _BEEP_STICKY_LOCK,
|
|
|
|
XkbStickyKeysMask);
|
|
|
|
|
|
|
|
}
|
|
|
|
xkbi->state.latched_mods &= ~common;
|
|
|
|
}
|
|
|
|
/* Latch remaining modifiers, if any. */
|
|
|
|
if (mask) {
|
|
|
|
xkbi->state.latched_mods |= mask;
|
|
|
|
filter->priv = LATCH_PENDING;
|
|
|
|
if (needBeep)
|
|
|
|
XkbDDXAccessXBeep(xkbi->device, _BEEP_STICKY_LATCH,
|
|
|
|
XkbStickyKeysMask);
|
2012-03-21 20:55:09 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
xkbi->groupChange = -XkbSAGroup(&filter->upAction.group);
|
xkb: Fixes to LatchMods/LatchGroup
The main problem this patch addresses is that if a latch is put on
multi-level key with a Latch/Lock/Set, it is possible that after all
keys are released, still base modifiers are set, which typically will
make the keyboard unusable. To see how it happens (without the patch),
assume that key AltGr sets Mod5 when pressed by itself, and latches Mod3
when pressed together with Shift. Now press Shift, then AltGr and
release both keys in reverse order. Mod3 is now latched, and the
LatchMods filter remains active as the second filter. Now press AltGr;
Mod5 base modifier gets set, and the SetMods filter will become active
as the first filter. Release AltGr: First, the SetMods filter will set
clearMods to Mod5, then the LatchMods filter will overwrite clearMods
with Mod3. Result: the Mod5 base modifier will remain set. This
example becomes practically relevant for the revised German standard
layout (DIN 2137-1:2012-06).
Other changes implement the latch behaviour more accurately according to
the specification. For example, releasing a modifier latching key can
at the same time clear a locked modifier, promote another modifier that
is latched to locked, and latch a third modifier. Overall, what the
code does should be straightforward to compare what the XKB protocol
specification demands, see the table in section 6.3.
Finally, releasing a key no longer cancels a latch that has not become
pending yet. In my opinion, the specification is not clear; it speaks
of "operating" a key, which the patch effectivly interprets as "press"
rather than "press or release". From my experience, using the latter
interpretation makes latches on higher levels practically unusable. In
the example given above, one would have to release AltGr always before
Shift to get the Mod3-Latch. The practical relevance of latches on
higher levels is once more given by the revised German standard layout.
Signed-off-by: Andreas Wettstein <wettstein509@solnet.ch>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2013-03-03 20:25:44 +01:00
|
|
|
/* ClearLocks */
|
2012-03-21 20:55:09 +01:00
|
|
|
if ((filter->upAction.group.flags & XkbSA_ClearLocks) &&
|
|
|
|
(xkbi->state.locked_group)) {
|
|
|
|
xkbi->state.locked_group = 0;
|
xkb: Fixes to LatchMods/LatchGroup
The main problem this patch addresses is that if a latch is put on
multi-level key with a Latch/Lock/Set, it is possible that after all
keys are released, still base modifiers are set, which typically will
make the keyboard unusable. To see how it happens (without the patch),
assume that key AltGr sets Mod5 when pressed by itself, and latches Mod3
when pressed together with Shift. Now press Shift, then AltGr and
release both keys in reverse order. Mod3 is now latched, and the
LatchMods filter remains active as the second filter. Now press AltGr;
Mod5 base modifier gets set, and the SetMods filter will become active
as the first filter. Release AltGr: First, the SetMods filter will set
clearMods to Mod5, then the LatchMods filter will overwrite clearMods
with Mod3. Result: the Mod5 base modifier will remain set. This
example becomes practically relevant for the revised German standard
layout (DIN 2137-1:2012-06).
Other changes implement the latch behaviour more accurately according to
the specification. For example, releasing a modifier latching key can
at the same time clear a locked modifier, promote another modifier that
is latched to locked, and latch a third modifier. Overall, what the
code does should be straightforward to compare what the XKB protocol
specification demands, see the table in section 6.3.
Finally, releasing a key no longer cancels a latch that has not become
pending yet. In my opinion, the specification is not clear; it speaks
of "operating" a key, which the patch effectivly interprets as "press"
rather than "press or release". From my experience, using the latter
interpretation makes latches on higher levels practically unusable. In
the example given above, one would have to release AltGr always before
Shift to get the Mod3-Latch. The practical relevance of latches on
higher levels is once more given by the revised German standard layout.
Signed-off-by: Andreas Wettstein <wettstein509@solnet.ch>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2013-03-03 20:25:44 +01:00
|
|
|
if (needBeep)
|
|
|
|
XkbDDXAccessXBeep(xkbi->device, _BEEP_STICKY_UNLOCK,
|
|
|
|
XkbStickyKeysMask);
|
2012-03-21 20:55:09 +01:00
|
|
|
}
|
xkb: Fixes to LatchMods/LatchGroup
The main problem this patch addresses is that if a latch is put on
multi-level key with a Latch/Lock/Set, it is possible that after all
keys are released, still base modifiers are set, which typically will
make the keyboard unusable. To see how it happens (without the patch),
assume that key AltGr sets Mod5 when pressed by itself, and latches Mod3
when pressed together with Shift. Now press Shift, then AltGr and
release both keys in reverse order. Mod3 is now latched, and the
LatchMods filter remains active as the second filter. Now press AltGr;
Mod5 base modifier gets set, and the SetMods filter will become active
as the first filter. Release AltGr: First, the SetMods filter will set
clearMods to Mod5, then the LatchMods filter will overwrite clearMods
with Mod3. Result: the Mod5 base modifier will remain set. This
example becomes practically relevant for the revised German standard
layout (DIN 2137-1:2012-06).
Other changes implement the latch behaviour more accurately according to
the specification. For example, releasing a modifier latching key can
at the same time clear a locked modifier, promote another modifier that
is latched to locked, and latch a third modifier. Overall, what the
code does should be straightforward to compare what the XKB protocol
specification demands, see the table in section 6.3.
Finally, releasing a key no longer cancels a latch that has not become
pending yet. In my opinion, the specification is not clear; it speaks
of "operating" a key, which the patch effectivly interprets as "press"
rather than "press or release". From my experience, using the latter
interpretation makes latches on higher levels practically unusable. In
the example given above, one would have to release AltGr always before
Shift to get the Mod3-Latch. The practical relevance of latches on
higher levels is once more given by the revised German standard layout.
Signed-off-by: Andreas Wettstein <wettstein509@solnet.ch>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2013-03-03 20:25:44 +01:00
|
|
|
/* LatchToLock */
|
|
|
|
else if ((filter->upAction.group.flags & XkbSA_LatchToLock)
|
|
|
|
&& (xkbi->state.latched_group)) {
|
|
|
|
xkbi->state.locked_group += XkbSAGroup(&filter->upAction.group);
|
|
|
|
xkbi->state.latched_group -= XkbSAGroup(&filter->upAction.group);
|
|
|
|
if(XkbSAGroup(&filter->upAction.group) && needBeep)
|
|
|
|
XkbDDXAccessXBeep(xkbi->device, _BEEP_STICKY_LOCK,
|
|
|
|
XkbStickyKeysMask);
|
2012-03-21 20:55:09 +01:00
|
|
|
}
|
xkb: Fixes to LatchMods/LatchGroup
The main problem this patch addresses is that if a latch is put on
multi-level key with a Latch/Lock/Set, it is possible that after all
keys are released, still base modifiers are set, which typically will
make the keyboard unusable. To see how it happens (without the patch),
assume that key AltGr sets Mod5 when pressed by itself, and latches Mod3
when pressed together with Shift. Now press Shift, then AltGr and
release both keys in reverse order. Mod3 is now latched, and the
LatchMods filter remains active as the second filter. Now press AltGr;
Mod5 base modifier gets set, and the SetMods filter will become active
as the first filter. Release AltGr: First, the SetMods filter will set
clearMods to Mod5, then the LatchMods filter will overwrite clearMods
with Mod3. Result: the Mod5 base modifier will remain set. This
example becomes practically relevant for the revised German standard
layout (DIN 2137-1:2012-06).
Other changes implement the latch behaviour more accurately according to
the specification. For example, releasing a modifier latching key can
at the same time clear a locked modifier, promote another modifier that
is latched to locked, and latch a third modifier. Overall, what the
code does should be straightforward to compare what the XKB protocol
specification demands, see the table in section 6.3.
Finally, releasing a key no longer cancels a latch that has not become
pending yet. In my opinion, the specification is not clear; it speaks
of "operating" a key, which the patch effectivly interprets as "press"
rather than "press or release". From my experience, using the latter
interpretation makes latches on higher levels practically unusable. In
the example given above, one would have to release AltGr always before
Shift to get the Mod3-Latch. The practical relevance of latches on
higher levels is once more given by the revised German standard layout.
Signed-off-by: Andreas Wettstein <wettstein509@solnet.ch>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2013-03-03 20:25:44 +01:00
|
|
|
/* Latch group */
|
|
|
|
else if(XkbSAGroup(&filter->upAction.group)){
|
|
|
|
xkbi->state.latched_group += XkbSAGroup(&filter->upAction.group);
|
|
|
|
filter->priv = LATCH_PENDING;
|
|
|
|
if (needBeep)
|
|
|
|
XkbDDXAccessXBeep(xkbi->device, _BEEP_STICKY_LATCH,
|
|
|
|
XkbStickyKeysMask);
|
2012-03-21 20:55:09 +01:00
|
|
|
}
|
|
|
|
}
|
xkb: Fixes to LatchMods/LatchGroup
The main problem this patch addresses is that if a latch is put on
multi-level key with a Latch/Lock/Set, it is possible that after all
keys are released, still base modifiers are set, which typically will
make the keyboard unusable. To see how it happens (without the patch),
assume that key AltGr sets Mod5 when pressed by itself, and latches Mod3
when pressed together with Shift. Now press Shift, then AltGr and
release both keys in reverse order. Mod3 is now latched, and the
LatchMods filter remains active as the second filter. Now press AltGr;
Mod5 base modifier gets set, and the SetMods filter will become active
as the first filter. Release AltGr: First, the SetMods filter will set
clearMods to Mod5, then the LatchMods filter will overwrite clearMods
with Mod3. Result: the Mod5 base modifier will remain set. This
example becomes practically relevant for the revised German standard
layout (DIN 2137-1:2012-06).
Other changes implement the latch behaviour more accurately according to
the specification. For example, releasing a modifier latching key can
at the same time clear a locked modifier, promote another modifier that
is latched to locked, and latch a third modifier. Overall, what the
code does should be straightforward to compare what the XKB protocol
specification demands, see the table in section 6.3.
Finally, releasing a key no longer cancels a latch that has not become
pending yet. In my opinion, the specification is not clear; it speaks
of "operating" a key, which the patch effectivly interprets as "press"
rather than "press or release". From my experience, using the latter
interpretation makes latches on higher levels practically unusable. In
the example given above, one would have to release AltGr always before
Shift to get the Mod3-Latch. The practical relevance of latches on
higher levels is once more given by the revised German standard layout.
Signed-off-by: Andreas Wettstein <wettstein509@solnet.ch>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2013-03-03 20:25:44 +01:00
|
|
|
|
|
|
|
if (filter->priv != LATCH_PENDING)
|
|
|
|
filter->active = 0;
|
2003-11-14 16:54:54 +01:00
|
|
|
}
|
xkb: Fixes to LatchMods/LatchGroup
The main problem this patch addresses is that if a latch is put on
multi-level key with a Latch/Lock/Set, it is possible that after all
keys are released, still base modifiers are set, which typically will
make the keyboard unusable. To see how it happens (without the patch),
assume that key AltGr sets Mod5 when pressed by itself, and latches Mod3
when pressed together with Shift. Now press Shift, then AltGr and
release both keys in reverse order. Mod3 is now latched, and the
LatchMods filter remains active as the second filter. Now press AltGr;
Mod5 base modifier gets set, and the SetMods filter will become active
as the first filter. Release AltGr: First, the SetMods filter will set
clearMods to Mod5, then the LatchMods filter will overwrite clearMods
with Mod3. Result: the Mod5 base modifier will remain set. This
example becomes practically relevant for the revised German standard
layout (DIN 2137-1:2012-06).
Other changes implement the latch behaviour more accurately according to
the specification. For example, releasing a modifier latching key can
at the same time clear a locked modifier, promote another modifier that
is latched to locked, and latch a third modifier. Overall, what the
code does should be straightforward to compare what the XKB protocol
specification demands, see the table in section 6.3.
Finally, releasing a key no longer cancels a latch that has not become
pending yet. In my opinion, the specification is not clear; it speaks
of "operating" a key, which the patch effectivly interprets as "press"
rather than "press or release". From my experience, using the latter
interpretation makes latches on higher levels practically unusable. In
the example given above, one would have to release AltGr always before
Shift to get the Mod3-Latch. The practical relevance of latches on
higher levels is once more given by the revised German standard layout.
Signed-off-by: Andreas Wettstein <wettstein509@solnet.ch>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2013-03-03 20:25:44 +01:00
|
|
|
else if (pAction && (filter->priv == LATCH_KEY_DOWN)) {
|
|
|
|
/* Latch was broken before it became pending: degrade to a
|
|
|
|
SetMods/SetGroup. */
|
|
|
|
if (filter->upAction.type == XkbSA_LatchMods)
|
|
|
|
filter->upAction.type = XkbSA_SetMods;
|
|
|
|
else
|
|
|
|
filter->upAction.type = XkbSA_SetGroup;
|
|
|
|
filter->filter = _XkbFilterSetState;
|
|
|
|
filter->priv = 0;
|
|
|
|
return filter->filter(xkbi, filter, keycode, pAction);
|
2003-11-14 16:54:54 +01:00
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2012-03-21 20:55:09 +01:00
|
|
|
_XkbFilterLockState(XkbSrvInfoPtr xkbi,
|
|
|
|
XkbFilterPtr filter, unsigned keycode, XkbAction *pAction)
|
2003-11-14 16:54:54 +01:00
|
|
|
{
|
2012-03-21 20:55:09 +01:00
|
|
|
if (pAction && (pAction->type == XkbSA_LockGroup)) {
|
|
|
|
if (pAction->group.flags & XkbSA_GroupAbsolute)
|
|
|
|
xkbi->state.locked_group = XkbSAGroup(&pAction->group);
|
|
|
|
else
|
|
|
|
xkbi->state.locked_group += XkbSAGroup(&pAction->group);
|
|
|
|
return 1;
|
2003-11-14 16:54:54 +01:00
|
|
|
}
|
2012-03-21 20:55:09 +01:00
|
|
|
if (filter->keycode == 0) { /* initial press */
|
|
|
|
filter->keycode = keycode;
|
|
|
|
filter->active = 1;
|
|
|
|
filter->filterOthers = 0;
|
|
|
|
filter->priv = xkbi->state.locked_mods & pAction->mods.mask;
|
|
|
|
filter->filter = _XkbFilterLockState;
|
|
|
|
filter->upAction = *pAction;
|
|
|
|
if (!(filter->upAction.mods.flags & XkbSA_LockNoLock))
|
|
|
|
xkbi->state.locked_mods |= pAction->mods.mask;
|
|
|
|
xkbi->setMods = pAction->mods.mask;
|
2003-11-14 16:54:54 +01:00
|
|
|
}
|
2012-03-21 20:55:09 +01:00
|
|
|
else if (filter->keycode == keycode) {
|
|
|
|
filter->active = 0;
|
|
|
|
xkbi->clearMods = filter->upAction.mods.mask;
|
|
|
|
if (!(filter->upAction.mods.flags & XkbSA_LockNoUnlock))
|
|
|
|
xkbi->state.locked_mods &= ~filter->priv;
|
2003-11-14 16:54:54 +01:00
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define ISO_KEY_DOWN 0
|
|
|
|
#define NO_ISO_LOCK 1
|
|
|
|
|
|
|
|
static int
|
2012-03-21 20:55:09 +01:00
|
|
|
_XkbFilterISOLock(XkbSrvInfoPtr xkbi,
|
|
|
|
XkbFilterPtr filter, unsigned keycode, XkbAction *pAction)
|
2003-11-14 16:54:54 +01:00
|
|
|
{
|
|
|
|
|
2012-03-21 20:55:09 +01:00
|
|
|
if (filter->keycode == 0) { /* initial press */
|
|
|
|
CARD8 flags = pAction->iso.flags;
|
|
|
|
|
|
|
|
filter->keycode = keycode;
|
|
|
|
filter->active = 1;
|
|
|
|
filter->filterOthers = 1;
|
|
|
|
filter->priv = ISO_KEY_DOWN;
|
|
|
|
filter->upAction = *pAction;
|
|
|
|
filter->filter = _XkbFilterISOLock;
|
|
|
|
if (flags & XkbSA_ISODfltIsGroup) {
|
|
|
|
xkbi->groupChange = XkbSAGroup(&pAction->iso);
|
|
|
|
xkbi->setMods = 0;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
xkbi->setMods = pAction->iso.mask;
|
|
|
|
xkbi->groupChange = 0;
|
|
|
|
}
|
|
|
|
if ((!(flags & XkbSA_ISONoAffectMods)) && (xkbi->state.base_mods)) {
|
|
|
|
filter->priv = NO_ISO_LOCK;
|
|
|
|
xkbi->state.locked_mods ^= xkbi->state.base_mods;
|
|
|
|
}
|
|
|
|
if ((!(flags & XkbSA_ISONoAffectGroup)) && (xkbi->state.base_group)) {
|
2003-11-14 16:54:54 +01:00
|
|
|
/* 6/22/93 (ef) -- lock groups if group key is down first */
|
2012-03-21 20:55:09 +01:00
|
|
|
}
|
|
|
|
if (!(flags & XkbSA_ISONoAffectPtr)) {
|
2003-11-14 16:54:54 +01:00
|
|
|
/* 6/22/93 (ef) -- lock mouse buttons if they're down */
|
2012-03-21 20:55:09 +01:00
|
|
|
}
|
2003-11-14 16:54:54 +01:00
|
|
|
}
|
2012-03-21 20:55:09 +01:00
|
|
|
else if (filter->keycode == keycode) {
|
|
|
|
CARD8 flags = filter->upAction.iso.flags;
|
|
|
|
|
|
|
|
if (flags & XkbSA_ISODfltIsGroup) {
|
|
|
|
xkbi->groupChange = -XkbSAGroup(&filter->upAction.iso);
|
|
|
|
xkbi->clearMods = 0;
|
|
|
|
if (filter->priv == ISO_KEY_DOWN)
|
|
|
|
xkbi->state.locked_group += XkbSAGroup(&filter->upAction.iso);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
xkbi->clearMods = filter->upAction.iso.mask;
|
|
|
|
xkbi->groupChange = 0;
|
|
|
|
if (filter->priv == ISO_KEY_DOWN)
|
|
|
|
xkbi->state.locked_mods ^= filter->upAction.iso.mask;
|
|
|
|
}
|
|
|
|
filter->active = 0;
|
2003-11-14 16:54:54 +01:00
|
|
|
}
|
|
|
|
else if (pAction) {
|
2012-03-21 20:55:09 +01:00
|
|
|
CARD8 flags = filter->upAction.iso.flags;
|
|
|
|
|
|
|
|
switch (pAction->type) {
|
|
|
|
case XkbSA_SetMods:
|
|
|
|
case XkbSA_LatchMods:
|
|
|
|
if (!(flags & XkbSA_ISONoAffectMods)) {
|
|
|
|
pAction->type = XkbSA_LockMods;
|
|
|
|
filter->priv = NO_ISO_LOCK;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case XkbSA_SetGroup:
|
|
|
|
case XkbSA_LatchGroup:
|
|
|
|
if (!(flags & XkbSA_ISONoAffectGroup)) {
|
|
|
|
pAction->type = XkbSA_LockGroup;
|
|
|
|
filter->priv = NO_ISO_LOCK;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case XkbSA_PtrBtn:
|
|
|
|
if (!(flags & XkbSA_ISONoAffectPtr)) {
|
|
|
|
pAction->type = XkbSA_LockPtrBtn;
|
|
|
|
filter->priv = NO_ISO_LOCK;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case XkbSA_SetControls:
|
|
|
|
if (!(flags & XkbSA_ISONoAffectCtrls)) {
|
|
|
|
pAction->type = XkbSA_LockControls;
|
|
|
|
filter->priv = NO_ISO_LOCK;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2003-11-14 16:54:54 +01:00
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static CARD32
|
2013-12-15 10:05:51 +01:00
|
|
|
_XkbPtrAccelExpire(OsTimerPtr timer, CARD32 now, void *arg)
|
2003-11-14 16:54:54 +01:00
|
|
|
{
|
2012-03-21 20:55:09 +01:00
|
|
|
XkbSrvInfoPtr xkbi = (XkbSrvInfoPtr) arg;
|
|
|
|
XkbControlsPtr ctrls = xkbi->desc->ctrls;
|
|
|
|
int dx, dy;
|
2003-11-14 16:54:54 +01:00
|
|
|
|
2012-03-21 20:55:09 +01:00
|
|
|
if (xkbi->mouseKey == 0)
|
|
|
|
return 0;
|
2003-11-14 16:54:54 +01:00
|
|
|
|
|
|
|
if (xkbi->mouseKeysAccel) {
|
2012-03-21 20:55:09 +01:00
|
|
|
if ((xkbi->mouseKeysCounter) < ctrls->mk_time_to_max) {
|
|
|
|
double step;
|
|
|
|
|
|
|
|
xkbi->mouseKeysCounter++;
|
|
|
|
step = xkbi->mouseKeysCurveFactor *
|
|
|
|
pow((double) xkbi->mouseKeysCounter, xkbi->mouseKeysCurve);
|
|
|
|
if (xkbi->mouseKeysDX < 0)
|
|
|
|
dx = floor(((double) xkbi->mouseKeysDX) * step);
|
|
|
|
else
|
|
|
|
dx = ceil(((double) xkbi->mouseKeysDX) * step);
|
|
|
|
if (xkbi->mouseKeysDY < 0)
|
|
|
|
dy = floor(((double) xkbi->mouseKeysDY) * step);
|
|
|
|
else
|
|
|
|
dy = ceil(((double) xkbi->mouseKeysDY) * step);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
dx = xkbi->mouseKeysDX * ctrls->mk_max_speed;
|
|
|
|
dy = xkbi->mouseKeysDY * ctrls->mk_max_speed;
|
|
|
|
}
|
|
|
|
if (xkbi->mouseKeysFlags & XkbSA_MoveAbsoluteX)
|
|
|
|
dx = xkbi->mouseKeysDX;
|
|
|
|
if (xkbi->mouseKeysFlags & XkbSA_MoveAbsoluteY)
|
|
|
|
dy = xkbi->mouseKeysDY;
|
2003-11-14 16:54:54 +01:00
|
|
|
}
|
|
|
|
else {
|
2012-03-21 20:55:09 +01:00
|
|
|
dx = xkbi->mouseKeysDX;
|
|
|
|
dy = xkbi->mouseKeysDY;
|
2003-11-14 16:54:54 +01:00
|
|
|
}
|
2012-03-21 20:55:09 +01:00
|
|
|
XkbFakePointerMotion(xkbi->device, xkbi->mouseKeysFlags, dx, dy);
|
2003-11-14 16:54:54 +01:00
|
|
|
return xkbi->desc->ctrls->mk_interval;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2012-03-21 20:55:09 +01:00
|
|
|
_XkbFilterPointerMove(XkbSrvInfoPtr xkbi,
|
|
|
|
XkbFilterPtr filter, unsigned keycode, XkbAction *pAction)
|
2003-11-14 16:54:54 +01:00
|
|
|
{
|
2012-03-21 20:55:09 +01:00
|
|
|
int x, y;
|
|
|
|
Bool accel;
|
|
|
|
|
|
|
|
if (filter->keycode == 0) { /* initial press */
|
|
|
|
filter->keycode = keycode;
|
|
|
|
filter->active = 1;
|
|
|
|
filter->filterOthers = 0;
|
|
|
|
filter->priv = 0;
|
|
|
|
filter->filter = _XkbFilterPointerMove;
|
|
|
|
filter->upAction = *pAction;
|
|
|
|
xkbi->mouseKeysCounter = 0;
|
|
|
|
xkbi->mouseKey = keycode;
|
|
|
|
accel = ((pAction->ptr.flags & XkbSA_NoAcceleration) == 0);
|
|
|
|
x = XkbPtrActionX(&pAction->ptr);
|
|
|
|
y = XkbPtrActionY(&pAction->ptr);
|
|
|
|
XkbFakePointerMotion(xkbi->device, pAction->ptr.flags, x, y);
|
|
|
|
AccessXCancelRepeatKey(xkbi, keycode);
|
|
|
|
xkbi->mouseKeysAccel = accel &&
|
|
|
|
(xkbi->desc->ctrls->enabled_ctrls & XkbMouseKeysAccelMask);
|
|
|
|
xkbi->mouseKeysFlags = pAction->ptr.flags;
|
|
|
|
xkbi->mouseKeysDX = XkbPtrActionX(&pAction->ptr);
|
|
|
|
xkbi->mouseKeysDY = XkbPtrActionY(&pAction->ptr);
|
|
|
|
xkbi->mouseKeyTimer = TimerSet(xkbi->mouseKeyTimer, 0,
|
|
|
|
xkbi->desc->ctrls->mk_delay,
|
2013-12-15 10:05:51 +01:00
|
|
|
_XkbPtrAccelExpire, (void *) xkbi);
|
2003-11-14 16:54:54 +01:00
|
|
|
}
|
2012-03-21 20:55:09 +01:00
|
|
|
else if (filter->keycode == keycode) {
|
|
|
|
filter->active = 0;
|
|
|
|
if (xkbi->mouseKey == keycode) {
|
|
|
|
xkbi->mouseKey = 0;
|
|
|
|
xkbi->mouseKeyTimer = TimerSet(xkbi->mouseKeyTimer, 0, 0,
|
|
|
|
NULL, NULL);
|
|
|
|
}
|
2003-11-14 16:54:54 +01:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2012-03-21 20:55:09 +01:00
|
|
|
_XkbFilterPointerBtn(XkbSrvInfoPtr xkbi,
|
|
|
|
XkbFilterPtr filter, unsigned keycode, XkbAction *pAction)
|
2003-11-14 16:54:54 +01:00
|
|
|
{
|
2012-03-21 20:55:09 +01:00
|
|
|
if (filter->keycode == 0) { /* initial press */
|
|
|
|
int button = pAction->btn.button;
|
|
|
|
|
|
|
|
if (button == XkbSA_UseDfltButton)
|
|
|
|
button = xkbi->desc->ctrls->mk_dflt_btn;
|
|
|
|
|
|
|
|
filter->keycode = keycode;
|
|
|
|
filter->active = 1;
|
|
|
|
filter->filterOthers = 0;
|
|
|
|
filter->priv = 0;
|
|
|
|
filter->filter = _XkbFilterPointerBtn;
|
|
|
|
filter->upAction = *pAction;
|
|
|
|
filter->upAction.btn.button = button;
|
|
|
|
switch (pAction->type) {
|
|
|
|
case XkbSA_LockPtrBtn:
|
|
|
|
if (((xkbi->lockedPtrButtons & (1 << button)) == 0) &&
|
|
|
|
((pAction->btn.flags & XkbSA_LockNoLock) == 0)) {
|
|
|
|
xkbi->lockedPtrButtons |= (1 << button);
|
|
|
|
AccessXCancelRepeatKey(xkbi, keycode);
|
|
|
|
XkbFakeDeviceButton(xkbi->device, 1, button);
|
|
|
|
filter->upAction.type = XkbSA_NoAction;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case XkbSA_PtrBtn:
|
|
|
|
{
|
|
|
|
register int i, nClicks;
|
|
|
|
|
|
|
|
AccessXCancelRepeatKey(xkbi, keycode);
|
|
|
|
if (pAction->btn.count > 0) {
|
|
|
|
nClicks = pAction->btn.count;
|
|
|
|
for (i = 0; i < nClicks; i++) {
|
|
|
|
XkbFakeDeviceButton(xkbi->device, 1, button);
|
|
|
|
XkbFakeDeviceButton(xkbi->device, 0, button);
|
|
|
|
}
|
|
|
|
filter->upAction.type = XkbSA_NoAction;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
XkbFakeDeviceButton(xkbi->device, 1, button);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case XkbSA_SetPtrDflt:
|
|
|
|
{
|
|
|
|
XkbControlsPtr ctrls = xkbi->desc->ctrls;
|
|
|
|
XkbControlsRec old;
|
|
|
|
xkbControlsNotify cn;
|
|
|
|
|
|
|
|
old = *ctrls;
|
|
|
|
AccessXCancelRepeatKey(xkbi, keycode);
|
|
|
|
switch (pAction->dflt.affect) {
|
|
|
|
case XkbSA_AffectDfltBtn:
|
|
|
|
if (pAction->dflt.flags & XkbSA_DfltBtnAbsolute)
|
|
|
|
ctrls->mk_dflt_btn = XkbSAPtrDfltValue(&pAction->dflt);
|
|
|
|
else {
|
|
|
|
ctrls->mk_dflt_btn += XkbSAPtrDfltValue(&pAction->dflt);
|
|
|
|
if (ctrls->mk_dflt_btn > 5)
|
|
|
|
ctrls->mk_dflt_btn = 5;
|
|
|
|
else if (ctrls->mk_dflt_btn < 1)
|
|
|
|
ctrls->mk_dflt_btn = 1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ErrorF
|
|
|
|
("Attempt to change unknown pointer default (%d) ignored\n",
|
|
|
|
pAction->dflt.affect);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (XkbComputeControlsNotify(xkbi->device,
|
|
|
|
&old, xkbi->desc->ctrls, &cn, FALSE)) {
|
|
|
|
cn.keycode = keycode;
|
|
|
|
/* XXX: what about DeviceKeyPress? */
|
|
|
|
cn.eventType = KeyPress;
|
|
|
|
cn.requestMajor = 0;
|
|
|
|
cn.requestMinor = 0;
|
|
|
|
XkbSendControlsNotify(xkbi->device, &cn);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2003-11-14 16:54:54 +01:00
|
|
|
}
|
2012-03-21 20:55:09 +01:00
|
|
|
else if (filter->keycode == keycode) {
|
|
|
|
int button = filter->upAction.btn.button;
|
|
|
|
|
|
|
|
switch (filter->upAction.type) {
|
|
|
|
case XkbSA_LockPtrBtn:
|
|
|
|
if (((filter->upAction.btn.flags & XkbSA_LockNoUnlock) != 0) ||
|
|
|
|
((xkbi->lockedPtrButtons & (1 << button)) == 0)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
xkbi->lockedPtrButtons &= ~(1 << button);
|
|
|
|
|
|
|
|
if (IsMaster(xkbi->device)) {
|
|
|
|
XkbMergeLockedPtrBtns(xkbi->device);
|
|
|
|
/* One SD still has lock set, don't post event */
|
|
|
|
if ((xkbi->lockedPtrButtons & (1 << button)) != 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* fallthrough */
|
|
|
|
case XkbSA_PtrBtn:
|
|
|
|
XkbFakeDeviceButton(xkbi->device, 0, button);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
filter->active = 0;
|
2003-11-14 16:54:54 +01:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2012-03-21 20:55:09 +01:00
|
|
|
_XkbFilterControls(XkbSrvInfoPtr xkbi,
|
|
|
|
XkbFilterPtr filter, unsigned keycode, XkbAction *pAction)
|
2003-11-14 16:54:54 +01:00
|
|
|
{
|
2012-03-21 20:55:09 +01:00
|
|
|
XkbControlsRec old;
|
|
|
|
XkbControlsPtr ctrls;
|
|
|
|
DeviceIntPtr kbd;
|
|
|
|
unsigned int change;
|
|
|
|
XkbEventCauseRec cause;
|
|
|
|
|
|
|
|
kbd = xkbi->device;
|
|
|
|
ctrls = xkbi->desc->ctrls;
|
|
|
|
old = *ctrls;
|
|
|
|
if (filter->keycode == 0) { /* initial press */
|
|
|
|
filter->keycode = keycode;
|
|
|
|
filter->active = 1;
|
|
|
|
filter->filterOthers = 0;
|
|
|
|
change = XkbActionCtrls(&pAction->ctrls);
|
|
|
|
filter->priv = change;
|
|
|
|
filter->filter = _XkbFilterControls;
|
|
|
|
filter->upAction = *pAction;
|
|
|
|
|
|
|
|
if (pAction->type == XkbSA_LockControls) {
|
|
|
|
filter->priv = (ctrls->enabled_ctrls & change);
|
|
|
|
change &= ~ctrls->enabled_ctrls;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (change) {
|
|
|
|
xkbControlsNotify cn;
|
|
|
|
XkbSrvLedInfoPtr sli;
|
|
|
|
|
|
|
|
ctrls->enabled_ctrls |= change;
|
|
|
|
if (XkbComputeControlsNotify(kbd, &old, ctrls, &cn, FALSE)) {
|
|
|
|
cn.keycode = keycode;
|
2007-09-06 11:19:57 +02:00
|
|
|
/* XXX: what about DeviceKeyPress? */
|
2012-03-21 20:55:09 +01:00
|
|
|
cn.eventType = KeyPress;
|
|
|
|
cn.requestMajor = 0;
|
|
|
|
cn.requestMinor = 0;
|
|
|
|
XkbSendControlsNotify(kbd, &cn);
|
|
|
|
}
|
|
|
|
|
|
|
|
XkbSetCauseKey(&cause, keycode, KeyPress);
|
|
|
|
|
|
|
|
/* If sticky keys were disabled, clear all locks and latches */
|
|
|
|
if ((old.enabled_ctrls & XkbStickyKeysMask) &&
|
|
|
|
(!(ctrls->enabled_ctrls & XkbStickyKeysMask))) {
|
|
|
|
XkbClearAllLatchesAndLocks(kbd, xkbi, FALSE, &cause);
|
|
|
|
}
|
|
|
|
sli = XkbFindSrvLedInfo(kbd, XkbDfltXIClass, XkbDfltXIId, 0);
|
|
|
|
XkbUpdateIndicators(kbd, sli->usesControls, TRUE, NULL, &cause);
|
|
|
|
if (XkbAX_NeedFeedback(ctrls, XkbAX_FeatureFBMask))
|
|
|
|
XkbDDXAccessXBeep(kbd, _BEEP_FEATURE_ON, change);
|
|
|
|
}
|
2003-11-14 16:54:54 +01:00
|
|
|
}
|
2012-03-21 20:55:09 +01:00
|
|
|
else if (filter->keycode == keycode) {
|
|
|
|
change = filter->priv;
|
|
|
|
if (change) {
|
|
|
|
xkbControlsNotify cn;
|
|
|
|
XkbSrvLedInfoPtr sli;
|
|
|
|
|
|
|
|
ctrls->enabled_ctrls &= ~change;
|
|
|
|
if (XkbComputeControlsNotify(kbd, &old, ctrls, &cn, FALSE)) {
|
|
|
|
cn.keycode = keycode;
|
|
|
|
cn.eventType = KeyRelease;
|
|
|
|
cn.requestMajor = 0;
|
|
|
|
cn.requestMinor = 0;
|
|
|
|
XkbSendControlsNotify(kbd, &cn);
|
|
|
|
}
|
|
|
|
|
|
|
|
XkbSetCauseKey(&cause, keycode, KeyRelease);
|
|
|
|
/* If sticky keys were disabled, clear all locks and latches */
|
|
|
|
if ((old.enabled_ctrls & XkbStickyKeysMask) &&
|
|
|
|
(!(ctrls->enabled_ctrls & XkbStickyKeysMask))) {
|
|
|
|
XkbClearAllLatchesAndLocks(kbd, xkbi, FALSE, &cause);
|
|
|
|
}
|
|
|
|
sli = XkbFindSrvLedInfo(kbd, XkbDfltXIClass, XkbDfltXIId, 0);
|
|
|
|
XkbUpdateIndicators(kbd, sli->usesControls, TRUE, NULL, &cause);
|
|
|
|
if (XkbAX_NeedFeedback(ctrls, XkbAX_FeatureFBMask))
|
|
|
|
XkbDDXAccessXBeep(kbd, _BEEP_FEATURE_OFF, change);
|
|
|
|
}
|
|
|
|
filter->keycode = 0;
|
|
|
|
filter->active = 0;
|
2003-11-14 16:54:54 +01:00
|
|
|
}
|
2003-11-14 17:49:22 +01:00
|
|
|
return 1;
|
2003-11-14 16:54:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2012-03-21 20:55:09 +01:00
|
|
|
_XkbFilterActionMessage(XkbSrvInfoPtr xkbi,
|
|
|
|
XkbFilterPtr filter,
|
|
|
|
unsigned keycode, XkbAction *pAction)
|
2003-11-14 16:54:54 +01:00
|
|
|
{
|
2012-03-21 20:55:09 +01:00
|
|
|
XkbMessageAction *pMsg;
|
|
|
|
DeviceIntPtr kbd;
|
|
|
|
|
2013-01-29 21:49:20 +01:00
|
|
|
if ((filter->keycode != 0) && (filter->keycode != keycode))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
/* This can happen if the key repeats, and the state (modifiers or group)
|
|
|
|
changes meanwhile. */
|
|
|
|
if ((filter->keycode == keycode) && pAction &&
|
|
|
|
(pAction->type != XkbSA_ActionMessage))
|
|
|
|
return 1;
|
|
|
|
|
2012-03-21 20:55:09 +01:00
|
|
|
kbd = xkbi->device;
|
|
|
|
if (filter->keycode == 0) { /* initial press */
|
|
|
|
pMsg = &pAction->msg;
|
|
|
|
if ((pMsg->flags & XkbSA_MessageOnRelease) ||
|
|
|
|
((pMsg->flags & XkbSA_MessageGenKeyEvent) == 0)) {
|
|
|
|
filter->keycode = keycode;
|
|
|
|
filter->active = 1;
|
|
|
|
filter->filterOthers = 0;
|
|
|
|
filter->priv = 0;
|
|
|
|
filter->filter = _XkbFilterActionMessage;
|
|
|
|
filter->upAction = *pAction;
|
|
|
|
}
|
|
|
|
if (pMsg->flags & XkbSA_MessageOnPress) {
|
|
|
|
xkbActionMessage msg;
|
|
|
|
|
|
|
|
msg.keycode = keycode;
|
|
|
|
msg.press = 1;
|
|
|
|
msg.keyEventFollows =
|
|
|
|
((pMsg->flags & XkbSA_MessageGenKeyEvent) != 0);
|
|
|
|
memcpy((char *) msg.message, (char *) pMsg->message,
|
|
|
|
XkbActionMessageLength);
|
|
|
|
XkbSendActionMessage(kbd, &msg);
|
|
|
|
}
|
|
|
|
return ((pAction->msg.flags & XkbSA_MessageGenKeyEvent) != 0);
|
2003-11-14 16:54:54 +01:00
|
|
|
}
|
2012-03-21 20:55:09 +01:00
|
|
|
else if (filter->keycode == keycode) {
|
|
|
|
pMsg = &filter->upAction.msg;
|
2013-01-29 21:49:20 +01:00
|
|
|
if (pAction == NULL) {
|
|
|
|
if (pMsg->flags & XkbSA_MessageOnRelease) {
|
|
|
|
xkbActionMessage msg;
|
|
|
|
|
|
|
|
msg.keycode = keycode;
|
|
|
|
msg.press = 0;
|
|
|
|
msg.keyEventFollows =
|
|
|
|
((pMsg->flags & XkbSA_MessageGenKeyEvent) != 0);
|
|
|
|
memcpy((char *) msg.message, (char *) pMsg->message,
|
|
|
|
XkbActionMessageLength);
|
|
|
|
XkbSendActionMessage(kbd, &msg);
|
|
|
|
}
|
|
|
|
filter->keycode = 0;
|
|
|
|
filter->active = 0;
|
|
|
|
return ((pMsg->flags & XkbSA_MessageGenKeyEvent) != 0);
|
|
|
|
} else if (memcmp(pMsg, pAction, 8) == 0) {
|
|
|
|
/* Repeat: If we send the same message, avoid multiple messages
|
|
|
|
on release from piling up. */
|
|
|
|
filter->keycode = 0;
|
|
|
|
filter->active = 0;
|
2012-03-21 20:55:09 +01:00
|
|
|
}
|
2003-11-14 16:54:54 +01:00
|
|
|
}
|
2011-11-30 20:20:21 +01:00
|
|
|
return 1;
|
2003-11-14 16:54:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2012-03-21 20:55:09 +01:00
|
|
|
_XkbFilterRedirectKey(XkbSrvInfoPtr xkbi,
|
|
|
|
XkbFilterPtr filter, unsigned keycode, XkbAction *pAction)
|
2003-11-14 16:54:54 +01:00
|
|
|
{
|
2012-03-21 20:55:09 +01:00
|
|
|
DeviceEvent ev;
|
|
|
|
int x, y;
|
2012-02-25 20:48:17 +01:00
|
|
|
XkbStateRec old, old_prev;
|
2012-03-21 20:55:09 +01:00
|
|
|
unsigned mods, mask;
|
|
|
|
xkbDeviceInfoPtr xkbPrivPtr = XKBDEVICEINFO(xkbi->device);
|
|
|
|
ProcessInputProc backupproc;
|
2003-11-14 16:54:54 +01:00
|
|
|
|
2013-01-29 21:49:20 +01:00
|
|
|
if ((filter->keycode != 0) && (filter->keycode != keycode))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
/* This can happen if the key repeats, and the state (modifiers or group)
|
|
|
|
changes meanwhile. */
|
|
|
|
if ((filter->keycode == keycode) && pAction &&
|
|
|
|
(pAction->type != XkbSA_RedirectKey))
|
|
|
|
return 1;
|
|
|
|
|
2006-11-04 20:47:55 +01:00
|
|
|
/* never actually used uninitialised, but gcc isn't smart enough
|
|
|
|
* to work that out. */
|
|
|
|
memset(&old, 0, sizeof(old));
|
2012-02-25 20:48:17 +01:00
|
|
|
memset(&old_prev, 0, sizeof(old_prev));
|
2010-08-19 07:33:57 +02:00
|
|
|
memset(&ev, 0, sizeof(ev));
|
2006-11-04 20:47:55 +01:00
|
|
|
|
2012-03-21 20:55:09 +01:00
|
|
|
GetSpritePosition(xkbi->device, &x, &y);
|
2009-02-02 08:18:16 +01:00
|
|
|
ev.header = ET_Internal;
|
|
|
|
ev.length = sizeof(DeviceEvent);
|
|
|
|
ev.time = GetTimeInMillis();
|
|
|
|
ev.root_x = x;
|
|
|
|
ev.root_y = y;
|
2012-02-25 20:48:17 +01:00
|
|
|
/* redirect actions do not work across devices, therefore the following is
|
|
|
|
* correct: */
|
|
|
|
ev.deviceid = xkbi->device->id;
|
|
|
|
/* filter->priv must be set up by the caller for the initial press. */
|
|
|
|
ev.sourceid = filter->priv;
|
2003-11-14 16:54:54 +01:00
|
|
|
|
2012-03-21 20:55:09 +01:00
|
|
|
if (filter->keycode == 0) { /* initial press */
|
|
|
|
if ((pAction->redirect.new_key < xkbi->desc->min_key_code) ||
|
|
|
|
(pAction->redirect.new_key > xkbi->desc->max_key_code)) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
filter->keycode = keycode;
|
|
|
|
filter->active = 1;
|
|
|
|
filter->filterOthers = 0;
|
|
|
|
filter->filter = _XkbFilterRedirectKey;
|
|
|
|
filter->upAction = *pAction;
|
2003-11-14 16:54:54 +01:00
|
|
|
|
2009-02-02 08:18:16 +01:00
|
|
|
ev.type = ET_KeyPress;
|
|
|
|
ev.detail.key = pAction->redirect.new_key;
|
2003-11-14 16:54:54 +01:00
|
|
|
|
2012-03-21 20:55:09 +01:00
|
|
|
mask = XkbSARedirectVModsMask(&pAction->redirect);
|
|
|
|
mods = XkbSARedirectVMods(&pAction->redirect);
|
|
|
|
if (mask)
|
|
|
|
XkbVirtualModsToReal(xkbi->desc, mask, &mask);
|
|
|
|
if (mods)
|
|
|
|
XkbVirtualModsToReal(xkbi->desc, mods, &mods);
|
|
|
|
mask |= pAction->redirect.mods_mask;
|
|
|
|
mods |= pAction->redirect.mods;
|
|
|
|
|
|
|
|
if (mask || mods) {
|
|
|
|
old = xkbi->state;
|
2012-02-25 20:48:17 +01:00
|
|
|
old_prev = xkbi->prev_state;
|
2012-03-21 20:55:09 +01:00
|
|
|
xkbi->state.base_mods &= ~mask;
|
|
|
|
xkbi->state.base_mods |= (mods & mask);
|
|
|
|
xkbi->state.latched_mods &= ~mask;
|
|
|
|
xkbi->state.latched_mods |= (mods & mask);
|
|
|
|
xkbi->state.locked_mods &= ~mask;
|
|
|
|
xkbi->state.locked_mods |= (mods & mask);
|
|
|
|
XkbComputeDerivedState(xkbi);
|
2012-02-25 20:48:17 +01:00
|
|
|
xkbi->prev_state = xkbi->state;
|
2012-03-21 20:55:09 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
UNWRAP_PROCESS_INPUT_PROC(xkbi->device, xkbPrivPtr, backupproc);
|
|
|
|
xkbi->device->public.processInputProc((InternalEvent *) &ev,
|
|
|
|
xkbi->device);
|
|
|
|
COND_WRAP_PROCESS_INPUT_PROC(xkbi->device, xkbPrivPtr, backupproc,
|
|
|
|
xkbUnwrapProc);
|
|
|
|
|
2012-02-25 20:48:17 +01:00
|
|
|
if (mask || mods) {
|
2012-03-21 20:55:09 +01:00
|
|
|
xkbi->state = old;
|
2012-02-25 20:48:17 +01:00
|
|
|
xkbi->prev_state = old_prev;
|
|
|
|
}
|
2013-01-29 21:49:20 +01:00
|
|
|
return 0;
|
2003-11-14 16:54:54 +01:00
|
|
|
}
|
2013-01-29 21:49:20 +01:00
|
|
|
else {
|
|
|
|
/* If it is a key release, or we redirect to another key, release the
|
|
|
|
previous new_key. Otherwise, repeat. */
|
|
|
|
ev.detail.key = filter->upAction.redirect.new_key;
|
|
|
|
if (pAction == NULL || ev.detail.key != pAction->redirect.new_key) {
|
|
|
|
ev.type = ET_KeyRelease;
|
|
|
|
filter->active = 0;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
ev.type = ET_KeyPress;
|
|
|
|
ev.key_repeat = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
mask = XkbSARedirectVModsMask(&filter->upAction.redirect);
|
|
|
|
mods = XkbSARedirectVMods(&filter->upAction.redirect);
|
|
|
|
if (mask)
|
|
|
|
XkbVirtualModsToReal(xkbi->desc, mask, &mask);
|
|
|
|
if (mods)
|
|
|
|
XkbVirtualModsToReal(xkbi->desc, mods, &mods);
|
|
|
|
mask |= filter->upAction.redirect.mods_mask;
|
|
|
|
mods |= filter->upAction.redirect.mods;
|
|
|
|
|
|
|
|
if (mask || mods) {
|
|
|
|
old = xkbi->state;
|
|
|
|
old_prev = xkbi->prev_state;
|
|
|
|
xkbi->state.base_mods &= ~mask;
|
|
|
|
xkbi->state.base_mods |= (mods & mask);
|
|
|
|
xkbi->state.latched_mods &= ~mask;
|
|
|
|
xkbi->state.latched_mods |= (mods & mask);
|
|
|
|
xkbi->state.locked_mods &= ~mask;
|
|
|
|
xkbi->state.locked_mods |= (mods & mask);
|
|
|
|
XkbComputeDerivedState(xkbi);
|
|
|
|
xkbi->prev_state = xkbi->state;
|
|
|
|
}
|
|
|
|
|
|
|
|
UNWRAP_PROCESS_INPUT_PROC(xkbi->device, xkbPrivPtr, backupproc);
|
|
|
|
xkbi->device->public.processInputProc((InternalEvent *) &ev,
|
|
|
|
xkbi->device);
|
|
|
|
COND_WRAP_PROCESS_INPUT_PROC(xkbi->device, xkbPrivPtr, backupproc,
|
|
|
|
xkbUnwrapProc);
|
|
|
|
|
|
|
|
if (mask || mods) {
|
|
|
|
xkbi->state = old;
|
|
|
|
xkbi->prev_state = old_prev;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We return 1 in case we have sent a release event because the new_key
|
|
|
|
has changed. Then, subsequently, we will call this function again
|
|
|
|
with the same pAction, which will create the press for the new
|
|
|
|
new_key. */
|
|
|
|
return (pAction && ev.detail.key != pAction->redirect.new_key);
|
2003-11-14 16:54:54 +01:00
|
|
|
}
|
2003-11-14 17:49:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2012-03-21 20:55:09 +01:00
|
|
|
_XkbFilterSwitchScreen(XkbSrvInfoPtr xkbi,
|
|
|
|
XkbFilterPtr filter,
|
|
|
|
unsigned keycode, XkbAction *pAction)
|
2003-11-14 17:49:22 +01:00
|
|
|
{
|
2007-12-05 20:37:48 +01:00
|
|
|
DeviceIntPtr dev = xkbi->device;
|
2012-03-21 20:55:09 +01:00
|
|
|
|
2007-12-05 20:37:48 +01:00
|
|
|
if (dev == inputInfo.keyboard)
|
|
|
|
return 0;
|
|
|
|
|
2012-03-21 20:55:09 +01:00
|
|
|
if (filter->keycode == 0) { /* initial press */
|
|
|
|
filter->keycode = keycode;
|
|
|
|
filter->active = 1;
|
|
|
|
filter->filterOthers = 0;
|
|
|
|
filter->filter = _XkbFilterSwitchScreen;
|
|
|
|
AccessXCancelRepeatKey(xkbi, keycode);
|
|
|
|
XkbDDXSwitchScreen(dev, keycode, pAction);
|
|
|
|
return 0;
|
2003-11-14 17:49:22 +01:00
|
|
|
}
|
2012-03-21 20:55:09 +01:00
|
|
|
else if (filter->keycode == keycode) {
|
|
|
|
filter->active = 0;
|
|
|
|
return 0;
|
2003-11-14 17:49:22 +01:00
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2012-03-21 20:55:09 +01:00
|
|
|
_XkbFilterXF86Private(XkbSrvInfoPtr xkbi,
|
|
|
|
XkbFilterPtr filter, unsigned keycode, XkbAction *pAction)
|
2003-11-14 17:49:22 +01:00
|
|
|
{
|
2007-12-05 20:37:48 +01:00
|
|
|
DeviceIntPtr dev = xkbi->device;
|
2012-03-21 20:55:09 +01:00
|
|
|
|
2007-12-05 20:37:48 +01:00
|
|
|
if (dev == inputInfo.keyboard)
|
|
|
|
return 0;
|
|
|
|
|
2012-03-21 20:55:09 +01:00
|
|
|
if (filter->keycode == 0) { /* initial press */
|
|
|
|
filter->keycode = keycode;
|
|
|
|
filter->active = 1;
|
|
|
|
filter->filterOthers = 0;
|
|
|
|
filter->filter = _XkbFilterXF86Private;
|
|
|
|
XkbDDXPrivate(dev, keycode, pAction);
|
|
|
|
return 0;
|
2003-11-14 17:49:22 +01:00
|
|
|
}
|
2012-03-21 20:55:09 +01:00
|
|
|
else if (filter->keycode == keycode) {
|
|
|
|
filter->active = 0;
|
|
|
|
return 0;
|
2003-11-14 17:49:22 +01:00
|
|
|
}
|
|
|
|
return 1;
|
2003-11-14 16:54:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2012-03-21 20:55:09 +01:00
|
|
|
_XkbFilterDeviceBtn(XkbSrvInfoPtr xkbi,
|
|
|
|
XkbFilterPtr filter, unsigned keycode, XkbAction *pAction)
|
2003-11-14 16:54:54 +01:00
|
|
|
{
|
2008-04-22 06:00:03 +02:00
|
|
|
if (xkbi->device == inputInfo.keyboard)
|
2007-12-05 20:37:48 +01:00
|
|
|
return 0;
|
|
|
|
|
2012-03-21 20:55:09 +01:00
|
|
|
if (filter->keycode == 0) { /* initial press */
|
|
|
|
DeviceIntPtr dev;
|
|
|
|
int button;
|
|
|
|
|
|
|
|
_XkbLookupButtonDevice(&dev, pAction->devbtn.device, serverClient,
|
|
|
|
DixUnknownAccess, &button);
|
|
|
|
if (!dev || !dev->public.on)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
button = pAction->devbtn.button;
|
|
|
|
if ((button < 1) || (button > dev->button->numButtons))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
filter->keycode = keycode;
|
|
|
|
filter->active = 1;
|
|
|
|
filter->filterOthers = 0;
|
|
|
|
filter->priv = 0;
|
|
|
|
filter->filter = _XkbFilterDeviceBtn;
|
|
|
|
filter->upAction = *pAction;
|
|
|
|
switch (pAction->type) {
|
|
|
|
case XkbSA_LockDeviceBtn:
|
|
|
|
if ((pAction->devbtn.flags & XkbSA_LockNoLock) ||
|
|
|
|
BitIsOn(dev->button->down, button))
|
|
|
|
return 0;
|
|
|
|
XkbFakeDeviceButton(dev, TRUE, button);
|
|
|
|
filter->upAction.type = XkbSA_NoAction;
|
|
|
|
break;
|
|
|
|
case XkbSA_DeviceBtn:
|
|
|
|
if (pAction->devbtn.count > 0) {
|
|
|
|
int nClicks, i;
|
|
|
|
|
|
|
|
nClicks = pAction->btn.count;
|
|
|
|
for (i = 0; i < nClicks; i++) {
|
|
|
|
XkbFakeDeviceButton(dev, TRUE, button);
|
|
|
|
XkbFakeDeviceButton(dev, FALSE, button);
|
|
|
|
}
|
|
|
|
filter->upAction.type = XkbSA_NoAction;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
XkbFakeDeviceButton(dev, TRUE, button);
|
|
|
|
break;
|
|
|
|
}
|
2003-11-14 16:54:54 +01:00
|
|
|
}
|
2012-03-21 20:55:09 +01:00
|
|
|
else if (filter->keycode == keycode) {
|
|
|
|
DeviceIntPtr dev;
|
|
|
|
int button;
|
|
|
|
|
|
|
|
filter->active = 0;
|
|
|
|
_XkbLookupButtonDevice(&dev, filter->upAction.devbtn.device,
|
|
|
|
serverClient, DixUnknownAccess, &button);
|
|
|
|
if (!dev || !dev->public.on)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
button = filter->upAction.btn.button;
|
|
|
|
switch (filter->upAction.type) {
|
|
|
|
case XkbSA_LockDeviceBtn:
|
|
|
|
if ((filter->upAction.devbtn.flags & XkbSA_LockNoUnlock) ||
|
|
|
|
!BitIsOn(dev->button->down, button))
|
|
|
|
return 0;
|
|
|
|
XkbFakeDeviceButton(dev, FALSE, button);
|
|
|
|
break;
|
|
|
|
case XkbSA_DeviceBtn:
|
|
|
|
XkbFakeDeviceButton(dev, FALSE, button);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
filter->active = 0;
|
2003-11-14 16:54:54 +01:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static XkbFilterPtr
|
2012-03-21 20:55:09 +01:00
|
|
|
_XkbNextFreeFilter(XkbSrvInfoPtr xkbi)
|
2003-11-14 16:54:54 +01:00
|
|
|
{
|
2012-03-21 20:55:09 +01:00
|
|
|
register int i;
|
2003-11-14 16:54:54 +01:00
|
|
|
|
2012-03-21 20:55:09 +01:00
|
|
|
if (xkbi->szFilters == 0) {
|
|
|
|
xkbi->szFilters = 4;
|
|
|
|
xkbi->filters = calloc(xkbi->szFilters, sizeof(XkbFilterRec));
|
|
|
|
/* 6/21/93 (ef) -- XXX! deal with allocation failure */
|
2003-11-14 16:54:54 +01:00
|
|
|
}
|
2012-03-21 20:55:09 +01:00
|
|
|
for (i = 0; i < xkbi->szFilters; i++) {
|
|
|
|
if (!xkbi->filters[i].active) {
|
|
|
|
xkbi->filters[i].keycode = 0;
|
|
|
|
return &xkbi->filters[i];
|
|
|
|
}
|
2003-11-14 16:54:54 +01:00
|
|
|
}
|
2012-03-21 20:55:09 +01:00
|
|
|
xkbi->szFilters *= 2;
|
|
|
|
xkbi->filters = realloc(xkbi->filters,
|
2010-01-15 06:32:09 +01:00
|
|
|
xkbi->szFilters * sizeof(XkbFilterRec));
|
2003-11-14 16:54:54 +01:00
|
|
|
/* 6/21/93 (ef) -- XXX! deal with allocation failure */
|
2012-03-21 20:55:09 +01:00
|
|
|
memset(&xkbi->filters[xkbi->szFilters / 2], 0,
|
|
|
|
(xkbi->szFilters / 2) * sizeof(XkbFilterRec));
|
|
|
|
return &xkbi->filters[xkbi->szFilters / 2];
|
2003-11-14 16:54:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2012-03-21 20:55:09 +01:00
|
|
|
_XkbApplyFilters(XkbSrvInfoPtr xkbi, unsigned kc, XkbAction *pAction)
|
2003-11-14 16:54:54 +01:00
|
|
|
{
|
2012-03-21 20:55:09 +01:00
|
|
|
register int i, send;
|
|
|
|
|
|
|
|
send = 1;
|
|
|
|
for (i = 0; i < xkbi->szFilters; i++) {
|
|
|
|
if ((xkbi->filters[i].active) && (xkbi->filters[i].filter))
|
|
|
|
send =
|
|
|
|
((*xkbi->filters[i].filter) (xkbi, &xkbi->filters[i], kc,
|
|
|
|
pAction)
|
|
|
|
&& send);
|
2003-11-14 16:54:54 +01:00
|
|
|
}
|
|
|
|
return send;
|
|
|
|
}
|
|
|
|
|
2014-02-26 07:03:19 +01:00
|
|
|
static int
|
|
|
|
_XkbEnsureStateChange(XkbSrvInfoPtr xkbi)
|
|
|
|
{
|
|
|
|
Bool genStateNotify = FALSE;
|
|
|
|
|
|
|
|
/* The state may change, so if we're not in the middle of sending a state
|
|
|
|
* notify, prepare for it */
|
|
|
|
if ((xkbi->flags & _XkbStateNotifyInProgress) == 0) {
|
|
|
|
xkbi->prev_state = xkbi->state;
|
|
|
|
xkbi->flags |= _XkbStateNotifyInProgress;
|
|
|
|
genStateNotify = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return genStateNotify;
|
|
|
|
}
|
|
|
|
|
2014-02-26 07:16:10 +01:00
|
|
|
static void
|
|
|
|
_XkbApplyState(DeviceIntPtr dev, Bool genStateNotify, int evtype, int key)
|
|
|
|
{
|
|
|
|
XkbSrvInfoPtr xkbi = dev->key->xkbInfo;
|
|
|
|
int changed;
|
|
|
|
|
|
|
|
XkbComputeDerivedState(xkbi);
|
|
|
|
|
|
|
|
changed = XkbStateChangedFlags(&xkbi->prev_state, &xkbi->state);
|
|
|
|
if (genStateNotify) {
|
|
|
|
if (changed) {
|
|
|
|
xkbStateNotify sn;
|
|
|
|
|
|
|
|
sn.keycode = key;
|
|
|
|
sn.eventType = evtype;
|
|
|
|
sn.requestMajor = sn.requestMinor = 0;
|
|
|
|
sn.changed = changed;
|
|
|
|
XkbSendStateNotify(dev, &sn);
|
|
|
|
}
|
|
|
|
xkbi->flags &= ~_XkbStateNotifyInProgress;
|
|
|
|
}
|
|
|
|
|
|
|
|
changed = XkbIndicatorsToUpdate(dev, changed, FALSE);
|
|
|
|
if (changed) {
|
|
|
|
XkbEventCauseRec cause;
|
|
|
|
XkbSetCauseKey(&cause, key, evtype);
|
|
|
|
XkbUpdateIndicators(dev, changed, FALSE, NULL, &cause);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-26 07:20:08 +01:00
|
|
|
void
|
|
|
|
XkbPushLockedStateToSlaves(DeviceIntPtr master, int evtype, int key)
|
|
|
|
{
|
|
|
|
DeviceIntPtr dev;
|
|
|
|
Bool genStateNotify;
|
|
|
|
|
|
|
|
nt_list_for_each_entry(dev, inputInfo.devices, next) {
|
|
|
|
if (!dev->key || GetMaster(dev, MASTER_KEYBOARD) != master)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
genStateNotify = _XkbEnsureStateChange(dev->key->xkbInfo);
|
|
|
|
|
|
|
|
dev->key->xkbInfo->state.locked_mods =
|
|
|
|
master->key->xkbInfo->state.locked_mods;
|
|
|
|
|
|
|
|
_XkbApplyState(dev, genStateNotify, evtype, key);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Rework symbol visibility for easier maintenance
Save in a few special cases, _X_EXPORT should not be used in C source
files. Instead, it should be used in headers, and the proper C source
include that header. Some special cases are symbols that need to be
shared between modules, but not expected to be used by external drivers,
and symbols that are accessible via LoaderSymbol/dlopen.
This patch also adds conditionally some new sdk header files, depending
on extensions enabled. These files were added to match pattern for
other extensions/modules, that is, have the headers "deciding" symbol
visibility in the sdk. These headers are:
o Xext/panoramiXsrv.h, Xext/panoramiX.h
o fbpict.h (unconditionally)
o vidmodeproc.h
o mioverlay.h (unconditionally, used only by xaa)
o xfixes.h (unconditionally, symbols required by dri2)
LoaderSymbol and similar functions now don't have different prototypes,
in loaderProcs.h and xf86Module.h, so that both headers can be included,
without the need of defining IN_LOADER.
xf86NewInputDevice() device prototype readded to xf86Xinput.h, but
not exported (and with a comment about it).
2008-12-03 08:43:34 +01:00
|
|
|
void
|
2012-03-21 20:55:09 +01:00
|
|
|
XkbHandleActions(DeviceIntPtr dev, DeviceIntPtr kbd, DeviceEvent *event)
|
2003-11-14 16:54:54 +01:00
|
|
|
{
|
2012-03-21 20:55:09 +01:00
|
|
|
int key, bit, i;
|
|
|
|
XkbSrvInfoPtr xkbi;
|
|
|
|
KeyClassPtr keyc;
|
2014-02-26 07:16:10 +01:00
|
|
|
int sendEvent;
|
2012-03-21 20:55:09 +01:00
|
|
|
Bool genStateNotify;
|
|
|
|
XkbAction act;
|
|
|
|
XkbFilterPtr filter;
|
|
|
|
Bool keyEvent;
|
|
|
|
Bool pressEvent;
|
|
|
|
ProcessInputProc backupproc;
|
|
|
|
|
|
|
|
xkbDeviceInfoPtr xkbPrivPtr = XKBDEVICEINFO(dev);
|
|
|
|
|
|
|
|
keyc = kbd->key;
|
|
|
|
xkbi = keyc->xkbInfo;
|
|
|
|
key = event->detail.key;
|
2014-02-26 07:03:19 +01:00
|
|
|
|
|
|
|
genStateNotify = _XkbEnsureStateChange(xkbi);
|
2003-11-14 16:54:54 +01:00
|
|
|
|
|
|
|
xkbi->clearMods = xkbi->setMods = 0;
|
|
|
|
xkbi->groupChange = 0;
|
|
|
|
|
|
|
|
sendEvent = 1;
|
2012-03-21 20:55:09 +01:00
|
|
|
keyEvent = ((event->type == ET_KeyPress) || (event->type == ET_KeyRelease));
|
|
|
|
pressEvent = ((event->type == ET_KeyPress) ||
|
|
|
|
(event->type == ET_ButtonPress));
|
2003-11-14 16:54:54 +01:00
|
|
|
|
|
|
|
if (pressEvent) {
|
2012-03-21 20:55:09 +01:00
|
|
|
if (keyEvent)
|
|
|
|
act = XkbGetKeyAction(xkbi, &xkbi->state, key);
|
|
|
|
else {
|
|
|
|
act = XkbGetButtonAction(kbd, dev, key);
|
|
|
|
key |= BTN_ACT_FLAG;
|
|
|
|
}
|
|
|
|
sendEvent = _XkbApplyFilters(xkbi, key, &act);
|
|
|
|
if (sendEvent) {
|
|
|
|
switch (act.type) {
|
|
|
|
case XkbSA_SetMods:
|
|
|
|
case XkbSA_SetGroup:
|
|
|
|
filter = _XkbNextFreeFilter(xkbi);
|
|
|
|
sendEvent = _XkbFilterSetState(xkbi, filter, key, &act);
|
|
|
|
break;
|
|
|
|
case XkbSA_LatchMods:
|
|
|
|
case XkbSA_LatchGroup:
|
|
|
|
filter = _XkbNextFreeFilter(xkbi);
|
|
|
|
sendEvent = _XkbFilterLatchState(xkbi, filter, key, &act);
|
|
|
|
break;
|
|
|
|
case XkbSA_LockMods:
|
|
|
|
case XkbSA_LockGroup:
|
|
|
|
filter = _XkbNextFreeFilter(xkbi);
|
|
|
|
sendEvent = _XkbFilterLockState(xkbi, filter, key, &act);
|
|
|
|
break;
|
|
|
|
case XkbSA_ISOLock:
|
|
|
|
filter = _XkbNextFreeFilter(xkbi);
|
|
|
|
sendEvent = _XkbFilterISOLock(xkbi, filter, key, &act);
|
|
|
|
break;
|
|
|
|
case XkbSA_MovePtr:
|
|
|
|
filter = _XkbNextFreeFilter(xkbi);
|
|
|
|
sendEvent = _XkbFilterPointerMove(xkbi, filter, key, &act);
|
|
|
|
break;
|
|
|
|
case XkbSA_PtrBtn:
|
|
|
|
case XkbSA_LockPtrBtn:
|
|
|
|
case XkbSA_SetPtrDflt:
|
|
|
|
filter = _XkbNextFreeFilter(xkbi);
|
|
|
|
sendEvent = _XkbFilterPointerBtn(xkbi, filter, key, &act);
|
|
|
|
break;
|
|
|
|
case XkbSA_Terminate:
|
|
|
|
sendEvent = XkbDDXTerminateServer(dev, key, &act);
|
|
|
|
break;
|
|
|
|
case XkbSA_SwitchScreen:
|
|
|
|
filter = _XkbNextFreeFilter(xkbi);
|
|
|
|
sendEvent = _XkbFilterSwitchScreen(xkbi, filter, key, &act);
|
|
|
|
break;
|
|
|
|
case XkbSA_SetControls:
|
|
|
|
case XkbSA_LockControls:
|
|
|
|
filter = _XkbNextFreeFilter(xkbi);
|
|
|
|
sendEvent = _XkbFilterControls(xkbi, filter, key, &act);
|
|
|
|
break;
|
|
|
|
case XkbSA_ActionMessage:
|
|
|
|
filter = _XkbNextFreeFilter(xkbi);
|
|
|
|
sendEvent = _XkbFilterActionMessage(xkbi, filter, key, &act);
|
|
|
|
break;
|
|
|
|
case XkbSA_RedirectKey:
|
|
|
|
filter = _XkbNextFreeFilter(xkbi);
|
2012-02-25 20:48:17 +01:00
|
|
|
/* redirect actions must create a new DeviceEvent. The
|
|
|
|
* source device id for this event cannot be obtained from
|
|
|
|
* xkbi, so we pass it here explicitly. The field deviceid
|
|
|
|
* equals to xkbi->device->id. */
|
|
|
|
filter->priv = event->sourceid;
|
2012-03-21 20:55:09 +01:00
|
|
|
sendEvent = _XkbFilterRedirectKey(xkbi, filter, key, &act);
|
|
|
|
break;
|
|
|
|
case XkbSA_DeviceBtn:
|
|
|
|
case XkbSA_LockDeviceBtn:
|
|
|
|
filter = _XkbNextFreeFilter(xkbi);
|
|
|
|
sendEvent = _XkbFilterDeviceBtn(xkbi, filter, key, &act);
|
|
|
|
break;
|
|
|
|
case XkbSA_XFree86Private:
|
|
|
|
filter = _XkbNextFreeFilter(xkbi);
|
|
|
|
sendEvent = _XkbFilterXF86Private(xkbi, filter, key, &act);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2003-11-14 16:54:54 +01:00
|
|
|
}
|
|
|
|
else {
|
2012-03-21 20:55:09 +01:00
|
|
|
if (!keyEvent)
|
|
|
|
key |= BTN_ACT_FLAG;
|
|
|
|
sendEvent = _XkbApplyFilters(xkbi, key, NULL);
|
2003-11-14 16:54:54 +01:00
|
|
|
}
|
|
|
|
|
2012-03-21 20:55:09 +01:00
|
|
|
if (xkbi->groupChange != 0)
|
|
|
|
xkbi->state.base_group += xkbi->groupChange;
|
2003-11-14 16:54:54 +01:00
|
|
|
if (xkbi->setMods) {
|
2012-03-21 20:55:09 +01:00
|
|
|
for (i = 0, bit = 1; xkbi->setMods; i++, bit <<= 1) {
|
|
|
|
if (xkbi->setMods & bit) {
|
|
|
|
keyc->modifierKeyCount[i]++;
|
|
|
|
xkbi->state.base_mods |= bit;
|
|
|
|
xkbi->setMods &= ~bit;
|
|
|
|
}
|
|
|
|
}
|
2003-11-14 16:54:54 +01:00
|
|
|
}
|
|
|
|
if (xkbi->clearMods) {
|
2012-03-21 20:55:09 +01:00
|
|
|
for (i = 0, bit = 1; xkbi->clearMods; i++, bit <<= 1) {
|
|
|
|
if (xkbi->clearMods & bit) {
|
|
|
|
keyc->modifierKeyCount[i]--;
|
|
|
|
if (keyc->modifierKeyCount[i] <= 0) {
|
|
|
|
xkbi->state.base_mods &= ~bit;
|
|
|
|
keyc->modifierKeyCount[i] = 0;
|
|
|
|
}
|
|
|
|
xkbi->clearMods &= ~bit;
|
|
|
|
}
|
|
|
|
}
|
2003-11-14 16:54:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (sendEvent) {
|
2007-09-27 04:14:03 +02:00
|
|
|
DeviceIntPtr tmpdev;
|
2012-03-21 20:55:09 +01:00
|
|
|
|
|
|
|
if (keyEvent)
|
2007-09-27 04:14:03 +02:00
|
|
|
tmpdev = dev;
|
2008-03-30 16:25:39 +02:00
|
|
|
else
|
2011-08-01 06:14:02 +02:00
|
|
|
tmpdev = GetMaster(dev, POINTER_OR_FLOAT);
|
2007-09-27 04:14:03 +02:00
|
|
|
|
2012-03-21 20:55:09 +01:00
|
|
|
UNWRAP_PROCESS_INPUT_PROC(tmpdev, xkbPrivPtr, backupproc);
|
|
|
|
dev->public.processInputProc((InternalEvent *) event, tmpdev);
|
2007-09-27 04:14:03 +02:00
|
|
|
COND_WRAP_PROCESS_INPUT_PROC(tmpdev, xkbPrivPtr,
|
2012-03-21 20:55:09 +01:00
|
|
|
backupproc, xkbUnwrapProc);
|
2003-11-14 16:54:54 +01:00
|
|
|
}
|
2007-10-27 20:31:39 +02:00
|
|
|
else if (keyEvent) {
|
2012-03-21 20:55:09 +01:00
|
|
|
FixKeyState(event, dev);
|
2007-10-27 20:31:39 +02:00
|
|
|
}
|
2003-11-14 17:49:22 +01:00
|
|
|
|
2014-02-26 07:16:10 +01:00
|
|
|
_XkbApplyState(dev, genStateNotify, event->type, key);
|
2014-02-26 07:20:08 +01:00
|
|
|
XkbPushLockedStateToSlaves(dev, event->type, key);
|
2003-11-14 16:54:54 +01:00
|
|
|
}
|
|
|
|
|
Rework symbol visibility for easier maintenance
Save in a few special cases, _X_EXPORT should not be used in C source
files. Instead, it should be used in headers, and the proper C source
include that header. Some special cases are symbols that need to be
shared between modules, but not expected to be used by external drivers,
and symbols that are accessible via LoaderSymbol/dlopen.
This patch also adds conditionally some new sdk header files, depending
on extensions enabled. These files were added to match pattern for
other extensions/modules, that is, have the headers "deciding" symbol
visibility in the sdk. These headers are:
o Xext/panoramiXsrv.h, Xext/panoramiX.h
o fbpict.h (unconditionally)
o vidmodeproc.h
o mioverlay.h (unconditionally, used only by xaa)
o xfixes.h (unconditionally, symbols required by dri2)
LoaderSymbol and similar functions now don't have different prototypes,
in loaderProcs.h and xf86Module.h, so that both headers can be included,
without the need of defining IN_LOADER.
xf86NewInputDevice() device prototype readded to xf86Xinput.h, but
not exported (and with a comment about it).
2008-12-03 08:43:34 +01:00
|
|
|
int
|
2012-03-21 20:55:09 +01:00
|
|
|
XkbLatchModifiers(DeviceIntPtr pXDev, CARD8 mask, CARD8 latches)
|
2003-11-14 16:54:54 +01:00
|
|
|
{
|
2012-03-21 20:55:09 +01:00
|
|
|
XkbSrvInfoPtr xkbi;
|
|
|
|
XkbFilterPtr filter;
|
|
|
|
XkbAction act;
|
|
|
|
unsigned clear;
|
|
|
|
|
|
|
|
if (pXDev && pXDev->key && pXDev->key->xkbInfo) {
|
|
|
|
xkbi = pXDev->key->xkbInfo;
|
|
|
|
clear = (mask & (~latches));
|
|
|
|
xkbi->state.latched_mods &= ~clear;
|
|
|
|
/* Clear any pending latch to locks.
|
|
|
|
*/
|
|
|
|
act.type = XkbSA_NoAction;
|
|
|
|
_XkbApplyFilters(xkbi, SYNTHETIC_KEYCODE, &act);
|
|
|
|
act.type = XkbSA_LatchMods;
|
|
|
|
act.mods.flags = 0;
|
|
|
|
act.mods.mask = mask & latches;
|
|
|
|
filter = _XkbNextFreeFilter(xkbi);
|
|
|
|
_XkbFilterLatchState(xkbi, filter, SYNTHETIC_KEYCODE, &act);
|
|
|
|
_XkbFilterLatchState(xkbi, filter, SYNTHETIC_KEYCODE,
|
|
|
|
(XkbAction *) NULL);
|
|
|
|
return Success;
|
2003-11-14 16:54:54 +01:00
|
|
|
}
|
|
|
|
return BadValue;
|
|
|
|
}
|
|
|
|
|
Rework symbol visibility for easier maintenance
Save in a few special cases, _X_EXPORT should not be used in C source
files. Instead, it should be used in headers, and the proper C source
include that header. Some special cases are symbols that need to be
shared between modules, but not expected to be used by external drivers,
and symbols that are accessible via LoaderSymbol/dlopen.
This patch also adds conditionally some new sdk header files, depending
on extensions enabled. These files were added to match pattern for
other extensions/modules, that is, have the headers "deciding" symbol
visibility in the sdk. These headers are:
o Xext/panoramiXsrv.h, Xext/panoramiX.h
o fbpict.h (unconditionally)
o vidmodeproc.h
o mioverlay.h (unconditionally, used only by xaa)
o xfixes.h (unconditionally, symbols required by dri2)
LoaderSymbol and similar functions now don't have different prototypes,
in loaderProcs.h and xf86Module.h, so that both headers can be included,
without the need of defining IN_LOADER.
xf86NewInputDevice() device prototype readded to xf86Xinput.h, but
not exported (and with a comment about it).
2008-12-03 08:43:34 +01:00
|
|
|
int
|
2012-03-21 20:55:09 +01:00
|
|
|
XkbLatchGroup(DeviceIntPtr pXDev, int group)
|
2003-11-14 16:54:54 +01:00
|
|
|
{
|
2012-03-21 20:55:09 +01:00
|
|
|
XkbSrvInfoPtr xkbi;
|
|
|
|
XkbFilterPtr filter;
|
|
|
|
XkbAction act;
|
|
|
|
|
|
|
|
if (pXDev && pXDev->key && pXDev->key->xkbInfo) {
|
|
|
|
xkbi = pXDev->key->xkbInfo;
|
|
|
|
act.type = XkbSA_LatchGroup;
|
|
|
|
act.group.flags = 0;
|
|
|
|
XkbSASetGroup(&act.group, group);
|
|
|
|
filter = _XkbNextFreeFilter(xkbi);
|
|
|
|
_XkbFilterLatchState(xkbi, filter, SYNTHETIC_KEYCODE, &act);
|
|
|
|
_XkbFilterLatchState(xkbi, filter, SYNTHETIC_KEYCODE,
|
|
|
|
(XkbAction *) NULL);
|
|
|
|
return Success;
|
2003-11-14 16:54:54 +01:00
|
|
|
}
|
|
|
|
return BadValue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/***====================================================================***/
|
|
|
|
|
Rework symbol visibility for easier maintenance
Save in a few special cases, _X_EXPORT should not be used in C source
files. Instead, it should be used in headers, and the proper C source
include that header. Some special cases are symbols that need to be
shared between modules, but not expected to be used by external drivers,
and symbols that are accessible via LoaderSymbol/dlopen.
This patch also adds conditionally some new sdk header files, depending
on extensions enabled. These files were added to match pattern for
other extensions/modules, that is, have the headers "deciding" symbol
visibility in the sdk. These headers are:
o Xext/panoramiXsrv.h, Xext/panoramiX.h
o fbpict.h (unconditionally)
o vidmodeproc.h
o mioverlay.h (unconditionally, used only by xaa)
o xfixes.h (unconditionally, symbols required by dri2)
LoaderSymbol and similar functions now don't have different prototypes,
in loaderProcs.h and xf86Module.h, so that both headers can be included,
without the need of defining IN_LOADER.
xf86NewInputDevice() device prototype readded to xf86Xinput.h, but
not exported (and with a comment about it).
2008-12-03 08:43:34 +01:00
|
|
|
void
|
2012-03-21 20:55:09 +01:00
|
|
|
XkbClearAllLatchesAndLocks(DeviceIntPtr dev,
|
|
|
|
XkbSrvInfoPtr xkbi,
|
|
|
|
Bool genEv, XkbEventCausePtr cause)
|
2003-11-14 16:54:54 +01:00
|
|
|
{
|
2012-03-21 20:55:09 +01:00
|
|
|
XkbStateRec os;
|
|
|
|
xkbStateNotify sn;
|
|
|
|
|
|
|
|
sn.changed = 0;
|
|
|
|
os = xkbi->state;
|
|
|
|
if (os.latched_mods) { /* clear all latches */
|
|
|
|
XkbLatchModifiers(dev, ~0, 0);
|
|
|
|
sn.changed |= XkbModifierLatchMask;
|
2003-11-14 16:54:54 +01:00
|
|
|
}
|
|
|
|
if (os.latched_group) {
|
2012-03-21 20:55:09 +01:00
|
|
|
XkbLatchGroup(dev, 0);
|
|
|
|
sn.changed |= XkbGroupLatchMask;
|
2003-11-14 16:54:54 +01:00
|
|
|
}
|
|
|
|
if (os.locked_mods) {
|
2012-03-21 20:55:09 +01:00
|
|
|
xkbi->state.locked_mods = 0;
|
|
|
|
sn.changed |= XkbModifierLockMask;
|
2003-11-14 16:54:54 +01:00
|
|
|
}
|
|
|
|
if (os.locked_group) {
|
2012-03-21 20:55:09 +01:00
|
|
|
xkbi->state.locked_group = 0;
|
|
|
|
sn.changed |= XkbGroupLockMask;
|
2003-11-14 16:54:54 +01:00
|
|
|
}
|
2012-03-21 20:55:09 +01:00
|
|
|
if (genEv && sn.changed) {
|
|
|
|
CARD32 changed;
|
|
|
|
|
|
|
|
XkbComputeDerivedState(xkbi);
|
|
|
|
sn.keycode = cause->kc;
|
|
|
|
sn.eventType = cause->event;
|
|
|
|
sn.requestMajor = cause->mjr;
|
|
|
|
sn.requestMinor = cause->mnr;
|
|
|
|
sn.changed = XkbStateChangedFlags(&os, &xkbi->state);
|
|
|
|
XkbSendStateNotify(dev, &sn);
|
|
|
|
changed = XkbIndicatorsToUpdate(dev, sn.changed, FALSE);
|
|
|
|
if (changed) {
|
|
|
|
XkbUpdateIndicators(dev, changed, TRUE, NULL, cause);
|
|
|
|
}
|
2003-11-14 16:54:54 +01:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
xkb: post-fix PointerKeys button events with a DeviceChangedEvent.
commit 14327858391ebe929b806efb53ad79e789361883
xkb: release XTEST pointer buttons on physical releases. (#28808)
revealed a bug with the XTEST/PointerKeys interaction.
Events resulting from PointerKeys are injected into the event processing
stream, not appended to the event queue. The events generated for the fake
button press include a DeviceChangedEvent (DCE), a raw button event and the
button event itself. The DCE causes the master to switch classes to the
attached XTEST pointer device.
Once the fake button is processed, normal event processing continues with
events in the EQ. The master still contains the XTEST classes, causing some
events to be dropped if e.g. the number of valuators of the event in the
queue exceeds the XTEST device's number of valuators.
Example: the EQ contains the following events, processed one-by-one, left to
right.
[DCE (dev)][Btn down][Btn up][Motion][Motion][...]
^ XkbFakeDeviceButton injects [DCE (XTEST)][Btn up]
Thus the event sequence processed looks like this:
[DCE (dev)][Btn down][Btn up][DCE (XTEST)][Btn up][Motion][Motion][...]
The first DCE causes the master to switch to the device. The button up event
injects a DCE to the XTEST device, causing the following Motion events to be
processed with the master still being on XTEST classes.
This patch post-fixes the injected event sequence with a DCE to restore the
classes of the original slave device, resulting in an event sequence like
this:
[DCE (dev)][Btn down][Btn up][DCE (XTEST)][Btn up][DCE (dev)][Motion][Motion]
Note that this is a simplified description. The event sequence injected by
the PointerKeys code is injected for the master device only and the matching
slave device that caused the injection has already finished processing on
the slave. Furthermore, the injection happens as part of the the XKB layer,
before the unwrapping of the processInputProc takes us into the DIX where
the DCE is actually handled.
Bug reproducible with a device that reports more than 2 valuators. Simply
cause button releases on the device and wait for a "too many valuators"
warning message.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Acked-by: Daniel Stone <daniel@fooishbar.org>
Reviewed-by: Keith Packard <keithp@keithp.com>
2010-07-23 03:46:30 +02:00
|
|
|
/*
|
|
|
|
* The event is injected into the event processing, not the EQ. Thus,
|
|
|
|
* ensure that we restore the master after the event sequence to the
|
|
|
|
* original set of classes. Otherwise, the master remains on the XTEST
|
|
|
|
* classes and drops events that don't fit into the XTEST layout (e.g.
|
|
|
|
* events with more than 2 valuators).
|
|
|
|
*
|
|
|
|
* FIXME: EQ injection in the processing stage is not designed for, so this
|
|
|
|
* is a rather awkward hack. The event list returned by GetPointerEvents()
|
|
|
|
* and friends is always prefixed with a DCE if the last _posted_ device was
|
|
|
|
* different. For normal events, this sequence then resets the master during
|
|
|
|
* the processing stage. Since we inject the PointerKey events in the
|
|
|
|
* processing stage though, we need to manually reset to restore the
|
|
|
|
* previous order, because the events already in the EQ must be sent for the
|
|
|
|
* right device.
|
|
|
|
* So we post-fix the event list we get from GPE with a DCE back to the
|
|
|
|
* previous slave device.
|
|
|
|
*
|
|
|
|
* First one on drinking island wins!
|
|
|
|
*/
|
2010-04-14 02:54:29 +02:00
|
|
|
static void
|
2012-03-21 20:55:09 +01:00
|
|
|
InjectPointerKeyEvents(DeviceIntPtr dev, int type, int button, int flags,
|
|
|
|
ValuatorMask *mask)
|
2010-04-14 02:54:29 +02:00
|
|
|
{
|
2012-03-21 20:55:09 +01:00
|
|
|
ScreenPtr pScreen;
|
|
|
|
InternalEvent *events;
|
|
|
|
int nevents, i;
|
|
|
|
DeviceIntPtr ptr, mpointer, lastSlave = NULL;
|
|
|
|
Bool saveWait;
|
2010-04-14 02:54:29 +02:00
|
|
|
|
xkb: post-fix PointerKeys button events with a DeviceChangedEvent.
commit 14327858391ebe929b806efb53ad79e789361883
xkb: release XTEST pointer buttons on physical releases. (#28808)
revealed a bug with the XTEST/PointerKeys interaction.
Events resulting from PointerKeys are injected into the event processing
stream, not appended to the event queue. The events generated for the fake
button press include a DeviceChangedEvent (DCE), a raw button event and the
button event itself. The DCE causes the master to switch classes to the
attached XTEST pointer device.
Once the fake button is processed, normal event processing continues with
events in the EQ. The master still contains the XTEST classes, causing some
events to be dropped if e.g. the number of valuators of the event in the
queue exceeds the XTEST device's number of valuators.
Example: the EQ contains the following events, processed one-by-one, left to
right.
[DCE (dev)][Btn down][Btn up][Motion][Motion][...]
^ XkbFakeDeviceButton injects [DCE (XTEST)][Btn up]
Thus the event sequence processed looks like this:
[DCE (dev)][Btn down][Btn up][DCE (XTEST)][Btn up][Motion][Motion][...]
The first DCE causes the master to switch to the device. The button up event
injects a DCE to the XTEST device, causing the following Motion events to be
processed with the master still being on XTEST classes.
This patch post-fixes the injected event sequence with a DCE to restore the
classes of the original slave device, resulting in an event sequence like
this:
[DCE (dev)][Btn down][Btn up][DCE (XTEST)][Btn up][DCE (dev)][Motion][Motion]
Note that this is a simplified description. The event sequence injected by
the PointerKeys code is injected for the master device only and the matching
slave device that caused the injection has already finished processing on
the slave. Furthermore, the injection happens as part of the the XKB layer,
before the unwrapping of the processInputProc takes us into the DIX where
the DCE is actually handled.
Bug reproducible with a device that reports more than 2 valuators. Simply
cause button releases on the device and wait for a "too many valuators"
warning message.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Acked-by: Daniel Stone <daniel@fooishbar.org>
Reviewed-by: Keith Packard <keithp@keithp.com>
2010-07-23 03:46:30 +02:00
|
|
|
if (IsMaster(dev)) {
|
|
|
|
mpointer = GetMaster(dev, MASTER_POINTER);
|
2011-02-18 03:28:43 +01:00
|
|
|
lastSlave = mpointer->lastSlave;
|
xkb: post-fix PointerKeys button events with a DeviceChangedEvent.
commit 14327858391ebe929b806efb53ad79e789361883
xkb: release XTEST pointer buttons on physical releases. (#28808)
revealed a bug with the XTEST/PointerKeys interaction.
Events resulting from PointerKeys are injected into the event processing
stream, not appended to the event queue. The events generated for the fake
button press include a DeviceChangedEvent (DCE), a raw button event and the
button event itself. The DCE causes the master to switch classes to the
attached XTEST pointer device.
Once the fake button is processed, normal event processing continues with
events in the EQ. The master still contains the XTEST classes, causing some
events to be dropped if e.g. the number of valuators of the event in the
queue exceeds the XTEST device's number of valuators.
Example: the EQ contains the following events, processed one-by-one, left to
right.
[DCE (dev)][Btn down][Btn up][Motion][Motion][...]
^ XkbFakeDeviceButton injects [DCE (XTEST)][Btn up]
Thus the event sequence processed looks like this:
[DCE (dev)][Btn down][Btn up][DCE (XTEST)][Btn up][Motion][Motion][...]
The first DCE causes the master to switch to the device. The button up event
injects a DCE to the XTEST device, causing the following Motion events to be
processed with the master still being on XTEST classes.
This patch post-fixes the injected event sequence with a DCE to restore the
classes of the original slave device, resulting in an event sequence like
this:
[DCE (dev)][Btn down][Btn up][DCE (XTEST)][Btn up][DCE (dev)][Motion][Motion]
Note that this is a simplified description. The event sequence injected by
the PointerKeys code is injected for the master device only and the matching
slave device that caused the injection has already finished processing on
the slave. Furthermore, the injection happens as part of the the XKB layer,
before the unwrapping of the processInputProc takes us into the DIX where
the DCE is actually handled.
Bug reproducible with a device that reports more than 2 valuators. Simply
cause button releases on the device and wait for a "too many valuators"
warning message.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Acked-by: Daniel Stone <daniel@fooishbar.org>
Reviewed-by: Keith Packard <keithp@keithp.com>
2010-07-23 03:46:30 +02:00
|
|
|
ptr = GetXTestDevice(mpointer);
|
2012-03-21 20:55:09 +01:00
|
|
|
}
|
|
|
|
else if (IsFloating(dev))
|
2010-04-14 02:54:29 +02:00
|
|
|
ptr = dev;
|
|
|
|
else
|
2010-06-29 07:24:51 +02:00
|
|
|
return;
|
2010-04-14 02:54:29 +02:00
|
|
|
|
xkb: post-fix PointerKeys button events with a DeviceChangedEvent.
commit 14327858391ebe929b806efb53ad79e789361883
xkb: release XTEST pointer buttons on physical releases. (#28808)
revealed a bug with the XTEST/PointerKeys interaction.
Events resulting from PointerKeys are injected into the event processing
stream, not appended to the event queue. The events generated for the fake
button press include a DeviceChangedEvent (DCE), a raw button event and the
button event itself. The DCE causes the master to switch classes to the
attached XTEST pointer device.
Once the fake button is processed, normal event processing continues with
events in the EQ. The master still contains the XTEST classes, causing some
events to be dropped if e.g. the number of valuators of the event in the
queue exceeds the XTEST device's number of valuators.
Example: the EQ contains the following events, processed one-by-one, left to
right.
[DCE (dev)][Btn down][Btn up][Motion][Motion][...]
^ XkbFakeDeviceButton injects [DCE (XTEST)][Btn up]
Thus the event sequence processed looks like this:
[DCE (dev)][Btn down][Btn up][DCE (XTEST)][Btn up][Motion][Motion][...]
The first DCE causes the master to switch to the device. The button up event
injects a DCE to the XTEST device, causing the following Motion events to be
processed with the master still being on XTEST classes.
This patch post-fixes the injected event sequence with a DCE to restore the
classes of the original slave device, resulting in an event sequence like
this:
[DCE (dev)][Btn down][Btn up][DCE (XTEST)][Btn up][DCE (dev)][Motion][Motion]
Note that this is a simplified description. The event sequence injected by
the PointerKeys code is injected for the master device only and the matching
slave device that caused the injection has already finished processing on
the slave. Furthermore, the injection happens as part of the the XKB layer,
before the unwrapping of the processInputProc takes us into the DIX where
the DCE is actually handled.
Bug reproducible with a device that reports more than 2 valuators. Simply
cause button releases on the device and wait for a "too many valuators"
warning message.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Acked-by: Daniel Stone <daniel@fooishbar.org>
Reviewed-by: Keith Packard <keithp@keithp.com>
2010-07-23 03:46:30 +02:00
|
|
|
events = InitEventList(GetMaximumEventsNum() + 1);
|
2010-04-14 02:54:29 +02:00
|
|
|
OsBlockSignals();
|
2010-06-04 04:00:54 +02:00
|
|
|
pScreen = miPointerGetScreen(ptr);
|
|
|
|
saveWait = miPointerSetWaitForUpdate(pScreen, FALSE);
|
2010-10-19 05:37:46 +02:00
|
|
|
nevents = GetPointerEvents(events, ptr, type, button, flags, mask);
|
xkb: post-fix PointerKeys button events with a DeviceChangedEvent.
commit 14327858391ebe929b806efb53ad79e789361883
xkb: release XTEST pointer buttons on physical releases. (#28808)
revealed a bug with the XTEST/PointerKeys interaction.
Events resulting from PointerKeys are injected into the event processing
stream, not appended to the event queue. The events generated for the fake
button press include a DeviceChangedEvent (DCE), a raw button event and the
button event itself. The DCE causes the master to switch classes to the
attached XTEST pointer device.
Once the fake button is processed, normal event processing continues with
events in the EQ. The master still contains the XTEST classes, causing some
events to be dropped if e.g. the number of valuators of the event in the
queue exceeds the XTEST device's number of valuators.
Example: the EQ contains the following events, processed one-by-one, left to
right.
[DCE (dev)][Btn down][Btn up][Motion][Motion][...]
^ XkbFakeDeviceButton injects [DCE (XTEST)][Btn up]
Thus the event sequence processed looks like this:
[DCE (dev)][Btn down][Btn up][DCE (XTEST)][Btn up][Motion][Motion][...]
The first DCE causes the master to switch to the device. The button up event
injects a DCE to the XTEST device, causing the following Motion events to be
processed with the master still being on XTEST classes.
This patch post-fixes the injected event sequence with a DCE to restore the
classes of the original slave device, resulting in an event sequence like
this:
[DCE (dev)][Btn down][Btn up][DCE (XTEST)][Btn up][DCE (dev)][Motion][Motion]
Note that this is a simplified description. The event sequence injected by
the PointerKeys code is injected for the master device only and the matching
slave device that caused the injection has already finished processing on
the slave. Furthermore, the injection happens as part of the the XKB layer,
before the unwrapping of the processInputProc takes us into the DIX where
the DCE is actually handled.
Bug reproducible with a device that reports more than 2 valuators. Simply
cause button releases on the device and wait for a "too many valuators"
warning message.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Acked-by: Daniel Stone <daniel@fooishbar.org>
Reviewed-by: Keith Packard <keithp@keithp.com>
2010-07-23 03:46:30 +02:00
|
|
|
if (IsMaster(dev) && (lastSlave && lastSlave != ptr))
|
2012-03-21 20:55:09 +01:00
|
|
|
UpdateFromMaster(&events[nevents], lastSlave, DEVCHANGE_POINTER_EVENT,
|
|
|
|
&nevents);
|
2010-06-04 04:00:54 +02:00
|
|
|
miPointerSetWaitForUpdate(pScreen, saveWait);
|
2010-04-14 02:54:29 +02:00
|
|
|
OsReleaseSignals();
|
|
|
|
|
|
|
|
for (i = 0; i < nevents; i++)
|
2011-04-14 14:05:41 +02:00
|
|
|
mieqProcessDeviceEvent(ptr, &events[i], NULL);
|
2010-04-14 02:54:29 +02:00
|
|
|
|
|
|
|
FreeEventList(events, GetMaximumEventsNum());
|
xkb: post-fix PointerKeys button events with a DeviceChangedEvent.
commit 14327858391ebe929b806efb53ad79e789361883
xkb: release XTEST pointer buttons on physical releases. (#28808)
revealed a bug with the XTEST/PointerKeys interaction.
Events resulting from PointerKeys are injected into the event processing
stream, not appended to the event queue. The events generated for the fake
button press include a DeviceChangedEvent (DCE), a raw button event and the
button event itself. The DCE causes the master to switch classes to the
attached XTEST pointer device.
Once the fake button is processed, normal event processing continues with
events in the EQ. The master still contains the XTEST classes, causing some
events to be dropped if e.g. the number of valuators of the event in the
queue exceeds the XTEST device's number of valuators.
Example: the EQ contains the following events, processed one-by-one, left to
right.
[DCE (dev)][Btn down][Btn up][Motion][Motion][...]
^ XkbFakeDeviceButton injects [DCE (XTEST)][Btn up]
Thus the event sequence processed looks like this:
[DCE (dev)][Btn down][Btn up][DCE (XTEST)][Btn up][Motion][Motion][...]
The first DCE causes the master to switch to the device. The button up event
injects a DCE to the XTEST device, causing the following Motion events to be
processed with the master still being on XTEST classes.
This patch post-fixes the injected event sequence with a DCE to restore the
classes of the original slave device, resulting in an event sequence like
this:
[DCE (dev)][Btn down][Btn up][DCE (XTEST)][Btn up][DCE (dev)][Motion][Motion]
Note that this is a simplified description. The event sequence injected by
the PointerKeys code is injected for the master device only and the matching
slave device that caused the injection has already finished processing on
the slave. Furthermore, the injection happens as part of the the XKB layer,
before the unwrapping of the processInputProc takes us into the DIX where
the DCE is actually handled.
Bug reproducible with a device that reports more than 2 valuators. Simply
cause button releases on the device and wait for a "too many valuators"
warning message.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Acked-by: Daniel Stone <daniel@fooishbar.org>
Reviewed-by: Keith Packard <keithp@keithp.com>
2010-07-23 03:46:30 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2012-03-21 20:55:09 +01:00
|
|
|
XkbFakePointerMotion(DeviceIntPtr dev, unsigned flags, int x, int y)
|
xkb: post-fix PointerKeys button events with a DeviceChangedEvent.
commit 14327858391ebe929b806efb53ad79e789361883
xkb: release XTEST pointer buttons on physical releases. (#28808)
revealed a bug with the XTEST/PointerKeys interaction.
Events resulting from PointerKeys are injected into the event processing
stream, not appended to the event queue. The events generated for the fake
button press include a DeviceChangedEvent (DCE), a raw button event and the
button event itself. The DCE causes the master to switch classes to the
attached XTEST pointer device.
Once the fake button is processed, normal event processing continues with
events in the EQ. The master still contains the XTEST classes, causing some
events to be dropped if e.g. the number of valuators of the event in the
queue exceeds the XTEST device's number of valuators.
Example: the EQ contains the following events, processed one-by-one, left to
right.
[DCE (dev)][Btn down][Btn up][Motion][Motion][...]
^ XkbFakeDeviceButton injects [DCE (XTEST)][Btn up]
Thus the event sequence processed looks like this:
[DCE (dev)][Btn down][Btn up][DCE (XTEST)][Btn up][Motion][Motion][...]
The first DCE causes the master to switch to the device. The button up event
injects a DCE to the XTEST device, causing the following Motion events to be
processed with the master still being on XTEST classes.
This patch post-fixes the injected event sequence with a DCE to restore the
classes of the original slave device, resulting in an event sequence like
this:
[DCE (dev)][Btn down][Btn up][DCE (XTEST)][Btn up][DCE (dev)][Motion][Motion]
Note that this is a simplified description. The event sequence injected by
the PointerKeys code is injected for the master device only and the matching
slave device that caused the injection has already finished processing on
the slave. Furthermore, the injection happens as part of the the XKB layer,
before the unwrapping of the processInputProc takes us into the DIX where
the DCE is actually handled.
Bug reproducible with a device that reports more than 2 valuators. Simply
cause button releases on the device and wait for a "too many valuators"
warning message.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Acked-by: Daniel Stone <daniel@fooishbar.org>
Reviewed-by: Keith Packard <keithp@keithp.com>
2010-07-23 03:46:30 +02:00
|
|
|
{
|
2012-03-21 20:55:09 +01:00
|
|
|
ValuatorMask mask;
|
|
|
|
int gpe_flags = 0;
|
xkb: post-fix PointerKeys button events with a DeviceChangedEvent.
commit 14327858391ebe929b806efb53ad79e789361883
xkb: release XTEST pointer buttons on physical releases. (#28808)
revealed a bug with the XTEST/PointerKeys interaction.
Events resulting from PointerKeys are injected into the event processing
stream, not appended to the event queue. The events generated for the fake
button press include a DeviceChangedEvent (DCE), a raw button event and the
button event itself. The DCE causes the master to switch classes to the
attached XTEST pointer device.
Once the fake button is processed, normal event processing continues with
events in the EQ. The master still contains the XTEST classes, causing some
events to be dropped if e.g. the number of valuators of the event in the
queue exceeds the XTEST device's number of valuators.
Example: the EQ contains the following events, processed one-by-one, left to
right.
[DCE (dev)][Btn down][Btn up][Motion][Motion][...]
^ XkbFakeDeviceButton injects [DCE (XTEST)][Btn up]
Thus the event sequence processed looks like this:
[DCE (dev)][Btn down][Btn up][DCE (XTEST)][Btn up][Motion][Motion][...]
The first DCE causes the master to switch to the device. The button up event
injects a DCE to the XTEST device, causing the following Motion events to be
processed with the master still being on XTEST classes.
This patch post-fixes the injected event sequence with a DCE to restore the
classes of the original slave device, resulting in an event sequence like
this:
[DCE (dev)][Btn down][Btn up][DCE (XTEST)][Btn up][DCE (dev)][Motion][Motion]
Note that this is a simplified description. The event sequence injected by
the PointerKeys code is injected for the master device only and the matching
slave device that caused the injection has already finished processing on
the slave. Furthermore, the injection happens as part of the the XKB layer,
before the unwrapping of the processInputProc takes us into the DIX where
the DCE is actually handled.
Bug reproducible with a device that reports more than 2 valuators. Simply
cause button releases on the device and wait for a "too many valuators"
warning message.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Acked-by: Daniel Stone <daniel@fooishbar.org>
Reviewed-by: Keith Packard <keithp@keithp.com>
2010-07-23 03:46:30 +02:00
|
|
|
|
|
|
|
/* ignore attached SDs */
|
2011-02-11 03:47:37 +01:00
|
|
|
if (!IsMaster(dev) && !IsFloating(dev))
|
xkb: post-fix PointerKeys button events with a DeviceChangedEvent.
commit 14327858391ebe929b806efb53ad79e789361883
xkb: release XTEST pointer buttons on physical releases. (#28808)
revealed a bug with the XTEST/PointerKeys interaction.
Events resulting from PointerKeys are injected into the event processing
stream, not appended to the event queue. The events generated for the fake
button press include a DeviceChangedEvent (DCE), a raw button event and the
button event itself. The DCE causes the master to switch classes to the
attached XTEST pointer device.
Once the fake button is processed, normal event processing continues with
events in the EQ. The master still contains the XTEST classes, causing some
events to be dropped if e.g. the number of valuators of the event in the
queue exceeds the XTEST device's number of valuators.
Example: the EQ contains the following events, processed one-by-one, left to
right.
[DCE (dev)][Btn down][Btn up][Motion][Motion][...]
^ XkbFakeDeviceButton injects [DCE (XTEST)][Btn up]
Thus the event sequence processed looks like this:
[DCE (dev)][Btn down][Btn up][DCE (XTEST)][Btn up][Motion][Motion][...]
The first DCE causes the master to switch to the device. The button up event
injects a DCE to the XTEST device, causing the following Motion events to be
processed with the master still being on XTEST classes.
This patch post-fixes the injected event sequence with a DCE to restore the
classes of the original slave device, resulting in an event sequence like
this:
[DCE (dev)][Btn down][Btn up][DCE (XTEST)][Btn up][DCE (dev)][Motion][Motion]
Note that this is a simplified description. The event sequence injected by
the PointerKeys code is injected for the master device only and the matching
slave device that caused the injection has already finished processing on
the slave. Furthermore, the injection happens as part of the the XKB layer,
before the unwrapping of the processInputProc takes us into the DIX where
the DCE is actually handled.
Bug reproducible with a device that reports more than 2 valuators. Simply
cause button releases on the device and wait for a "too many valuators"
warning message.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Acked-by: Daniel Stone <daniel@fooishbar.org>
Reviewed-by: Keith Packard <keithp@keithp.com>
2010-07-23 03:46:30 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
if (flags & XkbSA_MoveAbsoluteX || flags & XkbSA_MoveAbsoluteY)
|
|
|
|
gpe_flags = POINTER_ABSOLUTE;
|
|
|
|
else
|
|
|
|
gpe_flags = POINTER_RELATIVE;
|
|
|
|
|
2012-03-21 20:55:09 +01:00
|
|
|
valuator_mask_set_range(&mask, 0, 2, (int[]) {
|
|
|
|
x, y});
|
2010-10-19 05:37:46 +02:00
|
|
|
|
|
|
|
InjectPointerKeyEvents(dev, MotionNotify, 0, gpe_flags, &mask);
|
2010-04-14 02:54:29 +02:00
|
|
|
}
|
|
|
|
|
2010-07-01 04:44:57 +02:00
|
|
|
void
|
2012-03-21 20:55:09 +01:00
|
|
|
XkbFakeDeviceButton(DeviceIntPtr dev, Bool press, int button)
|
2010-04-14 02:54:29 +02:00
|
|
|
{
|
2012-03-21 20:55:09 +01:00
|
|
|
DeviceIntPtr ptr;
|
|
|
|
int down;
|
2010-04-14 02:54:29 +02:00
|
|
|
|
|
|
|
/* If dev is a slave device, and the SD is attached, do nothing. If we'd
|
|
|
|
* post through the attached master pointer we'd get duplicate events.
|
|
|
|
*
|
|
|
|
* if dev is a master keyboard, post through the XTEST device
|
|
|
|
*
|
|
|
|
* if dev is a floating slave, post through the device itself.
|
|
|
|
*/
|
|
|
|
|
xkb: post-fix PointerKeys button events with a DeviceChangedEvent.
commit 14327858391ebe929b806efb53ad79e789361883
xkb: release XTEST pointer buttons on physical releases. (#28808)
revealed a bug with the XTEST/PointerKeys interaction.
Events resulting from PointerKeys are injected into the event processing
stream, not appended to the event queue. The events generated for the fake
button press include a DeviceChangedEvent (DCE), a raw button event and the
button event itself. The DCE causes the master to switch classes to the
attached XTEST pointer device.
Once the fake button is processed, normal event processing continues with
events in the EQ. The master still contains the XTEST classes, causing some
events to be dropped if e.g. the number of valuators of the event in the
queue exceeds the XTEST device's number of valuators.
Example: the EQ contains the following events, processed one-by-one, left to
right.
[DCE (dev)][Btn down][Btn up][Motion][Motion][...]
^ XkbFakeDeviceButton injects [DCE (XTEST)][Btn up]
Thus the event sequence processed looks like this:
[DCE (dev)][Btn down][Btn up][DCE (XTEST)][Btn up][Motion][Motion][...]
The first DCE causes the master to switch to the device. The button up event
injects a DCE to the XTEST device, causing the following Motion events to be
processed with the master still being on XTEST classes.
This patch post-fixes the injected event sequence with a DCE to restore the
classes of the original slave device, resulting in an event sequence like
this:
[DCE (dev)][Btn down][Btn up][DCE (XTEST)][Btn up][DCE (dev)][Motion][Motion]
Note that this is a simplified description. The event sequence injected by
the PointerKeys code is injected for the master device only and the matching
slave device that caused the injection has already finished processing on
the slave. Furthermore, the injection happens as part of the the XKB layer,
before the unwrapping of the processInputProc takes us into the DIX where
the DCE is actually handled.
Bug reproducible with a device that reports more than 2 valuators. Simply
cause button releases on the device and wait for a "too many valuators"
warning message.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Acked-by: Daniel Stone <daniel@fooishbar.org>
Reviewed-by: Keith Packard <keithp@keithp.com>
2010-07-23 03:46:30 +02:00
|
|
|
if (IsMaster(dev)) {
|
|
|
|
DeviceIntPtr mpointer = GetMaster(dev, MASTER_POINTER);
|
2012-03-21 20:55:09 +01:00
|
|
|
|
xkb: post-fix PointerKeys button events with a DeviceChangedEvent.
commit 14327858391ebe929b806efb53ad79e789361883
xkb: release XTEST pointer buttons on physical releases. (#28808)
revealed a bug with the XTEST/PointerKeys interaction.
Events resulting from PointerKeys are injected into the event processing
stream, not appended to the event queue. The events generated for the fake
button press include a DeviceChangedEvent (DCE), a raw button event and the
button event itself. The DCE causes the master to switch classes to the
attached XTEST pointer device.
Once the fake button is processed, normal event processing continues with
events in the EQ. The master still contains the XTEST classes, causing some
events to be dropped if e.g. the number of valuators of the event in the
queue exceeds the XTEST device's number of valuators.
Example: the EQ contains the following events, processed one-by-one, left to
right.
[DCE (dev)][Btn down][Btn up][Motion][Motion][...]
^ XkbFakeDeviceButton injects [DCE (XTEST)][Btn up]
Thus the event sequence processed looks like this:
[DCE (dev)][Btn down][Btn up][DCE (XTEST)][Btn up][Motion][Motion][...]
The first DCE causes the master to switch to the device. The button up event
injects a DCE to the XTEST device, causing the following Motion events to be
processed with the master still being on XTEST classes.
This patch post-fixes the injected event sequence with a DCE to restore the
classes of the original slave device, resulting in an event sequence like
this:
[DCE (dev)][Btn down][Btn up][DCE (XTEST)][Btn up][DCE (dev)][Motion][Motion]
Note that this is a simplified description. The event sequence injected by
the PointerKeys code is injected for the master device only and the matching
slave device that caused the injection has already finished processing on
the slave. Furthermore, the injection happens as part of the the XKB layer,
before the unwrapping of the processInputProc takes us into the DIX where
the DCE is actually handled.
Bug reproducible with a device that reports more than 2 valuators. Simply
cause button releases on the device and wait for a "too many valuators"
warning message.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Acked-by: Daniel Stone <daniel@fooishbar.org>
Reviewed-by: Keith Packard <keithp@keithp.com>
2010-07-23 03:46:30 +02:00
|
|
|
ptr = GetXTestDevice(mpointer);
|
2012-03-21 20:55:09 +01:00
|
|
|
}
|
|
|
|
else if (IsFloating(dev))
|
2010-04-14 02:54:29 +02:00
|
|
|
ptr = dev;
|
|
|
|
else
|
|
|
|
return;
|
|
|
|
|
2010-07-23 05:24:34 +02:00
|
|
|
down = button_is_down(ptr, button, BUTTON_PROCESSED);
|
|
|
|
if (press == down)
|
|
|
|
return;
|
|
|
|
|
xkb: post-fix PointerKeys button events with a DeviceChangedEvent.
commit 14327858391ebe929b806efb53ad79e789361883
xkb: release XTEST pointer buttons on physical releases. (#28808)
revealed a bug with the XTEST/PointerKeys interaction.
Events resulting from PointerKeys are injected into the event processing
stream, not appended to the event queue. The events generated for the fake
button press include a DeviceChangedEvent (DCE), a raw button event and the
button event itself. The DCE causes the master to switch classes to the
attached XTEST pointer device.
Once the fake button is processed, normal event processing continues with
events in the EQ. The master still contains the XTEST classes, causing some
events to be dropped if e.g. the number of valuators of the event in the
queue exceeds the XTEST device's number of valuators.
Example: the EQ contains the following events, processed one-by-one, left to
right.
[DCE (dev)][Btn down][Btn up][Motion][Motion][...]
^ XkbFakeDeviceButton injects [DCE (XTEST)][Btn up]
Thus the event sequence processed looks like this:
[DCE (dev)][Btn down][Btn up][DCE (XTEST)][Btn up][Motion][Motion][...]
The first DCE causes the master to switch to the device. The button up event
injects a DCE to the XTEST device, causing the following Motion events to be
processed with the master still being on XTEST classes.
This patch post-fixes the injected event sequence with a DCE to restore the
classes of the original slave device, resulting in an event sequence like
this:
[DCE (dev)][Btn down][Btn up][DCE (XTEST)][Btn up][DCE (dev)][Motion][Motion]
Note that this is a simplified description. The event sequence injected by
the PointerKeys code is injected for the master device only and the matching
slave device that caused the injection has already finished processing on
the slave. Furthermore, the injection happens as part of the the XKB layer,
before the unwrapping of the processInputProc takes us into the DIX where
the DCE is actually handled.
Bug reproducible with a device that reports more than 2 valuators. Simply
cause button releases on the device and wait for a "too many valuators"
warning message.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Acked-by: Daniel Stone <daniel@fooishbar.org>
Reviewed-by: Keith Packard <keithp@keithp.com>
2010-07-23 03:46:30 +02:00
|
|
|
InjectPointerKeyEvents(dev, press ? ButtonPress : ButtonRelease,
|
2010-10-19 05:37:46 +02:00
|
|
|
button, 0, NULL);
|
2010-04-14 02:54:29 +02:00
|
|
|
}
|