XKBSetMap.c revision e9fcaa8a
1/************************************************************
2Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc.
3
4Permission to use, copy, modify, and distribute this
5software and its documentation for any purpose and without
6fee is hereby granted, provided that the above copyright
7notice appear in all copies and that both that copyright
8notice and this permission notice appear in supporting
9documentation, and that the name of Silicon Graphics not be
10used in advertising or publicity pertaining to distribution
11of the software without specific prior written permission.
12Silicon Graphics makes no representation about the suitability
13of this software for any purpose. It is provided "as is"
14without any express or implied warranty.
15
16SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
23THE 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
35static 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
57static 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
103static 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
124static void
125_XkbWriteKeySyms(Display *dpy,XkbDescPtr xkb,xkbSetMapReq *req)
126{
127register KeySym *	pSym;
128CARD32 *		outSym;
129XkbSymMapPtr		symMap;
130xkbSymMapWireDesc *desc;
131register 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
156static 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
176static 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
207static int
208_XkbSizeKeyBehaviors(XkbDescPtr	xkb,xkbSetMapReq *req)
209{
210register 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
228static void
229_XkbWriteKeyBehaviors(Display *dpy,XkbDescPtr xkb,xkbSetMapReq *req)
230{
231register int 		i,first,last;
232xkbBehaviorWireDesc *	wire;
233char *			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
255static unsigned
256_XkbSizeVirtualMods(xkbSetMapReq *req)
257{
258register 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
272static 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
292static int
293_XkbSizeKeyExplicit(XkbDescPtr xkb,xkbSetMapReq *req)
294{
295register 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
314static void
315_XkbWriteKeyExplicit(Display *dpy,XkbDescPtr xkb,xkbSetMapReq *req)
316{
317register int	i,first,last;
318CARD8 *		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
336static int
337_XkbSizeModifierMap(XkbDescPtr xkb,xkbSetMapReq *req)
338{
339register 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
358static void
359_XkbWriteModifierMap(Display *dpy,XkbDescPtr xkb,xkbSetMapReq *req)
360{
361register int	i,first,last;
362CARD8 *		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
382static int
383_XkbSizeVirtualModMap(XkbDescPtr xkb,xkbSetMapReq *req)
384{
385register 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
404static void
405_XkbWriteVirtualModMap(Display *dpy,XkbDescPtr xkb,xkbSetMapReq *req)
406{
407register int		i,first,last;
408xkbVModMapWireDesc *	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
428static void
429SendSetMap(Display *dpy,XkbDescPtr xkb,xkbSetMapReq *req)
430{
431xkbSetMapReq tmp;
432unsigned 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
464Bool
465XkbSetMap(Display *dpy,unsigned which,XkbDescPtr xkb)
466{
467register xkbSetMapReq *	req;
468XkbInfoPtr 		xkbi;
469XkbServerMapPtr		srv;
470XkbClientMapPtr		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
534Bool
535XkbChangeMap(Display *dpy,XkbDescPtr xkb,XkbMapChangesPtr changes)
536{
537register xkbSetMapReq *	req;
538XkbInfoPtr 		xkbi;
539XkbServerMapPtr		srv;
540XkbClientMapPtr		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
592