6e1bcfb3c6
tested by krw@ and dcoppa@ ok dcoppa@
1085 lines
36 KiB
C
1085 lines
36 KiB
C
/************************************************************
|
|
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.
|
|
|
|
********************************************************/
|
|
|
|
#ifdef HAVE_DIX_CONFIG_H
|
|
#include <dix-config.h>
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
#include <X11/X.h>
|
|
#include <X11/Xproto.h>
|
|
#include <X11/keysym.h>
|
|
#include <X11/extensions/XI.h>
|
|
#include <X11/extensions/XIproto.h>
|
|
#include "inputstr.h"
|
|
#include "exevents.h"
|
|
#include "exglobals.h"
|
|
#include "windowstr.h"
|
|
#include <xkbsrv.h>
|
|
#include "xkb.h"
|
|
|
|
/***====================================================================***/
|
|
|
|
/*
|
|
* This function sends out two kinds of notification:
|
|
* - Core mapping notify events sent to clients for whom kbd is the
|
|
* current core ('picked') keyboard _and_ have not explicitly
|
|
* selected for XKB mapping notify events;
|
|
* - Xi mapping events, sent unconditionally to all clients who have
|
|
* explicitly selected for them (including those who have explicitly
|
|
* selected for XKB mapping notify events!).
|
|
*/
|
|
static void
|
|
XkbSendLegacyMapNotify(DeviceIntPtr kbd, CARD16 xkb_event, CARD16 changed,
|
|
int first_key, int num_keys)
|
|
{
|
|
int i;
|
|
int keymap_changed = 0;
|
|
int modmap_changed = 0;
|
|
CARD32 time = GetTimeInMillis();
|
|
|
|
if (xkb_event == XkbNewKeyboardNotify) {
|
|
if (changed & XkbNKN_KeycodesMask) {
|
|
keymap_changed = 1;
|
|
modmap_changed = 1;
|
|
}
|
|
}
|
|
else if (xkb_event == XkbMapNotify) {
|
|
if (changed & XkbKeySymsMask)
|
|
keymap_changed = 1;
|
|
if (changed & XkbModifierMapMask)
|
|
modmap_changed = 1;
|
|
}
|
|
if (!keymap_changed && !modmap_changed)
|
|
return;
|
|
|
|
/* 0 is serverClient. */
|
|
for (i = 1; i < currentMaxClients; i++) {
|
|
if (!clients[i] || clients[i]->clientState != ClientStateRunning)
|
|
continue;
|
|
|
|
/* XKB allows clients to restrict the MappingNotify events sent to
|
|
* them. This was broken for three years. Sorry. */
|
|
if (xkb_event == XkbMapNotify &&
|
|
(clients[i]->xkbClientFlags & _XkbClientInitialized) &&
|
|
!(clients[i]->mapNotifyMask & changed))
|
|
continue;
|
|
/* Emulate previous server behaviour: any client which has activated
|
|
* XKB will not receive core events emulated from a NewKeyboardNotify
|
|
* at all. */
|
|
if (xkb_event == XkbNewKeyboardNotify &&
|
|
(clients[i]->xkbClientFlags & _XkbClientInitialized))
|
|
continue;
|
|
|
|
/* Don't send core events to clients who don't know about us. */
|
|
if (!XIShouldNotify(clients[i], kbd))
|
|
continue;
|
|
|
|
if (keymap_changed) {
|
|
xEvent core_mn = { .u.u.type = MappingNotify };
|
|
core_mn.u.mappingNotify.request = MappingKeyboard;
|
|
|
|
/* Clip the keycode range to what the client knows about, so it
|
|
* doesn't freak out. */
|
|
if (first_key >= clients[i]->minKC)
|
|
core_mn.u.mappingNotify.firstKeyCode = first_key;
|
|
else
|
|
core_mn.u.mappingNotify.firstKeyCode = clients[i]->minKC;
|
|
if (first_key + num_keys - 1 <= clients[i]->maxKC)
|
|
core_mn.u.mappingNotify.count = num_keys;
|
|
else
|
|
core_mn.u.mappingNotify.count = clients[i]->maxKC -
|
|
clients[i]->minKC + 1;
|
|
|
|
WriteEventsToClient(clients[i], 1, &core_mn);
|
|
}
|
|
if (modmap_changed) {
|
|
xEvent core_mn = {
|
|
.u.mappingNotify.request = MappingModifier,
|
|
.u.mappingNotify.firstKeyCode = 0,
|
|
.u.mappingNotify.count = 0
|
|
};
|
|
core_mn.u.u.type = MappingNotify;
|
|
WriteEventsToClient(clients[i], 1, &core_mn);
|
|
}
|
|
}
|
|
|
|
/* Hmm, maybe we can accidentally generate Xi events for core devices
|
|
* here? Clients might be upset, but that seems better than the
|
|
* alternative of stale keymaps. -ds */
|
|
if (keymap_changed) {
|
|
deviceMappingNotify xi_mn = {
|
|
.type = DeviceMappingNotify,
|
|
.deviceid = kbd->id,
|
|
.request = MappingKeyboard,
|
|
.firstKeyCode = first_key,
|
|
.count = num_keys,
|
|
.time = time
|
|
};
|
|
SendEventToAllWindows(kbd, DeviceMappingNotifyMask, (xEvent *) &xi_mn,
|
|
1);
|
|
}
|
|
if (modmap_changed) {
|
|
deviceMappingNotify xi_mn = {
|
|
.type = DeviceMappingNotify,
|
|
.deviceid = kbd->id,
|
|
.request = MappingModifier,
|
|
.firstKeyCode = 0,
|
|
.count = 0,
|
|
.time = time
|
|
};
|
|
SendEventToAllWindows(kbd, DeviceMappingNotifyMask, (xEvent *) &xi_mn,
|
|
1);
|
|
}
|
|
}
|
|
|
|
/***====================================================================***/
|
|
|
|
void
|
|
XkbSendNewKeyboardNotify(DeviceIntPtr kbd, xkbNewKeyboardNotify * pNKN)
|
|
{
|
|
int i;
|
|
Time time = GetTimeInMillis();
|
|
CARD16 changed = pNKN->changed;
|
|
|
|
pNKN->type = XkbEventCode + XkbEventBase;
|
|
pNKN->xkbType = XkbNewKeyboardNotify;
|
|
|
|
for (i = 1; i < currentMaxClients; i++) {
|
|
if (!clients[i] || clients[i]->clientState != ClientStateRunning)
|
|
continue;
|
|
|
|
if (!(clients[i]->newKeyboardNotifyMask & changed))
|
|
continue;
|
|
|
|
pNKN->sequenceNumber = clients[i]->sequence;
|
|
pNKN->time = time;
|
|
pNKN->changed = changed;
|
|
if (clients[i]->swapped) {
|
|
swaps(&pNKN->sequenceNumber);
|
|
swapl(&pNKN->time);
|
|
swaps(&pNKN->changed);
|
|
}
|
|
WriteToClient(clients[i], sizeof(xEvent), pNKN);
|
|
|
|
if (changed & XkbNKN_KeycodesMask) {
|
|
clients[i]->minKC = pNKN->minKeyCode;
|
|
clients[i]->maxKC = pNKN->maxKeyCode;
|
|
}
|
|
}
|
|
|
|
XkbSendLegacyMapNotify(kbd, XkbNewKeyboardNotify, changed, pNKN->minKeyCode,
|
|
pNKN->maxKeyCode - pNKN->minKeyCode + 1);
|
|
|
|
return;
|
|
}
|
|
|
|
/***====================================================================***/
|
|
|
|
void
|
|
XkbSendStateNotify(DeviceIntPtr kbd, xkbStateNotify * pSN)
|
|
{
|
|
XkbSrvInfoPtr xkbi;
|
|
XkbStatePtr state;
|
|
XkbInterestPtr interest;
|
|
Time time;
|
|
register CARD16 changed, bState;
|
|
|
|
interest = kbd->xkb_interest;
|
|
if (!interest || !kbd->key || !kbd->key->xkbInfo)
|
|
return;
|
|
xkbi = kbd->key->xkbInfo;
|
|
state = &xkbi->state;
|
|
|
|
pSN->type = XkbEventCode + XkbEventBase;
|
|
pSN->xkbType = XkbStateNotify;
|
|
pSN->deviceID = kbd->id;
|
|
pSN->time = time = GetTimeInMillis();
|
|
pSN->mods = state->mods;
|
|
pSN->baseMods = state->base_mods;
|
|
pSN->latchedMods = state->latched_mods;
|
|
pSN->lockedMods = state->locked_mods;
|
|
pSN->group = state->group;
|
|
pSN->baseGroup = state->base_group;
|
|
pSN->latchedGroup = state->latched_group;
|
|
pSN->lockedGroup = state->locked_group;
|
|
pSN->compatState = state->compat_state;
|
|
pSN->grabMods = state->grab_mods;
|
|
pSN->compatGrabMods = state->compat_grab_mods;
|
|
pSN->lookupMods = state->lookup_mods;
|
|
pSN->compatLookupMods = state->compat_lookup_mods;
|
|
pSN->ptrBtnState = state->ptr_buttons;
|
|
changed = pSN->changed;
|
|
bState = pSN->ptrBtnState;
|
|
|
|
while (interest) {
|
|
if ((!interest->client->clientGone) &&
|
|
(interest->client->xkbClientFlags & _XkbClientInitialized) &&
|
|
(interest->stateNotifyMask & changed)) {
|
|
pSN->sequenceNumber = interest->client->sequence;
|
|
pSN->time = time;
|
|
pSN->changed = changed;
|
|
pSN->ptrBtnState = bState;
|
|
if (interest->client->swapped) {
|
|
swaps(&pSN->sequenceNumber);
|
|
swapl(&pSN->time);
|
|
swaps(&pSN->changed);
|
|
swaps(&pSN->ptrBtnState);
|
|
}
|
|
WriteToClient(interest->client, sizeof(xEvent), pSN);
|
|
}
|
|
interest = interest->next;
|
|
}
|
|
return;
|
|
}
|
|
|
|
/***====================================================================***/
|
|
|
|
/*
|
|
* This function sends out XKB mapping notify events to clients which
|
|
* have explicitly selected for them. Core and Xi events are handled by
|
|
* XkbSendLegacyMapNotify. */
|
|
void
|
|
XkbSendMapNotify(DeviceIntPtr kbd, xkbMapNotify * pMN)
|
|
{
|
|
int i;
|
|
CARD32 time = GetTimeInMillis();
|
|
CARD16 changed = pMN->changed;
|
|
XkbSrvInfoPtr xkbi = kbd->key->xkbInfo;
|
|
|
|
pMN->minKeyCode = xkbi->desc->min_key_code;
|
|
pMN->maxKeyCode = xkbi->desc->max_key_code;
|
|
pMN->type = XkbEventCode + XkbEventBase;
|
|
pMN->xkbType = XkbMapNotify;
|
|
pMN->deviceID = kbd->id;
|
|
|
|
/* 0 is serverClient. */
|
|
for (i = 1; i < currentMaxClients; i++) {
|
|
if (!clients[i] || clients[i]->clientState != ClientStateRunning)
|
|
continue;
|
|
|
|
if (!(clients[i]->mapNotifyMask & changed))
|
|
continue;
|
|
|
|
pMN->time = time;
|
|
pMN->sequenceNumber = clients[i]->sequence;
|
|
pMN->changed = changed;
|
|
|
|
if (clients[i]->swapped) {
|
|
swaps(&pMN->sequenceNumber);
|
|
swapl(&pMN->time);
|
|
swaps(&pMN->changed);
|
|
}
|
|
WriteToClient(clients[i], sizeof(xEvent), pMN);
|
|
}
|
|
|
|
XkbSendLegacyMapNotify(kbd, XkbMapNotify, changed, pMN->firstKeySym,
|
|
pMN->nKeySyms);
|
|
}
|
|
|
|
int
|
|
XkbComputeControlsNotify(DeviceIntPtr kbd,
|
|
XkbControlsPtr old,
|
|
XkbControlsPtr new,
|
|
xkbControlsNotify * pCN, Bool forceCtrlProc)
|
|
{
|
|
int i;
|
|
CARD32 changedControls;
|
|
|
|
changedControls = 0;
|
|
|
|
if (!kbd || !kbd->kbdfeed)
|
|
return 0;
|
|
|
|
if (old->enabled_ctrls != new->enabled_ctrls)
|
|
changedControls |= XkbControlsEnabledMask;
|
|
if ((old->repeat_delay != new->repeat_delay) ||
|
|
(old->repeat_interval != new->repeat_interval))
|
|
changedControls |= XkbRepeatKeysMask;
|
|
for (i = 0; i < XkbPerKeyBitArraySize; i++)
|
|
if (old->per_key_repeat[i] != new->per_key_repeat[i])
|
|
changedControls |= XkbPerKeyRepeatMask;
|
|
if (old->slow_keys_delay != new->slow_keys_delay)
|
|
changedControls |= XkbSlowKeysMask;
|
|
if (old->debounce_delay != new->debounce_delay)
|
|
changedControls |= XkbBounceKeysMask;
|
|
if ((old->mk_delay != new->mk_delay) ||
|
|
(old->mk_interval != new->mk_interval) ||
|
|
(old->mk_dflt_btn != new->mk_dflt_btn))
|
|
changedControls |= XkbMouseKeysMask;
|
|
if ((old->mk_time_to_max != new->mk_time_to_max) ||
|
|
(old->mk_curve != new->mk_curve) ||
|
|
(old->mk_max_speed != new->mk_max_speed))
|
|
changedControls |= XkbMouseKeysAccelMask;
|
|
if (old->ax_options != new->ax_options)
|
|
changedControls |= XkbAccessXKeysMask;
|
|
if ((old->ax_options ^ new->ax_options) & XkbAX_SKOptionsMask)
|
|
changedControls |= XkbStickyKeysMask;
|
|
if ((old->ax_options ^ new->ax_options) & XkbAX_FBOptionsMask)
|
|
changedControls |= XkbAccessXFeedbackMask;
|
|
if ((old->ax_timeout != new->ax_timeout) ||
|
|
(old->axt_ctrls_mask != new->axt_ctrls_mask) ||
|
|
(old->axt_ctrls_values != new->axt_ctrls_values) ||
|
|
(old->axt_opts_mask != new->axt_opts_mask) ||
|
|
(old->axt_opts_values != new->axt_opts_values)) {
|
|
changedControls |= XkbAccessXTimeoutMask;
|
|
}
|
|
if ((old->internal.mask != new->internal.mask) ||
|
|
(old->internal.real_mods != new->internal.real_mods) ||
|
|
(old->internal.vmods != new->internal.vmods))
|
|
changedControls |= XkbInternalModsMask;
|
|
if ((old->ignore_lock.mask != new->ignore_lock.mask) ||
|
|
(old->ignore_lock.real_mods != new->ignore_lock.real_mods) ||
|
|
(old->ignore_lock.vmods != new->ignore_lock.vmods))
|
|
changedControls |= XkbIgnoreLockModsMask;
|
|
|
|
if (new->enabled_ctrls & XkbRepeatKeysMask)
|
|
kbd->kbdfeed->ctrl.autoRepeat = TRUE;
|
|
else
|
|
kbd->kbdfeed->ctrl.autoRepeat = FALSE;
|
|
|
|
if (kbd->kbdfeed && kbd->kbdfeed->CtrlProc &&
|
|
(changedControls || forceCtrlProc))
|
|
(*kbd->kbdfeed->CtrlProc) (kbd, &kbd->kbdfeed->ctrl);
|
|
|
|
if ((!changedControls) && (old->num_groups == new->num_groups))
|
|
return 0;
|
|
|
|
if (!kbd->xkb_interest)
|
|
return 0;
|
|
|
|
pCN->changedControls = changedControls;
|
|
pCN->enabledControls = new->enabled_ctrls;
|
|
pCN->enabledControlChanges = (new->enabled_ctrls ^ old->enabled_ctrls);
|
|
pCN->numGroups = new->num_groups;
|
|
|
|
return 1;
|
|
}
|
|
|
|
void
|
|
XkbSendControlsNotify(DeviceIntPtr kbd, xkbControlsNotify * pCN)
|
|
{
|
|
int initialized;
|
|
CARD32 changedControls, enabledControls, enabledChanges = 0;
|
|
XkbSrvInfoPtr xkbi;
|
|
XkbInterestPtr interest;
|
|
Time time = 0;
|
|
|
|
interest = kbd->xkb_interest;
|
|
if (!interest || !kbd->key || !kbd->key->xkbInfo)
|
|
return;
|
|
xkbi = kbd->key->xkbInfo;
|
|
|
|
initialized = 0;
|
|
enabledControls = xkbi->desc->ctrls->enabled_ctrls;
|
|
changedControls = pCN->changedControls;
|
|
pCN->numGroups = xkbi->desc->ctrls->num_groups;
|
|
while (interest) {
|
|
if ((!interest->client->clientGone) &&
|
|
(interest->client->xkbClientFlags & _XkbClientInitialized) &&
|
|
(interest->ctrlsNotifyMask & changedControls)) {
|
|
if (!initialized) {
|
|
pCN->type = XkbEventCode + XkbEventBase;
|
|
pCN->xkbType = XkbControlsNotify;
|
|
pCN->deviceID = kbd->id;
|
|
pCN->time = time = GetTimeInMillis();
|
|
enabledChanges = pCN->enabledControlChanges;
|
|
initialized = 1;
|
|
}
|
|
pCN->changedControls = changedControls;
|
|
pCN->enabledControls = enabledControls;
|
|
pCN->enabledControlChanges = enabledChanges;
|
|
pCN->sequenceNumber = interest->client->sequence;
|
|
pCN->time = time;
|
|
if (interest->client->swapped) {
|
|
swaps(&pCN->sequenceNumber);
|
|
swapl(&pCN->changedControls);
|
|
swapl(&pCN->enabledControls);
|
|
swapl(&pCN->enabledControlChanges);
|
|
swapl(&pCN->time);
|
|
}
|
|
WriteToClient(interest->client, sizeof(xEvent), pCN);
|
|
}
|
|
interest = interest->next;
|
|
}
|
|
return;
|
|
}
|
|
|
|
static void
|
|
XkbSendIndicatorNotify(DeviceIntPtr kbd, int xkbType, xkbIndicatorNotify * pEv)
|
|
{
|
|
int initialized;
|
|
XkbInterestPtr interest;
|
|
Time time = 0;
|
|
CARD32 state, changed;
|
|
|
|
interest = kbd->xkb_interest;
|
|
if (!interest)
|
|
return;
|
|
|
|
initialized = 0;
|
|
state = pEv->state;
|
|
changed = pEv->changed;
|
|
while (interest) {
|
|
if ((!interest->client->clientGone) &&
|
|
(interest->client->xkbClientFlags & _XkbClientInitialized) &&
|
|
(((xkbType == XkbIndicatorStateNotify) &&
|
|
(interest->iStateNotifyMask & changed)) ||
|
|
((xkbType == XkbIndicatorMapNotify) &&
|
|
(interest->iMapNotifyMask & changed)))) {
|
|
if (!initialized) {
|
|
pEv->type = XkbEventCode + XkbEventBase;
|
|
pEv->xkbType = xkbType;
|
|
pEv->deviceID = kbd->id;
|
|
pEv->time = time = GetTimeInMillis();
|
|
initialized = 1;
|
|
}
|
|
pEv->sequenceNumber = interest->client->sequence;
|
|
pEv->time = time;
|
|
pEv->changed = changed;
|
|
pEv->state = state;
|
|
if (interest->client->swapped) {
|
|
swaps(&pEv->sequenceNumber);
|
|
swapl(&pEv->time);
|
|
swapl(&pEv->changed);
|
|
swapl(&pEv->state);
|
|
}
|
|
WriteToClient(interest->client, sizeof(xEvent), pEv);
|
|
}
|
|
interest = interest->next;
|
|
}
|
|
return;
|
|
}
|
|
|
|
void
|
|
XkbHandleBell(BOOL force,
|
|
BOOL eventOnly,
|
|
DeviceIntPtr kbd,
|
|
CARD8 percent,
|
|
void *pCtrl,
|
|
CARD8 class, Atom name, WindowPtr pWin, ClientPtr pClient)
|
|
{
|
|
xkbBellNotify bn;
|
|
int initialized;
|
|
XkbSrvInfoPtr xkbi;
|
|
XkbInterestPtr interest;
|
|
CARD8 id;
|
|
CARD16 pitch, duration;
|
|
Time time = 0;
|
|
XID winID = 0;
|
|
|
|
if (!kbd->key || !kbd->key->xkbInfo)
|
|
return;
|
|
|
|
xkbi = kbd->key->xkbInfo;
|
|
|
|
if ((force || (xkbi->desc->ctrls->enabled_ctrls & XkbAudibleBellMask)) &&
|
|
(!eventOnly)) {
|
|
if (kbd->kbdfeed->BellProc)
|
|
(*kbd->kbdfeed->BellProc) (percent, kbd, (void *) pCtrl, class);
|
|
}
|
|
interest = kbd->xkb_interest;
|
|
if ((!interest) || (force))
|
|
return;
|
|
|
|
if (class == KbdFeedbackClass) {
|
|
KeybdCtrl *pKeyCtrl = (KeybdCtrl *) pCtrl;
|
|
|
|
id = pKeyCtrl->id;
|
|
pitch = pKeyCtrl->bell_pitch;
|
|
duration = pKeyCtrl->bell_duration;
|
|
}
|
|
else if (class == BellFeedbackClass) {
|
|
BellCtrl *pBellCtrl = (BellCtrl *) pCtrl;
|
|
|
|
id = pBellCtrl->id;
|
|
pitch = pBellCtrl->pitch;
|
|
duration = pBellCtrl->duration;
|
|
}
|
|
else
|
|
return;
|
|
|
|
initialized = 0;
|
|
while (interest) {
|
|
if ((!interest->client->clientGone) &&
|
|
(interest->client->xkbClientFlags & _XkbClientInitialized) &&
|
|
(interest->bellNotifyMask)) {
|
|
if (!initialized) {
|
|
time = GetTimeInMillis();
|
|
bn.type = XkbEventCode + XkbEventBase;
|
|
bn.xkbType = XkbBellNotify;
|
|
bn.deviceID = kbd->id;
|
|
bn.bellClass = class;
|
|
bn.bellID = id;
|
|
bn.percent = percent;
|
|
bn.eventOnly = (eventOnly != 0);
|
|
winID = (pWin ? pWin->drawable.id : None);
|
|
initialized = 1;
|
|
}
|
|
bn.sequenceNumber = interest->client->sequence;
|
|
bn.time = time;
|
|
bn.pitch = pitch;
|
|
bn.duration = duration;
|
|
bn.name = name;
|
|
bn.window = winID;
|
|
if (interest->client->swapped) {
|
|
swaps(&bn.sequenceNumber);
|
|
swapl(&bn.time);
|
|
swaps(&bn.pitch);
|
|
swaps(&bn.duration);
|
|
swapl(&bn.name);
|
|
swapl(&bn.window);
|
|
}
|
|
WriteToClient(interest->client, sizeof(xEvent), &bn);
|
|
}
|
|
interest = interest->next;
|
|
}
|
|
return;
|
|
}
|
|
|
|
void
|
|
XkbSendAccessXNotify(DeviceIntPtr kbd, xkbAccessXNotify * pEv)
|
|
{
|
|
int initialized;
|
|
XkbInterestPtr interest;
|
|
Time time = 0;
|
|
CARD16 sk_delay, db_delay;
|
|
|
|
interest = kbd->xkb_interest;
|
|
if (!interest)
|
|
return;
|
|
|
|
initialized = 0;
|
|
sk_delay = pEv->slowKeysDelay;
|
|
db_delay = pEv->debounceDelay;
|
|
while (interest) {
|
|
if ((!interest->client->clientGone) &&
|
|
(interest->client->xkbClientFlags & _XkbClientInitialized) &&
|
|
(interest->accessXNotifyMask & (1 << pEv->detail))) {
|
|
if (!initialized) {
|
|
pEv->type = XkbEventCode + XkbEventBase;
|
|
pEv->xkbType = XkbAccessXNotify;
|
|
pEv->deviceID = kbd->id;
|
|
pEv->time = time = GetTimeInMillis();
|
|
initialized = 1;
|
|
}
|
|
pEv->sequenceNumber = interest->client->sequence;
|
|
pEv->time = time;
|
|
pEv->slowKeysDelay = sk_delay;
|
|
pEv->debounceDelay = db_delay;
|
|
if (interest->client->swapped) {
|
|
swaps(&pEv->sequenceNumber);
|
|
swapl(&pEv->time);
|
|
swaps(&pEv->slowKeysDelay);
|
|
swaps(&pEv->debounceDelay);
|
|
}
|
|
WriteToClient(interest->client, sizeof(xEvent), pEv);
|
|
}
|
|
interest = interest->next;
|
|
}
|
|
return;
|
|
}
|
|
|
|
void
|
|
XkbSendNamesNotify(DeviceIntPtr kbd, xkbNamesNotify * pEv)
|
|
{
|
|
int initialized;
|
|
XkbInterestPtr interest;
|
|
Time time = 0;
|
|
CARD16 changed, changedVirtualMods;
|
|
CARD32 changedIndicators;
|
|
|
|
interest = kbd->xkb_interest;
|
|
if (!interest)
|
|
return;
|
|
|
|
initialized = 0;
|
|
changed = pEv->changed;
|
|
changedIndicators = pEv->changedIndicators;
|
|
changedVirtualMods = pEv->changedVirtualMods;
|
|
while (interest) {
|
|
if ((!interest->client->clientGone) &&
|
|
(interest->client->xkbClientFlags & _XkbClientInitialized) &&
|
|
(interest->namesNotifyMask & pEv->changed)) {
|
|
if (!initialized) {
|
|
pEv->type = XkbEventCode + XkbEventBase;
|
|
pEv->xkbType = XkbNamesNotify;
|
|
pEv->deviceID = kbd->id;
|
|
pEv->time = time = GetTimeInMillis();
|
|
initialized = 1;
|
|
}
|
|
pEv->sequenceNumber = interest->client->sequence;
|
|
pEv->time = time;
|
|
pEv->changed = changed;
|
|
pEv->changedIndicators = changedIndicators;
|
|
pEv->changedVirtualMods = changedVirtualMods;
|
|
if (interest->client->swapped) {
|
|
swaps(&pEv->sequenceNumber);
|
|
swapl(&pEv->time);
|
|
swaps(&pEv->changed);
|
|
swapl(&pEv->changedIndicators);
|
|
swaps(&pEv->changedVirtualMods);
|
|
}
|
|
WriteToClient(interest->client, sizeof(xEvent), pEv);
|
|
}
|
|
interest = interest->next;
|
|
}
|
|
return;
|
|
}
|
|
|
|
void
|
|
XkbSendCompatMapNotify(DeviceIntPtr kbd, xkbCompatMapNotify * pEv)
|
|
{
|
|
int initialized;
|
|
XkbInterestPtr interest;
|
|
Time time = 0;
|
|
CARD16 firstSI = 0, nSI = 0, nTotalSI = 0;
|
|
|
|
interest = kbd->xkb_interest;
|
|
if (!interest)
|
|
return;
|
|
|
|
initialized = 0;
|
|
while (interest) {
|
|
if ((!interest->client->clientGone) &&
|
|
(interest->client->xkbClientFlags & _XkbClientInitialized) &&
|
|
(interest->compatNotifyMask)) {
|
|
if (!initialized) {
|
|
pEv->type = XkbEventCode + XkbEventBase;
|
|
pEv->xkbType = XkbCompatMapNotify;
|
|
pEv->deviceID = kbd->id;
|
|
pEv->time = time = GetTimeInMillis();
|
|
firstSI = pEv->firstSI;
|
|
nSI = pEv->nSI;
|
|
nTotalSI = pEv->nTotalSI;
|
|
initialized = 1;
|
|
}
|
|
pEv->sequenceNumber = interest->client->sequence;
|
|
pEv->time = time;
|
|
pEv->firstSI = firstSI;
|
|
pEv->nSI = nSI;
|
|
pEv->nTotalSI = nTotalSI;
|
|
if (interest->client->swapped) {
|
|
swaps(&pEv->sequenceNumber);
|
|
swapl(&pEv->time);
|
|
swaps(&pEv->firstSI);
|
|
swaps(&pEv->nSI);
|
|
swaps(&pEv->nTotalSI);
|
|
}
|
|
WriteToClient(interest->client, sizeof(xEvent), pEv);
|
|
}
|
|
interest = interest->next;
|
|
}
|
|
return;
|
|
}
|
|
|
|
void
|
|
XkbSendActionMessage(DeviceIntPtr kbd, xkbActionMessage * pEv)
|
|
{
|
|
int initialized;
|
|
XkbSrvInfoPtr xkbi;
|
|
XkbInterestPtr interest;
|
|
Time time = 0;
|
|
|
|
interest = kbd->xkb_interest;
|
|
if (!interest || !kbd->key || !kbd->key->xkbInfo)
|
|
return;
|
|
|
|
xkbi = kbd->key->xkbInfo;
|
|
|
|
initialized = 0;
|
|
pEv->mods = xkbi->state.mods;
|
|
pEv->group = xkbi->state.group;
|
|
while (interest) {
|
|
if ((!interest->client->clientGone) &&
|
|
(interest->client->xkbClientFlags & _XkbClientInitialized) &&
|
|
(interest->actionMessageMask)) {
|
|
if (!initialized) {
|
|
pEv->type = XkbEventCode + XkbEventBase;
|
|
pEv->xkbType = XkbActionMessage;
|
|
pEv->deviceID = kbd->id;
|
|
pEv->sequenceNumber = interest->client->sequence;
|
|
pEv->time = time = GetTimeInMillis();
|
|
initialized = 1;
|
|
}
|
|
pEv->sequenceNumber = interest->client->sequence;
|
|
pEv->time = time;
|
|
if (interest->client->swapped) {
|
|
swaps(&pEv->sequenceNumber);
|
|
swapl(&pEv->time);
|
|
}
|
|
WriteToClient(interest->client, sizeof(xEvent), pEv);
|
|
}
|
|
interest = interest->next;
|
|
}
|
|
return;
|
|
}
|
|
|
|
void
|
|
XkbSendExtensionDeviceNotify(DeviceIntPtr dev,
|
|
ClientPtr client, xkbExtensionDeviceNotify * pEv)
|
|
{
|
|
int initialized;
|
|
XkbInterestPtr interest;
|
|
Time time = 0;
|
|
CARD32 defined, state;
|
|
CARD16 reason;
|
|
|
|
interest = dev->xkb_interest;
|
|
if (!interest)
|
|
return;
|
|
|
|
initialized = 0;
|
|
reason = pEv->reason;
|
|
defined = pEv->ledsDefined;
|
|
state = pEv->ledState;
|
|
while (interest) {
|
|
if ((!interest->client->clientGone) &&
|
|
(interest->client->xkbClientFlags & _XkbClientInitialized) &&
|
|
(interest->extDevNotifyMask & reason)) {
|
|
if (!initialized) {
|
|
pEv->type = XkbEventCode + XkbEventBase;
|
|
pEv->xkbType = XkbExtensionDeviceNotify;
|
|
pEv->deviceID = dev->id;
|
|
pEv->sequenceNumber = interest->client->sequence;
|
|
pEv->time = time = GetTimeInMillis();
|
|
initialized = 1;
|
|
}
|
|
else {
|
|
pEv->sequenceNumber = interest->client->sequence;
|
|
pEv->time = time;
|
|
pEv->ledsDefined = defined;
|
|
pEv->ledState = state;
|
|
pEv->reason = reason;
|
|
pEv->supported = XkbXI_AllFeaturesMask;
|
|
}
|
|
if (interest->client->swapped) {
|
|
swaps(&pEv->sequenceNumber);
|
|
swapl(&pEv->time);
|
|
swapl(&pEv->ledsDefined);
|
|
swapl(&pEv->ledState);
|
|
swaps(&pEv->reason);
|
|
swaps(&pEv->supported);
|
|
}
|
|
WriteToClient(interest->client, sizeof(xEvent), pEv);
|
|
}
|
|
interest = interest->next;
|
|
}
|
|
return;
|
|
}
|
|
|
|
void
|
|
XkbSendNotification(DeviceIntPtr kbd,
|
|
XkbChangesPtr pChanges, XkbEventCausePtr cause)
|
|
{
|
|
XkbSrvLedInfoPtr sli;
|
|
|
|
sli = NULL;
|
|
if (pChanges->state_changes) {
|
|
xkbStateNotify sn;
|
|
|
|
sn.changed = pChanges->state_changes;
|
|
sn.keycode = cause->kc;
|
|
sn.eventType = cause->event;
|
|
sn.requestMajor = cause->mjr;
|
|
sn.requestMinor = cause->mnr;
|
|
XkbSendStateNotify(kbd, &sn);
|
|
}
|
|
if (pChanges->map.changed) {
|
|
xkbMapNotify mn;
|
|
|
|
memset(&mn, 0, sizeof(xkbMapNotify));
|
|
mn.changed = pChanges->map.changed;
|
|
mn.firstType = pChanges->map.first_type;
|
|
mn.nTypes = pChanges->map.num_types;
|
|
mn.firstKeySym = pChanges->map.first_key_sym;
|
|
mn.nKeySyms = pChanges->map.num_key_syms;
|
|
mn.firstKeyAct = pChanges->map.first_key_act;
|
|
mn.nKeyActs = pChanges->map.num_key_acts;
|
|
mn.firstKeyBehavior = pChanges->map.first_key_behavior;
|
|
mn.nKeyBehaviors = pChanges->map.num_key_behaviors;
|
|
mn.virtualMods = pChanges->map.vmods;
|
|
mn.firstKeyExplicit = pChanges->map.first_key_explicit;
|
|
mn.nKeyExplicit = pChanges->map.num_key_explicit;
|
|
mn.firstModMapKey = pChanges->map.first_modmap_key;
|
|
mn.nModMapKeys = pChanges->map.num_modmap_keys;
|
|
mn.firstVModMapKey = pChanges->map.first_vmodmap_key;
|
|
mn.nVModMapKeys = pChanges->map.num_vmodmap_keys;
|
|
XkbSendMapNotify(kbd, &mn);
|
|
}
|
|
if ((pChanges->ctrls.changed_ctrls) ||
|
|
(pChanges->ctrls.enabled_ctrls_changes)) {
|
|
xkbControlsNotify cn;
|
|
|
|
memset(&cn, 0, sizeof(xkbControlsNotify));
|
|
cn.changedControls = pChanges->ctrls.changed_ctrls;
|
|
cn.enabledControlChanges = pChanges->ctrls.enabled_ctrls_changes;
|
|
cn.keycode = cause->kc;
|
|
cn.eventType = cause->event;
|
|
cn.requestMajor = cause->mjr;
|
|
cn.requestMinor = cause->mnr;
|
|
XkbSendControlsNotify(kbd, &cn);
|
|
}
|
|
if (pChanges->indicators.map_changes) {
|
|
xkbIndicatorNotify in;
|
|
|
|
if (sli == NULL)
|
|
sli = XkbFindSrvLedInfo(kbd, XkbDfltXIClass, XkbDfltXIId, 0);
|
|
memset(&in, 0, sizeof(xkbIndicatorNotify));
|
|
in.state = sli->effectiveState;
|
|
in.changed = pChanges->indicators.map_changes;
|
|
XkbSendIndicatorNotify(kbd, XkbIndicatorMapNotify, &in);
|
|
}
|
|
if (pChanges->indicators.state_changes) {
|
|
xkbIndicatorNotify in;
|
|
|
|
if (sli == NULL)
|
|
sli = XkbFindSrvLedInfo(kbd, XkbDfltXIClass, XkbDfltXIId, 0);
|
|
memset(&in, 0, sizeof(xkbIndicatorNotify));
|
|
in.state = sli->effectiveState;
|
|
in.changed = pChanges->indicators.state_changes;
|
|
XkbSendIndicatorNotify(kbd, XkbIndicatorStateNotify, &in);
|
|
}
|
|
if (pChanges->names.changed) {
|
|
xkbNamesNotify nn;
|
|
|
|
memset(&nn, 0, sizeof(xkbNamesNotify));
|
|
nn.changed = pChanges->names.changed;
|
|
nn.firstType = pChanges->names.first_type;
|
|
nn.nTypes = pChanges->names.num_types;
|
|
nn.firstLevelName = pChanges->names.first_lvl;
|
|
nn.nLevelNames = pChanges->names.num_lvls;
|
|
nn.nRadioGroups = pChanges->names.num_rg;
|
|
nn.changedVirtualMods = pChanges->names.changed_vmods;
|
|
nn.changedIndicators = pChanges->names.changed_indicators;
|
|
XkbSendNamesNotify(kbd, &nn);
|
|
}
|
|
if ((pChanges->compat.changed_groups) || (pChanges->compat.num_si > 0)) {
|
|
xkbCompatMapNotify cmn;
|
|
|
|
memset(&cmn, 0, sizeof(xkbCompatMapNotify));
|
|
cmn.changedGroups = pChanges->compat.changed_groups;
|
|
cmn.firstSI = pChanges->compat.first_si;
|
|
cmn.nSI = pChanges->compat.num_si;
|
|
cmn.nTotalSI = kbd->key->xkbInfo->desc->compat->num_si;
|
|
XkbSendCompatMapNotify(kbd, &cmn);
|
|
}
|
|
return;
|
|
}
|
|
|
|
/***====================================================================***/
|
|
|
|
void
|
|
XkbFilterEvents(ClientPtr client, int nEvents, xEvent *xE)
|
|
{
|
|
DeviceIntPtr dev = NULL;
|
|
XkbSrvInfoPtr xkbi;
|
|
CARD8 type = xE[0].u.u.type;
|
|
|
|
if (xE->u.u.type & EXTENSION_EVENT_BASE)
|
|
dev = XIGetDevice(xE);
|
|
|
|
if (!dev)
|
|
dev = PickKeyboard(client);
|
|
|
|
if (!dev->key)
|
|
return;
|
|
|
|
xkbi = dev->key->xkbInfo;
|
|
|
|
if (client->xkbClientFlags & _XkbClientInitialized) {
|
|
if ((xkbDebugFlags & 0x10) &&
|
|
(type == KeyPress || type == KeyRelease ||
|
|
type == DeviceKeyPress || type == DeviceKeyRelease))
|
|
DebugF("[xkb] XkbFilterWriteEvents (XKB client): state 0x%04x\n",
|
|
xE[0].u.keyButtonPointer.state);
|
|
|
|
if (dev->deviceGrab.grab != NullGrab && dev->deviceGrab.fromPassiveGrab
|
|
&& (type == KeyPress || type == KeyRelease || type == DeviceKeyPress
|
|
|| type == DeviceKeyRelease)) {
|
|
unsigned int state, flags;
|
|
|
|
flags = client->xkbClientFlags;
|
|
state = xkbi->state.compat_grab_mods;
|
|
if (flags & XkbPCF_GrabsUseXKBStateMask) {
|
|
int group;
|
|
|
|
if (flags & XkbPCF_LookupStateWhenGrabbed) {
|
|
group = xkbi->state.group;
|
|
state = xkbi->state.lookup_mods;
|
|
}
|
|
else {
|
|
state = xkbi->state.grab_mods;
|
|
group = xkbi->state.base_group + xkbi->state.latched_group;
|
|
if (group < 0 || group >= xkbi->desc->ctrls->num_groups)
|
|
group = XkbAdjustGroup(group, xkbi->desc->ctrls);
|
|
}
|
|
state = XkbBuildCoreState(state, group);
|
|
}
|
|
else if (flags & XkbPCF_LookupStateWhenGrabbed) {
|
|
state = xkbi->state.compat_lookup_mods;
|
|
}
|
|
xE[0].u.keyButtonPointer.state = state;
|
|
}
|
|
}
|
|
else {
|
|
if ((xkbDebugFlags & 0x4) &&
|
|
(xE[0].u.u.type == KeyPress || xE[0].u.u.type == KeyRelease ||
|
|
xE[0].u.u.type == DeviceKeyPress ||
|
|
xE[0].u.u.type == DeviceKeyRelease)) {
|
|
DebugF("[xkb] XKbFilterWriteEvents (non-XKB):\n");
|
|
DebugF("[xkb] event= 0x%04x\n", xE[0].u.keyButtonPointer.state);
|
|
DebugF("[xkb] lookup= 0x%02x, grab= 0x%02x\n",
|
|
xkbi->state.lookup_mods, xkbi->state.grab_mods);
|
|
DebugF("[xkb] compat lookup= 0x%02x, grab= 0x%02x\n",
|
|
xkbi->state.compat_lookup_mods,
|
|
xkbi->state.compat_grab_mods);
|
|
}
|
|
if (type >= KeyPress && type <= MotionNotify) {
|
|
CARD16 old, new;
|
|
|
|
old = xE[0].u.keyButtonPointer.state & ~0x1f00;
|
|
new = xE[0].u.keyButtonPointer.state & 0x1F00;
|
|
|
|
if (old == XkbStateFieldFromRec(&xkbi->state))
|
|
new |= xkbi->state.compat_lookup_mods;
|
|
else
|
|
new |= xkbi->state.compat_grab_mods;
|
|
xE[0].u.keyButtonPointer.state = new;
|
|
}
|
|
else if (type == EnterNotify || type == LeaveNotify) {
|
|
xE[0].u.enterLeave.state &= 0x1F00;
|
|
xE[0].u.enterLeave.state |= xkbi->state.compat_grab_mods;
|
|
}
|
|
else if (type >= DeviceKeyPress && type <= DeviceMotionNotify) {
|
|
CARD16 old, new;
|
|
deviceKeyButtonPointer *kbp = (deviceKeyButtonPointer *) &xE[0];
|
|
|
|
old = kbp->state & ~0x1F00;
|
|
new = kbp->state & 0x1F00;
|
|
if (old == XkbStateFieldFromRec(&xkbi->state))
|
|
new |= xkbi->state.compat_lookup_mods;
|
|
else
|
|
new |= xkbi->state.compat_grab_mods;
|
|
kbp->state = new;
|
|
}
|
|
}
|
|
}
|
|
|
|
/***====================================================================***/
|
|
|
|
XkbInterestPtr
|
|
XkbFindClientResource(DevicePtr inDev, ClientPtr client)
|
|
{
|
|
DeviceIntPtr dev = (DeviceIntPtr) inDev;
|
|
XkbInterestPtr interest;
|
|
|
|
if (dev->xkb_interest) {
|
|
interest = dev->xkb_interest;
|
|
while (interest) {
|
|
if (interest->client == client) {
|
|
return interest;
|
|
}
|
|
interest = interest->next;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
XkbInterestPtr
|
|
XkbAddClientResource(DevicePtr inDev, ClientPtr client, XID id)
|
|
{
|
|
DeviceIntPtr dev = (DeviceIntPtr) inDev;
|
|
XkbInterestPtr interest;
|
|
|
|
interest = dev->xkb_interest;
|
|
while (interest) {
|
|
if (interest->client == client)
|
|
return ((interest->resource == id) ? interest : NULL);
|
|
interest = interest->next;
|
|
}
|
|
interest = calloc(1, sizeof(XkbInterestRec));
|
|
if (interest) {
|
|
interest->dev = dev;
|
|
interest->client = client;
|
|
interest->resource = id;
|
|
interest->next = dev->xkb_interest;
|
|
dev->xkb_interest = interest;
|
|
return interest;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
int
|
|
XkbRemoveResourceClient(DevicePtr inDev, XID id)
|
|
{
|
|
XkbSrvInfoPtr xkbi;
|
|
DeviceIntPtr dev = (DeviceIntPtr) inDev;
|
|
XkbInterestPtr interest;
|
|
Bool found;
|
|
unsigned long autoCtrls, autoValues;
|
|
ClientPtr client = NULL;
|
|
|
|
found = FALSE;
|
|
|
|
if (!dev->key || !dev->key->xkbInfo)
|
|
return found;
|
|
|
|
autoCtrls = autoValues = 0;
|
|
if (dev->xkb_interest) {
|
|
interest = dev->xkb_interest;
|
|
if (interest && (interest->resource == id)) {
|
|
dev->xkb_interest = interest->next;
|
|
autoCtrls = interest->autoCtrls;
|
|
autoValues = interest->autoCtrlValues;
|
|
client = interest->client;
|
|
free(interest);
|
|
found = TRUE;
|
|
}
|
|
while ((!found) && (interest->next)) {
|
|
if (interest->next->resource == id) {
|
|
XkbInterestPtr victim = interest->next;
|
|
|
|
interest->next = victim->next;
|
|
autoCtrls = victim->autoCtrls;
|
|
autoValues = victim->autoCtrlValues;
|
|
client = victim->client;
|
|
free(victim);
|
|
found = TRUE;
|
|
}
|
|
interest = interest->next;
|
|
}
|
|
}
|
|
if (found && autoCtrls && dev->key && dev->key->xkbInfo) {
|
|
XkbEventCauseRec cause;
|
|
|
|
xkbi = dev->key->xkbInfo;
|
|
XkbSetCauseXkbReq(&cause, X_kbPerClientFlags, client);
|
|
XkbEnableDisableControls(xkbi, autoCtrls, autoValues, NULL, &cause);
|
|
}
|
|
return found;
|
|
}
|