xref: /OK3568_Linux_fs/external/xserver/xkb/XKBMisc.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /************************************************************
2*4882a593Smuzhiyun Copyright (c) 1993 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 <X11/X.h>
33*4882a593Smuzhiyun #include <X11/Xproto.h>
34*4882a593Smuzhiyun #include "misc.h"
35*4882a593Smuzhiyun #include "inputstr.h"
36*4882a593Smuzhiyun #include <X11/keysym.h>
37*4882a593Smuzhiyun #define	XKBSRV_NEED_FILE_FUNCS
38*4882a593Smuzhiyun #include <xkbsrv.h>
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun /***====================================================================***/
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun #define	CORE_SYM(i)	(i<map_width?core_syms[i]:NoSymbol)
43*4882a593Smuzhiyun #define	XKB_OFFSET(g,l)	(((g)*groupsWidth)+(l))
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun int
XkbKeyTypesForCoreSymbols(XkbDescPtr xkb,int map_width,KeySym * core_syms,unsigned int protected,int * types_inout,KeySym * xkb_syms_rtrn)46*4882a593Smuzhiyun XkbKeyTypesForCoreSymbols(XkbDescPtr xkb,
47*4882a593Smuzhiyun                           int map_width,
48*4882a593Smuzhiyun                           KeySym * core_syms,
49*4882a593Smuzhiyun                           unsigned int protected,
50*4882a593Smuzhiyun                           int *types_inout, KeySym * xkb_syms_rtrn)
51*4882a593Smuzhiyun {
52*4882a593Smuzhiyun     register int i;
53*4882a593Smuzhiyun     unsigned int empty;
54*4882a593Smuzhiyun     int nSyms[XkbNumKbdGroups];
55*4882a593Smuzhiyun     int nGroups, tmp, groupsWidth;
56*4882a593Smuzhiyun     BOOL replicated = FALSE;
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun     /* Section 12.2 of the protocol describes this process in more detail */
59*4882a593Smuzhiyun     /* Step 1:  find the # of symbols in the core mapping per group */
60*4882a593Smuzhiyun     groupsWidth = 2;
61*4882a593Smuzhiyun     for (i = 0; i < XkbNumKbdGroups; i++) {
62*4882a593Smuzhiyun         if ((protected & (1 << i)) && (types_inout[i] < xkb->map->num_types)) {
63*4882a593Smuzhiyun             nSyms[i] = xkb->map->types[types_inout[i]].num_levels;
64*4882a593Smuzhiyun             if (nSyms[i] > groupsWidth)
65*4882a593Smuzhiyun                 groupsWidth = nSyms[i];
66*4882a593Smuzhiyun         }
67*4882a593Smuzhiyun         else {
68*4882a593Smuzhiyun             types_inout[i] = XkbTwoLevelIndex;  /* don't really know, yet */
69*4882a593Smuzhiyun             nSyms[i] = 2;
70*4882a593Smuzhiyun         }
71*4882a593Smuzhiyun     }
72*4882a593Smuzhiyun     if (nSyms[XkbGroup1Index] < 2)
73*4882a593Smuzhiyun         nSyms[XkbGroup1Index] = 2;
74*4882a593Smuzhiyun     if (nSyms[XkbGroup2Index] < 2)
75*4882a593Smuzhiyun         nSyms[XkbGroup2Index] = 2;
76*4882a593Smuzhiyun     /* Step 2:  Copy the symbols from the core ordering to XKB ordering */
77*4882a593Smuzhiyun     /*          symbols in the core are in the order:                   */
78*4882a593Smuzhiyun     /*          G1L1 G1L2 G2L1 G2L2 [G1L[3-n]] [G2L[3-n]] [G3L*] [G3L*] */
79*4882a593Smuzhiyun     xkb_syms_rtrn[XKB_OFFSET(XkbGroup1Index, 0)] = CORE_SYM(0);
80*4882a593Smuzhiyun     xkb_syms_rtrn[XKB_OFFSET(XkbGroup1Index, 1)] = CORE_SYM(1);
81*4882a593Smuzhiyun     for (i = 2; i < nSyms[XkbGroup1Index]; i++) {
82*4882a593Smuzhiyun         xkb_syms_rtrn[XKB_OFFSET(XkbGroup1Index, i)] = CORE_SYM(2 + i);
83*4882a593Smuzhiyun     }
84*4882a593Smuzhiyun     xkb_syms_rtrn[XKB_OFFSET(XkbGroup2Index, 0)] = CORE_SYM(2);
85*4882a593Smuzhiyun     xkb_syms_rtrn[XKB_OFFSET(XkbGroup2Index, 1)] = CORE_SYM(3);
86*4882a593Smuzhiyun     tmp = 2 + (nSyms[XkbGroup1Index] - 2);      /* offset to extra group2 syms */
87*4882a593Smuzhiyun     for (i = 2; i < nSyms[XkbGroup2Index]; i++) {
88*4882a593Smuzhiyun         xkb_syms_rtrn[XKB_OFFSET(XkbGroup2Index, i)] = CORE_SYM(tmp + i);
89*4882a593Smuzhiyun     }
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun     /* Special case: if only the first group is explicit, and the symbols
92*4882a593Smuzhiyun      * replicate across all groups, then we have a Section 12.4 replication */
93*4882a593Smuzhiyun     if ((protected & ~XkbExplicitKeyType1Mask) == 0) {
94*4882a593Smuzhiyun         int j, width = nSyms[XkbGroup1Index];
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun         replicated = TRUE;
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun         /* Check ABAB in ABABCDECDEABCDE */
99*4882a593Smuzhiyun         if ((width > 0 && CORE_SYM(0) != CORE_SYM(2)) ||
100*4882a593Smuzhiyun             (width > 1 && CORE_SYM(1) != CORE_SYM(3)))
101*4882a593Smuzhiyun             replicated = FALSE;
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun         /* Check CDECDE in ABABCDECDEABCDE */
104*4882a593Smuzhiyun         for (i = 2; i < width && replicated; i++) {
105*4882a593Smuzhiyun             if (CORE_SYM(2 + i) != CORE_SYM(i + width))
106*4882a593Smuzhiyun                 replicated = FALSE;
107*4882a593Smuzhiyun         }
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun         /* Check ABCDE in ABABCDECDEABCDE */
110*4882a593Smuzhiyun         for (j = 2; replicated &&
111*4882a593Smuzhiyun              j < XkbNumKbdGroups && map_width >= width * (j + 1); j++) {
112*4882a593Smuzhiyun             for (i = 0; i < width && replicated; i++) {
113*4882a593Smuzhiyun                 if (CORE_SYM(((i < 2) ? i : 2 + i)) != CORE_SYM(i + width * j))
114*4882a593Smuzhiyun                     replicated = FALSE;
115*4882a593Smuzhiyun             }
116*4882a593Smuzhiyun         }
117*4882a593Smuzhiyun     }
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun     if (replicated) {
120*4882a593Smuzhiyun         nSyms[XkbGroup2Index] = 0;
121*4882a593Smuzhiyun         nSyms[XkbGroup3Index] = 0;
122*4882a593Smuzhiyun         nSyms[XkbGroup4Index] = 0;
123*4882a593Smuzhiyun         nGroups = 1;
124*4882a593Smuzhiyun     }
125*4882a593Smuzhiyun     else {
126*4882a593Smuzhiyun         tmp = nSyms[XkbGroup1Index] + nSyms[XkbGroup2Index];
127*4882a593Smuzhiyun         if ((tmp >= map_width) &&
128*4882a593Smuzhiyun             ((protected & (XkbExplicitKeyType3Mask | XkbExplicitKeyType4Mask))
129*4882a593Smuzhiyun              == 0)) {
130*4882a593Smuzhiyun             nSyms[XkbGroup3Index] = 0;
131*4882a593Smuzhiyun             nSyms[XkbGroup4Index] = 0;
132*4882a593Smuzhiyun             nGroups = 2;
133*4882a593Smuzhiyun         }
134*4882a593Smuzhiyun         else {
135*4882a593Smuzhiyun             nGroups = 3;
136*4882a593Smuzhiyun             for (i = 0; i < nSyms[XkbGroup3Index]; i++, tmp++) {
137*4882a593Smuzhiyun                 xkb_syms_rtrn[XKB_OFFSET(XkbGroup3Index, i)] = CORE_SYM(tmp);
138*4882a593Smuzhiyun             }
139*4882a593Smuzhiyun             if ((tmp < map_width) || (protected & XkbExplicitKeyType4Mask)) {
140*4882a593Smuzhiyun                 nGroups = 4;
141*4882a593Smuzhiyun                 for (i = 0; i < nSyms[XkbGroup4Index]; i++, tmp++) {
142*4882a593Smuzhiyun                     xkb_syms_rtrn[XKB_OFFSET(XkbGroup4Index, i)] =
143*4882a593Smuzhiyun                         CORE_SYM(tmp);
144*4882a593Smuzhiyun                 }
145*4882a593Smuzhiyun             }
146*4882a593Smuzhiyun             else {
147*4882a593Smuzhiyun                 nSyms[XkbGroup4Index] = 0;
148*4882a593Smuzhiyun             }
149*4882a593Smuzhiyun         }
150*4882a593Smuzhiyun     }
151*4882a593Smuzhiyun     /* steps 3&4: alphanumeric expansion,  assign canonical types */
152*4882a593Smuzhiyun     empty = 0;
153*4882a593Smuzhiyun     for (i = 0; i < nGroups; i++) {
154*4882a593Smuzhiyun         KeySym *syms;
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun         syms = &xkb_syms_rtrn[XKB_OFFSET(i, 0)];
157*4882a593Smuzhiyun         if ((nSyms[i] > 1) && (syms[1] == NoSymbol) && (syms[0] != NoSymbol)) {
158*4882a593Smuzhiyun             KeySym upper, lower;
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun             XkbConvertCase(syms[0], &lower, &upper);
161*4882a593Smuzhiyun             if (upper != lower) {
162*4882a593Smuzhiyun                 xkb_syms_rtrn[XKB_OFFSET(i, 0)] = lower;
163*4882a593Smuzhiyun                 xkb_syms_rtrn[XKB_OFFSET(i, 1)] = upper;
164*4882a593Smuzhiyun                 if ((protected & (1 << i)) == 0)
165*4882a593Smuzhiyun                     types_inout[i] = XkbAlphabeticIndex;
166*4882a593Smuzhiyun             }
167*4882a593Smuzhiyun             else if ((protected & (1 << i)) == 0) {
168*4882a593Smuzhiyun                 types_inout[i] = XkbOneLevelIndex;
169*4882a593Smuzhiyun                 /*      nSyms[i]=       1; */
170*4882a593Smuzhiyun             }
171*4882a593Smuzhiyun         }
172*4882a593Smuzhiyun         if (((protected & (1 << i)) == 0) &&
173*4882a593Smuzhiyun             (types_inout[i] == XkbTwoLevelIndex)) {
174*4882a593Smuzhiyun             if (XkbKSIsKeypad(syms[0]) || XkbKSIsKeypad(syms[1]))
175*4882a593Smuzhiyun                 types_inout[i] = XkbKeypadIndex;
176*4882a593Smuzhiyun             else {
177*4882a593Smuzhiyun                 KeySym upper, lower;
178*4882a593Smuzhiyun 
179*4882a593Smuzhiyun                 XkbConvertCase(syms[0], &lower, &upper);
180*4882a593Smuzhiyun                 if ((syms[0] == lower) && (syms[1] == upper))
181*4882a593Smuzhiyun                     types_inout[i] = XkbAlphabeticIndex;
182*4882a593Smuzhiyun             }
183*4882a593Smuzhiyun         }
184*4882a593Smuzhiyun         if (syms[0] == NoSymbol) {
185*4882a593Smuzhiyun             register int n;
186*4882a593Smuzhiyun             Bool found;
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun             for (n = 1, found = FALSE; (!found) && (n < nSyms[i]); n++) {
189*4882a593Smuzhiyun                 found = (syms[n] != NoSymbol);
190*4882a593Smuzhiyun             }
191*4882a593Smuzhiyun             if (!found)
192*4882a593Smuzhiyun                 empty |= (1 << i);
193*4882a593Smuzhiyun         }
194*4882a593Smuzhiyun     }
195*4882a593Smuzhiyun     /* step 5: squoosh out empty groups */
196*4882a593Smuzhiyun     if (empty) {
197*4882a593Smuzhiyun         for (i = nGroups - 1; i >= 0; i--) {
198*4882a593Smuzhiyun             if (((empty & (1 << i)) == 0) || (protected & (1 << i)))
199*4882a593Smuzhiyun                 break;
200*4882a593Smuzhiyun             nGroups--;
201*4882a593Smuzhiyun         }
202*4882a593Smuzhiyun     }
203*4882a593Smuzhiyun     if (nGroups < 1)
204*4882a593Smuzhiyun         return 0;
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun     /* step 6: replicate group 1 into group two, if necessary */
207*4882a593Smuzhiyun     if ((nGroups > 1) &&
208*4882a593Smuzhiyun         ((empty & (XkbGroup1Mask | XkbGroup2Mask)) == XkbGroup2Mask)) {
209*4882a593Smuzhiyun         if ((protected & (XkbExplicitKeyType1Mask | XkbExplicitKeyType2Mask)) ==
210*4882a593Smuzhiyun             0) {
211*4882a593Smuzhiyun             nSyms[XkbGroup2Index] = nSyms[XkbGroup1Index];
212*4882a593Smuzhiyun             types_inout[XkbGroup2Index] = types_inout[XkbGroup1Index];
213*4882a593Smuzhiyun             memcpy((char *) &xkb_syms_rtrn[2], (char *) xkb_syms_rtrn,
214*4882a593Smuzhiyun                    2 * sizeof(KeySym));
215*4882a593Smuzhiyun         }
216*4882a593Smuzhiyun         else if (types_inout[XkbGroup1Index] == types_inout[XkbGroup2Index]) {
217*4882a593Smuzhiyun             memcpy((char *) &xkb_syms_rtrn[nSyms[XkbGroup1Index]],
218*4882a593Smuzhiyun                    (char *) xkb_syms_rtrn,
219*4882a593Smuzhiyun                    nSyms[XkbGroup1Index] * sizeof(KeySym));
220*4882a593Smuzhiyun         }
221*4882a593Smuzhiyun     }
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun     /* step 7: check for all groups identical or all width 1
224*4882a593Smuzhiyun      *
225*4882a593Smuzhiyun      * Special feature: if group 1 has an explicit type and all other groups
226*4882a593Smuzhiyun      * have canonical types with same symbols, we assume it's info lost from
227*4882a593Smuzhiyun      * the core replication.
228*4882a593Smuzhiyun      */
229*4882a593Smuzhiyun     if (nGroups > 1) {
230*4882a593Smuzhiyun         Bool sameType, allOneLevel, canonical = TRUE;
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun         allOneLevel = (xkb->map->types[types_inout[0]].num_levels == 1);
233*4882a593Smuzhiyun         for (i = 1, sameType = TRUE; (allOneLevel || sameType) && (i < nGroups);
234*4882a593Smuzhiyun              i++) {
235*4882a593Smuzhiyun             sameType = (sameType &&
236*4882a593Smuzhiyun                         (types_inout[i] == types_inout[XkbGroup1Index]));
237*4882a593Smuzhiyun             if (allOneLevel)
238*4882a593Smuzhiyun                 allOneLevel = (xkb->map->types[types_inout[i]].num_levels == 1);
239*4882a593Smuzhiyun             if (types_inout[i] > XkbLastRequiredType)
240*4882a593Smuzhiyun                 canonical = FALSE;
241*4882a593Smuzhiyun         }
242*4882a593Smuzhiyun         if (((sameType) || canonical) &&
243*4882a593Smuzhiyun             (!(protected &
244*4882a593Smuzhiyun                (XkbExplicitKeyTypesMask & ~XkbExplicitKeyType1Mask)))) {
245*4882a593Smuzhiyun             register int s;
246*4882a593Smuzhiyun             Bool identical;
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun             for (i = 1, identical = TRUE; identical && (i < nGroups); i++) {
249*4882a593Smuzhiyun                 KeySym *syms;
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun                 if (nSyms[i] != nSyms[XkbGroup1Index])
252*4882a593Smuzhiyun                     identical = FALSE;
253*4882a593Smuzhiyun                 syms = &xkb_syms_rtrn[XKB_OFFSET(i, 0)];
254*4882a593Smuzhiyun                 for (s = 0; identical && (s < nSyms[i]); s++) {
255*4882a593Smuzhiyun                     if (syms[s] != xkb_syms_rtrn[s])
256*4882a593Smuzhiyun                         identical = FALSE;
257*4882a593Smuzhiyun                 }
258*4882a593Smuzhiyun             }
259*4882a593Smuzhiyun             if (identical)
260*4882a593Smuzhiyun                 nGroups = 1;
261*4882a593Smuzhiyun         }
262*4882a593Smuzhiyun         if (allOneLevel && (nGroups > 1)) {
263*4882a593Smuzhiyun             KeySym *syms;
264*4882a593Smuzhiyun 
265*4882a593Smuzhiyun             syms = &xkb_syms_rtrn[nSyms[XkbGroup1Index]];
266*4882a593Smuzhiyun             nSyms[XkbGroup1Index] = 1;
267*4882a593Smuzhiyun             for (i = 1; i < nGroups; i++) {
268*4882a593Smuzhiyun                 xkb_syms_rtrn[i] = syms[0];
269*4882a593Smuzhiyun                 syms += nSyms[i];
270*4882a593Smuzhiyun                 nSyms[i] = 1;
271*4882a593Smuzhiyun             }
272*4882a593Smuzhiyun         }
273*4882a593Smuzhiyun     }
274*4882a593Smuzhiyun     return nGroups;
275*4882a593Smuzhiyun }
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun static XkbSymInterpretPtr
_XkbFindMatchingInterp(XkbDescPtr xkb,KeySym sym,unsigned int real_mods,unsigned int level)278*4882a593Smuzhiyun _XkbFindMatchingInterp(XkbDescPtr xkb,
279*4882a593Smuzhiyun                        KeySym sym, unsigned int real_mods, unsigned int level)
280*4882a593Smuzhiyun {
281*4882a593Smuzhiyun     register unsigned i;
282*4882a593Smuzhiyun     XkbSymInterpretPtr interp, rtrn;
283*4882a593Smuzhiyun     CARD8 mods;
284*4882a593Smuzhiyun 
285*4882a593Smuzhiyun     rtrn = NULL;
286*4882a593Smuzhiyun     interp = xkb->compat->sym_interpret;
287*4882a593Smuzhiyun     for (i = 0; i < xkb->compat->num_si; i++, interp++) {
288*4882a593Smuzhiyun         if ((interp->sym == NoSymbol) || (sym == interp->sym)) {
289*4882a593Smuzhiyun             int match;
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun             if ((level == 0) || ((interp->match & XkbSI_LevelOneOnly) == 0))
292*4882a593Smuzhiyun                 mods = real_mods;
293*4882a593Smuzhiyun             else
294*4882a593Smuzhiyun                 mods = 0;
295*4882a593Smuzhiyun             switch (interp->match & XkbSI_OpMask) {
296*4882a593Smuzhiyun             case XkbSI_NoneOf:
297*4882a593Smuzhiyun                 match = ((interp->mods & mods) == 0);
298*4882a593Smuzhiyun                 break;
299*4882a593Smuzhiyun             case XkbSI_AnyOfOrNone:
300*4882a593Smuzhiyun                 match = ((mods == 0) || ((interp->mods & mods) != 0));
301*4882a593Smuzhiyun                 break;
302*4882a593Smuzhiyun             case XkbSI_AnyOf:
303*4882a593Smuzhiyun                 match = ((interp->mods & mods) != 0);
304*4882a593Smuzhiyun                 break;
305*4882a593Smuzhiyun             case XkbSI_AllOf:
306*4882a593Smuzhiyun                 match = ((interp->mods & mods) == interp->mods);
307*4882a593Smuzhiyun                 break;
308*4882a593Smuzhiyun             case XkbSI_Exactly:
309*4882a593Smuzhiyun                 match = (interp->mods == mods);
310*4882a593Smuzhiyun                 break;
311*4882a593Smuzhiyun             default:
312*4882a593Smuzhiyun                 match = 0;
313*4882a593Smuzhiyun                 break;
314*4882a593Smuzhiyun             }
315*4882a593Smuzhiyun             if (match) {
316*4882a593Smuzhiyun                 if (interp->sym != NoSymbol) {
317*4882a593Smuzhiyun                     return interp;
318*4882a593Smuzhiyun                 }
319*4882a593Smuzhiyun                 else if (rtrn == NULL) {
320*4882a593Smuzhiyun                     rtrn = interp;
321*4882a593Smuzhiyun                 }
322*4882a593Smuzhiyun             }
323*4882a593Smuzhiyun         }
324*4882a593Smuzhiyun     }
325*4882a593Smuzhiyun     return rtrn;
326*4882a593Smuzhiyun }
327*4882a593Smuzhiyun 
328*4882a593Smuzhiyun static void
_XkbAddKeyChange(KeyCode * pFirst,unsigned char * pNum,KeyCode newKey)329*4882a593Smuzhiyun _XkbAddKeyChange(KeyCode *pFirst, unsigned char *pNum, KeyCode newKey)
330*4882a593Smuzhiyun {
331*4882a593Smuzhiyun     KeyCode last;
332*4882a593Smuzhiyun 
333*4882a593Smuzhiyun     last = (*pFirst) + (*pNum);
334*4882a593Smuzhiyun     if (newKey < *pFirst) {
335*4882a593Smuzhiyun         *pFirst = newKey;
336*4882a593Smuzhiyun         *pNum = (last - newKey) + 1;
337*4882a593Smuzhiyun     }
338*4882a593Smuzhiyun     else if (newKey > last) {
339*4882a593Smuzhiyun         *pNum = (last - *pFirst) + 1;
340*4882a593Smuzhiyun     }
341*4882a593Smuzhiyun     return;
342*4882a593Smuzhiyun }
343*4882a593Smuzhiyun 
344*4882a593Smuzhiyun static void
_XkbSetActionKeyMods(XkbDescPtr xkb,XkbAction * act,unsigned mods)345*4882a593Smuzhiyun _XkbSetActionKeyMods(XkbDescPtr xkb, XkbAction *act, unsigned mods)
346*4882a593Smuzhiyun {
347*4882a593Smuzhiyun     unsigned tmp;
348*4882a593Smuzhiyun 
349*4882a593Smuzhiyun     switch (act->type) {
350*4882a593Smuzhiyun     case XkbSA_SetMods:
351*4882a593Smuzhiyun     case XkbSA_LatchMods:
352*4882a593Smuzhiyun     case XkbSA_LockMods:
353*4882a593Smuzhiyun         if (act->mods.flags & XkbSA_UseModMapMods)
354*4882a593Smuzhiyun             act->mods.real_mods = act->mods.mask = mods;
355*4882a593Smuzhiyun         if ((tmp = XkbModActionVMods(&act->mods)) != 0) {
356*4882a593Smuzhiyun             XkbVirtualModsToReal(xkb, tmp, &tmp);
357*4882a593Smuzhiyun             act->mods.mask |= tmp;
358*4882a593Smuzhiyun         }
359*4882a593Smuzhiyun         break;
360*4882a593Smuzhiyun     case XkbSA_ISOLock:
361*4882a593Smuzhiyun         if (act->iso.flags & XkbSA_UseModMapMods)
362*4882a593Smuzhiyun             act->iso.real_mods = act->iso.mask = mods;
363*4882a593Smuzhiyun         if ((tmp = XkbModActionVMods(&act->iso)) != 0) {
364*4882a593Smuzhiyun             XkbVirtualModsToReal(xkb, tmp, &tmp);
365*4882a593Smuzhiyun             act->iso.mask |= tmp;
366*4882a593Smuzhiyun         }
367*4882a593Smuzhiyun         break;
368*4882a593Smuzhiyun     }
369*4882a593Smuzhiyun     return;
370*4882a593Smuzhiyun }
371*4882a593Smuzhiyun 
372*4882a593Smuzhiyun #define	IBUF_SIZE	8
373*4882a593Smuzhiyun 
374*4882a593Smuzhiyun Bool
XkbApplyCompatMapToKey(XkbDescPtr xkb,KeyCode key,XkbChangesPtr changes)375*4882a593Smuzhiyun XkbApplyCompatMapToKey(XkbDescPtr xkb, KeyCode key, XkbChangesPtr changes)
376*4882a593Smuzhiyun {
377*4882a593Smuzhiyun     KeySym *syms;
378*4882a593Smuzhiyun     unsigned char explicit, mods;
379*4882a593Smuzhiyun     XkbSymInterpretPtr *interps, ibuf[IBUF_SIZE];
380*4882a593Smuzhiyun     int n, nSyms, found;
381*4882a593Smuzhiyun     unsigned changed, tmp;
382*4882a593Smuzhiyun 
383*4882a593Smuzhiyun     if ((!xkb) || (!xkb->map) || (!xkb->map->key_sym_map) ||
384*4882a593Smuzhiyun         (!xkb->compat) || (!xkb->compat->sym_interpret) ||
385*4882a593Smuzhiyun         (key < xkb->min_key_code) || (key > xkb->max_key_code)) {
386*4882a593Smuzhiyun         return FALSE;
387*4882a593Smuzhiyun     }
388*4882a593Smuzhiyun     if (((!xkb->server) || (!xkb->server->key_acts)) &&
389*4882a593Smuzhiyun         (XkbAllocServerMap(xkb, XkbAllServerInfoMask, 0) != Success)) {
390*4882a593Smuzhiyun         return FALSE;
391*4882a593Smuzhiyun     }
392*4882a593Smuzhiyun     changed = 0;                /* keeps track of what has changed in _this_ call */
393*4882a593Smuzhiyun     explicit = xkb->server->explicit[key];
394*4882a593Smuzhiyun     if (explicit & XkbExplicitInterpretMask)    /* nothing to do */
395*4882a593Smuzhiyun         return TRUE;
396*4882a593Smuzhiyun     mods = (xkb->map->modmap ? xkb->map->modmap[key] : 0);
397*4882a593Smuzhiyun     nSyms = XkbKeyNumSyms(xkb, key);
398*4882a593Smuzhiyun     syms = XkbKeySymsPtr(xkb, key);
399*4882a593Smuzhiyun     if (nSyms > IBUF_SIZE) {
400*4882a593Smuzhiyun         interps = calloc(nSyms, sizeof(XkbSymInterpretPtr));
401*4882a593Smuzhiyun         if (interps == NULL) {
402*4882a593Smuzhiyun             interps = ibuf;
403*4882a593Smuzhiyun             nSyms = IBUF_SIZE;
404*4882a593Smuzhiyun         }
405*4882a593Smuzhiyun     }
406*4882a593Smuzhiyun     else {
407*4882a593Smuzhiyun         interps = ibuf;
408*4882a593Smuzhiyun     }
409*4882a593Smuzhiyun     found = 0;
410*4882a593Smuzhiyun     for (n = 0; n < nSyms; n++) {
411*4882a593Smuzhiyun         unsigned level = (n % XkbKeyGroupsWidth(xkb, key));
412*4882a593Smuzhiyun 
413*4882a593Smuzhiyun         interps[n] = NULL;
414*4882a593Smuzhiyun         if (syms[n] != NoSymbol) {
415*4882a593Smuzhiyun             interps[n] = _XkbFindMatchingInterp(xkb, syms[n], mods, level);
416*4882a593Smuzhiyun             if (interps[n] && interps[n]->act.type != XkbSA_NoAction)
417*4882a593Smuzhiyun                 found++;
418*4882a593Smuzhiyun             else
419*4882a593Smuzhiyun                 interps[n] = NULL;
420*4882a593Smuzhiyun         }
421*4882a593Smuzhiyun     }
422*4882a593Smuzhiyun     /* 1/28/96 (ef) -- XXX! WORKING HERE */
423*4882a593Smuzhiyun     if (!found) {
424*4882a593Smuzhiyun         if (xkb->server->key_acts[key] != 0) {
425*4882a593Smuzhiyun             xkb->server->key_acts[key] = 0;
426*4882a593Smuzhiyun             changed |= XkbKeyActionsMask;
427*4882a593Smuzhiyun         }
428*4882a593Smuzhiyun     }
429*4882a593Smuzhiyun     else {
430*4882a593Smuzhiyun         XkbAction *pActs;
431*4882a593Smuzhiyun         unsigned int new_vmodmask;
432*4882a593Smuzhiyun 
433*4882a593Smuzhiyun         changed |= XkbKeyActionsMask;
434*4882a593Smuzhiyun         pActs = XkbResizeKeyActions(xkb, key, nSyms);
435*4882a593Smuzhiyun         if (!pActs) {
436*4882a593Smuzhiyun             if (nSyms > IBUF_SIZE)
437*4882a593Smuzhiyun                 free(interps);
438*4882a593Smuzhiyun             return FALSE;
439*4882a593Smuzhiyun         }
440*4882a593Smuzhiyun         new_vmodmask = 0;
441*4882a593Smuzhiyun         for (n = 0; n < nSyms; n++) {
442*4882a593Smuzhiyun             if (interps[n]) {
443*4882a593Smuzhiyun                 unsigned effMods;
444*4882a593Smuzhiyun 
445*4882a593Smuzhiyun                 pActs[n] = *((XkbAction *) &interps[n]->act);
446*4882a593Smuzhiyun                 if ((n == 0) || ((interps[n]->match & XkbSI_LevelOneOnly) == 0)) {
447*4882a593Smuzhiyun                     effMods = mods;
448*4882a593Smuzhiyun                     if (interps[n]->virtual_mod != XkbNoModifier)
449*4882a593Smuzhiyun                         new_vmodmask |= (1 << interps[n]->virtual_mod);
450*4882a593Smuzhiyun                 }
451*4882a593Smuzhiyun                 else
452*4882a593Smuzhiyun                     effMods = 0;
453*4882a593Smuzhiyun                 _XkbSetActionKeyMods(xkb, &pActs[n], effMods);
454*4882a593Smuzhiyun             }
455*4882a593Smuzhiyun             else
456*4882a593Smuzhiyun                 pActs[n].type = XkbSA_NoAction;
457*4882a593Smuzhiyun         }
458*4882a593Smuzhiyun         if (((explicit & XkbExplicitVModMapMask) == 0) &&
459*4882a593Smuzhiyun             (xkb->server->vmodmap[key] != new_vmodmask)) {
460*4882a593Smuzhiyun             changed |= XkbVirtualModMapMask;
461*4882a593Smuzhiyun             xkb->server->vmodmap[key] = new_vmodmask;
462*4882a593Smuzhiyun         }
463*4882a593Smuzhiyun         if (interps[0]) {
464*4882a593Smuzhiyun             if ((interps[0]->flags & XkbSI_LockingKey) &&
465*4882a593Smuzhiyun                 ((explicit & XkbExplicitBehaviorMask) == 0)) {
466*4882a593Smuzhiyun                 xkb->server->behaviors[key].type = XkbKB_Lock;
467*4882a593Smuzhiyun                 changed |= XkbKeyBehaviorsMask;
468*4882a593Smuzhiyun             }
469*4882a593Smuzhiyun             if (((explicit & XkbExplicitAutoRepeatMask) == 0) && (xkb->ctrls)) {
470*4882a593Smuzhiyun                 CARD8 old;
471*4882a593Smuzhiyun 
472*4882a593Smuzhiyun                 old = BitIsOn(xkb->ctrls->per_key_repeat, key);
473*4882a593Smuzhiyun                 if (interps[0]->flags & XkbSI_AutoRepeat)
474*4882a593Smuzhiyun                     SetBit(xkb->ctrls->per_key_repeat, key);
475*4882a593Smuzhiyun                 else
476*4882a593Smuzhiyun                     ClearBit(xkb->ctrls->per_key_repeat, key);
477*4882a593Smuzhiyun                 if (changes && old != BitIsOn(xkb->ctrls->per_key_repeat, key))
478*4882a593Smuzhiyun                     changes->ctrls.changed_ctrls |= XkbPerKeyRepeatMask;
479*4882a593Smuzhiyun             }
480*4882a593Smuzhiyun         }
481*4882a593Smuzhiyun     }
482*4882a593Smuzhiyun     if ((!found) || (interps[0] == NULL)) {
483*4882a593Smuzhiyun         if (((explicit & XkbExplicitAutoRepeatMask) == 0) && (xkb->ctrls)) {
484*4882a593Smuzhiyun             CARD8 old;
485*4882a593Smuzhiyun 
486*4882a593Smuzhiyun             old = BitIsOn(xkb->ctrls->per_key_repeat, key);
487*4882a593Smuzhiyun             SetBit(xkb->ctrls->per_key_repeat, key);
488*4882a593Smuzhiyun             if (changes && (old != BitIsOn(xkb->ctrls->per_key_repeat, key)))
489*4882a593Smuzhiyun                 changes->ctrls.changed_ctrls |= XkbPerKeyRepeatMask;
490*4882a593Smuzhiyun         }
491*4882a593Smuzhiyun         if (((explicit & XkbExplicitBehaviorMask) == 0) &&
492*4882a593Smuzhiyun             (xkb->server->behaviors[key].type == XkbKB_Lock)) {
493*4882a593Smuzhiyun             xkb->server->behaviors[key].type = XkbKB_Default;
494*4882a593Smuzhiyun             changed |= XkbKeyBehaviorsMask;
495*4882a593Smuzhiyun         }
496*4882a593Smuzhiyun     }
497*4882a593Smuzhiyun     if (changes) {
498*4882a593Smuzhiyun         XkbMapChangesPtr mc;
499*4882a593Smuzhiyun 
500*4882a593Smuzhiyun         mc = &changes->map;
501*4882a593Smuzhiyun         tmp = (changed & mc->changed);
502*4882a593Smuzhiyun         if (tmp & XkbKeyActionsMask)
503*4882a593Smuzhiyun             _XkbAddKeyChange(&mc->first_key_act, &mc->num_key_acts, key);
504*4882a593Smuzhiyun         else if (changed & XkbKeyActionsMask) {
505*4882a593Smuzhiyun             mc->changed |= XkbKeyActionsMask;
506*4882a593Smuzhiyun             mc->first_key_act = key;
507*4882a593Smuzhiyun             mc->num_key_acts = 1;
508*4882a593Smuzhiyun         }
509*4882a593Smuzhiyun         if (tmp & XkbKeyBehaviorsMask) {
510*4882a593Smuzhiyun             _XkbAddKeyChange(&mc->first_key_behavior, &mc->num_key_behaviors,
511*4882a593Smuzhiyun                              key);
512*4882a593Smuzhiyun         }
513*4882a593Smuzhiyun         else if (changed & XkbKeyBehaviorsMask) {
514*4882a593Smuzhiyun             mc->changed |= XkbKeyBehaviorsMask;
515*4882a593Smuzhiyun             mc->first_key_behavior = key;
516*4882a593Smuzhiyun             mc->num_key_behaviors = 1;
517*4882a593Smuzhiyun         }
518*4882a593Smuzhiyun         if (tmp & XkbVirtualModMapMask)
519*4882a593Smuzhiyun             _XkbAddKeyChange(&mc->first_vmodmap_key, &mc->num_vmodmap_keys,
520*4882a593Smuzhiyun                              key);
521*4882a593Smuzhiyun         else if (changed & XkbVirtualModMapMask) {
522*4882a593Smuzhiyun             mc->changed |= XkbVirtualModMapMask;
523*4882a593Smuzhiyun             mc->first_vmodmap_key = key;
524*4882a593Smuzhiyun             mc->num_vmodmap_keys = 1;
525*4882a593Smuzhiyun         }
526*4882a593Smuzhiyun         mc->changed |= changed;
527*4882a593Smuzhiyun     }
528*4882a593Smuzhiyun     if (interps != ibuf)
529*4882a593Smuzhiyun         free(interps);
530*4882a593Smuzhiyun     return TRUE;
531*4882a593Smuzhiyun }
532*4882a593Smuzhiyun 
533*4882a593Smuzhiyun Status
XkbChangeTypesOfKey(XkbDescPtr xkb,int key,int nGroups,unsigned groups,int * newTypesIn,XkbMapChangesPtr changes)534*4882a593Smuzhiyun XkbChangeTypesOfKey(XkbDescPtr xkb,
535*4882a593Smuzhiyun                     int key,
536*4882a593Smuzhiyun                     int nGroups,
537*4882a593Smuzhiyun                     unsigned groups, int *newTypesIn, XkbMapChangesPtr changes)
538*4882a593Smuzhiyun {
539*4882a593Smuzhiyun     XkbKeyTypePtr pOldType, pNewType;
540*4882a593Smuzhiyun     register int i;
541*4882a593Smuzhiyun     int width, nOldGroups, oldWidth, newTypes[XkbNumKbdGroups];
542*4882a593Smuzhiyun 
543*4882a593Smuzhiyun     if ((!xkb) || (!XkbKeycodeInRange(xkb, key)) || (!xkb->map) ||
544*4882a593Smuzhiyun         (!xkb->map->types) || (!newTypesIn) ||
545*4882a593Smuzhiyun         ((groups & XkbAllGroupsMask) == 0) || (nGroups > XkbNumKbdGroups)) {
546*4882a593Smuzhiyun         return BadMatch;
547*4882a593Smuzhiyun     }
548*4882a593Smuzhiyun     if (nGroups == 0) {
549*4882a593Smuzhiyun         for (i = 0; i < XkbNumKbdGroups; i++) {
550*4882a593Smuzhiyun             xkb->map->key_sym_map[key].kt_index[i] = XkbOneLevelIndex;
551*4882a593Smuzhiyun         }
552*4882a593Smuzhiyun         i = xkb->map->key_sym_map[key].group_info;
553*4882a593Smuzhiyun         i = XkbSetNumGroups(i, 0);
554*4882a593Smuzhiyun         xkb->map->key_sym_map[key].group_info = i;
555*4882a593Smuzhiyun         XkbResizeKeySyms(xkb, key, 0);
556*4882a593Smuzhiyun         return Success;
557*4882a593Smuzhiyun     }
558*4882a593Smuzhiyun 
559*4882a593Smuzhiyun     nOldGroups = XkbKeyNumGroups(xkb, key);
560*4882a593Smuzhiyun     oldWidth = XkbKeyGroupsWidth(xkb, key);
561*4882a593Smuzhiyun     for (width = i = 0; i < nGroups; i++) {
562*4882a593Smuzhiyun         if (groups & (1 << i))
563*4882a593Smuzhiyun             newTypes[i] = newTypesIn[i];
564*4882a593Smuzhiyun         else if (i < nOldGroups)
565*4882a593Smuzhiyun             newTypes[i] = XkbKeyKeyTypeIndex(xkb, key, i);
566*4882a593Smuzhiyun         else if (nOldGroups > 0)
567*4882a593Smuzhiyun             newTypes[i] = XkbKeyKeyTypeIndex(xkb, key, XkbGroup1Index);
568*4882a593Smuzhiyun         else
569*4882a593Smuzhiyun             newTypes[i] = XkbTwoLevelIndex;
570*4882a593Smuzhiyun         if (newTypes[i] > xkb->map->num_types)
571*4882a593Smuzhiyun             return BadMatch;
572*4882a593Smuzhiyun         pNewType = &xkb->map->types[newTypes[i]];
573*4882a593Smuzhiyun         if (pNewType->num_levels > width)
574*4882a593Smuzhiyun             width = pNewType->num_levels;
575*4882a593Smuzhiyun     }
576*4882a593Smuzhiyun     if ((xkb->ctrls) && (nGroups > xkb->ctrls->num_groups))
577*4882a593Smuzhiyun         xkb->ctrls->num_groups = nGroups;
578*4882a593Smuzhiyun     if ((width != oldWidth) || (nGroups != nOldGroups)) {
579*4882a593Smuzhiyun         KeySym oldSyms[XkbMaxSymsPerKey], *pSyms;
580*4882a593Smuzhiyun         int nCopy;
581*4882a593Smuzhiyun 
582*4882a593Smuzhiyun         if (nOldGroups == 0) {
583*4882a593Smuzhiyun             pSyms = XkbResizeKeySyms(xkb, key, width * nGroups);
584*4882a593Smuzhiyun             if (pSyms != NULL) {
585*4882a593Smuzhiyun                 i = xkb->map->key_sym_map[key].group_info;
586*4882a593Smuzhiyun                 i = XkbSetNumGroups(i, nGroups);
587*4882a593Smuzhiyun                 xkb->map->key_sym_map[key].group_info = i;
588*4882a593Smuzhiyun                 xkb->map->key_sym_map[key].width = width;
589*4882a593Smuzhiyun                 for (i = 0; i < nGroups; i++) {
590*4882a593Smuzhiyun                     xkb->map->key_sym_map[key].kt_index[i] = newTypes[i];
591*4882a593Smuzhiyun                 }
592*4882a593Smuzhiyun                 return Success;
593*4882a593Smuzhiyun             }
594*4882a593Smuzhiyun             return BadAlloc;
595*4882a593Smuzhiyun         }
596*4882a593Smuzhiyun         pSyms = XkbKeySymsPtr(xkb, key);
597*4882a593Smuzhiyun         memcpy(oldSyms, pSyms, XkbKeyNumSyms(xkb, key) * sizeof(KeySym));
598*4882a593Smuzhiyun         pSyms = XkbResizeKeySyms(xkb, key, width * nGroups);
599*4882a593Smuzhiyun         if (pSyms == NULL)
600*4882a593Smuzhiyun             return BadAlloc;
601*4882a593Smuzhiyun         memset(pSyms, 0, width * nGroups * sizeof(KeySym));
602*4882a593Smuzhiyun         for (i = 0; (i < nGroups) && (i < nOldGroups); i++) {
603*4882a593Smuzhiyun             pOldType = XkbKeyKeyType(xkb, key, i);
604*4882a593Smuzhiyun             pNewType = &xkb->map->types[newTypes[i]];
605*4882a593Smuzhiyun             if (pNewType->num_levels > pOldType->num_levels)
606*4882a593Smuzhiyun                 nCopy = pOldType->num_levels;
607*4882a593Smuzhiyun             else
608*4882a593Smuzhiyun                 nCopy = pNewType->num_levels;
609*4882a593Smuzhiyun             memcpy(&pSyms[i * width], &oldSyms[i * oldWidth],
610*4882a593Smuzhiyun                    nCopy * sizeof(KeySym));
611*4882a593Smuzhiyun         }
612*4882a593Smuzhiyun         if (XkbKeyHasActions(xkb, key)) {
613*4882a593Smuzhiyun             XkbAction oldActs[XkbMaxSymsPerKey], *pActs;
614*4882a593Smuzhiyun 
615*4882a593Smuzhiyun             pActs = XkbKeyActionsPtr(xkb, key);
616*4882a593Smuzhiyun             memcpy(oldActs, pActs, XkbKeyNumSyms(xkb, key) * sizeof(XkbAction));
617*4882a593Smuzhiyun             pActs = XkbResizeKeyActions(xkb, key, width * nGroups);
618*4882a593Smuzhiyun             if (pActs == NULL)
619*4882a593Smuzhiyun                 return BadAlloc;
620*4882a593Smuzhiyun             memset(pActs, 0, width * nGroups * sizeof(XkbAction));
621*4882a593Smuzhiyun             for (i = 0; (i < nGroups) && (i < nOldGroups); i++) {
622*4882a593Smuzhiyun                 pOldType = XkbKeyKeyType(xkb, key, i);
623*4882a593Smuzhiyun                 pNewType = &xkb->map->types[newTypes[i]];
624*4882a593Smuzhiyun                 if (pNewType->num_levels > pOldType->num_levels)
625*4882a593Smuzhiyun                     nCopy = pOldType->num_levels;
626*4882a593Smuzhiyun                 else
627*4882a593Smuzhiyun                     nCopy = pNewType->num_levels;
628*4882a593Smuzhiyun                 memcpy(&pActs[i * width], &oldActs[i * oldWidth],
629*4882a593Smuzhiyun                        nCopy * sizeof(XkbAction));
630*4882a593Smuzhiyun             }
631*4882a593Smuzhiyun         }
632*4882a593Smuzhiyun         i = xkb->map->key_sym_map[key].group_info;
633*4882a593Smuzhiyun         i = XkbSetNumGroups(i, nGroups);
634*4882a593Smuzhiyun         xkb->map->key_sym_map[key].group_info = i;
635*4882a593Smuzhiyun         xkb->map->key_sym_map[key].width = width;
636*4882a593Smuzhiyun     }
637*4882a593Smuzhiyun     width = 0;
638*4882a593Smuzhiyun     for (i = 0; i < nGroups; i++) {
639*4882a593Smuzhiyun         xkb->map->key_sym_map[key].kt_index[i] = newTypes[i];
640*4882a593Smuzhiyun         if (xkb->map->types[newTypes[i]].num_levels > width)
641*4882a593Smuzhiyun             width = xkb->map->types[newTypes[i]].num_levels;
642*4882a593Smuzhiyun     }
643*4882a593Smuzhiyun     xkb->map->key_sym_map[key].width = width;
644*4882a593Smuzhiyun     if (changes != NULL) {
645*4882a593Smuzhiyun         if (changes->changed & XkbKeySymsMask) {
646*4882a593Smuzhiyun             _XkbAddKeyChange(&changes->first_key_sym, &changes->num_key_syms,
647*4882a593Smuzhiyun                              key);
648*4882a593Smuzhiyun         }
649*4882a593Smuzhiyun         else {
650*4882a593Smuzhiyun             changes->changed |= XkbKeySymsMask;
651*4882a593Smuzhiyun             changes->first_key_sym = key;
652*4882a593Smuzhiyun             changes->num_key_syms = 1;
653*4882a593Smuzhiyun         }
654*4882a593Smuzhiyun     }
655*4882a593Smuzhiyun     return Success;
656*4882a593Smuzhiyun }
657*4882a593Smuzhiyun 
658*4882a593Smuzhiyun /***====================================================================***/
659*4882a593Smuzhiyun 
660*4882a593Smuzhiyun Bool
XkbVirtualModsToReal(XkbDescPtr xkb,unsigned virtual_mask,unsigned * mask_rtrn)661*4882a593Smuzhiyun XkbVirtualModsToReal(XkbDescPtr xkb, unsigned virtual_mask, unsigned *mask_rtrn)
662*4882a593Smuzhiyun {
663*4882a593Smuzhiyun     register int i, bit;
664*4882a593Smuzhiyun     register unsigned mask;
665*4882a593Smuzhiyun 
666*4882a593Smuzhiyun     if (xkb == NULL)
667*4882a593Smuzhiyun         return FALSE;
668*4882a593Smuzhiyun     if (virtual_mask == 0) {
669*4882a593Smuzhiyun         *mask_rtrn = 0;
670*4882a593Smuzhiyun         return TRUE;
671*4882a593Smuzhiyun     }
672*4882a593Smuzhiyun     if (xkb->server == NULL)
673*4882a593Smuzhiyun         return FALSE;
674*4882a593Smuzhiyun     for (i = mask = 0, bit = 1; i < XkbNumVirtualMods; i++, bit <<= 1) {
675*4882a593Smuzhiyun         if (virtual_mask & bit)
676*4882a593Smuzhiyun             mask |= xkb->server->vmods[i];
677*4882a593Smuzhiyun     }
678*4882a593Smuzhiyun     *mask_rtrn = mask;
679*4882a593Smuzhiyun     return TRUE;
680*4882a593Smuzhiyun }
681*4882a593Smuzhiyun 
682*4882a593Smuzhiyun /***====================================================================***/
683*4882a593Smuzhiyun 
684*4882a593Smuzhiyun static Bool
XkbUpdateActionVirtualMods(XkbDescPtr xkb,XkbAction * act,unsigned changed)685*4882a593Smuzhiyun XkbUpdateActionVirtualMods(XkbDescPtr xkb, XkbAction *act, unsigned changed)
686*4882a593Smuzhiyun {
687*4882a593Smuzhiyun     unsigned int tmp;
688*4882a593Smuzhiyun 
689*4882a593Smuzhiyun     switch (act->type) {
690*4882a593Smuzhiyun     case XkbSA_SetMods:
691*4882a593Smuzhiyun     case XkbSA_LatchMods:
692*4882a593Smuzhiyun     case XkbSA_LockMods:
693*4882a593Smuzhiyun         if (((tmp = XkbModActionVMods(&act->mods)) & changed) != 0) {
694*4882a593Smuzhiyun             XkbVirtualModsToReal(xkb, tmp, &tmp);
695*4882a593Smuzhiyun             act->mods.mask = act->mods.real_mods;
696*4882a593Smuzhiyun             act->mods.mask |= tmp;
697*4882a593Smuzhiyun             return TRUE;
698*4882a593Smuzhiyun         }
699*4882a593Smuzhiyun         break;
700*4882a593Smuzhiyun     case XkbSA_ISOLock:
701*4882a593Smuzhiyun         if ((((tmp = XkbModActionVMods(&act->iso)) != 0) & changed) != 0) {
702*4882a593Smuzhiyun             XkbVirtualModsToReal(xkb, tmp, &tmp);
703*4882a593Smuzhiyun             act->iso.mask = act->iso.real_mods;
704*4882a593Smuzhiyun             act->iso.mask |= tmp;
705*4882a593Smuzhiyun             return TRUE;
706*4882a593Smuzhiyun         }
707*4882a593Smuzhiyun         break;
708*4882a593Smuzhiyun     }
709*4882a593Smuzhiyun     return FALSE;
710*4882a593Smuzhiyun }
711*4882a593Smuzhiyun 
712*4882a593Smuzhiyun static void
XkbUpdateKeyTypeVirtualMods(XkbDescPtr xkb,XkbKeyTypePtr type,unsigned int changed,XkbChangesPtr changes)713*4882a593Smuzhiyun XkbUpdateKeyTypeVirtualMods(XkbDescPtr xkb,
714*4882a593Smuzhiyun                             XkbKeyTypePtr type,
715*4882a593Smuzhiyun                             unsigned int changed, XkbChangesPtr changes)
716*4882a593Smuzhiyun {
717*4882a593Smuzhiyun     register unsigned int i;
718*4882a593Smuzhiyun     unsigned int mask;
719*4882a593Smuzhiyun 
720*4882a593Smuzhiyun     XkbVirtualModsToReal(xkb, type->mods.vmods, &mask);
721*4882a593Smuzhiyun     type->mods.mask = type->mods.real_mods | mask;
722*4882a593Smuzhiyun     if ((type->map_count > 0) && (type->mods.vmods != 0)) {
723*4882a593Smuzhiyun         XkbKTMapEntryPtr entry;
724*4882a593Smuzhiyun 
725*4882a593Smuzhiyun         for (i = 0, entry = type->map; i < type->map_count; i++, entry++) {
726*4882a593Smuzhiyun             if (entry->mods.vmods != 0) {
727*4882a593Smuzhiyun                 XkbVirtualModsToReal(xkb, entry->mods.vmods, &mask);
728*4882a593Smuzhiyun                 entry->mods.mask = entry->mods.real_mods | mask;
729*4882a593Smuzhiyun                 /* entry is active if vmods are bound */
730*4882a593Smuzhiyun                 entry->active = (mask != 0);
731*4882a593Smuzhiyun             }
732*4882a593Smuzhiyun             else
733*4882a593Smuzhiyun                 entry->active = 1;
734*4882a593Smuzhiyun         }
735*4882a593Smuzhiyun     }
736*4882a593Smuzhiyun     if (changes) {
737*4882a593Smuzhiyun         int type_ndx;
738*4882a593Smuzhiyun 
739*4882a593Smuzhiyun         type_ndx = type - xkb->map->types;
740*4882a593Smuzhiyun         if ((type_ndx < 0) || (type_ndx > xkb->map->num_types))
741*4882a593Smuzhiyun             return;
742*4882a593Smuzhiyun         if (changes->map.changed & XkbKeyTypesMask) {
743*4882a593Smuzhiyun             int last;
744*4882a593Smuzhiyun 
745*4882a593Smuzhiyun             last = changes->map.first_type + changes->map.num_types - 1;
746*4882a593Smuzhiyun             if (type_ndx < changes->map.first_type) {
747*4882a593Smuzhiyun                 changes->map.first_type = type_ndx;
748*4882a593Smuzhiyun                 changes->map.num_types = (last - type_ndx) + 1;
749*4882a593Smuzhiyun             }
750*4882a593Smuzhiyun             else if (type_ndx > last) {
751*4882a593Smuzhiyun                 changes->map.num_types =
752*4882a593Smuzhiyun                     (type_ndx - changes->map.first_type) + 1;
753*4882a593Smuzhiyun             }
754*4882a593Smuzhiyun         }
755*4882a593Smuzhiyun         else {
756*4882a593Smuzhiyun             changes->map.changed |= XkbKeyTypesMask;
757*4882a593Smuzhiyun             changes->map.first_type = type_ndx;
758*4882a593Smuzhiyun             changes->map.num_types = 1;
759*4882a593Smuzhiyun         }
760*4882a593Smuzhiyun     }
761*4882a593Smuzhiyun     return;
762*4882a593Smuzhiyun }
763*4882a593Smuzhiyun 
764*4882a593Smuzhiyun Bool
XkbApplyVirtualModChanges(XkbDescPtr xkb,unsigned changed,XkbChangesPtr changes)765*4882a593Smuzhiyun XkbApplyVirtualModChanges(XkbDescPtr xkb, unsigned changed,
766*4882a593Smuzhiyun                           XkbChangesPtr changes)
767*4882a593Smuzhiyun {
768*4882a593Smuzhiyun     register int i;
769*4882a593Smuzhiyun     unsigned int checkState = 0;
770*4882a593Smuzhiyun 
771*4882a593Smuzhiyun     if ((!xkb) || (!xkb->map) || (changed == 0))
772*4882a593Smuzhiyun         return FALSE;
773*4882a593Smuzhiyun     for (i = 0; i < xkb->map->num_types; i++) {
774*4882a593Smuzhiyun         if (xkb->map->types[i].mods.vmods & changed)
775*4882a593Smuzhiyun             XkbUpdateKeyTypeVirtualMods(xkb, &xkb->map->types[i], changed,
776*4882a593Smuzhiyun                                         changes);
777*4882a593Smuzhiyun     }
778*4882a593Smuzhiyun     if (changed & xkb->ctrls->internal.vmods) {
779*4882a593Smuzhiyun         unsigned int newMask;
780*4882a593Smuzhiyun 
781*4882a593Smuzhiyun         XkbVirtualModsToReal(xkb, xkb->ctrls->internal.vmods, &newMask);
782*4882a593Smuzhiyun         newMask |= xkb->ctrls->internal.real_mods;
783*4882a593Smuzhiyun         if (xkb->ctrls->internal.mask != newMask) {
784*4882a593Smuzhiyun             xkb->ctrls->internal.mask = newMask;
785*4882a593Smuzhiyun             if (changes) {
786*4882a593Smuzhiyun                 changes->ctrls.changed_ctrls |= XkbInternalModsMask;
787*4882a593Smuzhiyun                 checkState = TRUE;
788*4882a593Smuzhiyun             }
789*4882a593Smuzhiyun         }
790*4882a593Smuzhiyun     }
791*4882a593Smuzhiyun     if (changed & xkb->ctrls->ignore_lock.vmods) {
792*4882a593Smuzhiyun         unsigned int newMask;
793*4882a593Smuzhiyun 
794*4882a593Smuzhiyun         XkbVirtualModsToReal(xkb, xkb->ctrls->ignore_lock.vmods, &newMask);
795*4882a593Smuzhiyun         newMask |= xkb->ctrls->ignore_lock.real_mods;
796*4882a593Smuzhiyun         if (xkb->ctrls->ignore_lock.mask != newMask) {
797*4882a593Smuzhiyun             xkb->ctrls->ignore_lock.mask = newMask;
798*4882a593Smuzhiyun             if (changes) {
799*4882a593Smuzhiyun                 changes->ctrls.changed_ctrls |= XkbIgnoreLockModsMask;
800*4882a593Smuzhiyun                 checkState = TRUE;
801*4882a593Smuzhiyun             }
802*4882a593Smuzhiyun         }
803*4882a593Smuzhiyun     }
804*4882a593Smuzhiyun     if (xkb->indicators != NULL) {
805*4882a593Smuzhiyun         XkbIndicatorMapPtr map;
806*4882a593Smuzhiyun 
807*4882a593Smuzhiyun         map = &xkb->indicators->maps[0];
808*4882a593Smuzhiyun         for (i = 0; i < XkbNumIndicators; i++, map++) {
809*4882a593Smuzhiyun             if (map->mods.vmods & changed) {
810*4882a593Smuzhiyun                 unsigned int newMask;
811*4882a593Smuzhiyun 
812*4882a593Smuzhiyun                 XkbVirtualModsToReal(xkb, map->mods.vmods, &newMask);
813*4882a593Smuzhiyun                 newMask |= map->mods.real_mods;
814*4882a593Smuzhiyun                 if (newMask != map->mods.mask) {
815*4882a593Smuzhiyun                     map->mods.mask = newMask;
816*4882a593Smuzhiyun                     if (changes) {
817*4882a593Smuzhiyun                         changes->indicators.map_changes |= (1 << i);
818*4882a593Smuzhiyun                         checkState = TRUE;
819*4882a593Smuzhiyun                     }
820*4882a593Smuzhiyun                 }
821*4882a593Smuzhiyun             }
822*4882a593Smuzhiyun         }
823*4882a593Smuzhiyun     }
824*4882a593Smuzhiyun     if (xkb->compat != NULL) {
825*4882a593Smuzhiyun         XkbCompatMapPtr compat;
826*4882a593Smuzhiyun 
827*4882a593Smuzhiyun         compat = xkb->compat;
828*4882a593Smuzhiyun         for (i = 0; i < XkbNumKbdGroups; i++) {
829*4882a593Smuzhiyun             unsigned int newMask;
830*4882a593Smuzhiyun 
831*4882a593Smuzhiyun             XkbVirtualModsToReal(xkb, compat->groups[i].vmods, &newMask);
832*4882a593Smuzhiyun             newMask |= compat->groups[i].real_mods;
833*4882a593Smuzhiyun             if (compat->groups[i].mask != newMask) {
834*4882a593Smuzhiyun                 compat->groups[i].mask = newMask;
835*4882a593Smuzhiyun                 if (changes) {
836*4882a593Smuzhiyun                     changes->compat.changed_groups |= (1 << i);
837*4882a593Smuzhiyun                     checkState = TRUE;
838*4882a593Smuzhiyun                 }
839*4882a593Smuzhiyun             }
840*4882a593Smuzhiyun         }
841*4882a593Smuzhiyun     }
842*4882a593Smuzhiyun     if (xkb->map && xkb->server) {
843*4882a593Smuzhiyun         int highChange = 0, lowChange = -1;
844*4882a593Smuzhiyun 
845*4882a593Smuzhiyun         for (i = xkb->min_key_code; i <= xkb->max_key_code; i++) {
846*4882a593Smuzhiyun             if (XkbKeyHasActions(xkb, i)) {
847*4882a593Smuzhiyun                 register XkbAction *pAct;
848*4882a593Smuzhiyun                 register int n;
849*4882a593Smuzhiyun 
850*4882a593Smuzhiyun                 pAct = XkbKeyActionsPtr(xkb, i);
851*4882a593Smuzhiyun                 for (n = XkbKeyNumActions(xkb, i); n > 0; n--, pAct++) {
852*4882a593Smuzhiyun                     if ((pAct->type != XkbSA_NoAction) &&
853*4882a593Smuzhiyun                         XkbUpdateActionVirtualMods(xkb, pAct, changed)) {
854*4882a593Smuzhiyun                         if (lowChange < 0)
855*4882a593Smuzhiyun                             lowChange = i;
856*4882a593Smuzhiyun                         highChange = i;
857*4882a593Smuzhiyun                     }
858*4882a593Smuzhiyun                 }
859*4882a593Smuzhiyun             }
860*4882a593Smuzhiyun         }
861*4882a593Smuzhiyun         if (changes && (lowChange > 0)) {       /* something changed */
862*4882a593Smuzhiyun             if (changes->map.changed & XkbKeyActionsMask) {
863*4882a593Smuzhiyun                 int last;
864*4882a593Smuzhiyun 
865*4882a593Smuzhiyun                 if (changes->map.first_key_act < lowChange)
866*4882a593Smuzhiyun                     lowChange = changes->map.first_key_act;
867*4882a593Smuzhiyun                 last =
868*4882a593Smuzhiyun                     changes->map.first_key_act + changes->map.num_key_acts - 1;
869*4882a593Smuzhiyun                 if (last > highChange)
870*4882a593Smuzhiyun                     highChange = last;
871*4882a593Smuzhiyun             }
872*4882a593Smuzhiyun             changes->map.changed |= XkbKeyActionsMask;
873*4882a593Smuzhiyun             changes->map.first_key_act = lowChange;
874*4882a593Smuzhiyun             changes->map.num_key_acts = (highChange - lowChange) + 1;
875*4882a593Smuzhiyun         }
876*4882a593Smuzhiyun     }
877*4882a593Smuzhiyun     return checkState;
878*4882a593Smuzhiyun }
879