1066 lines
31 KiB
C
1066 lines
31 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>
|
|
#define NEED_EVENTS 1
|
|
#include <X11/X.h>
|
|
#include <X11/Xproto.h>
|
|
#include "misc.h"
|
|
#include "inputstr.h"
|
|
|
|
#include <X11/extensions/XI.h>
|
|
#include <X11/extensions/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 (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.
|
|
*/
|
|
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);
|
|
}
|
|
|
|
/***====================================================================***/
|
|
|
|
/*
|
|
* 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;
|
|
|
|
bzero((char *)&changes,sizeof(XkbChangesRec));
|
|
bzero((char *)&ed,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;
|
|
}
|
|
|
|
/***====================================================================***/
|
|
|
|
/*
|
|
* 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;
|
|
}
|
|
|
|
/***====================================================================***/
|
|
|
|
/*
|
|
* 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
|
|
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
|
|
* 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)
|
|
dev= (DeviceIntPtr)LookupKeyboardDevice();
|
|
|
|
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 (!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= _XkbTypedCalloc(1,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->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= _XkbTypedCalloc(1,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;
|
|
}
|
|
if ((sli->names==NULL)&&(needed_parts&XkbXI_IndicatorNamesMask))
|
|
sli->names= _XkbTypedCalloc(XkbNumIndicators,Atom);
|
|
if ((sli->maps==NULL)&&(needed_parts&XkbXI_IndicatorMapsMask))
|
|
sli->maps= _XkbTypedCalloc(XkbNumIndicators,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) {
|
|
if (sli->maps) _XkbFree(sli->maps);
|
|
if (sli->names) _XkbFree(sli->names);
|
|
}
|
|
sli->maps= NULL;
|
|
sli->names= NULL;
|
|
_XkbFree(sli);
|
|
return;
|
|
}
|
|
|
|
|
|
/***====================================================================***/
|
|
|
|
/*
|
|
* 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)) {
|
|
XkbSrvLedInfoPtr sli;
|
|
sli= dev->kbdfeed->xkb_sli;
|
|
if (dev->kbdfeed->xkb_sli==NULL) {
|
|
sli= XkbAllocSrvLedInfo(dev,dev->kbdfeed,NULL,needed_parts);
|
|
dev->kbdfeed->xkb_sli= sli;
|
|
}
|
|
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->names==NULL)&&(needed_parts&XkbXI_IndicatorNamesMask))
|
|
sli->names= _XkbTypedCalloc(XkbNumIndicators,Atom);
|
|
if ((sli->maps==NULL)&&(needed_parts&XkbXI_IndicatorMapsMask))
|
|
sli->maps= _XkbTypedCalloc(XkbNumIndicators,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);
|
|
bzero((char *)changes,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 && (ed->reason)) {
|
|
if ((dev!=kbd)&&(ed->reason&XkbXI_IndicatorStateMask))
|
|
XkbDDXUpdateDeviceIndicators(dev,sli,sli->effectiveState);
|
|
XkbSendExtensionDeviceNotify(dev,cause->client,ed);
|
|
}
|
|
bzero((char *)ed,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= (DeviceIntPtr)LookupKeyboardDevice();
|
|
|
|
if (ed==NULL) {
|
|
ed= &my_ed;
|
|
bzero((char *)ed,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;
|
|
bzero((char *)changes,sizeof(XkbChangesRec));
|
|
}
|
|
changes->names.changed|= XkbIndicatorNamesMask;
|
|
changes->names.changed_indicators|= changed_names;
|
|
}
|
|
|
|
ed->reason|= (XkbXI_IndicatorNamesMask&(~XkbXI_KeyboardsMask));
|
|
ed->ledClass= sli->class;
|
|
ed->ledID= sli->id;
|
|
ed->ledsDefined= sli->namesPresent|sli->mapsPresent;
|
|
ed->ledState= sli->effectiveState;
|
|
ed->unsupported= XkbXI_KeyboardsMask;
|
|
ed->supported= XkbXI_AllFeaturesMask&(~XkbXI_KeyboardsMask);
|
|
|
|
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= (DeviceIntPtr)LookupKeyboardDevice();
|
|
|
|
if (ed==NULL) {
|
|
ed= &my_ed;
|
|
bzero((char *)ed,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;
|
|
bzero((char *)changes,sizeof(XkbChangesRec));
|
|
}
|
|
changes->indicators.map_changes|= changed_maps;
|
|
}
|
|
|
|
XkbCheckIndicatorMaps(dev,sli,changed_maps);
|
|
|
|
ed->reason|= (XkbXI_IndicatorMapsMask&(~XkbXI_KeyboardsMask));
|
|
ed->ledClass= sli->class;
|
|
ed->ledID= sli->id;
|
|
ed->ledsDefined= sli->namesPresent|sli->mapsPresent;
|
|
ed->ledState= sli->effectiveState;
|
|
ed->unsupported|= XkbXI_KeyboardsMask&XkbXI_IndicatorMapsMask;
|
|
ed->supported= XkbXI_AllFeaturesMask&(~XkbXI_KeyboardsMask);
|
|
|
|
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= (DeviceIntPtr)LookupKeyboardDevice();
|
|
xkbi= kbd->key->xkbInfo;
|
|
|
|
if (changes==NULL) {
|
|
changes= &my_changes;
|
|
bzero((char *)changes,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;
|
|
bzero((char *)ed,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&(~XkbXI_KeyboardsMask));
|
|
ed->ledClass= sli->class;
|
|
ed->ledID= sli->id;
|
|
ed->ledsDefined= sli->namesPresent|sli->mapsPresent;
|
|
ed->ledState= sli->effectiveState;
|
|
ed->unsupported|= XkbXI_KeyboardsMask&XkbXI_IndicatorStateMask;
|
|
ed->supported= XkbXI_AllFeaturesMask&(~XkbXI_KeyboardsMask);
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
/***====================================================================***/
|
|
|
|
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= (DeviceIntPtr)LookupKeyboardDevice();
|
|
|
|
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;
|
|
bzero((char *)ed,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;
|
|
bzero((char *)changes,sizeof(XkbChangesRec));
|
|
}
|
|
changes->indicators.state_changes|= affected;
|
|
}
|
|
|
|
ed->reason|= (XkbXI_IndicatorStateMask&(~XkbXI_KeyboardsMask));
|
|
ed->ledClass= sli->class;
|
|
ed->ledID= sli->id;
|
|
ed->ledsDefined= sli->namesPresent|sli->mapsPresent;
|
|
ed->ledState= sli->effectiveState;
|
|
ed->unsupported|= XkbXI_KeyboardsMask&XkbXI_IndicatorStateMask;
|
|
ed->supported= XkbXI_AllFeaturesMask&(~XkbXI_KeyboardsMask);
|
|
|
|
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
|
|
_UpdateButtonVMods( XkbDescPtr xkb,
|
|
unsigned num_btns,
|
|
XkbAction * acts,
|
|
unsigned changed,
|
|
xkbExtensionDeviceNotify * ed_inout)
|
|
{
|
|
register int i;
|
|
|
|
for (i=0;i<num_btns;i++,acts++) {
|
|
if ((acts->any.type!=XkbSA_NoAction)&&
|
|
XkbUpdateActionVirtualMods(xkb,acts,changed)) {
|
|
if ((ed_inout->reason&XkbXI_ButtonActionsMask)==0) {
|
|
ed_inout->reason|= XkbXI_ButtonActionsMask;
|
|
ed_inout->firstBtn= i;
|
|
ed_inout->nBtns= 1;
|
|
}
|
|
else {
|
|
ed_inout->nBtns= (i-ed_inout->firstBtn)+1;
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
static void
|
|
_UpdateMapVMods( XkbDescPtr xkb,
|
|
register XkbIndicatorMapPtr map,
|
|
unsigned changed_vmods,
|
|
unsigned * changed_maps_rtrn)
|
|
{
|
|
register int i;
|
|
|
|
*changed_maps_rtrn= 0;
|
|
for (i=0;i<XkbNumIndicators;i++,map++) {
|
|
if (map->mods.vmods&changed_vmods) {
|
|
map->mods.mask= map->mods.real_mods;
|
|
map->mods.mask|= XkbMaskForVMask(xkb,map->mods.vmods);
|
|
*changed_maps_rtrn|= (1L<<i);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
static void
|
|
_UpdateDeviceVMods( DeviceIntPtr dev,
|
|
XkbDescPtr xkb,
|
|
unsigned changed,
|
|
XkbEventCausePtr cause)
|
|
{
|
|
xkbExtensionDeviceNotify ed;
|
|
XkbSrvLedInfoPtr sli;
|
|
unsigned changed_maps;
|
|
|
|
bzero((char *)&ed,sizeof(xkbExtensionDeviceNotify));
|
|
ed.deviceID= dev->id;
|
|
if ((dev->button)&&(dev->button->xkb_acts)) {
|
|
_UpdateButtonVMods(xkb,dev->button->numButtons,
|
|
dev->button->xkb_acts,changed,&ed);
|
|
}
|
|
if (dev->kbdfeed) {
|
|
KbdFeedbackPtr kf;
|
|
for (kf=dev->kbdfeed;kf!=NULL;kf=kf->next) {
|
|
if ((kf->xkb_sli==NULL)||(kf->xkb_sli->maps==NULL))
|
|
continue;
|
|
sli= kf->xkb_sli;
|
|
_UpdateMapVMods(xkb,sli->maps,changed,&changed_maps);
|
|
if (changed_maps) {
|
|
if (ed.reason&XkbXI_IndicatorsMask) {
|
|
XkbSendExtensionDeviceNotify(dev,NULL,&ed);
|
|
ed.reason= 0;
|
|
ed.firstBtn= ed.nBtns;
|
|
}
|
|
ed.ledClass= sli->class;
|
|
ed.ledID= sli->id;
|
|
ed.ledsDefined= sli->namesPresent|sli->mapsPresent;
|
|
ed.reason|= XkbXI_IndicatorMapsMask;
|
|
XkbUpdateLedAutoState(dev,sli,changed_maps,&ed,NULL,cause);
|
|
}
|
|
}
|
|
}
|
|
if (dev->leds) {
|
|
LedFeedbackPtr lf;
|
|
for (lf=dev->leds;lf!=NULL;lf=lf->next) {
|
|
if ((lf->xkb_sli==NULL)||(lf->xkb_sli->maps==NULL))
|
|
continue;
|
|
sli= lf->xkb_sli;
|
|
_UpdateMapVMods(xkb,sli->maps,changed,&changed_maps);
|
|
if (changed_maps) {
|
|
if (ed.reason&XkbXI_IndicatorsMask) {
|
|
XkbSendExtensionDeviceNotify(dev,NULL,&ed);
|
|
ed.reason= 0;
|
|
ed.firstBtn= ed.nBtns;
|
|
}
|
|
ed.ledClass= sli->class;
|
|
ed.ledID= sli->id;
|
|
ed.ledsDefined= sli->namesPresent|sli->mapsPresent;
|
|
ed.reason|= XkbXI_IndicatorMapsMask;
|
|
XkbUpdateLedAutoState(dev,sli,changed_maps,&ed,NULL,cause);
|
|
}
|
|
}
|
|
}
|
|
if (ed.reason!=0)
|
|
XkbSendExtensionDeviceNotify(dev,NULL,&ed);
|
|
return;
|
|
}
|
|
|
|
void
|
|
XkbApplyVModChangesToAllDevices( DeviceIntPtr dev,
|
|
XkbDescPtr xkb,
|
|
unsigned changed,
|
|
XkbEventCausePtr cause)
|
|
{
|
|
DeviceIntPtr edev;
|
|
if (dev!=(DeviceIntPtr)LookupKeyboardDevice())
|
|
return;
|
|
for (edev=inputInfo.devices;edev!=NULL;edev=edev->next) {
|
|
if (edev->key)
|
|
continue;
|
|
_UpdateDeviceVMods(edev,xkb,changed,cause);
|
|
}
|
|
for (edev=inputInfo.off_devices;edev!=NULL;edev=edev->next) {
|
|
if (edev->key)
|
|
continue;
|
|
_UpdateDeviceVMods(edev,xkb,changed,cause);
|
|
}
|
|
return;
|
|
}
|