xref: /OK3568_Linux_fs/external/xserver/xkb/xkbLEDs.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /************************************************************
2*4882a593Smuzhiyun Copyright (c) 1995 by Silicon Graphics Computer Systems, Inc.
3*4882a593Smuzhiyun 
4*4882a593Smuzhiyun Permission to use, copy, modify, and distribute this
5*4882a593Smuzhiyun software and its documentation for any purpose and without
6*4882a593Smuzhiyun fee is hereby granted, provided that the above copyright
7*4882a593Smuzhiyun notice appear in all copies and that both that copyright
8*4882a593Smuzhiyun notice and this permission notice appear in supporting
9*4882a593Smuzhiyun documentation, and that the name of Silicon Graphics not be
10*4882a593Smuzhiyun used in advertising or publicity pertaining to distribution
11*4882a593Smuzhiyun of the software without specific prior written permission.
12*4882a593Smuzhiyun Silicon Graphics makes no representation about the suitability
13*4882a593Smuzhiyun of this software for any purpose. It is provided "as is"
14*4882a593Smuzhiyun without any express or implied warranty.
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17*4882a593Smuzhiyun SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18*4882a593Smuzhiyun AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19*4882a593Smuzhiyun GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20*4882a593Smuzhiyun DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21*4882a593Smuzhiyun DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22*4882a593Smuzhiyun OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
23*4882a593Smuzhiyun THE USE OR PERFORMANCE OF THIS SOFTWARE.
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun ********************************************************/
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun #ifdef HAVE_DIX_CONFIG_H
28*4882a593Smuzhiyun #include <dix-config.h>
29*4882a593Smuzhiyun #endif
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun #include <stdio.h>
32*4882a593Smuzhiyun #include <ctype.h>
33*4882a593Smuzhiyun #include <math.h>
34*4882a593Smuzhiyun #include <X11/X.h>
35*4882a593Smuzhiyun #include <X11/Xproto.h>
36*4882a593Smuzhiyun #include "misc.h"
37*4882a593Smuzhiyun #include "inputstr.h"
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun #include <X11/extensions/XI.h>
40*4882a593Smuzhiyun #include <xkbsrv.h>
41*4882a593Smuzhiyun #include "xkb.h"
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun /***====================================================================***/
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun         /*
46*4882a593Smuzhiyun          * unsigned
47*4882a593Smuzhiyun          * XkbIndicatorsToUpdate(dev,changed,check_devs_rtrn)
48*4882a593Smuzhiyun          *
49*4882a593Smuzhiyun          * Given a keyboard and a set of state components that have changed,
50*4882a593Smuzhiyun          * this function returns the indicators on the default keyboard
51*4882a593Smuzhiyun          * feedback that might be affected.   It also reports whether or not
52*4882a593Smuzhiyun          * any extension devices might be affected in check_devs_rtrn.
53*4882a593Smuzhiyun          */
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun unsigned
XkbIndicatorsToUpdate(DeviceIntPtr dev,unsigned long state_changes,Bool enable_changes)56*4882a593Smuzhiyun XkbIndicatorsToUpdate(DeviceIntPtr dev,
57*4882a593Smuzhiyun                       unsigned long state_changes, Bool enable_changes)
58*4882a593Smuzhiyun {
59*4882a593Smuzhiyun     register unsigned update = 0;
60*4882a593Smuzhiyun     XkbSrvLedInfoPtr sli;
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun     sli = XkbFindSrvLedInfo(dev, XkbDfltXIClass, XkbDfltXIId, 0);
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun     if (!sli)
65*4882a593Smuzhiyun         return update;
66*4882a593Smuzhiyun 
67*4882a593Smuzhiyun     if (state_changes & (XkbModifierStateMask | XkbGroupStateMask))
68*4882a593Smuzhiyun         update |= sli->usesEffective;
69*4882a593Smuzhiyun     if (state_changes & (XkbModifierBaseMask | XkbGroupBaseMask))
70*4882a593Smuzhiyun         update |= sli->usesBase;
71*4882a593Smuzhiyun     if (state_changes & (XkbModifierLatchMask | XkbGroupLatchMask))
72*4882a593Smuzhiyun         update |= sli->usesLatched;
73*4882a593Smuzhiyun     if (state_changes & (XkbModifierLockMask | XkbGroupLockMask))
74*4882a593Smuzhiyun         update |= sli->usesLocked;
75*4882a593Smuzhiyun     if (state_changes & XkbCompatStateMask)
76*4882a593Smuzhiyun         update |= sli->usesCompat;
77*4882a593Smuzhiyun     if (enable_changes)
78*4882a593Smuzhiyun         update |= sli->usesControls;
79*4882a593Smuzhiyun     return update;
80*4882a593Smuzhiyun }
81*4882a593Smuzhiyun 
82*4882a593Smuzhiyun /***====================================================================***/
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun         /*
85*4882a593Smuzhiyun          * Bool
86*4882a593Smuzhiyun          *XkbApplyLEDChangeToKeyboard(xkbi,map,on,change)
87*4882a593Smuzhiyun          *
88*4882a593Smuzhiyun          * Some indicators "drive" the keyboard when their state is explicitly
89*4882a593Smuzhiyun          * changed, as described in section 9.2.1 of the XKB protocol spec.
90*4882a593Smuzhiyun          * This function updates the state and controls for the keyboard
91*4882a593Smuzhiyun          * specified by 'xkbi' to reflect any changes that are required
92*4882a593Smuzhiyun          * when the indicator described by 'map' is turned on or off.  The
93*4882a593Smuzhiyun          * extent of the changes is reported in change, which must be defined.
94*4882a593Smuzhiyun          */
95*4882a593Smuzhiyun static Bool
XkbApplyLEDChangeToKeyboard(XkbSrvInfoPtr xkbi,XkbIndicatorMapPtr map,Bool on,XkbChangesPtr change)96*4882a593Smuzhiyun XkbApplyLEDChangeToKeyboard(XkbSrvInfoPtr xkbi,
97*4882a593Smuzhiyun                             XkbIndicatorMapPtr map,
98*4882a593Smuzhiyun                             Bool on, XkbChangesPtr change)
99*4882a593Smuzhiyun {
100*4882a593Smuzhiyun     Bool ctrlChange, stateChange;
101*4882a593Smuzhiyun     XkbStatePtr state;
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun     if ((map->flags & XkbIM_NoExplicit) ||
104*4882a593Smuzhiyun         ((map->flags & XkbIM_LEDDrivesKB) == 0))
105*4882a593Smuzhiyun         return FALSE;
106*4882a593Smuzhiyun     ctrlChange = stateChange = FALSE;
107*4882a593Smuzhiyun     if (map->ctrls) {
108*4882a593Smuzhiyun         XkbControlsPtr ctrls = xkbi->desc->ctrls;
109*4882a593Smuzhiyun         unsigned old;
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun         old = ctrls->enabled_ctrls;
112*4882a593Smuzhiyun         if (on)
113*4882a593Smuzhiyun             ctrls->enabled_ctrls |= map->ctrls;
114*4882a593Smuzhiyun         else
115*4882a593Smuzhiyun             ctrls->enabled_ctrls &= ~map->ctrls;
116*4882a593Smuzhiyun         if (old != ctrls->enabled_ctrls) {
117*4882a593Smuzhiyun             change->ctrls.changed_ctrls = XkbControlsEnabledMask;
118*4882a593Smuzhiyun             change->ctrls.enabled_ctrls_changes = old ^ ctrls->enabled_ctrls;
119*4882a593Smuzhiyun             ctrlChange = TRUE;
120*4882a593Smuzhiyun         }
121*4882a593Smuzhiyun     }
122*4882a593Smuzhiyun     state = &xkbi->state;
123*4882a593Smuzhiyun     if ((map->groups) && ((map->which_groups & (~XkbIM_UseBase)) != 0)) {
124*4882a593Smuzhiyun         register int i;
125*4882a593Smuzhiyun         register unsigned bit, match;
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun         if (on)
128*4882a593Smuzhiyun             match = (map->groups) & XkbAllGroupsMask;
129*4882a593Smuzhiyun         else
130*4882a593Smuzhiyun             match = (~map->groups) & XkbAllGroupsMask;
131*4882a593Smuzhiyun         if (map->which_groups & (XkbIM_UseLocked | XkbIM_UseEffective)) {
132*4882a593Smuzhiyun             for (i = 0, bit = 1; i < XkbNumKbdGroups; i++, bit <<= 1) {
133*4882a593Smuzhiyun                 if (bit & match)
134*4882a593Smuzhiyun                     break;
135*4882a593Smuzhiyun             }
136*4882a593Smuzhiyun             if (map->which_groups & XkbIM_UseLatched)
137*4882a593Smuzhiyun                 XkbLatchGroup(xkbi->device, 0); /* unlatch group */
138*4882a593Smuzhiyun             state->locked_group = i;
139*4882a593Smuzhiyun             stateChange = TRUE;
140*4882a593Smuzhiyun         }
141*4882a593Smuzhiyun         else if (map->which_groups & (XkbIM_UseLatched | XkbIM_UseEffective)) {
142*4882a593Smuzhiyun             for (i = 0, bit = 1; i < XkbNumKbdGroups; i++, bit <<= 1) {
143*4882a593Smuzhiyun                 if (bit & match)
144*4882a593Smuzhiyun                     break;
145*4882a593Smuzhiyun             }
146*4882a593Smuzhiyun             state->locked_group = 0;
147*4882a593Smuzhiyun             XkbLatchGroup(xkbi->device, i);
148*4882a593Smuzhiyun             stateChange = TRUE;
149*4882a593Smuzhiyun         }
150*4882a593Smuzhiyun     }
151*4882a593Smuzhiyun     if ((map->mods.mask) && ((map->which_mods & (~XkbIM_UseBase)) != 0)) {
152*4882a593Smuzhiyun         if (map->which_mods & (XkbIM_UseLocked | XkbIM_UseEffective)) {
153*4882a593Smuzhiyun             register unsigned long old;
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun             old = state->locked_mods;
156*4882a593Smuzhiyun             if (on)
157*4882a593Smuzhiyun                 state->locked_mods |= map->mods.mask;
158*4882a593Smuzhiyun             else
159*4882a593Smuzhiyun                 state->locked_mods &= ~map->mods.mask;
160*4882a593Smuzhiyun             if (state->locked_mods != old)
161*4882a593Smuzhiyun                 stateChange = TRUE;
162*4882a593Smuzhiyun         }
163*4882a593Smuzhiyun         if (map->which_mods & (XkbIM_UseLatched | XkbIM_UseEffective)) {
164*4882a593Smuzhiyun             register unsigned long newmods;
165*4882a593Smuzhiyun 
166*4882a593Smuzhiyun             newmods = state->latched_mods;
167*4882a593Smuzhiyun             if (on)
168*4882a593Smuzhiyun                 newmods |= map->mods.mask;
169*4882a593Smuzhiyun             else
170*4882a593Smuzhiyun                 newmods &= ~map->mods.mask;
171*4882a593Smuzhiyun             if (newmods != state->locked_mods) {
172*4882a593Smuzhiyun                 newmods &= map->mods.mask;
173*4882a593Smuzhiyun                 XkbLatchModifiers(xkbi->device, map->mods.mask, newmods);
174*4882a593Smuzhiyun                 stateChange = TRUE;
175*4882a593Smuzhiyun             }
176*4882a593Smuzhiyun         }
177*4882a593Smuzhiyun     }
178*4882a593Smuzhiyun     return stateChange || ctrlChange;
179*4882a593Smuzhiyun }
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun         /*
182*4882a593Smuzhiyun          * Bool
183*4882a593Smuzhiyun          * ComputeAutoState(map,state,ctrls)
184*4882a593Smuzhiyun          *
185*4882a593Smuzhiyun          * This function reports the effect of applying the specified
186*4882a593Smuzhiyun          * indicator map given the specified state and controls, as
187*4882a593Smuzhiyun          * described in section 9.2 of the XKB protocol specification.
188*4882a593Smuzhiyun          */
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun static Bool
ComputeAutoState(XkbIndicatorMapPtr map,XkbStatePtr state,XkbControlsPtr ctrls)191*4882a593Smuzhiyun ComputeAutoState(XkbIndicatorMapPtr map,
192*4882a593Smuzhiyun                  XkbStatePtr state, XkbControlsPtr ctrls)
193*4882a593Smuzhiyun {
194*4882a593Smuzhiyun     Bool on;
195*4882a593Smuzhiyun     CARD8 mods, group;
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun     on = FALSE;
198*4882a593Smuzhiyun     mods = group = 0;
199*4882a593Smuzhiyun     if (map->which_mods & XkbIM_UseAnyMods) {
200*4882a593Smuzhiyun         if (map->which_mods & XkbIM_UseBase)
201*4882a593Smuzhiyun             mods |= state->base_mods;
202*4882a593Smuzhiyun         if (map->which_mods & XkbIM_UseLatched)
203*4882a593Smuzhiyun             mods |= state->latched_mods;
204*4882a593Smuzhiyun         if (map->which_mods & XkbIM_UseLocked)
205*4882a593Smuzhiyun             mods |= state->locked_mods;
206*4882a593Smuzhiyun         if (map->which_mods & XkbIM_UseEffective)
207*4882a593Smuzhiyun             mods |= state->mods;
208*4882a593Smuzhiyun         if (map->which_mods & XkbIM_UseCompat)
209*4882a593Smuzhiyun             mods |= state->compat_state;
210*4882a593Smuzhiyun         on = ((map->mods.mask & mods) != 0);
211*4882a593Smuzhiyun         on = on || ((mods == 0) && (map->mods.mask == 0) &&
212*4882a593Smuzhiyun                     (map->mods.vmods == 0));
213*4882a593Smuzhiyun     }
214*4882a593Smuzhiyun     if (map->which_groups & XkbIM_UseAnyGroup) {
215*4882a593Smuzhiyun         if (map->which_groups & XkbIM_UseBase)
216*4882a593Smuzhiyun             group |= (1L << state->base_group);
217*4882a593Smuzhiyun         if (map->which_groups & XkbIM_UseLatched)
218*4882a593Smuzhiyun             group |= (1L << state->latched_group);
219*4882a593Smuzhiyun         if (map->which_groups & XkbIM_UseLocked)
220*4882a593Smuzhiyun             group |= (1L << state->locked_group);
221*4882a593Smuzhiyun         if (map->which_groups & XkbIM_UseEffective)
222*4882a593Smuzhiyun             group |= (1L << state->group);
223*4882a593Smuzhiyun         on = on || (((map->groups & group) != 0) || (map->groups == 0));
224*4882a593Smuzhiyun     }
225*4882a593Smuzhiyun     if (map->ctrls)
226*4882a593Smuzhiyun         on = on || (ctrls->enabled_ctrls & map->ctrls);
227*4882a593Smuzhiyun     return on;
228*4882a593Smuzhiyun }
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun static void
XkbUpdateLedAutoState(DeviceIntPtr dev,XkbSrvLedInfoPtr sli,unsigned maps_to_check,xkbExtensionDeviceNotify * ed,XkbChangesPtr changes,XkbEventCausePtr cause)231*4882a593Smuzhiyun XkbUpdateLedAutoState(DeviceIntPtr dev,
232*4882a593Smuzhiyun                       XkbSrvLedInfoPtr sli,
233*4882a593Smuzhiyun                       unsigned maps_to_check,
234*4882a593Smuzhiyun                       xkbExtensionDeviceNotify * ed,
235*4882a593Smuzhiyun                       XkbChangesPtr changes, XkbEventCausePtr cause)
236*4882a593Smuzhiyun {
237*4882a593Smuzhiyun     DeviceIntPtr kbd;
238*4882a593Smuzhiyun     XkbStatePtr state;
239*4882a593Smuzhiyun     XkbControlsPtr ctrls;
240*4882a593Smuzhiyun     XkbChangesRec my_changes;
241*4882a593Smuzhiyun     xkbExtensionDeviceNotify my_ed;
242*4882a593Smuzhiyun     register unsigned i, bit, affected;
243*4882a593Smuzhiyun     register XkbIndicatorMapPtr map;
244*4882a593Smuzhiyun     unsigned oldState;
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun     if ((maps_to_check == 0) || (sli->maps == NULL) || (sli->mapsPresent == 0))
247*4882a593Smuzhiyun         return;
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun     if (dev->key && dev->key->xkbInfo)
250*4882a593Smuzhiyun         kbd = dev;
251*4882a593Smuzhiyun     else
252*4882a593Smuzhiyun         kbd = inputInfo.keyboard;
253*4882a593Smuzhiyun 
254*4882a593Smuzhiyun     state = &kbd->key->xkbInfo->state;
255*4882a593Smuzhiyun     ctrls = kbd->key->xkbInfo->desc->ctrls;
256*4882a593Smuzhiyun     affected = maps_to_check;
257*4882a593Smuzhiyun     oldState = sli->effectiveState;
258*4882a593Smuzhiyun     sli->autoState &= ~affected;
259*4882a593Smuzhiyun     for (i = 0, bit = 1; (i < XkbNumIndicators) && (affected); i++, bit <<= 1) {
260*4882a593Smuzhiyun         if ((affected & bit) == 0)
261*4882a593Smuzhiyun             continue;
262*4882a593Smuzhiyun         affected &= ~bit;
263*4882a593Smuzhiyun         map = &sli->maps[i];
264*4882a593Smuzhiyun         if ((!(map->flags & XkbIM_NoAutomatic)) &&
265*4882a593Smuzhiyun             ComputeAutoState(map, state, ctrls))
266*4882a593Smuzhiyun             sli->autoState |= bit;
267*4882a593Smuzhiyun     }
268*4882a593Smuzhiyun     sli->effectiveState = (sli->autoState | sli->explicitState);
269*4882a593Smuzhiyun     affected = sli->effectiveState ^ oldState;
270*4882a593Smuzhiyun     if (affected == 0)
271*4882a593Smuzhiyun         return;
272*4882a593Smuzhiyun 
273*4882a593Smuzhiyun     if (ed == NULL) {
274*4882a593Smuzhiyun         ed = &my_ed;
275*4882a593Smuzhiyun         memset((char *) ed, 0, sizeof(xkbExtensionDeviceNotify));
276*4882a593Smuzhiyun     }
277*4882a593Smuzhiyun     else if ((ed->reason & XkbXI_IndicatorsMask) &&
278*4882a593Smuzhiyun              ((ed->ledClass != sli->class) || (ed->ledID != sli->id))) {
279*4882a593Smuzhiyun         XkbFlushLedEvents(dev, kbd, sli, ed, changes, cause);
280*4882a593Smuzhiyun     }
281*4882a593Smuzhiyun 
282*4882a593Smuzhiyun     if ((kbd == dev) && (sli->flags & XkbSLI_IsDefault)) {
283*4882a593Smuzhiyun         if (changes == NULL) {
284*4882a593Smuzhiyun             changes = &my_changes;
285*4882a593Smuzhiyun             memset((char *) changes, 0, sizeof(XkbChangesRec));
286*4882a593Smuzhiyun         }
287*4882a593Smuzhiyun         changes->indicators.state_changes |= affected;
288*4882a593Smuzhiyun     }
289*4882a593Smuzhiyun 
290*4882a593Smuzhiyun     ed->reason |= XkbXI_IndicatorStateMask;
291*4882a593Smuzhiyun     ed->ledClass = sli->class;
292*4882a593Smuzhiyun     ed->ledID = sli->id;
293*4882a593Smuzhiyun     ed->ledsDefined = sli->namesPresent | sli->mapsPresent;
294*4882a593Smuzhiyun     ed->ledState = sli->effectiveState;
295*4882a593Smuzhiyun     ed->unsupported = 0;
296*4882a593Smuzhiyun     ed->supported = XkbXI_AllFeaturesMask;
297*4882a593Smuzhiyun 
298*4882a593Smuzhiyun     if (changes != &my_changes)
299*4882a593Smuzhiyun         changes = NULL;
300*4882a593Smuzhiyun     if (ed != &my_ed)
301*4882a593Smuzhiyun         ed = NULL;
302*4882a593Smuzhiyun     if (changes || ed)
303*4882a593Smuzhiyun         XkbFlushLedEvents(dev, kbd, sli, ed, changes, cause);
304*4882a593Smuzhiyun     return;
305*4882a593Smuzhiyun }
306*4882a593Smuzhiyun 
307*4882a593Smuzhiyun void
XkbUpdateAllDeviceIndicators(XkbChangesPtr changes,XkbEventCausePtr cause)308*4882a593Smuzhiyun XkbUpdateAllDeviceIndicators(XkbChangesPtr changes, XkbEventCausePtr cause)
309*4882a593Smuzhiyun {
310*4882a593Smuzhiyun     DeviceIntPtr edev;
311*4882a593Smuzhiyun     XkbSrvLedInfoPtr sli;
312*4882a593Smuzhiyun 
313*4882a593Smuzhiyun     for (edev = inputInfo.devices; edev != NULL; edev = edev->next) {
314*4882a593Smuzhiyun         if (edev->kbdfeed) {
315*4882a593Smuzhiyun             KbdFeedbackPtr kf;
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun             for (kf = edev->kbdfeed; kf != NULL; kf = kf->next) {
318*4882a593Smuzhiyun                 if ((kf->xkb_sli == NULL) || (kf->xkb_sli->maps == NULL))
319*4882a593Smuzhiyun                     continue;
320*4882a593Smuzhiyun                 sli = kf->xkb_sli;
321*4882a593Smuzhiyun                 XkbUpdateLedAutoState(edev, sli, sli->mapsPresent, NULL,
322*4882a593Smuzhiyun                                       changes, cause);
323*4882a593Smuzhiyun 
324*4882a593Smuzhiyun             }
325*4882a593Smuzhiyun         }
326*4882a593Smuzhiyun         if (edev->leds) {
327*4882a593Smuzhiyun             LedFeedbackPtr lf;
328*4882a593Smuzhiyun 
329*4882a593Smuzhiyun             for (lf = edev->leds; lf != NULL; lf = lf->next) {
330*4882a593Smuzhiyun                 if ((lf->xkb_sli == NULL) || (lf->xkb_sli->maps == NULL))
331*4882a593Smuzhiyun                     continue;
332*4882a593Smuzhiyun                 sli = lf->xkb_sli;
333*4882a593Smuzhiyun                 XkbUpdateLedAutoState(edev, sli, sli->mapsPresent, NULL,
334*4882a593Smuzhiyun                                       changes, cause);
335*4882a593Smuzhiyun 
336*4882a593Smuzhiyun             }
337*4882a593Smuzhiyun         }
338*4882a593Smuzhiyun     }
339*4882a593Smuzhiyun     return;
340*4882a593Smuzhiyun }
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun /***====================================================================***/
343*4882a593Smuzhiyun 
344*4882a593Smuzhiyun         /*
345*4882a593Smuzhiyun          * void
346*4882a593Smuzhiyun          * XkbSetIndicators(dev,affect,values,cause)
347*4882a593Smuzhiyun          *
348*4882a593Smuzhiyun          * Attempts to change the indicators specified in 'affect' to the
349*4882a593Smuzhiyun          * states specified in 'values' for the default keyboard feedback
350*4882a593Smuzhiyun          * on the keyboard specified by 'dev.'   Attempts to change indicator
351*4882a593Smuzhiyun          * state might be ignored or have no affect, depending on the XKB
352*4882a593Smuzhiyun          * indicator map for any affected indicators, as described in section
353*4882a593Smuzhiyun          * 9.2 of the XKB protocol specification.
354*4882a593Smuzhiyun          *
355*4882a593Smuzhiyun          * If 'changes' is non-NULL, this function notes any changes to the
356*4882a593Smuzhiyun          * keyboard state, controls, or indicator state that result from this
357*4882a593Smuzhiyun          * attempted change.   If 'changes' is NULL, this function generates
358*4882a593Smuzhiyun          * XKB events to report any such changes to interested clients.
359*4882a593Smuzhiyun          *
360*4882a593Smuzhiyun          * If 'cause' is non-NULL, it specifies the reason for the change,
361*4882a593Smuzhiyun          * as reported in some XKB events.   If it is NULL, this function
362*4882a593Smuzhiyun          * assumes that the change is the result of a core protocol
363*4882a593Smuzhiyun          * ChangeKeyboardMapping request.
364*4882a593Smuzhiyun          */
365*4882a593Smuzhiyun 
366*4882a593Smuzhiyun void
XkbSetIndicators(DeviceIntPtr dev,CARD32 affect,CARD32 values,XkbEventCausePtr cause)367*4882a593Smuzhiyun XkbSetIndicators(DeviceIntPtr dev,
368*4882a593Smuzhiyun                  CARD32 affect, CARD32 values, XkbEventCausePtr cause)
369*4882a593Smuzhiyun {
370*4882a593Smuzhiyun     XkbSrvLedInfoPtr sli;
371*4882a593Smuzhiyun     XkbChangesRec changes;
372*4882a593Smuzhiyun     xkbExtensionDeviceNotify ed;
373*4882a593Smuzhiyun     unsigned side_affected;
374*4882a593Smuzhiyun 
375*4882a593Smuzhiyun     memset((char *) &changes, 0, sizeof(XkbChangesRec));
376*4882a593Smuzhiyun     memset((char *) &ed, 0, sizeof(xkbExtensionDeviceNotify));
377*4882a593Smuzhiyun     sli = XkbFindSrvLedInfo(dev, XkbDfltXIClass, XkbDfltXIId, 0);
378*4882a593Smuzhiyun     sli->explicitState &= ~affect;
379*4882a593Smuzhiyun     sli->explicitState |= (affect & values);
380*4882a593Smuzhiyun     XkbApplyLedStateChanges(dev, sli, affect, &ed, &changes, cause);
381*4882a593Smuzhiyun 
382*4882a593Smuzhiyun     side_affected = 0;
383*4882a593Smuzhiyun     if (changes.state_changes != 0)
384*4882a593Smuzhiyun         side_affected |=
385*4882a593Smuzhiyun             XkbIndicatorsToUpdate(dev, changes.state_changes, FALSE);
386*4882a593Smuzhiyun     if (changes.ctrls.enabled_ctrls_changes)
387*4882a593Smuzhiyun         side_affected |= sli->usesControls;
388*4882a593Smuzhiyun 
389*4882a593Smuzhiyun     if (side_affected) {
390*4882a593Smuzhiyun         XkbUpdateLedAutoState(dev, sli, side_affected, &ed, &changes, cause);
391*4882a593Smuzhiyun         affect |= side_affected;
392*4882a593Smuzhiyun     }
393*4882a593Smuzhiyun     if (changes.state_changes || changes.ctrls.enabled_ctrls_changes)
394*4882a593Smuzhiyun         XkbUpdateAllDeviceIndicators(NULL, cause);
395*4882a593Smuzhiyun 
396*4882a593Smuzhiyun     XkbFlushLedEvents(dev, dev, sli, &ed, &changes, cause);
397*4882a593Smuzhiyun     return;
398*4882a593Smuzhiyun }
399*4882a593Smuzhiyun 
400*4882a593Smuzhiyun /***====================================================================***/
401*4882a593Smuzhiyun 
402*4882a593Smuzhiyun /***====================================================================***/
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun         /*
405*4882a593Smuzhiyun          * void
406*4882a593Smuzhiyun          * XkbUpdateIndicators(dev,update,check_edevs,changes,cause)
407*4882a593Smuzhiyun          *
408*4882a593Smuzhiyun          * Applies the indicator maps for any indicators specified in
409*4882a593Smuzhiyun          * 'update' from the default keyboard feedback on the device
410*4882a593Smuzhiyun          * specified by 'dev.'
411*4882a593Smuzhiyun          *
412*4882a593Smuzhiyun          * If 'changes' is NULL, this function generates and XKB events
413*4882a593Smuzhiyun          * required to report the necessary changes, otherwise it simply
414*4882a593Smuzhiyun          * notes the indicators with changed state.
415*4882a593Smuzhiyun          *
416*4882a593Smuzhiyun          * If 'check_edevs' is TRUE, this function also checks the indicator
417*4882a593Smuzhiyun          * maps for any open extension devices that have them, and updates
418*4882a593Smuzhiyun          * the state of any extension device indicators as necessary.
419*4882a593Smuzhiyun          */
420*4882a593Smuzhiyun 
421*4882a593Smuzhiyun void
XkbUpdateIndicators(DeviceIntPtr dev,register CARD32 update,Bool check_edevs,XkbChangesPtr changes,XkbEventCausePtr cause)422*4882a593Smuzhiyun XkbUpdateIndicators(DeviceIntPtr dev,
423*4882a593Smuzhiyun                     register CARD32 update,
424*4882a593Smuzhiyun                     Bool check_edevs,
425*4882a593Smuzhiyun                     XkbChangesPtr changes, XkbEventCausePtr cause)
426*4882a593Smuzhiyun {
427*4882a593Smuzhiyun     XkbSrvLedInfoPtr sli;
428*4882a593Smuzhiyun 
429*4882a593Smuzhiyun     sli = XkbFindSrvLedInfo(dev, XkbDfltXIClass, XkbDfltXIId, 0);
430*4882a593Smuzhiyun     XkbUpdateLedAutoState(dev, sli, update, NULL, changes, cause);
431*4882a593Smuzhiyun     if (check_edevs)
432*4882a593Smuzhiyun         XkbUpdateAllDeviceIndicators(changes, cause);
433*4882a593Smuzhiyun     return;
434*4882a593Smuzhiyun }
435*4882a593Smuzhiyun 
436*4882a593Smuzhiyun /***====================================================================***/
437*4882a593Smuzhiyun 
438*4882a593Smuzhiyun /***====================================================================***/
439*4882a593Smuzhiyun 
440*4882a593Smuzhiyun         /*
441*4882a593Smuzhiyun          * void
442*4882a593Smuzhiyun          * XkbCheckIndicatorMaps(dev,sli,which)
443*4882a593Smuzhiyun          *
444*4882a593Smuzhiyun          * Updates the 'indicator accelerators' for the indicators specified
445*4882a593Smuzhiyun          * by 'which' in the feedback specified by 'sli.' The indicator
446*4882a593Smuzhiyun          * accelerators are internal to the server and are used to simplify
447*4882a593Smuzhiyun          * and speed up the process of figuring out which indicators might
448*4882a593Smuzhiyun          * be affected by a particular change in keyboard state or controls.
449*4882a593Smuzhiyun          */
450*4882a593Smuzhiyun 
451*4882a593Smuzhiyun void
XkbCheckIndicatorMaps(DeviceIntPtr dev,XkbSrvLedInfoPtr sli,unsigned which)452*4882a593Smuzhiyun XkbCheckIndicatorMaps(DeviceIntPtr dev, XkbSrvLedInfoPtr sli, unsigned which)
453*4882a593Smuzhiyun {
454*4882a593Smuzhiyun     register unsigned i, bit;
455*4882a593Smuzhiyun     XkbIndicatorMapPtr map;
456*4882a593Smuzhiyun     XkbDescPtr xkb;
457*4882a593Smuzhiyun 
458*4882a593Smuzhiyun     if ((sli->flags & XkbSLI_HasOwnState) == 0)
459*4882a593Smuzhiyun         return;
460*4882a593Smuzhiyun 
461*4882a593Smuzhiyun     sli->usesBase &= ~which;
462*4882a593Smuzhiyun     sli->usesLatched &= ~which;
463*4882a593Smuzhiyun     sli->usesLocked &= ~which;
464*4882a593Smuzhiyun     sli->usesEffective &= ~which;
465*4882a593Smuzhiyun     sli->usesCompat &= ~which;
466*4882a593Smuzhiyun     sli->usesControls &= ~which;
467*4882a593Smuzhiyun     sli->mapsPresent &= ~which;
468*4882a593Smuzhiyun 
469*4882a593Smuzhiyun     xkb = dev->key->xkbInfo->desc;
470*4882a593Smuzhiyun     for (i = 0, bit = 1, map = sli->maps; i < XkbNumIndicators;
471*4882a593Smuzhiyun          i++, bit <<= 1, map++) {
472*4882a593Smuzhiyun         if (which & bit) {
473*4882a593Smuzhiyun             CARD8 what;
474*4882a593Smuzhiyun 
475*4882a593Smuzhiyun             if (!map || !XkbIM_InUse(map))
476*4882a593Smuzhiyun                 continue;
477*4882a593Smuzhiyun             sli->mapsPresent |= bit;
478*4882a593Smuzhiyun 
479*4882a593Smuzhiyun             what = (map->which_mods | map->which_groups);
480*4882a593Smuzhiyun             if (what & XkbIM_UseBase)
481*4882a593Smuzhiyun                 sli->usesBase |= bit;
482*4882a593Smuzhiyun             if (what & XkbIM_UseLatched)
483*4882a593Smuzhiyun                 sli->usesLatched |= bit;
484*4882a593Smuzhiyun             if (what & XkbIM_UseLocked)
485*4882a593Smuzhiyun                 sli->usesLocked |= bit;
486*4882a593Smuzhiyun             if (what & XkbIM_UseEffective)
487*4882a593Smuzhiyun                 sli->usesEffective |= bit;
488*4882a593Smuzhiyun             if (what & XkbIM_UseCompat)
489*4882a593Smuzhiyun                 sli->usesCompat |= bit;
490*4882a593Smuzhiyun             if (map->ctrls)
491*4882a593Smuzhiyun                 sli->usesControls |= bit;
492*4882a593Smuzhiyun 
493*4882a593Smuzhiyun             map->mods.mask = map->mods.real_mods;
494*4882a593Smuzhiyun             if (map->mods.vmods != 0) {
495*4882a593Smuzhiyun                 map->mods.mask |= XkbMaskForVMask(xkb, map->mods.vmods);
496*4882a593Smuzhiyun             }
497*4882a593Smuzhiyun         }
498*4882a593Smuzhiyun     }
499*4882a593Smuzhiyun     sli->usedComponents = 0;
500*4882a593Smuzhiyun     if (sli->usesBase)
501*4882a593Smuzhiyun         sli->usedComponents |= XkbModifierBaseMask | XkbGroupBaseMask;
502*4882a593Smuzhiyun     if (sli->usesLatched)
503*4882a593Smuzhiyun         sli->usedComponents |= XkbModifierLatchMask | XkbGroupLatchMask;
504*4882a593Smuzhiyun     if (sli->usesLocked)
505*4882a593Smuzhiyun         sli->usedComponents |= XkbModifierLockMask | XkbGroupLockMask;
506*4882a593Smuzhiyun     if (sli->usesEffective)
507*4882a593Smuzhiyun         sli->usedComponents |= XkbModifierStateMask | XkbGroupStateMask;
508*4882a593Smuzhiyun     if (sli->usesCompat)
509*4882a593Smuzhiyun         sli->usedComponents |= XkbCompatStateMask;
510*4882a593Smuzhiyun     return;
511*4882a593Smuzhiyun }
512*4882a593Smuzhiyun 
513*4882a593Smuzhiyun /***====================================================================***/
514*4882a593Smuzhiyun 
515*4882a593Smuzhiyun         /*
516*4882a593Smuzhiyun          * XkbSrvLedInfoPtr
517*4882a593Smuzhiyun          * XkbAllocSrvLedInfo(dev,kf,lf,needed_parts)
518*4882a593Smuzhiyun          *
519*4882a593Smuzhiyun          * Allocates an XkbSrvLedInfoPtr for the feedback specified by either
520*4882a593Smuzhiyun          * 'kf' or 'lf' on the keyboard specified by 'dev.'
521*4882a593Smuzhiyun          *
522*4882a593Smuzhiyun          * If 'needed_parts' is non-zero, this function makes sure that any
523*4882a593Smuzhiyun          * of the parts speicified therein are allocated.
524*4882a593Smuzhiyun          */
525*4882a593Smuzhiyun XkbSrvLedInfoPtr
XkbAllocSrvLedInfo(DeviceIntPtr dev,KbdFeedbackPtr kf,LedFeedbackPtr lf,unsigned needed_parts)526*4882a593Smuzhiyun XkbAllocSrvLedInfo(DeviceIntPtr dev,
527*4882a593Smuzhiyun                    KbdFeedbackPtr kf, LedFeedbackPtr lf, unsigned needed_parts)
528*4882a593Smuzhiyun {
529*4882a593Smuzhiyun     XkbSrvLedInfoPtr sli;
530*4882a593Smuzhiyun     Bool checkAccel;
531*4882a593Smuzhiyun     Bool checkNames;
532*4882a593Smuzhiyun 
533*4882a593Smuzhiyun     sli = NULL;
534*4882a593Smuzhiyun     checkAccel = checkNames = FALSE;
535*4882a593Smuzhiyun     if ((kf != NULL) && (kf->xkb_sli == NULL)) {
536*4882a593Smuzhiyun         kf->xkb_sli = sli = calloc(1, sizeof(XkbSrvLedInfoRec));
537*4882a593Smuzhiyun         if (sli == NULL)
538*4882a593Smuzhiyun             return NULL;        /* ALLOCATION ERROR */
539*4882a593Smuzhiyun         if (dev->key && dev->key->xkbInfo)
540*4882a593Smuzhiyun             sli->flags = XkbSLI_HasOwnState;
541*4882a593Smuzhiyun         else
542*4882a593Smuzhiyun             sli->flags = 0;
543*4882a593Smuzhiyun         sli->class = KbdFeedbackClass;
544*4882a593Smuzhiyun         sli->id = kf->ctrl.id;
545*4882a593Smuzhiyun         sli->fb.kf = kf;
546*4882a593Smuzhiyun 
547*4882a593Smuzhiyun         sli->autoState = 0;
548*4882a593Smuzhiyun         sli->explicitState = kf->ctrl.leds;
549*4882a593Smuzhiyun         sli->effectiveState = kf->ctrl.leds;
550*4882a593Smuzhiyun 
551*4882a593Smuzhiyun         if ((kf == dev->kbdfeed) && (dev->key) && (dev->key->xkbInfo)) {
552*4882a593Smuzhiyun             XkbDescPtr xkb;
553*4882a593Smuzhiyun 
554*4882a593Smuzhiyun             xkb = dev->key->xkbInfo->desc;
555*4882a593Smuzhiyun             sli->flags |= XkbSLI_IsDefault;
556*4882a593Smuzhiyun             sli->physIndicators = xkb->indicators->phys_indicators;
557*4882a593Smuzhiyun             sli->names = xkb->names->indicators;
558*4882a593Smuzhiyun             sli->maps = xkb->indicators->maps;
559*4882a593Smuzhiyun             checkNames = checkAccel = TRUE;
560*4882a593Smuzhiyun         }
561*4882a593Smuzhiyun         else {
562*4882a593Smuzhiyun             sli->physIndicators = XkbAllIndicatorsMask;
563*4882a593Smuzhiyun             sli->names = NULL;
564*4882a593Smuzhiyun             sli->maps = NULL;
565*4882a593Smuzhiyun         }
566*4882a593Smuzhiyun     }
567*4882a593Smuzhiyun     else if ((kf != NULL) && ((kf->xkb_sli->flags & XkbSLI_IsDefault) != 0)) {
568*4882a593Smuzhiyun         XkbDescPtr xkb;
569*4882a593Smuzhiyun 
570*4882a593Smuzhiyun         xkb = dev->key->xkbInfo->desc;
571*4882a593Smuzhiyun         sli = kf->xkb_sli;
572*4882a593Smuzhiyun         sli->physIndicators = xkb->indicators->phys_indicators;
573*4882a593Smuzhiyun         if (xkb->names->indicators != sli->names) {
574*4882a593Smuzhiyun             checkNames = TRUE;
575*4882a593Smuzhiyun             sli->names = xkb->names->indicators;
576*4882a593Smuzhiyun         }
577*4882a593Smuzhiyun         if (xkb->indicators->maps != sli->maps) {
578*4882a593Smuzhiyun             checkAccel = TRUE;
579*4882a593Smuzhiyun             sli->maps = xkb->indicators->maps;
580*4882a593Smuzhiyun         }
581*4882a593Smuzhiyun     }
582*4882a593Smuzhiyun     else if ((lf != NULL) && (lf->xkb_sli == NULL)) {
583*4882a593Smuzhiyun         lf->xkb_sli = sli = calloc(1, sizeof(XkbSrvLedInfoRec));
584*4882a593Smuzhiyun         if (sli == NULL)
585*4882a593Smuzhiyun             return NULL;        /* ALLOCATION ERROR */
586*4882a593Smuzhiyun         if (dev->key && dev->key->xkbInfo)
587*4882a593Smuzhiyun             sli->flags = XkbSLI_HasOwnState;
588*4882a593Smuzhiyun         else
589*4882a593Smuzhiyun             sli->flags = 0;
590*4882a593Smuzhiyun         sli->class = LedFeedbackClass;
591*4882a593Smuzhiyun         sli->id = lf->ctrl.id;
592*4882a593Smuzhiyun         sli->fb.lf = lf;
593*4882a593Smuzhiyun 
594*4882a593Smuzhiyun         sli->physIndicators = lf->ctrl.led_mask;
595*4882a593Smuzhiyun         sli->autoState = 0;
596*4882a593Smuzhiyun         sli->explicitState = lf->ctrl.led_values;
597*4882a593Smuzhiyun         sli->effectiveState = lf->ctrl.led_values;
598*4882a593Smuzhiyun         sli->maps = NULL;
599*4882a593Smuzhiyun         sli->names = NULL;
600*4882a593Smuzhiyun     }
601*4882a593Smuzhiyun     else
602*4882a593Smuzhiyun         return NULL;
603*4882a593Smuzhiyun     if ((sli->names == NULL) && (needed_parts & XkbXI_IndicatorNamesMask))
604*4882a593Smuzhiyun         sli->names = calloc(XkbNumIndicators, sizeof(Atom));
605*4882a593Smuzhiyun     if ((sli->maps == NULL) && (needed_parts & XkbXI_IndicatorMapsMask))
606*4882a593Smuzhiyun         sli->maps = calloc(XkbNumIndicators, sizeof(XkbIndicatorMapRec));
607*4882a593Smuzhiyun     if (checkNames) {
608*4882a593Smuzhiyun         register unsigned i, bit;
609*4882a593Smuzhiyun 
610*4882a593Smuzhiyun         sli->namesPresent = 0;
611*4882a593Smuzhiyun         for (i = 0, bit = 1; i < XkbNumIndicators; i++, bit <<= 1) {
612*4882a593Smuzhiyun             if (sli->names[i] != None)
613*4882a593Smuzhiyun                 sli->namesPresent |= bit;
614*4882a593Smuzhiyun         }
615*4882a593Smuzhiyun     }
616*4882a593Smuzhiyun     if (checkAccel)
617*4882a593Smuzhiyun         XkbCheckIndicatorMaps(dev, sli, XkbAllIndicatorsMask);
618*4882a593Smuzhiyun     return sli;
619*4882a593Smuzhiyun }
620*4882a593Smuzhiyun 
621*4882a593Smuzhiyun void
XkbFreeSrvLedInfo(XkbSrvLedInfoPtr sli)622*4882a593Smuzhiyun XkbFreeSrvLedInfo(XkbSrvLedInfoPtr sli)
623*4882a593Smuzhiyun {
624*4882a593Smuzhiyun     if ((sli->flags & XkbSLI_IsDefault) == 0) {
625*4882a593Smuzhiyun         free(sli->maps);
626*4882a593Smuzhiyun         free(sli->names);
627*4882a593Smuzhiyun     }
628*4882a593Smuzhiyun     sli->maps = NULL;
629*4882a593Smuzhiyun     sli->names = NULL;
630*4882a593Smuzhiyun     free(sli);
631*4882a593Smuzhiyun     return;
632*4882a593Smuzhiyun }
633*4882a593Smuzhiyun 
634*4882a593Smuzhiyun /*
635*4882a593Smuzhiyun  * XkbSrvLedInfoPtr
636*4882a593Smuzhiyun  * XkbCopySrvLedInfo(dev,src,kf,lf)
637*4882a593Smuzhiyun  *
638*4882a593Smuzhiyun  * Takes the given XkbSrvLedInfoPtr and duplicates it. A deep copy is made,
639*4882a593Smuzhiyun  * thus the new copy behaves like the original one and can be freed with
640*4882a593Smuzhiyun  * XkbFreeSrvLedInfo.
641*4882a593Smuzhiyun  */
642*4882a593Smuzhiyun XkbSrvLedInfoPtr
XkbCopySrvLedInfo(DeviceIntPtr from,XkbSrvLedInfoPtr src,KbdFeedbackPtr kf,LedFeedbackPtr lf)643*4882a593Smuzhiyun XkbCopySrvLedInfo(DeviceIntPtr from,
644*4882a593Smuzhiyun                   XkbSrvLedInfoPtr src, KbdFeedbackPtr kf, LedFeedbackPtr lf)
645*4882a593Smuzhiyun {
646*4882a593Smuzhiyun     XkbSrvLedInfoPtr sli_new = NULL;
647*4882a593Smuzhiyun 
648*4882a593Smuzhiyun     if (!src)
649*4882a593Smuzhiyun         goto finish;
650*4882a593Smuzhiyun 
651*4882a593Smuzhiyun     sli_new = calloc(1, sizeof(XkbSrvLedInfoRec));
652*4882a593Smuzhiyun     if (!sli_new)
653*4882a593Smuzhiyun         goto finish;
654*4882a593Smuzhiyun 
655*4882a593Smuzhiyun     memcpy(sli_new, src, sizeof(XkbSrvLedInfoRec));
656*4882a593Smuzhiyun     if (sli_new->class == KbdFeedbackClass)
657*4882a593Smuzhiyun         sli_new->fb.kf = kf;
658*4882a593Smuzhiyun     else
659*4882a593Smuzhiyun         sli_new->fb.lf = lf;
660*4882a593Smuzhiyun 
661*4882a593Smuzhiyun     if (!(sli_new->flags & XkbSLI_IsDefault)) {
662*4882a593Smuzhiyun         sli_new->names = calloc(XkbNumIndicators, sizeof(Atom));
663*4882a593Smuzhiyun         sli_new->maps = calloc(XkbNumIndicators, sizeof(XkbIndicatorMapRec));
664*4882a593Smuzhiyun     }                           /* else sli_new->names/maps is pointing to
665*4882a593Smuzhiyun                                    dev->key->xkbInfo->desc->names->indicators;
666*4882a593Smuzhiyun                                    dev->key->xkbInfo->desc->names->indicators; */
667*4882a593Smuzhiyun 
668*4882a593Smuzhiyun  finish:
669*4882a593Smuzhiyun     return sli_new;
670*4882a593Smuzhiyun }
671*4882a593Smuzhiyun 
672*4882a593Smuzhiyun /***====================================================================***/
673*4882a593Smuzhiyun 
674*4882a593Smuzhiyun         /*
675*4882a593Smuzhiyun          * XkbSrvLedInfoPtr
676*4882a593Smuzhiyun          * XkbFindSrvLedInfo(dev,class,id,needed_parts)
677*4882a593Smuzhiyun          *
678*4882a593Smuzhiyun          * Finds the XkbSrvLedInfoPtr for the specified 'class' and 'id'
679*4882a593Smuzhiyun          * on the device specified by 'dev.'   If the class and id specify
680*4882a593Smuzhiyun          * a valid device feedback, this function returns the existing
681*4882a593Smuzhiyun          * feedback or allocates a new one.
682*4882a593Smuzhiyun          *
683*4882a593Smuzhiyun          */
684*4882a593Smuzhiyun 
685*4882a593Smuzhiyun XkbSrvLedInfoPtr
XkbFindSrvLedInfo(DeviceIntPtr dev,unsigned class,unsigned id,unsigned needed_parts)686*4882a593Smuzhiyun XkbFindSrvLedInfo(DeviceIntPtr dev,
687*4882a593Smuzhiyun                   unsigned class, unsigned id, unsigned needed_parts)
688*4882a593Smuzhiyun {
689*4882a593Smuzhiyun     XkbSrvLedInfoPtr sli;
690*4882a593Smuzhiyun 
691*4882a593Smuzhiyun     /* optimization to check for most common case */
692*4882a593Smuzhiyun     if (((class == XkbDfltXIClass) && (id == XkbDfltXIId)) && (dev->kbdfeed)) {
693*4882a593Smuzhiyun         if (dev->kbdfeed->xkb_sli == NULL) {
694*4882a593Smuzhiyun             dev->kbdfeed->xkb_sli =
695*4882a593Smuzhiyun                 XkbAllocSrvLedInfo(dev, dev->kbdfeed, NULL, needed_parts);
696*4882a593Smuzhiyun         }
697*4882a593Smuzhiyun         return dev->kbdfeed->xkb_sli;
698*4882a593Smuzhiyun     }
699*4882a593Smuzhiyun 
700*4882a593Smuzhiyun     sli = NULL;
701*4882a593Smuzhiyun     if (class == XkbDfltXIClass) {
702*4882a593Smuzhiyun         if (dev->kbdfeed)
703*4882a593Smuzhiyun             class = KbdFeedbackClass;
704*4882a593Smuzhiyun         else if (dev->leds)
705*4882a593Smuzhiyun             class = LedFeedbackClass;
706*4882a593Smuzhiyun         else
707*4882a593Smuzhiyun             return NULL;
708*4882a593Smuzhiyun     }
709*4882a593Smuzhiyun     if (class == KbdFeedbackClass) {
710*4882a593Smuzhiyun         KbdFeedbackPtr kf;
711*4882a593Smuzhiyun 
712*4882a593Smuzhiyun         for (kf = dev->kbdfeed; kf != NULL; kf = kf->next) {
713*4882a593Smuzhiyun             if ((id == XkbDfltXIId) || (id == kf->ctrl.id)) {
714*4882a593Smuzhiyun                 if (kf->xkb_sli == NULL)
715*4882a593Smuzhiyun                     kf->xkb_sli =
716*4882a593Smuzhiyun                         XkbAllocSrvLedInfo(dev, kf, NULL, needed_parts);
717*4882a593Smuzhiyun                 sli = kf->xkb_sli;
718*4882a593Smuzhiyun                 break;
719*4882a593Smuzhiyun             }
720*4882a593Smuzhiyun         }
721*4882a593Smuzhiyun     }
722*4882a593Smuzhiyun     else if (class == LedFeedbackClass) {
723*4882a593Smuzhiyun         LedFeedbackPtr lf;
724*4882a593Smuzhiyun 
725*4882a593Smuzhiyun         for (lf = dev->leds; lf != NULL; lf = lf->next) {
726*4882a593Smuzhiyun             if ((id == XkbDfltXIId) || (id == lf->ctrl.id)) {
727*4882a593Smuzhiyun                 if (lf->xkb_sli == NULL)
728*4882a593Smuzhiyun                     lf->xkb_sli =
729*4882a593Smuzhiyun                         XkbAllocSrvLedInfo(dev, NULL, lf, needed_parts);
730*4882a593Smuzhiyun                 sli = lf->xkb_sli;
731*4882a593Smuzhiyun                 break;
732*4882a593Smuzhiyun             }
733*4882a593Smuzhiyun         }
734*4882a593Smuzhiyun     }
735*4882a593Smuzhiyun     if (sli) {
736*4882a593Smuzhiyun         if ((sli->names == NULL) && (needed_parts & XkbXI_IndicatorNamesMask))
737*4882a593Smuzhiyun             sli->names = calloc(XkbNumIndicators, sizeof(Atom));
738*4882a593Smuzhiyun         if ((sli->maps == NULL) && (needed_parts & XkbXI_IndicatorMapsMask))
739*4882a593Smuzhiyun             sli->maps = calloc(XkbNumIndicators, sizeof(XkbIndicatorMapRec));
740*4882a593Smuzhiyun     }
741*4882a593Smuzhiyun     return sli;
742*4882a593Smuzhiyun }
743*4882a593Smuzhiyun 
744*4882a593Smuzhiyun /***====================================================================***/
745*4882a593Smuzhiyun 
746*4882a593Smuzhiyun void
XkbFlushLedEvents(DeviceIntPtr dev,DeviceIntPtr kbd,XkbSrvLedInfoPtr sli,xkbExtensionDeviceNotify * ed,XkbChangesPtr changes,XkbEventCausePtr cause)747*4882a593Smuzhiyun XkbFlushLedEvents(DeviceIntPtr dev,
748*4882a593Smuzhiyun                   DeviceIntPtr kbd,
749*4882a593Smuzhiyun                   XkbSrvLedInfoPtr sli,
750*4882a593Smuzhiyun                   xkbExtensionDeviceNotify * ed,
751*4882a593Smuzhiyun                   XkbChangesPtr changes, XkbEventCausePtr cause)
752*4882a593Smuzhiyun {
753*4882a593Smuzhiyun     if (changes) {
754*4882a593Smuzhiyun         if (changes->indicators.state_changes)
755*4882a593Smuzhiyun             XkbDDXUpdateDeviceIndicators(dev, sli, sli->effectiveState);
756*4882a593Smuzhiyun         XkbSendNotification(kbd, changes, cause);
757*4882a593Smuzhiyun         memset((char *) changes, 0, sizeof(XkbChangesRec));
758*4882a593Smuzhiyun 
759*4882a593Smuzhiyun         if (XkbAX_NeedFeedback
760*4882a593Smuzhiyun             (kbd->key->xkbInfo->desc->ctrls, XkbAX_IndicatorFBMask)) {
761*4882a593Smuzhiyun             if (sli->effectiveState)
762*4882a593Smuzhiyun                 /* it appears that the which parameter is not used */
763*4882a593Smuzhiyun                 XkbDDXAccessXBeep(dev, _BEEP_LED_ON, XkbAccessXFeedbackMask);
764*4882a593Smuzhiyun             else
765*4882a593Smuzhiyun                 XkbDDXAccessXBeep(dev, _BEEP_LED_OFF, XkbAccessXFeedbackMask);
766*4882a593Smuzhiyun         }
767*4882a593Smuzhiyun     }
768*4882a593Smuzhiyun     if (ed) {
769*4882a593Smuzhiyun         if (ed->reason) {
770*4882a593Smuzhiyun             if ((dev != kbd) && (ed->reason & XkbXI_IndicatorStateMask))
771*4882a593Smuzhiyun                 XkbDDXUpdateDeviceIndicators(dev, sli, sli->effectiveState);
772*4882a593Smuzhiyun             XkbSendExtensionDeviceNotify(dev, cause->client, ed);
773*4882a593Smuzhiyun         }
774*4882a593Smuzhiyun         memset((char *) ed, 0, sizeof(XkbExtensionDeviceNotify));
775*4882a593Smuzhiyun     }
776*4882a593Smuzhiyun     return;
777*4882a593Smuzhiyun }
778*4882a593Smuzhiyun 
779*4882a593Smuzhiyun /***====================================================================***/
780*4882a593Smuzhiyun 
781*4882a593Smuzhiyun void
XkbApplyLedNameChanges(DeviceIntPtr dev,XkbSrvLedInfoPtr sli,unsigned changed_names,xkbExtensionDeviceNotify * ed,XkbChangesPtr changes,XkbEventCausePtr cause)782*4882a593Smuzhiyun XkbApplyLedNameChanges(DeviceIntPtr dev,
783*4882a593Smuzhiyun                        XkbSrvLedInfoPtr sli,
784*4882a593Smuzhiyun                        unsigned changed_names,
785*4882a593Smuzhiyun                        xkbExtensionDeviceNotify * ed,
786*4882a593Smuzhiyun                        XkbChangesPtr changes, XkbEventCausePtr cause)
787*4882a593Smuzhiyun {
788*4882a593Smuzhiyun     DeviceIntPtr kbd;
789*4882a593Smuzhiyun     XkbChangesRec my_changes;
790*4882a593Smuzhiyun     xkbExtensionDeviceNotify my_ed;
791*4882a593Smuzhiyun 
792*4882a593Smuzhiyun     if (changed_names == 0)
793*4882a593Smuzhiyun         return;
794*4882a593Smuzhiyun     if (dev->key && dev->key->xkbInfo)
795*4882a593Smuzhiyun         kbd = dev;
796*4882a593Smuzhiyun     else
797*4882a593Smuzhiyun         kbd = inputInfo.keyboard;
798*4882a593Smuzhiyun 
799*4882a593Smuzhiyun     if (ed == NULL) {
800*4882a593Smuzhiyun         ed = &my_ed;
801*4882a593Smuzhiyun         memset((char *) ed, 0, sizeof(xkbExtensionDeviceNotify));
802*4882a593Smuzhiyun     }
803*4882a593Smuzhiyun     else if ((ed->reason & XkbXI_IndicatorsMask) &&
804*4882a593Smuzhiyun              ((ed->ledClass != sli->class) || (ed->ledID != sli->id))) {
805*4882a593Smuzhiyun         XkbFlushLedEvents(dev, kbd, sli, ed, changes, cause);
806*4882a593Smuzhiyun     }
807*4882a593Smuzhiyun 
808*4882a593Smuzhiyun     if ((kbd == dev) && (sli->flags & XkbSLI_IsDefault)) {
809*4882a593Smuzhiyun         if (changes == NULL) {
810*4882a593Smuzhiyun             changes = &my_changes;
811*4882a593Smuzhiyun             memset((char *) changes, 0, sizeof(XkbChangesRec));
812*4882a593Smuzhiyun         }
813*4882a593Smuzhiyun         changes->names.changed |= XkbIndicatorNamesMask;
814*4882a593Smuzhiyun         changes->names.changed_indicators |= changed_names;
815*4882a593Smuzhiyun     }
816*4882a593Smuzhiyun 
817*4882a593Smuzhiyun     ed->reason |= XkbXI_IndicatorNamesMask;
818*4882a593Smuzhiyun     ed->ledClass = sli->class;
819*4882a593Smuzhiyun     ed->ledID = sli->id;
820*4882a593Smuzhiyun     ed->ledsDefined = sli->namesPresent | sli->mapsPresent;
821*4882a593Smuzhiyun     ed->ledState = sli->effectiveState;
822*4882a593Smuzhiyun     ed->unsupported = 0;
823*4882a593Smuzhiyun     ed->supported = XkbXI_AllFeaturesMask;
824*4882a593Smuzhiyun 
825*4882a593Smuzhiyun     if (changes != &my_changes)
826*4882a593Smuzhiyun         changes = NULL;
827*4882a593Smuzhiyun     if (ed != &my_ed)
828*4882a593Smuzhiyun         ed = NULL;
829*4882a593Smuzhiyun     if (changes || ed)
830*4882a593Smuzhiyun         XkbFlushLedEvents(dev, kbd, sli, ed, changes, cause);
831*4882a593Smuzhiyun     return;
832*4882a593Smuzhiyun }
833*4882a593Smuzhiyun 
834*4882a593Smuzhiyun /***====================================================================***/
835*4882a593Smuzhiyun 
836*4882a593Smuzhiyun         /*
837*4882a593Smuzhiyun          * void
838*4882a593Smuzhiyun          * XkbApplyLedMapChanges(dev,sli,changed_maps,changes,cause)
839*4882a593Smuzhiyun          *
840*4882a593Smuzhiyun          * Handles all of the secondary effects of the changes to the
841*4882a593Smuzhiyun          * feedback specified by 'sli' on the device specified by 'dev.'
842*4882a593Smuzhiyun          *
843*4882a593Smuzhiyun          * If 'changed_maps' specifies any indicators, this function generates
844*4882a593Smuzhiyun          * XkbExtensionDeviceNotify events and possibly IndicatorMapNotify
845*4882a593Smuzhiyun          * events to report the changes, and recalculates the effective
846*4882a593Smuzhiyun          * state of each indicator with a changed map.  If any indicators
847*4882a593Smuzhiyun          * change state, the server generates XkbExtensionDeviceNotify and
848*4882a593Smuzhiyun          * XkbIndicatorStateNotify events as appropriate.
849*4882a593Smuzhiyun          *
850*4882a593Smuzhiyun          * If 'changes' is non-NULL, this function updates it to reflect
851*4882a593Smuzhiyun          * any changes to the keyboard state or controls or to the 'core'
852*4882a593Smuzhiyun          * indicator names, maps, or state.   If 'changes' is NULL, this
853*4882a593Smuzhiyun          * function generates XKB events as needed to report the changes.
854*4882a593Smuzhiyun          * If 'dev' is not a keyboard device, any changes are reported
855*4882a593Smuzhiyun          * for the core keyboard.
856*4882a593Smuzhiyun          *
857*4882a593Smuzhiyun          * The 'cause' specifies the reason for the event (key event or
858*4882a593Smuzhiyun          * request) for the change, as reported in some XKB events.
859*4882a593Smuzhiyun          */
860*4882a593Smuzhiyun 
861*4882a593Smuzhiyun void
XkbApplyLedMapChanges(DeviceIntPtr dev,XkbSrvLedInfoPtr sli,unsigned changed_maps,xkbExtensionDeviceNotify * ed,XkbChangesPtr changes,XkbEventCausePtr cause)862*4882a593Smuzhiyun XkbApplyLedMapChanges(DeviceIntPtr dev,
863*4882a593Smuzhiyun                       XkbSrvLedInfoPtr sli,
864*4882a593Smuzhiyun                       unsigned changed_maps,
865*4882a593Smuzhiyun                       xkbExtensionDeviceNotify * ed,
866*4882a593Smuzhiyun                       XkbChangesPtr changes, XkbEventCausePtr cause)
867*4882a593Smuzhiyun {
868*4882a593Smuzhiyun     DeviceIntPtr kbd;
869*4882a593Smuzhiyun     XkbChangesRec my_changes;
870*4882a593Smuzhiyun     xkbExtensionDeviceNotify my_ed;
871*4882a593Smuzhiyun 
872*4882a593Smuzhiyun     if (changed_maps == 0)
873*4882a593Smuzhiyun         return;
874*4882a593Smuzhiyun     if (dev->key && dev->key->xkbInfo)
875*4882a593Smuzhiyun         kbd = dev;
876*4882a593Smuzhiyun     else
877*4882a593Smuzhiyun         kbd = inputInfo.keyboard;
878*4882a593Smuzhiyun 
879*4882a593Smuzhiyun     if (ed == NULL) {
880*4882a593Smuzhiyun         ed = &my_ed;
881*4882a593Smuzhiyun         memset((char *) ed, 0, sizeof(xkbExtensionDeviceNotify));
882*4882a593Smuzhiyun     }
883*4882a593Smuzhiyun     else if ((ed->reason & XkbXI_IndicatorsMask) &&
884*4882a593Smuzhiyun              ((ed->ledClass != sli->class) || (ed->ledID != sli->id))) {
885*4882a593Smuzhiyun         XkbFlushLedEvents(dev, kbd, sli, ed, changes, cause);
886*4882a593Smuzhiyun     }
887*4882a593Smuzhiyun 
888*4882a593Smuzhiyun     if ((kbd == dev) && (sli->flags & XkbSLI_IsDefault)) {
889*4882a593Smuzhiyun         if (changes == NULL) {
890*4882a593Smuzhiyun             changes = &my_changes;
891*4882a593Smuzhiyun             memset((char *) changes, 0, sizeof(XkbChangesRec));
892*4882a593Smuzhiyun         }
893*4882a593Smuzhiyun         changes->indicators.map_changes |= changed_maps;
894*4882a593Smuzhiyun     }
895*4882a593Smuzhiyun 
896*4882a593Smuzhiyun     XkbCheckIndicatorMaps(dev, sli, changed_maps);
897*4882a593Smuzhiyun 
898*4882a593Smuzhiyun     ed->reason |= XkbXI_IndicatorMapsMask;
899*4882a593Smuzhiyun     ed->ledClass = sli->class;
900*4882a593Smuzhiyun     ed->ledID = sli->id;
901*4882a593Smuzhiyun     ed->ledsDefined = sli->namesPresent | sli->mapsPresent;
902*4882a593Smuzhiyun     ed->ledState = sli->effectiveState;
903*4882a593Smuzhiyun     ed->unsupported = 0;
904*4882a593Smuzhiyun     ed->supported = XkbXI_AllFeaturesMask;
905*4882a593Smuzhiyun 
906*4882a593Smuzhiyun     XkbUpdateLedAutoState(dev, sli, changed_maps, ed, changes, cause);
907*4882a593Smuzhiyun 
908*4882a593Smuzhiyun     if (changes != &my_changes)
909*4882a593Smuzhiyun         changes = NULL;
910*4882a593Smuzhiyun     if (ed != &my_ed)
911*4882a593Smuzhiyun         ed = NULL;
912*4882a593Smuzhiyun     if (changes || ed)
913*4882a593Smuzhiyun         XkbFlushLedEvents(dev, kbd, sli, ed, changes, cause);
914*4882a593Smuzhiyun     return;
915*4882a593Smuzhiyun }
916*4882a593Smuzhiyun 
917*4882a593Smuzhiyun /***====================================================================***/
918*4882a593Smuzhiyun 
919*4882a593Smuzhiyun void
XkbApplyLedStateChanges(DeviceIntPtr dev,XkbSrvLedInfoPtr sli,unsigned changed_leds,xkbExtensionDeviceNotify * ed,XkbChangesPtr changes,XkbEventCausePtr cause)920*4882a593Smuzhiyun XkbApplyLedStateChanges(DeviceIntPtr dev,
921*4882a593Smuzhiyun                         XkbSrvLedInfoPtr sli,
922*4882a593Smuzhiyun                         unsigned changed_leds,
923*4882a593Smuzhiyun                         xkbExtensionDeviceNotify * ed,
924*4882a593Smuzhiyun                         XkbChangesPtr changes, XkbEventCausePtr cause)
925*4882a593Smuzhiyun {
926*4882a593Smuzhiyun     XkbSrvInfoPtr xkbi;
927*4882a593Smuzhiyun     DeviceIntPtr kbd;
928*4882a593Smuzhiyun     XkbChangesRec my_changes;
929*4882a593Smuzhiyun     xkbExtensionDeviceNotify my_ed;
930*4882a593Smuzhiyun     register unsigned i, bit, affected;
931*4882a593Smuzhiyun     XkbIndicatorMapPtr map;
932*4882a593Smuzhiyun     unsigned oldState;
933*4882a593Smuzhiyun     Bool kb_changed;
934*4882a593Smuzhiyun 
935*4882a593Smuzhiyun     if (changed_leds == 0)
936*4882a593Smuzhiyun         return;
937*4882a593Smuzhiyun     if (dev->key && dev->key->xkbInfo)
938*4882a593Smuzhiyun         kbd = dev;
939*4882a593Smuzhiyun     else
940*4882a593Smuzhiyun         kbd = inputInfo.keyboard;
941*4882a593Smuzhiyun     xkbi = kbd->key->xkbInfo;
942*4882a593Smuzhiyun 
943*4882a593Smuzhiyun     if (changes == NULL) {
944*4882a593Smuzhiyun         changes = &my_changes;
945*4882a593Smuzhiyun         memset((char *) changes, 0, sizeof(XkbChangesRec));
946*4882a593Smuzhiyun     }
947*4882a593Smuzhiyun 
948*4882a593Smuzhiyun     kb_changed = FALSE;
949*4882a593Smuzhiyun     affected = changed_leds;
950*4882a593Smuzhiyun     oldState = sli->effectiveState;
951*4882a593Smuzhiyun     for (i = 0, bit = 1; (i < XkbNumIndicators) && (affected); i++, bit <<= 1) {
952*4882a593Smuzhiyun         if ((affected & bit) == 0)
953*4882a593Smuzhiyun             continue;
954*4882a593Smuzhiyun         affected &= ~bit;
955*4882a593Smuzhiyun         map = &sli->maps[i];
956*4882a593Smuzhiyun         if (map->flags & XkbIM_NoExplicit) {
957*4882a593Smuzhiyun             sli->explicitState &= ~bit;
958*4882a593Smuzhiyun             continue;
959*4882a593Smuzhiyun         }
960*4882a593Smuzhiyun         if (map->flags & XkbIM_LEDDrivesKB) {
961*4882a593Smuzhiyun             Bool on = ((sli->explicitState & bit) != 0);
962*4882a593Smuzhiyun 
963*4882a593Smuzhiyun             if (XkbApplyLEDChangeToKeyboard(xkbi, map, on, changes))
964*4882a593Smuzhiyun                 kb_changed = TRUE;
965*4882a593Smuzhiyun         }
966*4882a593Smuzhiyun     }
967*4882a593Smuzhiyun     sli->effectiveState = (sli->autoState | sli->explicitState);
968*4882a593Smuzhiyun     affected = sli->effectiveState ^ oldState;
969*4882a593Smuzhiyun 
970*4882a593Smuzhiyun     if (ed == NULL) {
971*4882a593Smuzhiyun         ed = &my_ed;
972*4882a593Smuzhiyun         memset((char *) ed, 0, sizeof(xkbExtensionDeviceNotify));
973*4882a593Smuzhiyun     }
974*4882a593Smuzhiyun     else if (affected && (ed->reason & XkbXI_IndicatorsMask) &&
975*4882a593Smuzhiyun              ((ed->ledClass != sli->class) || (ed->ledID != sli->id))) {
976*4882a593Smuzhiyun         XkbFlushLedEvents(dev, kbd, sli, ed, changes, cause);
977*4882a593Smuzhiyun     }
978*4882a593Smuzhiyun 
979*4882a593Smuzhiyun     if ((kbd == dev) && (sli->flags & XkbSLI_IsDefault))
980*4882a593Smuzhiyun         changes->indicators.state_changes |= affected;
981*4882a593Smuzhiyun     if (affected) {
982*4882a593Smuzhiyun         ed->reason |= XkbXI_IndicatorStateMask;
983*4882a593Smuzhiyun         ed->ledClass = sli->class;
984*4882a593Smuzhiyun         ed->ledID = sli->id;
985*4882a593Smuzhiyun         ed->ledsDefined = sli->namesPresent | sli->mapsPresent;
986*4882a593Smuzhiyun         ed->ledState = sli->effectiveState;
987*4882a593Smuzhiyun         ed->unsupported = 0;
988*4882a593Smuzhiyun         ed->supported = XkbXI_AllFeaturesMask;
989*4882a593Smuzhiyun     }
990*4882a593Smuzhiyun 
991*4882a593Smuzhiyun     if (kb_changed) {
992*4882a593Smuzhiyun         XkbComputeDerivedState(kbd->key->xkbInfo);
993*4882a593Smuzhiyun         XkbUpdateLedAutoState(dev, sli, sli->mapsPresent, ed, changes, cause);
994*4882a593Smuzhiyun     }
995*4882a593Smuzhiyun 
996*4882a593Smuzhiyun     if (changes != &my_changes)
997*4882a593Smuzhiyun         changes = NULL;
998*4882a593Smuzhiyun     if (ed != &my_ed)
999*4882a593Smuzhiyun         ed = NULL;
1000*4882a593Smuzhiyun     if (changes || ed)
1001*4882a593Smuzhiyun         XkbFlushLedEvents(dev, kbd, sli, ed, changes, cause);
1002*4882a593Smuzhiyun     if (kb_changed)
1003*4882a593Smuzhiyun         XkbUpdateAllDeviceIndicators(NULL, cause);
1004*4882a593Smuzhiyun     return;
1005*4882a593Smuzhiyun }
1006