#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 "XI.h"
#include "XKBsrv.h"
#include "xkb.h"
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( 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);
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( 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;
}
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( 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(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( 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;
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;
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( DeviceIntPtr dev,
unsigned class,
unsigned id,
unsigned needed_parts)
{
XkbSrvLedInfoPtr sli;
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)
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&(~XkbXIUnsupported));
ed->ledClass= sli->class;
ed->ledID= sli->id;
ed->ledsDefined= sli->namesPresent|sli->mapsPresent;
ed->ledState= sli->effectiveState;
ed->unsupported|= XkbXIUnsupported&XkbXI_IndicatorNamesMask;
ed->supported= XkbXI_AllFeaturesMask&(~XkbXIUnsupported);
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( 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&(~XkbXIUnsupported));
ed->ledClass= sli->class;
ed->ledID= sli->id;
ed->ledsDefined= sli->namesPresent|sli->mapsPresent;
ed->ledState= sli->effectiveState;
ed->unsupported|= XkbXIUnsupported&XkbXI_IndicatorMapsMask;
ed->supported= XkbXI_AllFeaturesMask&(~XkbXIUnsupported);
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&(~XkbXIUnsupported));
ed->ledClass= sli->class;
ed->ledID= sli->id;
ed->ledsDefined= sli->namesPresent|sli->mapsPresent;
ed->ledState= sli->effectiveState;
ed->unsupported|= XkbXIUnsupported&XkbXI_IndicatorStateMask;
ed->supported= XkbXI_AllFeaturesMask&(~XkbXIUnsupported);
}
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&(~XkbXIUnsupported));
ed->ledClass= sli->class;
ed->ledID= sli->id;
ed->ledsDefined= sli->namesPresent|sli->mapsPresent;
ed->ledState= sli->effectiveState;
ed->unsupported|= XkbXIUnsupported&XkbXI_IndicatorStateMask;
ed->supported= XkbXI_AllFeaturesMask&(~XkbXIUnsupported);
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;
}