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