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