1006 lines
33 KiB
C
1006 lines
33 KiB
C
/************************************************************
|
|
Copyright (c) 1995 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 <ctype.h>
|
|
#include <math.h>
|
|
#include <X11/X.h>
|
|
#include <X11/Xproto.h>
|
|
#include "misc.h"
|
|
#include "inputstr.h"
|
|
|
|
#include <X11/extensions/XI.h>
|
|
#include <xkbsrv.h>
|
|
#include "xkb.h"
|
|
|
|
/***====================================================================***/
|
|
|
|
/*
|
|
* unsigned
|
|
* XkbIndicatorsToUpdate(dev,changed,check_devs_rtrn)
|
|
*
|
|
* Given a keyboard and a set of state components that have changed,
|
|
* this function returns the indicators on the default keyboard
|
|
* feedback that might be affected. It also reports whether or not
|
|
* any extension devices might be affected in check_devs_rtrn.
|
|
*/
|
|
|
|
unsigned
|
|
XkbIndicatorsToUpdate(DeviceIntPtr dev,
|
|
unsigned long state_changes, Bool enable_changes)
|
|
{
|
|
register unsigned update = 0;
|
|
XkbSrvLedInfoPtr sli;
|
|
|
|
sli = XkbFindSrvLedInfo(dev, XkbDfltXIClass, XkbDfltXIId, 0);
|
|
|
|
if (!sli)
|
|
return update;
|
|
|
|
if (state_changes & (XkbModifierStateMask | XkbGroupStateMask))
|
|
update |= sli->usesEffective;
|
|
if (state_changes & (XkbModifierBaseMask | XkbGroupBaseMask))
|
|
update |= sli->usesBase;
|
|
if (state_changes & (XkbModifierLatchMask | XkbGroupLatchMask))
|
|
update |= sli->usesLatched;
|
|
if (state_changes & (XkbModifierLockMask | XkbGroupLockMask))
|
|
update |= sli->usesLocked;
|
|
if (state_changes & XkbCompatStateMask)
|
|
update |= sli->usesCompat;
|
|
if (enable_changes)
|
|
update |= sli->usesControls;
|
|
return update;
|
|
}
|
|
|
|
/***====================================================================***/
|
|
|
|
/*
|
|
* Bool
|
|
*XkbApplyLEDChangeToKeyboard(xkbi,map,on,change)
|
|
*
|
|
* Some indicators "drive" the keyboard when their state is explicitly
|
|
* changed, as described in section 9.2.1 of the XKB protocol spec.
|
|
* This function updates the state and controls for the keyboard
|
|
* specified by 'xkbi' to reflect any changes that are required
|
|
* when the indicator described by 'map' is turned on or off. The
|
|
* extent of the changes is reported in change, which must be defined.
|
|
*/
|
|
static Bool
|
|
XkbApplyLEDChangeToKeyboard(XkbSrvInfoPtr xkbi,
|
|
XkbIndicatorMapPtr map,
|
|
Bool on, XkbChangesPtr change)
|
|
{
|
|
Bool ctrlChange, stateChange;
|
|
XkbStatePtr state;
|
|
|
|
if ((map->flags & XkbIM_NoExplicit) ||
|
|
((map->flags & XkbIM_LEDDrivesKB) == 0))
|
|
return FALSE;
|
|
ctrlChange = stateChange = FALSE;
|
|
if (map->ctrls) {
|
|
XkbControlsPtr ctrls = xkbi->desc->ctrls;
|
|
unsigned old;
|
|
|
|
old = ctrls->enabled_ctrls;
|
|
if (on)
|
|
ctrls->enabled_ctrls |= map->ctrls;
|
|
else
|
|
ctrls->enabled_ctrls &= ~map->ctrls;
|
|
if (old != ctrls->enabled_ctrls) {
|
|
change->ctrls.changed_ctrls = XkbControlsEnabledMask;
|
|
change->ctrls.enabled_ctrls_changes = old ^ ctrls->enabled_ctrls;
|
|
ctrlChange = TRUE;
|
|
}
|
|
}
|
|
state = &xkbi->state;
|
|
if ((map->groups) && ((map->which_groups & (~XkbIM_UseBase)) != 0)) {
|
|
register int i;
|
|
register unsigned bit, match;
|
|
|
|
if (on)
|
|
match = (map->groups) & XkbAllGroupsMask;
|
|
else
|
|
match = (~map->groups) & XkbAllGroupsMask;
|
|
if (map->which_groups & (XkbIM_UseLocked | XkbIM_UseEffective)) {
|
|
for (i = 0, bit = 1; i < XkbNumKbdGroups; i++, bit <<= 1) {
|
|
if (bit & match)
|
|
break;
|
|
}
|
|
if (map->which_groups & XkbIM_UseLatched)
|
|
XkbLatchGroup(xkbi->device, 0); /* unlatch group */
|
|
state->locked_group = i;
|
|
stateChange = TRUE;
|
|
}
|
|
else if (map->which_groups & (XkbIM_UseLatched | XkbIM_UseEffective)) {
|
|
for (i = 0, bit = 1; i < XkbNumKbdGroups; i++, bit <<= 1) {
|
|
if (bit & match)
|
|
break;
|
|
}
|
|
state->locked_group = 0;
|
|
XkbLatchGroup(xkbi->device, i);
|
|
stateChange = TRUE;
|
|
}
|
|
}
|
|
if ((map->mods.mask) && ((map->which_mods & (~XkbIM_UseBase)) != 0)) {
|
|
if (map->which_mods & (XkbIM_UseLocked | XkbIM_UseEffective)) {
|
|
register unsigned long old;
|
|
|
|
old = state->locked_mods;
|
|
if (on)
|
|
state->locked_mods |= map->mods.mask;
|
|
else
|
|
state->locked_mods &= ~map->mods.mask;
|
|
if (state->locked_mods != old)
|
|
stateChange = TRUE;
|
|
}
|
|
if (map->which_mods & (XkbIM_UseLatched | XkbIM_UseEffective)) {
|
|
register unsigned long newmods;
|
|
|
|
newmods = state->latched_mods;
|
|
if (on)
|
|
newmods |= map->mods.mask;
|
|
else
|
|
newmods &= ~map->mods.mask;
|
|
if (newmods != state->locked_mods) {
|
|
newmods &= map->mods.mask;
|
|
XkbLatchModifiers(xkbi->device, map->mods.mask, newmods);
|
|
stateChange = TRUE;
|
|
}
|
|
}
|
|
}
|
|
return stateChange || ctrlChange;
|
|
}
|
|
|
|
/*
|
|
* Bool
|
|
* ComputeAutoState(map,state,ctrls)
|
|
*
|
|
* This function reports the effect of applying the specified
|
|
* indicator map given the specified state and controls, as
|
|
* described in section 9.2 of the XKB protocol specification.
|
|
*/
|
|
|
|
static Bool
|
|
ComputeAutoState(XkbIndicatorMapPtr map,
|
|
XkbStatePtr state, XkbControlsPtr ctrls)
|
|
{
|
|
Bool on;
|
|
CARD8 mods, group;
|
|
|
|
on = FALSE;
|
|
mods = group = 0;
|
|
if (map->which_mods & XkbIM_UseAnyMods) {
|
|
if (map->which_mods & XkbIM_UseBase)
|
|
mods |= state->base_mods;
|
|
if (map->which_mods & XkbIM_UseLatched)
|
|
mods |= state->latched_mods;
|
|
if (map->which_mods & XkbIM_UseLocked)
|
|
mods |= state->locked_mods;
|
|
if (map->which_mods & XkbIM_UseEffective)
|
|
mods |= state->mods;
|
|
if (map->which_mods & XkbIM_UseCompat)
|
|
mods |= state->compat_state;
|
|
on = ((map->mods.mask & mods) != 0);
|
|
on = on || ((mods == 0) && (map->mods.mask == 0) &&
|
|
(map->mods.vmods == 0));
|
|
}
|
|
if (map->which_groups & XkbIM_UseAnyGroup) {
|
|
if (map->which_groups & XkbIM_UseBase)
|
|
group |= (1L << state->base_group);
|
|
if (map->which_groups & XkbIM_UseLatched)
|
|
group |= (1L << state->latched_group);
|
|
if (map->which_groups & XkbIM_UseLocked)
|
|
group |= (1L << state->locked_group);
|
|
if (map->which_groups & XkbIM_UseEffective)
|
|
group |= (1L << state->group);
|
|
on = on || (((map->groups & group) != 0) || (map->groups == 0));
|
|
}
|
|
if (map->ctrls)
|
|
on = on || (ctrls->enabled_ctrls & map->ctrls);
|
|
return on;
|
|
}
|
|
|
|
static void
|
|
XkbUpdateLedAutoState(DeviceIntPtr dev,
|
|
XkbSrvLedInfoPtr sli,
|
|
unsigned maps_to_check,
|
|
xkbExtensionDeviceNotify * ed,
|
|
XkbChangesPtr changes, XkbEventCausePtr cause)
|
|
{
|
|
DeviceIntPtr kbd;
|
|
XkbStatePtr state;
|
|
XkbControlsPtr ctrls;
|
|
XkbChangesRec my_changes;
|
|
xkbExtensionDeviceNotify my_ed;
|
|
register unsigned i, bit, affected;
|
|
register XkbIndicatorMapPtr map;
|
|
unsigned oldState;
|
|
|
|
if ((maps_to_check == 0) || (sli->maps == NULL) || (sli->mapsPresent == 0))
|
|
return;
|
|
|
|
if (dev->key && dev->key->xkbInfo)
|
|
kbd = dev;
|
|
else
|
|
kbd = inputInfo.keyboard;
|
|
|
|
state = &kbd->key->xkbInfo->state;
|
|
ctrls = kbd->key->xkbInfo->desc->ctrls;
|
|
affected = maps_to_check;
|
|
oldState = sli->effectiveState;
|
|
sli->autoState &= ~affected;
|
|
for (i = 0, bit = 1; (i < XkbNumIndicators) && (affected); i++, bit <<= 1) {
|
|
if ((affected & bit) == 0)
|
|
continue;
|
|
affected &= ~bit;
|
|
map = &sli->maps[i];
|
|
if ((!(map->flags & XkbIM_NoAutomatic)) &&
|
|
ComputeAutoState(map, state, ctrls))
|
|
sli->autoState |= bit;
|
|
}
|
|
sli->effectiveState = (sli->autoState | sli->explicitState);
|
|
affected = sli->effectiveState ^ oldState;
|
|
if (affected == 0)
|
|
return;
|
|
|
|
if (ed == NULL) {
|
|
ed = &my_ed;
|
|
memset((char *) ed, 0, sizeof(xkbExtensionDeviceNotify));
|
|
}
|
|
else if ((ed->reason & XkbXI_IndicatorsMask) &&
|
|
((ed->ledClass != sli->class) || (ed->ledID != sli->id))) {
|
|
XkbFlushLedEvents(dev, kbd, sli, ed, changes, cause);
|
|
}
|
|
|
|
if ((kbd == dev) && (sli->flags & XkbSLI_IsDefault)) {
|
|
if (changes == NULL) {
|
|
changes = &my_changes;
|
|
memset((char *) changes, 0, sizeof(XkbChangesRec));
|
|
}
|
|
changes->indicators.state_changes |= affected;
|
|
}
|
|
|
|
ed->reason |= XkbXI_IndicatorStateMask;
|
|
ed->ledClass = sli->class;
|
|
ed->ledID = sli->id;
|
|
ed->ledsDefined = sli->namesPresent | sli->mapsPresent;
|
|
ed->ledState = sli->effectiveState;
|
|
ed->unsupported = 0;
|
|
ed->supported = XkbXI_AllFeaturesMask;
|
|
|
|
if (changes != &my_changes)
|
|
changes = NULL;
|
|
if (ed != &my_ed)
|
|
ed = NULL;
|
|
if (changes || ed)
|
|
XkbFlushLedEvents(dev, kbd, sli, ed, changes, cause);
|
|
return;
|
|
}
|
|
|
|
static void
|
|
XkbUpdateAllDeviceIndicators(XkbChangesPtr changes, XkbEventCausePtr cause)
|
|
{
|
|
DeviceIntPtr edev;
|
|
XkbSrvLedInfoPtr sli;
|
|
|
|
for (edev = inputInfo.devices; edev != NULL; edev = edev->next) {
|
|
if (edev->kbdfeed) {
|
|
KbdFeedbackPtr kf;
|
|
|
|
for (kf = edev->kbdfeed; kf != NULL; kf = kf->next) {
|
|
if ((kf->xkb_sli == NULL) || (kf->xkb_sli->maps == NULL))
|
|
continue;
|
|
sli = kf->xkb_sli;
|
|
XkbUpdateLedAutoState(edev, sli, sli->mapsPresent, NULL,
|
|
changes, cause);
|
|
|
|
}
|
|
}
|
|
if (edev->leds) {
|
|
LedFeedbackPtr lf;
|
|
|
|
for (lf = edev->leds; lf != NULL; lf = lf->next) {
|
|
if ((lf->xkb_sli == NULL) || (lf->xkb_sli->maps == NULL))
|
|
continue;
|
|
sli = lf->xkb_sli;
|
|
XkbUpdateLedAutoState(edev, sli, sli->mapsPresent, NULL,
|
|
changes, cause);
|
|
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
/***====================================================================***/
|
|
|
|
/*
|
|
* void
|
|
* XkbSetIndicators(dev,affect,values,cause)
|
|
*
|
|
* Attempts to change the indicators specified in 'affect' to the
|
|
* states specified in 'values' for the default keyboard feedback
|
|
* on the keyboard specified by 'dev.' Attempts to change indicator
|
|
* state might be ignored or have no affect, depending on the XKB
|
|
* indicator map for any affected indicators, as described in section
|
|
* 9.2 of the XKB protocol specification.
|
|
*
|
|
* If 'changes' is non-NULL, this function notes any changes to the
|
|
* keyboard state, controls, or indicator state that result from this
|
|
* attempted change. If 'changes' is NULL, this function generates
|
|
* XKB events to report any such changes to interested clients.
|
|
*
|
|
* If 'cause' is non-NULL, it specifies the reason for the change,
|
|
* as reported in some XKB events. If it is NULL, this function
|
|
* assumes that the change is the result of a core protocol
|
|
* ChangeKeyboardMapping request.
|
|
*/
|
|
|
|
void
|
|
XkbSetIndicators(DeviceIntPtr dev,
|
|
CARD32 affect, CARD32 values, XkbEventCausePtr cause)
|
|
{
|
|
XkbSrvLedInfoPtr sli;
|
|
XkbChangesRec changes;
|
|
xkbExtensionDeviceNotify ed;
|
|
unsigned side_affected;
|
|
|
|
memset((char *) &changes, 0, sizeof(XkbChangesRec));
|
|
memset((char *) &ed, 0, sizeof(xkbExtensionDeviceNotify));
|
|
sli = XkbFindSrvLedInfo(dev, XkbDfltXIClass, XkbDfltXIId, 0);
|
|
sli->explicitState &= ~affect;
|
|
sli->explicitState |= (affect & values);
|
|
XkbApplyLedStateChanges(dev, sli, affect, &ed, &changes, cause);
|
|
|
|
side_affected = 0;
|
|
if (changes.state_changes != 0)
|
|
side_affected |=
|
|
XkbIndicatorsToUpdate(dev, changes.state_changes, FALSE);
|
|
if (changes.ctrls.enabled_ctrls_changes)
|
|
side_affected |= sli->usesControls;
|
|
|
|
if (side_affected) {
|
|
XkbUpdateLedAutoState(dev, sli, side_affected, &ed, &changes, cause);
|
|
affect |= side_affected;
|
|
}
|
|
if (changes.state_changes || changes.ctrls.enabled_ctrls_changes)
|
|
XkbUpdateAllDeviceIndicators(NULL, cause);
|
|
|
|
XkbFlushLedEvents(dev, dev, sli, &ed, &changes, cause);
|
|
return;
|
|
}
|
|
|
|
/***====================================================================***/
|
|
|
|
/***====================================================================***/
|
|
|
|
/*
|
|
* void
|
|
* XkbUpdateIndicators(dev,update,check_edevs,changes,cause)
|
|
*
|
|
* Applies the indicator maps for any indicators specified in
|
|
* 'update' from the default keyboard feedback on the device
|
|
* specified by 'dev.'
|
|
*
|
|
* If 'changes' is NULL, this function generates and XKB events
|
|
* required to report the necessary changes, otherwise it simply
|
|
* notes the indicators with changed state.
|
|
*
|
|
* If 'check_edevs' is TRUE, this function also checks the indicator
|
|
* maps for any open extension devices that have them, and updates
|
|
* the state of any extension device indicators as necessary.
|
|
*/
|
|
|
|
void
|
|
XkbUpdateIndicators(DeviceIntPtr dev,
|
|
register CARD32 update,
|
|
Bool check_edevs,
|
|
XkbChangesPtr changes, XkbEventCausePtr cause)
|
|
{
|
|
XkbSrvLedInfoPtr sli;
|
|
|
|
sli = XkbFindSrvLedInfo(dev, XkbDfltXIClass, XkbDfltXIId, 0);
|
|
XkbUpdateLedAutoState(dev, sli, update, NULL, changes, cause);
|
|
if (check_edevs)
|
|
XkbUpdateAllDeviceIndicators(changes, cause);
|
|
return;
|
|
}
|
|
|
|
/***====================================================================***/
|
|
|
|
/***====================================================================***/
|
|
|
|
/*
|
|
* void
|
|
* XkbCheckIndicatorMaps(dev,sli,which)
|
|
*
|
|
* Updates the 'indicator accelerators' for the indicators specified
|
|
* by 'which' in the feedback specified by 'sli.' The indicator
|
|
* accelerators are internal to the server and are used to simplify
|
|
* and speed up the process of figuring out which indicators might
|
|
* be affected by a particular change in keyboard state or controls.
|
|
*/
|
|
|
|
void
|
|
XkbCheckIndicatorMaps(DeviceIntPtr dev, XkbSrvLedInfoPtr sli, unsigned which)
|
|
{
|
|
register unsigned i, bit;
|
|
XkbIndicatorMapPtr map;
|
|
XkbDescPtr xkb;
|
|
|
|
if ((sli->flags & XkbSLI_HasOwnState) == 0)
|
|
return;
|
|
|
|
sli->usesBase &= ~which;
|
|
sli->usesLatched &= ~which;
|
|
sli->usesLocked &= ~which;
|
|
sli->usesEffective &= ~which;
|
|
sli->usesCompat &= ~which;
|
|
sli->usesControls &= ~which;
|
|
sli->mapsPresent &= ~which;
|
|
|
|
xkb = dev->key->xkbInfo->desc;
|
|
for (i = 0, bit = 1, map = sli->maps; i < XkbNumIndicators;
|
|
i++, bit <<= 1, map++) {
|
|
if (which & bit) {
|
|
CARD8 what;
|
|
|
|
if (!map || !XkbIM_InUse(map))
|
|
continue;
|
|
sli->mapsPresent |= bit;
|
|
|
|
what = (map->which_mods | map->which_groups);
|
|
if (what & XkbIM_UseBase)
|
|
sli->usesBase |= bit;
|
|
if (what & XkbIM_UseLatched)
|
|
sli->usesLatched |= bit;
|
|
if (what & XkbIM_UseLocked)
|
|
sli->usesLocked |= bit;
|
|
if (what & XkbIM_UseEffective)
|
|
sli->usesEffective |= bit;
|
|
if (what & XkbIM_UseCompat)
|
|
sli->usesCompat |= bit;
|
|
if (map->ctrls)
|
|
sli->usesControls |= bit;
|
|
|
|
map->mods.mask = map->mods.real_mods;
|
|
if (map->mods.vmods != 0) {
|
|
map->mods.mask |= XkbMaskForVMask(xkb, map->mods.vmods);
|
|
}
|
|
}
|
|
}
|
|
sli->usedComponents = 0;
|
|
if (sli->usesBase)
|
|
sli->usedComponents |= XkbModifierBaseMask | XkbGroupBaseMask;
|
|
if (sli->usesLatched)
|
|
sli->usedComponents |= XkbModifierLatchMask | XkbGroupLatchMask;
|
|
if (sli->usesLocked)
|
|
sli->usedComponents |= XkbModifierLockMask | XkbGroupLockMask;
|
|
if (sli->usesEffective)
|
|
sli->usedComponents |= XkbModifierStateMask | XkbGroupStateMask;
|
|
if (sli->usesCompat)
|
|
sli->usedComponents |= XkbCompatStateMask;
|
|
return;
|
|
}
|
|
|
|
/***====================================================================***/
|
|
|
|
/*
|
|
* XkbSrvLedInfoPtr
|
|
* XkbAllocSrvLedInfo(dev,kf,lf,needed_parts)
|
|
*
|
|
* Allocates an XkbSrvLedInfoPtr for the feedback specified by either
|
|
* 'kf' or 'lf' on the keyboard specified by 'dev.'
|
|
*
|
|
* If 'needed_parts' is non-zero, this function makes sure that any
|
|
* of the parts speicified therein are allocated.
|
|
*/
|
|
XkbSrvLedInfoPtr
|
|
XkbAllocSrvLedInfo(DeviceIntPtr dev,
|
|
KbdFeedbackPtr kf, LedFeedbackPtr lf, unsigned needed_parts)
|
|
{
|
|
XkbSrvLedInfoPtr sli;
|
|
Bool checkAccel;
|
|
Bool checkNames;
|
|
|
|
sli = NULL;
|
|
checkAccel = checkNames = FALSE;
|
|
if ((kf != NULL) && (kf->xkb_sli == NULL)) {
|
|
kf->xkb_sli = sli = calloc(1, sizeof(XkbSrvLedInfoRec));
|
|
if (sli == NULL)
|
|
return NULL; /* ALLOCATION ERROR */
|
|
if (dev->key && dev->key->xkbInfo)
|
|
sli->flags = XkbSLI_HasOwnState;
|
|
else
|
|
sli->flags = 0;
|
|
sli->class = KbdFeedbackClass;
|
|
sli->id = kf->ctrl.id;
|
|
sli->fb.kf = kf;
|
|
|
|
sli->autoState = 0;
|
|
sli->explicitState = kf->ctrl.leds;
|
|
sli->effectiveState = kf->ctrl.leds;
|
|
|
|
if ((kf == dev->kbdfeed) && (dev->key) && (dev->key->xkbInfo)) {
|
|
XkbDescPtr xkb;
|
|
|
|
xkb = dev->key->xkbInfo->desc;
|
|
sli->flags |= XkbSLI_IsDefault;
|
|
sli->physIndicators = xkb->indicators->phys_indicators;
|
|
sli->names = xkb->names->indicators;
|
|
sli->maps = xkb->indicators->maps;
|
|
checkNames = checkAccel = TRUE;
|
|
}
|
|
else {
|
|
sli->physIndicators = XkbAllIndicatorsMask;
|
|
sli->names = NULL;
|
|
sli->maps = NULL;
|
|
}
|
|
}
|
|
else if ((kf != NULL) && ((kf->xkb_sli->flags & XkbSLI_IsDefault) != 0)) {
|
|
XkbDescPtr xkb;
|
|
|
|
xkb = dev->key->xkbInfo->desc;
|
|
sli = kf->xkb_sli;
|
|
sli->physIndicators = xkb->indicators->phys_indicators;
|
|
if (xkb->names->indicators != sli->names) {
|
|
checkNames = TRUE;
|
|
sli->names = xkb->names->indicators;
|
|
}
|
|
if (xkb->indicators->maps != sli->maps) {
|
|
checkAccel = TRUE;
|
|
sli->maps = xkb->indicators->maps;
|
|
}
|
|
}
|
|
else if ((lf != NULL) && (lf->xkb_sli == NULL)) {
|
|
lf->xkb_sli = sli = calloc(1, sizeof(XkbSrvLedInfoRec));
|
|
if (sli == NULL)
|
|
return NULL; /* ALLOCATION ERROR */
|
|
if (dev->key && dev->key->xkbInfo)
|
|
sli->flags = XkbSLI_HasOwnState;
|
|
else
|
|
sli->flags = 0;
|
|
sli->class = LedFeedbackClass;
|
|
sli->id = lf->ctrl.id;
|
|
sli->fb.lf = lf;
|
|
|
|
sli->physIndicators = lf->ctrl.led_mask;
|
|
sli->autoState = 0;
|
|
sli->explicitState = lf->ctrl.led_values;
|
|
sli->effectiveState = lf->ctrl.led_values;
|
|
sli->maps = NULL;
|
|
sli->names = NULL;
|
|
}
|
|
else
|
|
return NULL;
|
|
if ((sli->names == NULL) && (needed_parts & XkbXI_IndicatorNamesMask))
|
|
sli->names = calloc(XkbNumIndicators, sizeof(Atom));
|
|
if ((sli->maps == NULL) && (needed_parts & XkbXI_IndicatorMapsMask))
|
|
sli->maps = calloc(XkbNumIndicators, sizeof(XkbIndicatorMapRec));
|
|
if (checkNames) {
|
|
register unsigned i, bit;
|
|
|
|
sli->namesPresent = 0;
|
|
for (i = 0, bit = 1; i < XkbNumIndicators; i++, bit <<= 1) {
|
|
if (sli->names[i] != None)
|
|
sli->namesPresent |= bit;
|
|
}
|
|
}
|
|
if (checkAccel)
|
|
XkbCheckIndicatorMaps(dev, sli, XkbAllIndicatorsMask);
|
|
return sli;
|
|
}
|
|
|
|
void
|
|
XkbFreeSrvLedInfo(XkbSrvLedInfoPtr sli)
|
|
{
|
|
if ((sli->flags & XkbSLI_IsDefault) == 0) {
|
|
free(sli->maps);
|
|
free(sli->names);
|
|
}
|
|
sli->maps = NULL;
|
|
sli->names = NULL;
|
|
free(sli);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* XkbSrvLedInfoPtr
|
|
* XkbCopySrvLedInfo(dev,src,kf,lf)
|
|
*
|
|
* Takes the given XkbSrvLedInfoPtr and duplicates it. A deep copy is made,
|
|
* thus the new copy behaves like the original one and can be freed with
|
|
* XkbFreeSrvLedInfo.
|
|
*/
|
|
XkbSrvLedInfoPtr
|
|
XkbCopySrvLedInfo(DeviceIntPtr from,
|
|
XkbSrvLedInfoPtr src, KbdFeedbackPtr kf, LedFeedbackPtr lf)
|
|
{
|
|
XkbSrvLedInfoPtr sli_new = NULL;
|
|
|
|
if (!src)
|
|
goto finish;
|
|
|
|
sli_new = calloc(1, sizeof(XkbSrvLedInfoRec));
|
|
if (!sli_new)
|
|
goto finish;
|
|
|
|
memcpy(sli_new, src, sizeof(XkbSrvLedInfoRec));
|
|
if (sli_new->class == KbdFeedbackClass)
|
|
sli_new->fb.kf = kf;
|
|
else
|
|
sli_new->fb.lf = lf;
|
|
|
|
if (!(sli_new->flags & XkbSLI_IsDefault)) {
|
|
sli_new->names = calloc(XkbNumIndicators, sizeof(Atom));
|
|
sli_new->maps = calloc(XkbNumIndicators, sizeof(XkbIndicatorMapRec));
|
|
} /* else sli_new->names/maps is pointing to
|
|
dev->key->xkbInfo->desc->names->indicators;
|
|
dev->key->xkbInfo->desc->names->indicators; */
|
|
|
|
finish:
|
|
return sli_new;
|
|
}
|
|
|
|
/***====================================================================***/
|
|
|
|
/*
|
|
* XkbSrvLedInfoPtr
|
|
* XkbFindSrvLedInfo(dev,class,id,needed_parts)
|
|
*
|
|
* Finds the XkbSrvLedInfoPtr for the specified 'class' and 'id'
|
|
* on the device specified by 'dev.' If the class and id specify
|
|
* a valid device feedback, this function returns the existing
|
|
* feedback or allocates a new one.
|
|
*
|
|
*/
|
|
|
|
XkbSrvLedInfoPtr
|
|
XkbFindSrvLedInfo(DeviceIntPtr dev,
|
|
unsigned class, unsigned id, unsigned needed_parts)
|
|
{
|
|
XkbSrvLedInfoPtr sli;
|
|
|
|
/* optimization to check for most common case */
|
|
if (((class == XkbDfltXIClass) && (id == XkbDfltXIId)) && (dev->kbdfeed)) {
|
|
if (dev->kbdfeed->xkb_sli == NULL) {
|
|
dev->kbdfeed->xkb_sli =
|
|
XkbAllocSrvLedInfo(dev, dev->kbdfeed, NULL, needed_parts);
|
|
}
|
|
return dev->kbdfeed->xkb_sli;
|
|
}
|
|
|
|
sli = NULL;
|
|
if (class == XkbDfltXIClass) {
|
|
if (dev->kbdfeed)
|
|
class = KbdFeedbackClass;
|
|
else if (dev->leds)
|
|
class = LedFeedbackClass;
|
|
else
|
|
return NULL;
|
|
}
|
|
if (class == KbdFeedbackClass) {
|
|
KbdFeedbackPtr kf;
|
|
|
|
for (kf = dev->kbdfeed; kf != NULL; kf = kf->next) {
|
|
if ((id == XkbDfltXIId) || (id == kf->ctrl.id)) {
|
|
if (kf->xkb_sli == NULL)
|
|
kf->xkb_sli =
|
|
XkbAllocSrvLedInfo(dev, kf, NULL, needed_parts);
|
|
sli = kf->xkb_sli;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else if (class == LedFeedbackClass) {
|
|
LedFeedbackPtr lf;
|
|
|
|
for (lf = dev->leds; lf != NULL; lf = lf->next) {
|
|
if ((id == XkbDfltXIId) || (id == lf->ctrl.id)) {
|
|
if (lf->xkb_sli == NULL)
|
|
lf->xkb_sli =
|
|
XkbAllocSrvLedInfo(dev, NULL, lf, needed_parts);
|
|
sli = lf->xkb_sli;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (sli) {
|
|
if ((sli->names == NULL) && (needed_parts & XkbXI_IndicatorNamesMask))
|
|
sli->names = calloc(XkbNumIndicators, sizeof(Atom));
|
|
if ((sli->maps == NULL) && (needed_parts & XkbXI_IndicatorMapsMask))
|
|
sli->maps = calloc(XkbNumIndicators, sizeof(XkbIndicatorMapRec));
|
|
}
|
|
return sli;
|
|
}
|
|
|
|
/***====================================================================***/
|
|
|
|
void
|
|
XkbFlushLedEvents(DeviceIntPtr dev,
|
|
DeviceIntPtr kbd,
|
|
XkbSrvLedInfoPtr sli,
|
|
xkbExtensionDeviceNotify * ed,
|
|
XkbChangesPtr changes, XkbEventCausePtr cause)
|
|
{
|
|
if (changes) {
|
|
if (changes->indicators.state_changes)
|
|
XkbDDXUpdateDeviceIndicators(dev, sli, sli->effectiveState);
|
|
XkbSendNotification(kbd, changes, cause);
|
|
memset((char *) changes, 0, sizeof(XkbChangesRec));
|
|
|
|
if (XkbAX_NeedFeedback
|
|
(kbd->key->xkbInfo->desc->ctrls, XkbAX_IndicatorFBMask)) {
|
|
if (sli->effectiveState)
|
|
/* it appears that the which parameter is not used */
|
|
XkbDDXAccessXBeep(dev, _BEEP_LED_ON, XkbAccessXFeedbackMask);
|
|
else
|
|
XkbDDXAccessXBeep(dev, _BEEP_LED_OFF, XkbAccessXFeedbackMask);
|
|
}
|
|
}
|
|
if (ed) {
|
|
if (ed->reason) {
|
|
if ((dev != kbd) && (ed->reason & XkbXI_IndicatorStateMask))
|
|
XkbDDXUpdateDeviceIndicators(dev, sli, sli->effectiveState);
|
|
XkbSendExtensionDeviceNotify(dev, cause->client, ed);
|
|
}
|
|
memset((char *) ed, 0, sizeof(XkbExtensionDeviceNotify));
|
|
}
|
|
return;
|
|
}
|
|
|
|
/***====================================================================***/
|
|
|
|
void
|
|
XkbApplyLedNameChanges(DeviceIntPtr dev,
|
|
XkbSrvLedInfoPtr sli,
|
|
unsigned changed_names,
|
|
xkbExtensionDeviceNotify * ed,
|
|
XkbChangesPtr changes, XkbEventCausePtr cause)
|
|
{
|
|
DeviceIntPtr kbd;
|
|
XkbChangesRec my_changes;
|
|
xkbExtensionDeviceNotify my_ed;
|
|
|
|
if (changed_names == 0)
|
|
return;
|
|
if (dev->key && dev->key->xkbInfo)
|
|
kbd = dev;
|
|
else
|
|
kbd = inputInfo.keyboard;
|
|
|
|
if (ed == NULL) {
|
|
ed = &my_ed;
|
|
memset((char *) ed, 0, sizeof(xkbExtensionDeviceNotify));
|
|
}
|
|
else if ((ed->reason & XkbXI_IndicatorsMask) &&
|
|
((ed->ledClass != sli->class) || (ed->ledID != sli->id))) {
|
|
XkbFlushLedEvents(dev, kbd, sli, ed, changes, cause);
|
|
}
|
|
|
|
if ((kbd == dev) && (sli->flags & XkbSLI_IsDefault)) {
|
|
if (changes == NULL) {
|
|
changes = &my_changes;
|
|
memset((char *) changes, 0, sizeof(XkbChangesRec));
|
|
}
|
|
changes->names.changed |= XkbIndicatorNamesMask;
|
|
changes->names.changed_indicators |= changed_names;
|
|
}
|
|
|
|
ed->reason |= XkbXI_IndicatorNamesMask;
|
|
ed->ledClass = sli->class;
|
|
ed->ledID = sli->id;
|
|
ed->ledsDefined = sli->namesPresent | sli->mapsPresent;
|
|
ed->ledState = sli->effectiveState;
|
|
ed->unsupported = 0;
|
|
ed->supported = XkbXI_AllFeaturesMask;
|
|
|
|
if (changes != &my_changes)
|
|
changes = NULL;
|
|
if (ed != &my_ed)
|
|
ed = NULL;
|
|
if (changes || ed)
|
|
XkbFlushLedEvents(dev, kbd, sli, ed, changes, cause);
|
|
return;
|
|
}
|
|
|
|
/***====================================================================***/
|
|
|
|
/*
|
|
* void
|
|
* XkbApplyLedMapChanges(dev,sli,changed_maps,changes,cause)
|
|
*
|
|
* Handles all of the secondary effects of the changes to the
|
|
* feedback specified by 'sli' on the device specified by 'dev.'
|
|
*
|
|
* If 'changed_maps' specifies any indicators, this function generates
|
|
* XkbExtensionDeviceNotify events and possibly IndicatorMapNotify
|
|
* events to report the changes, and recalculates the effective
|
|
* state of each indicator with a changed map. If any indicators
|
|
* change state, the server generates XkbExtensionDeviceNotify and
|
|
* XkbIndicatorStateNotify events as appropriate.
|
|
*
|
|
* If 'changes' is non-NULL, this function updates it to reflect
|
|
* any changes to the keyboard state or controls or to the 'core'
|
|
* indicator names, maps, or state. If 'changes' is NULL, this
|
|
* function generates XKB events as needed to report the changes.
|
|
* If 'dev' is not a keyboard device, any changes are reported
|
|
* for the core keyboard.
|
|
*
|
|
* The 'cause' specifies the reason for the event (key event or
|
|
* request) for the change, as reported in some XKB events.
|
|
*/
|
|
|
|
void
|
|
XkbApplyLedMapChanges(DeviceIntPtr dev,
|
|
XkbSrvLedInfoPtr sli,
|
|
unsigned changed_maps,
|
|
xkbExtensionDeviceNotify * ed,
|
|
XkbChangesPtr changes, XkbEventCausePtr cause)
|
|
{
|
|
DeviceIntPtr kbd;
|
|
XkbChangesRec my_changes;
|
|
xkbExtensionDeviceNotify my_ed;
|
|
|
|
if (changed_maps == 0)
|
|
return;
|
|
if (dev->key && dev->key->xkbInfo)
|
|
kbd = dev;
|
|
else
|
|
kbd = inputInfo.keyboard;
|
|
|
|
if (ed == NULL) {
|
|
ed = &my_ed;
|
|
memset((char *) ed, 0, sizeof(xkbExtensionDeviceNotify));
|
|
}
|
|
else if ((ed->reason & XkbXI_IndicatorsMask) &&
|
|
((ed->ledClass != sli->class) || (ed->ledID != sli->id))) {
|
|
XkbFlushLedEvents(dev, kbd, sli, ed, changes, cause);
|
|
}
|
|
|
|
if ((kbd == dev) && (sli->flags & XkbSLI_IsDefault)) {
|
|
if (changes == NULL) {
|
|
changes = &my_changes;
|
|
memset((char *) changes, 0, sizeof(XkbChangesRec));
|
|
}
|
|
changes->indicators.map_changes |= changed_maps;
|
|
}
|
|
|
|
XkbCheckIndicatorMaps(dev, sli, changed_maps);
|
|
|
|
ed->reason |= XkbXI_IndicatorMapsMask;
|
|
ed->ledClass = sli->class;
|
|
ed->ledID = sli->id;
|
|
ed->ledsDefined = sli->namesPresent | sli->mapsPresent;
|
|
ed->ledState = sli->effectiveState;
|
|
ed->unsupported = 0;
|
|
ed->supported = XkbXI_AllFeaturesMask;
|
|
|
|
XkbUpdateLedAutoState(dev, sli, changed_maps, ed, changes, cause);
|
|
|
|
if (changes != &my_changes)
|
|
changes = NULL;
|
|
if (ed != &my_ed)
|
|
ed = NULL;
|
|
if (changes || ed)
|
|
XkbFlushLedEvents(dev, kbd, sli, ed, changes, cause);
|
|
return;
|
|
}
|
|
|
|
/***====================================================================***/
|
|
|
|
void
|
|
XkbApplyLedStateChanges(DeviceIntPtr dev,
|
|
XkbSrvLedInfoPtr sli,
|
|
unsigned changed_leds,
|
|
xkbExtensionDeviceNotify * ed,
|
|
XkbChangesPtr changes, XkbEventCausePtr cause)
|
|
{
|
|
XkbSrvInfoPtr xkbi;
|
|
DeviceIntPtr kbd;
|
|
XkbChangesRec my_changes;
|
|
xkbExtensionDeviceNotify my_ed;
|
|
register unsigned i, bit, affected;
|
|
XkbIndicatorMapPtr map;
|
|
unsigned oldState;
|
|
Bool kb_changed;
|
|
|
|
if (changed_leds == 0)
|
|
return;
|
|
if (dev->key && dev->key->xkbInfo)
|
|
kbd = dev;
|
|
else
|
|
kbd = inputInfo.keyboard;
|
|
xkbi = kbd->key->xkbInfo;
|
|
|
|
if (changes == NULL) {
|
|
changes = &my_changes;
|
|
memset((char *) changes, 0, sizeof(XkbChangesRec));
|
|
}
|
|
|
|
kb_changed = FALSE;
|
|
affected = changed_leds;
|
|
oldState = sli->effectiveState;
|
|
for (i = 0, bit = 1; (i < XkbNumIndicators) && (affected); i++, bit <<= 1) {
|
|
if ((affected & bit) == 0)
|
|
continue;
|
|
affected &= ~bit;
|
|
map = &sli->maps[i];
|
|
if (map->flags & XkbIM_NoExplicit) {
|
|
sli->explicitState &= ~bit;
|
|
continue;
|
|
}
|
|
if (map->flags & XkbIM_LEDDrivesKB) {
|
|
Bool on = ((sli->explicitState & bit) != 0);
|
|
|
|
if (XkbApplyLEDChangeToKeyboard(xkbi, map, on, changes))
|
|
kb_changed = TRUE;
|
|
}
|
|
}
|
|
sli->effectiveState = (sli->autoState | sli->explicitState);
|
|
affected = sli->effectiveState ^ oldState;
|
|
|
|
if (ed == NULL) {
|
|
ed = &my_ed;
|
|
memset((char *) ed, 0, sizeof(xkbExtensionDeviceNotify));
|
|
}
|
|
else if (affected && (ed->reason & XkbXI_IndicatorsMask) &&
|
|
((ed->ledClass != sli->class) || (ed->ledID != sli->id))) {
|
|
XkbFlushLedEvents(dev, kbd, sli, ed, changes, cause);
|
|
}
|
|
|
|
if ((kbd == dev) && (sli->flags & XkbSLI_IsDefault))
|
|
changes->indicators.state_changes |= affected;
|
|
if (affected) {
|
|
ed->reason |= XkbXI_IndicatorStateMask;
|
|
ed->ledClass = sli->class;
|
|
ed->ledID = sli->id;
|
|
ed->ledsDefined = sli->namesPresent | sli->mapsPresent;
|
|
ed->ledState = sli->effectiveState;
|
|
ed->unsupported = 0;
|
|
ed->supported = XkbXI_AllFeaturesMask;
|
|
}
|
|
|
|
if (kb_changed) {
|
|
XkbComputeDerivedState(kbd->key->xkbInfo);
|
|
XkbUpdateLedAutoState(dev, sli, sli->mapsPresent, ed, changes, cause);
|
|
}
|
|
|
|
if (changes != &my_changes)
|
|
changes = NULL;
|
|
if (ed != &my_ed)
|
|
ed = NULL;
|
|
if (changes || ed)
|
|
XkbFlushLedEvents(dev, kbd, sli, ed, changes, cause);
|
|
if (kb_changed)
|
|
XkbUpdateAllDeviceIndicators(NULL, cause);
|
|
return;
|
|
}
|