cad9364b75a449837af86911eee7e71d26f70154
[platform/upstream/libX11.git] / src / xkb / XKBSetMap.c
1 /************************************************************
2 Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc.
3
4 Permission to use, copy, modify, and distribute this
5 software and its documentation for any purpose and without
6 fee is hereby granted, provided that the above copyright
7 notice appear in all copies and that both that copyright
8 notice and this permission notice appear in supporting
9 documentation, and that the name of Silicon Graphics not be
10 used in advertising or publicity pertaining to distribution
11 of the software without specific prior written permission.
12 Silicon Graphics makes no representation about the suitability
13 of this software for any purpose. It is provided "as is"
14 without any express or implied warranty.
15
16 SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17 SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18 AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19 GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20 DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21 DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22 OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
23 THE USE OR PERFORMANCE OF THIS SOFTWARE.
24
25 ********************************************************/
26
27 #ifdef HAVE_CONFIG_H
28 #include <config.h>
29 #endif
30 #include <stdio.h>
31 #include "Xlibint.h"
32 #include <X11/extensions/XKBproto.h>
33 #include "XKBlibint.h"
34
35 static int
36 _XkbSizeKeyTypes(XkbDescPtr xkb,xkbSetMapReq *req)
37 {
38     XkbKeyTypePtr       map;
39     int                 i,len;
40
41     if (((req->present&XkbKeyTypesMask)==0)||(req->nTypes==0)) {
42         req->present&= ~XkbKeyTypesMask;
43         req->firstType= req->nTypes= 0;
44         return 0;
45     }
46     len= 0;
47     map= &xkb->map->types[req->firstType];
48     for (i=0;i<req->nTypes;i++,map++){
49         len+= SIZEOF(xkbKeyTypeWireDesc);
50         len+= map->map_count*SIZEOF(xkbKTSetMapEntryWireDesc);
51         if (map->preserve)
52             len+= map->map_count*SIZEOF(xkbModsWireDesc);
53     }
54     return len;
55 }
56
57 static void
58 _XkbWriteKeyTypes(Display *dpy,XkbDescPtr xkb,xkbSetMapReq *req)
59 {
60     char *              buf;
61     XkbKeyTypePtr       type;
62     int                 i,n,sz;
63     xkbKeyTypeWireDesc *desc;
64
65     if ((req->present&XkbKeyTypesMask)==0)
66         return;
67     type= &xkb->map->types[req->firstType];
68     for (i=0;i<req->nTypes;i++,type++) {
69         sz= SIZEOF(xkbKeyTypeWireDesc);
70         sz+= type->map_count*SIZEOF(xkbKTSetMapEntryWireDesc);
71         if (type->preserve)
72             sz+= type->map_count*SIZEOF(xkbModsWireDesc);
73         BufAlloc(xkbKeyTypeWireDesc *,desc,sz);
74         desc->mask = type->mods.mask;
75         desc->realMods = type->mods.real_mods;
76         desc->virtualMods = type->mods.vmods;
77         desc->numLevels = type->num_levels;
78         desc->nMapEntries = type->map_count;
79         desc->preserve = (type->preserve!=NULL);
80         buf= (char *)&desc[1];
81         if (desc->nMapEntries>0) {
82             xkbKTSetMapEntryWireDesc *wire;
83             wire= (xkbKTSetMapEntryWireDesc *)buf;
84             for (n=0;n<type->map_count;n++,wire++) {
85                 wire->level= type->map[n].level;
86                 wire->realMods= type->map[n].mods.real_mods;
87                 wire->virtualMods= type->map[n].mods.vmods;
88             }
89             buf= (char *)wire;
90             if (type->preserve) {
91                 xkbModsWireDesc *pwire;
92                 pwire= (xkbModsWireDesc *)buf;
93                 for (n=0;n<type->map_count;n++,pwire++) {
94                     pwire->realMods= type->preserve[n].real_mods;
95                     pwire->virtualMods= type->preserve[n].vmods;
96                 }
97             }
98         }
99     }
100     return;
101 }
102
103 static int
104 _XkbSizeKeySyms(XkbDescPtr xkb,xkbSetMapReq *req)
105 {
106     int                 i,len;
107     unsigned            nSyms;
108
109     if (((req->present&XkbKeySymsMask)==0)||(req->nKeySyms==0)) {
110         req->present&= ~XkbKeySymsMask;
111         req->firstKeySym= req->nKeySyms= 0;
112         req->totalSyms= 0;
113         return 0;
114     }
115     len= (int)(req->nKeySyms*sizeof(XkbSymMapRec));
116     for (i=nSyms=0;i<req->nKeySyms;i++) {
117         nSyms+= XkbKeyNumSyms(xkb,i+req->firstKeySym);
118     }
119     len+= nSyms*sizeof(CARD32);
120     req->totalSyms= nSyms;
121     return len;
122 }
123
124 static void
125 _XkbWriteKeySyms(Display *dpy,XkbDescPtr xkb,xkbSetMapReq *req)
126 {
127 register KeySym *       pSym;
128 CARD32 *                outSym;
129 XkbSymMapPtr            symMap;
130 xkbSymMapWireDesc *desc;
131 register int    i;
132
133     if ((req->present&XkbKeySymsMask)==0)
134         return;
135     symMap = &xkb->map->key_sym_map[req->firstKeySym];
136     for (i=0;i<req->nKeySyms;i++,symMap++) {
137         BufAlloc(xkbSymMapWireDesc *,desc,
138                  SIZEOF(xkbSymMapWireDesc)+
139                  (XkbKeyNumSyms(xkb,i+req->firstKeySym)*sizeof(CARD32)));
140         desc->ktIndex[0] = symMap->kt_index[0];
141         desc->ktIndex[1] = symMap->kt_index[1];
142         desc->ktIndex[2] = symMap->kt_index[2];
143         desc->ktIndex[3] = symMap->kt_index[3];
144         desc->groupInfo = symMap->group_info;
145         desc->width = symMap->width;
146         desc->nSyms = XkbKeyNumSyms(xkb,i+req->firstKeySym);
147         outSym = (CARD32 *)&desc[1];
148         if (desc->nSyms>0) {
149              pSym = XkbKeySymsPtr(xkb,i+req->firstKeySym);
150             _XkbWriteCopyKeySyms(pSym,outSym,desc->nSyms);
151         }
152     }
153     return;
154 }
155
156 static int
157 _XkbSizeKeyActions(XkbDescPtr xkb,xkbSetMapReq *req)
158 {
159     int                 i,len,nActs;
160
161     if (((req->present&XkbKeyActionsMask)==0)||(req->nKeyActs==0)) {
162         req->present&= ~XkbKeyActionsMask;
163         req->firstKeyAct= req->nKeyActs= 0;
164         req->totalActs= 0;
165         return 0;
166     }
167     for (nActs=i=0;i<req->nKeyActs;i++) {
168         if (xkb->server->key_acts[i+req->firstKeyAct]!=0)
169             nActs+= XkbKeyNumActions(xkb,i+req->firstKeyAct);
170     }
171     len= XkbPaddedSize(req->nKeyActs)+(nActs*SIZEOF(xkbActionWireDesc));
172     req->totalActs= nActs;
173     return len;
174 }
175
176 static void
177 _XkbWriteKeyActions(Display *dpy,XkbDescPtr xkb,xkbSetMapReq *req)
178 {
179     register int         i;
180     int                  n;
181     CARD8               *numDesc;
182     XkbAction           *actDesc;
183
184     if ((req->present&XkbKeyActionsMask)==0)
185         return;
186     n = XkbPaddedSize(req->nKeyActs);
187     n+= (req->totalActs*SIZEOF(xkbActionWireDesc));
188
189     BufAlloc(CARD8 *,numDesc,n);
190     for (i=0;i<req->nKeyActs;i++) {
191         if (xkb->server->key_acts[i+req->firstKeyAct]==0)
192              numDesc[i] = 0;
193         else numDesc[i] = XkbKeyNumActions(xkb,(i+req->firstKeyAct));
194     }
195     actDesc = (XkbAction *)&numDesc[XkbPaddedSize(req->nKeyActs)];
196     for (i=0;i<req->nKeyActs;i++) {
197         if (xkb->server->key_acts[i+req->firstKeyAct]!=0) {
198             n = XkbKeyNumActions(xkb,(i+req->firstKeyAct));
199             memcpy(actDesc,XkbKeyActionsPtr(xkb,(i+req->firstKeyAct)),
200                                                    n*SIZEOF(xkbActionWireDesc));
201             actDesc+= n;
202         }
203     }
204     return;
205 }
206
207 static int
208 _XkbSizeKeyBehaviors(XkbDescPtr xkb,xkbSetMapReq *req)
209 {
210 register int i,first,last,nFound;
211
212     if (((req->present&XkbKeyBehaviorsMask)==0)||(req->nKeyBehaviors<1)) {
213         req->present&= ~XkbKeyBehaviorsMask;
214         req->firstKeyBehavior= req->nKeyBehaviors= 0;
215         req->totalKeyBehaviors= 0;
216         return 0;
217     }
218     first= req->firstKeyBehavior;
219     last= first+req->nKeyBehaviors-1;
220     for (i=first,nFound=0;i<=last;i++) {
221         if (xkb->server->behaviors[i].type!=XkbKB_Default)
222             nFound++;
223     }
224     req->totalKeyBehaviors= nFound;
225     return (nFound*SIZEOF(xkbBehaviorWireDesc));
226 }
227
228 static void
229 _XkbWriteKeyBehaviors(Display *dpy,XkbDescPtr xkb,xkbSetMapReq *req)
230 {
231 register int            i,first,last;
232 xkbBehaviorWireDesc *   wire;
233 char *                  buf;
234
235     if ((req->present&XkbKeyBehaviorsMask)==0)
236         return;
237     first= req->firstKeyBehavior;
238     last= first+req->nKeyBehaviors-1;
239
240     i= req->totalKeyBehaviors*SIZEOF(xkbBehaviorWireDesc);
241     BufAlloc(char *,buf,i);
242     wire= (xkbBehaviorWireDesc *)buf;
243     for (i=first;i<=last;i++) {
244         if (xkb->server->behaviors[i].type!=XkbKB_Default) {
245             wire->key= i;
246             wire->type= xkb->server->behaviors[i].type;
247             wire->data= xkb->server->behaviors[i].data;
248             buf+= SIZEOF(xkbBehaviorWireDesc);
249             wire= (xkbBehaviorWireDesc *)buf;
250         }
251     }
252     return;
253 }
254
255 static unsigned
256 _XkbSizeVirtualMods(xkbSetMapReq *req)
257 {
258 register int i,bit,nMods;
259
260    if (((req->present&XkbVirtualModsMask)==0)||(req->virtualMods==0)) {
261         req->present&= ~XkbVirtualModsMask;
262         req->virtualMods= 0;
263         return 0;
264    }
265    for (i=nMods=0,bit=1;i<XkbNumVirtualMods;i++,bit<<=1) {
266         if (req->virtualMods&bit)
267             nMods++;
268    }
269    return XkbPaddedSize(nMods);
270 }
271
272 static void
273 _XkbWriteVirtualMods(   Display *       dpy,
274                         XkbDescPtr      xkb,
275                         xkbSetMapReq *  req,
276                         unsigned        size)
277 {
278     register int         i,bit;
279     CARD8               *vmods;
280
281     /* This was req->present&XkbVirtualModsMask==0, and '==' beats '&' */
282     if (((req->present & XkbVirtualModsMask) == 0) || (size < 1))
283         return;
284     BufAlloc(CARD8 *,vmods,size);
285     for (i=0,bit=1;i<XkbNumVirtualMods;i++,bit<<=1) {
286         if (req->virtualMods&bit)
287             *vmods++= xkb->server->vmods[i];
288     }
289     return;
290 }
291
292 static int
293 _XkbSizeKeyExplicit(XkbDescPtr xkb,xkbSetMapReq *req)
294 {
295 register int i,first,last,nFound;
296
297     if (((req->present&XkbExplicitComponentsMask)==0)||(req->nKeyExplicit==0)) {
298         req->present&= ~XkbExplicitComponentsMask;
299         req->firstKeyExplicit= req->nKeyExplicit= 0;
300         req->totalKeyExplicit= 0;
301         return 0;
302     }
303     first= req->firstKeyExplicit;
304     last= first+req->nKeyExplicit-1;
305
306     for (i=first,nFound=0;i<=last;i++) {
307         if (xkb->server->explicit[i]!=0)
308             nFound++;
309     }
310     req->totalKeyExplicit= nFound;
311     return XkbPaddedSize((nFound*2));
312 }
313
314 static void
315 _XkbWriteKeyExplicit(Display *dpy,XkbDescPtr xkb,xkbSetMapReq *req)
316 {
317 register int    i,first,last;
318 CARD8 *         wire;
319
320     if ((req->present&XkbExplicitComponentsMask)==0)
321         return;
322     first= req->firstKeyExplicit;
323     last= first+req->nKeyExplicit - 1;
324     i= XkbPaddedSize((req->totalKeyExplicit*2));
325     BufAlloc(CARD8 *,wire,i);
326     for (i=first;i<=last;i++) {
327         if (xkb->server->explicit[i]!=0) {
328             wire[0]= i;
329             wire[1]= xkb->server->explicit[i];
330             wire+= 2;
331         }
332     }
333     return;
334 }
335
336 static int
337 _XkbSizeModifierMap(XkbDescPtr xkb,xkbSetMapReq *req)
338 {
339 register int i,first,last,nFound;
340
341     if (((req->present&XkbModifierMapMask)==0)||(req->nModMapKeys==0)) {
342         req->present&= ~XkbModifierMapMask;
343         req->firstModMapKey= req->nModMapKeys= 0;
344         req->totalModMapKeys= 0;
345         return 0;
346     }
347     first= req->firstModMapKey;
348     last= first+req->nModMapKeys-1;
349
350     for (i=first,nFound=0;i<=last;i++) {
351         if (xkb->map->modmap[i]!=0)
352             nFound++;
353     }
354     req->totalModMapKeys= nFound;
355     return XkbPaddedSize((nFound*2));
356 }
357
358 static void
359 _XkbWriteModifierMap(Display *dpy,XkbDescPtr xkb,xkbSetMapReq *req)
360 {
361 register int    i,first,last;
362 CARD8 *         wire;
363
364     if ((req->present&XkbModifierMapMask)==0)
365         return;
366     first= req->firstModMapKey;
367     last= first+req->nModMapKeys-1;
368     if (req->totalModMapKeys>0) {
369         i= XkbPaddedSize((req->totalModMapKeys*2));
370         BufAlloc(CARD8 *,wire,i);
371         for (i=first;i<=last;i++) {
372             if (xkb->map->modmap[i]!=0) {
373                 wire[0]= i;
374                 wire[1]= xkb->map->modmap[i];
375                 wire+= 2;
376             }
377         }
378     }
379     return;
380 }
381
382 static int
383 _XkbSizeVirtualModMap(XkbDescPtr xkb,xkbSetMapReq *req)
384 {
385 register int i,first,last,nFound;
386
387     if (((req->present&XkbVirtualModMapMask)==0)||(req->nVModMapKeys==0)) {
388         req->present&= ~XkbVirtualModMapMask;
389         req->firstVModMapKey= req->nVModMapKeys= 0;
390         req->totalVModMapKeys= 0;
391         return 0;
392     }
393     first= req->firstVModMapKey;
394     last= first+req->nVModMapKeys-1;
395
396     for (i=first,nFound=0;i<=last;i++) {
397         if (xkb->server->vmodmap[i]!=0)
398             nFound++;
399     }
400     req->totalVModMapKeys= nFound;
401     return nFound*SIZEOF(xkbVModMapWireDesc);
402 }
403
404 static void
405 _XkbWriteVirtualModMap(Display *dpy,XkbDescPtr xkb,xkbSetMapReq *req)
406 {
407 register int            i,first,last;
408 xkbVModMapWireDesc *    wire;
409
410     if ((req->present&XkbVirtualModMapMask)==0)
411         return;
412     first= req->firstVModMapKey;
413     last= first+req->nVModMapKeys-1;
414     if (req->totalVModMapKeys>0) {
415         i= req->totalVModMapKeys*SIZEOF(xkbVModMapWireDesc);
416         BufAlloc(xkbVModMapWireDesc *,wire,i);
417         for (i=first;i<=last;i++) {
418             if (xkb->server->vmodmap[i]!=0) {
419                 wire->key= i;
420                 wire->vmods= xkb->server->vmodmap[i];
421                 wire++;
422             }
423         }
424     }
425     return;
426 }
427
428 static void
429 SendSetMap(Display *dpy,XkbDescPtr xkb,xkbSetMapReq *req)
430 {
431 xkbSetMapReq tmp;
432 unsigned szMods;
433
434     req->length+= _XkbSizeKeyTypes(xkb,req)/4;
435     req->length+= _XkbSizeKeySyms(xkb,req)/4;
436     req->length+= _XkbSizeKeyActions(xkb,req)/4;
437     req->length+= _XkbSizeKeyBehaviors(xkb,req)/4;
438     szMods= _XkbSizeVirtualMods(req);
439     req->length+= szMods/4;
440     req->length+= _XkbSizeKeyExplicit(xkb,req)/4;
441     req->length+= _XkbSizeModifierMap(xkb,req)/4;
442     req->length+= _XkbSizeVirtualModMap(xkb,req)/4;
443
444     tmp= *req;
445     if ( tmp.nTypes>0 )
446         _XkbWriteKeyTypes(dpy,xkb,&tmp);
447     if ( tmp.nKeySyms>0 )
448         _XkbWriteKeySyms(dpy,xkb,&tmp);
449     if ( tmp.nKeyActs )
450         _XkbWriteKeyActions(dpy,xkb,&tmp);
451     if ( tmp.totalKeyBehaviors>0 )
452         _XkbWriteKeyBehaviors(dpy,xkb,&tmp);
453     if ( tmp.virtualMods )
454         _XkbWriteVirtualMods(dpy,xkb,&tmp,szMods);
455     if ( tmp.totalKeyExplicit>0)
456         _XkbWriteKeyExplicit(dpy,xkb,&tmp);
457     if ( tmp.totalModMapKeys>0)
458         _XkbWriteModifierMap(dpy,xkb,&tmp);
459     if ( tmp.totalVModMapKeys>0)
460         _XkbWriteVirtualModMap(dpy,xkb,&tmp);
461     return;
462 }
463
464 Bool
465 XkbSetMap(Display *dpy,unsigned which,XkbDescPtr xkb)
466 {
467 register xkbSetMapReq * req;
468 XkbInfoPtr              xkbi;
469 XkbServerMapPtr         srv;
470 XkbClientMapPtr         map;
471
472     if ((dpy->flags & XlibDisplayNoXkb) ||
473         (!dpy->xkb_info && !XkbUseExtension(dpy,NULL,NULL))||
474         (!xkb))
475         return False;
476     map= xkb->map;
477     srv= xkb->server;
478
479     if (((which&XkbKeyTypesMask)&&((!map)||(!map->types)))||
480         ((which&XkbKeySymsMask)&&((!map)||(!map->syms)||(!map->key_sym_map)))||
481         ((which&XkbKeyActionsMask)&&((!srv)||(!srv->key_acts)))||
482         ((which&XkbKeyBehaviorsMask)&&((!srv)||(!srv->behaviors)))||
483         ((which&XkbVirtualModsMask)&&(!srv))||
484         ((which&XkbExplicitComponentsMask)&&((!srv)||(!srv->explicit)))||
485         ((which&XkbModifierMapMask)&&((!map)||(!map->modmap)))||
486         ((which&XkbVirtualModMapMask)&&((!srv)||(!srv->vmodmap))))
487         return False;
488
489     LockDisplay(dpy);
490     xkbi = dpy->xkb_info;
491     GetReq(kbSetMap, req);
492     req->reqType = xkbi->codes->major_opcode;
493     req->xkbReqType = X_kbSetMap;
494     req->deviceSpec = xkb->device_spec;
495     req->present = which;
496     req->flags = XkbSetMapAllFlags;
497     req->minKeyCode= xkb->min_key_code;
498     req->maxKeyCode= xkb->max_key_code;
499     req->firstType = 0;
500     if (which&XkbKeyTypesMask)  req->nTypes = map->num_types;
501     else                        req->nTypes = 0;
502     if (which&XkbKeySymsMask) {
503         req->firstKeySym = xkb->min_key_code;
504         req->nKeySyms = XkbNumKeys(xkb);
505     }
506     if (which&XkbKeyActionsMask) {
507         req->firstKeyAct = xkb->min_key_code;
508         req->nKeyActs = XkbNumKeys(xkb);
509     }
510     if (which&XkbKeyBehaviorsMask) {
511         req->firstKeyBehavior = xkb->min_key_code;
512         req->nKeyBehaviors = XkbNumKeys(xkb);
513     }
514     if (which&XkbVirtualModsMask)
515         req->virtualMods= ~0;
516     if (which&XkbExplicitComponentsMask) {
517         req->firstKeyExplicit= xkb->min_key_code;
518         req->nKeyExplicit = XkbNumKeys(xkb);
519     }
520     if (which&XkbModifierMapMask) {
521         req->firstModMapKey= xkb->min_key_code;
522         req->nModMapKeys = XkbNumKeys(xkb);
523     }
524     if (which&XkbVirtualModMapMask) {
525         req->firstVModMapKey= xkb->min_key_code;
526         req->nVModMapKeys = XkbNumKeys(xkb);
527     }
528     SendSetMap(dpy,xkb,req);
529     UnlockDisplay(dpy);
530     SyncHandle();
531     return True;
532 }
533
534 Bool
535 XkbChangeMap(Display *dpy,XkbDescPtr xkb,XkbMapChangesPtr changes)
536 {
537 register xkbSetMapReq * req;
538 XkbInfoPtr              xkbi;
539 XkbServerMapPtr         srv;
540 XkbClientMapPtr         map;
541
542     if ((dpy->flags & XlibDisplayNoXkb) ||
543         (!dpy->xkb_info && !XkbUseExtension(dpy,NULL,NULL))||
544         (!xkb)||(!changes))
545         return False;
546     srv= xkb->server;
547     map= xkb->map;
548
549     if (((changes->changed&XkbKeyTypesMask)&&((!map)||(!map->types)))||
550         ((changes->changed&XkbKeySymsMask)&&((!map)||(!map->syms)||
551                                 (!map->key_sym_map)))||
552         ((changes->changed&XkbKeyActionsMask)&&((!srv)||(!srv->key_acts)))||
553         ((changes->changed&XkbKeyBehaviorsMask)&&((!srv)||(!srv->behaviors)))||
554         ((changes->changed&XkbVirtualModsMask)&&(!srv))||
555         ((changes->changed&XkbExplicitComponentsMask)&&
556                                 ((!srv)||(!srv->explicit)))||
557         ((changes->changed&XkbModifierMapMask)&&((!map)||(!map->modmap)))||
558         ((changes->changed&XkbVirtualModMapMask)&&((!srv)||(!srv->vmodmap))))
559         return False;
560
561     LockDisplay(dpy);
562     xkbi = dpy->xkb_info;
563     GetReq(kbSetMap, req);
564     req->reqType = xkbi->codes->major_opcode;
565     req->xkbReqType = X_kbSetMap;
566     req->deviceSpec = xkb->device_spec;
567     req->present = changes->changed;
568     req->flags = XkbSetMapRecomputeActions;
569     req->minKeyCode= xkb->min_key_code;
570     req->maxKeyCode= xkb->max_key_code;
571     req->firstType = changes->first_type;
572     req->nTypes = changes->num_types;
573     req->firstKeySym = changes->first_key_sym;
574     req->nKeySyms = changes->num_key_syms;
575     req->firstKeyAct = changes->first_key_act;
576     req->nKeyActs = changes->num_key_acts;
577     req->firstKeyBehavior = changes->first_key_behavior;
578     req->nKeyBehaviors = changes->num_key_behaviors;
579     req->virtualMods = changes->vmods;
580     req->firstKeyExplicit = changes->first_key_explicit;
581     req->nKeyExplicit = changes->num_key_explicit;
582     req->firstModMapKey = changes->first_modmap_key;
583     req->nModMapKeys = changes->num_modmap_keys;
584     req->firstVModMapKey = changes->first_vmodmap_key;
585     req->nVModMapKeys = changes->num_vmodmap_keys;
586     SendSetMap(dpy,xkb,req);
587     UnlockDisplay(dpy);
588     SyncHandle();
589     return True;
590 }
591