xkbInit.c revision 05b261ec
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_DIX_CONFIG_H
28#include <dix-config.h>
29#endif
30
31#ifdef HAVE_XKB_CONFIG_H
32#include <xkb-config.h>
33#endif
34
35#include <stdio.h>
36#include <stdlib.h>
37#include <ctype.h>
38#include <unistd.h>
39#include <math.h>
40#define NEED_EVENTS 1
41#include <X11/X.h>
42#include <X11/Xproto.h>
43#include <X11/keysym.h>
44#include <X11/Xatom.h>
45#include "misc.h"
46#include "inputstr.h"
47#include "opaque.h"
48#include "property.h"
49#define	XKBSRV_NEED_FILE_FUNCS
50#include <xkbsrv.h>
51#include <X11/extensions/XKBgeom.h>
52#include <X11/extensions/XKMformat.h>
53#include <X11/extensions/XKBfile.h>
54#include "xkb.h"
55
56#define	CREATE_ATOM(s)	MakeAtom(s,sizeof(s)-1,1)
57
58#ifdef sgi
59#define LED_CAPS	5
60#define	LED_NUM		6
61#define	LED_SCROLL	7
62#define	PHYS_LEDS	0x7f
63#define	LED_COMPOSE	8
64#else
65#if defined(ultrix) || defined(__osf__) || defined(__alpha) || defined(__alpha__)
66#define	LED_COMPOSE	2
67#define LED_CAPS	3
68#define	LED_SCROLL	4
69#define	LED_NUM		5
70#define	PHYS_LEDS	0x1f
71#else
72#ifdef sun
73#define LED_NUM		1
74#define	LED_SCROLL	2
75#define	LED_COMPOSE	3
76#define LED_CAPS	4
77#define	PHYS_LEDS	0x0f
78#else
79#define	LED_CAPS	1
80#define	LED_NUM		2
81#define	LED_SCROLL	3
82#define	PHYS_LEDS	0x07
83#endif
84#endif
85#endif
86
87#define	MAX_TOC	16
88typedef struct	_SrvXkmInfo {
89	DeviceIntPtr	dev;
90	FILE *		file;
91	XkbFileInfo	xkbinfo;
92} SrvXkmInfo;
93
94
95/***====================================================================***/
96
97#ifndef XKB_BASE_DIRECTORY
98#define	XKB_BASE_DIRECTORY	"/usr/lib/X11/xkb"
99#endif
100#ifndef XKB_BIN_DIRECTORY
101#define	XKB_BIN_DIRECTORY	XKB_BASE_DIRECTORY
102#endif
103#ifndef XKB_DFLT_RULES_FILE
104#define	XKB_DFLT_RULES_FILE	"rules"
105#endif
106#ifndef XKB_DFLT_KB_LAYOUT
107#define	XKB_DFLT_KB_LAYOUT	"us"
108#endif
109#ifndef XKB_DFLT_KB_MODEL
110#define	XKB_DFLT_KB_MODEL	"dflt"
111#endif
112#ifndef XKB_DFLT_KB_VARIANT
113#define	XKB_DFLT_KB_VARIANT	NULL
114#endif
115#ifndef XKB_DFLT_KB_OPTIONS
116#define	XKB_DFLT_KB_OPTIONS	NULL
117#endif
118#ifndef XKB_DFLT_DISABLED
119#define	XKB_DFLT_DISABLED	True
120#endif
121#ifndef XKB_DFLT_RULES_PROP
122#define	XKB_DFLT_RULES_PROP	True
123#endif
124
125char	*		XkbBaseDirectory=	XKB_BASE_DIRECTORY;
126char	*		XkbBinDirectory=	XKB_BIN_DIRECTORY;
127static int	 	XkbWantAccessX=		0;
128static XkbFileInfo *	_XkbInitFileInfo=	NULL;
129
130static Bool		rulesDefined=		False;
131static char *		XkbRulesFile=		NULL;
132static char *		XkbModelDflt=		NULL;
133static char *		XkbLayoutDflt=		NULL;
134static char *		XkbVariantDflt=		NULL;
135static char *		XkbOptionsDflt=		NULL;
136
137static char *		XkbModelUsed=	NULL;
138static char *		XkbLayoutUsed=	NULL;
139static char *		XkbVariantUsed=	NULL;
140static char *		XkbOptionsUsed=	NULL;
141
142_X_EXPORT Bool		noXkbExtension=		XKB_DFLT_DISABLED;
143static Bool		XkbWantRulesProp=	XKB_DFLT_RULES_PROP;
144
145/***====================================================================***/
146
147static char *
148XkbGetRulesDflts(XkbRF_VarDefsPtr defs)
149{
150    if (XkbModelDflt)	defs->model= XkbModelDflt;
151    else		defs->model= XKB_DFLT_KB_MODEL;
152    if (XkbLayoutDflt)	defs->layout= XkbLayoutDflt;
153    else		defs->layout= XKB_DFLT_KB_LAYOUT;
154    if (XkbVariantDflt)	defs->variant= XkbVariantDflt;
155    else		defs->variant= XKB_DFLT_KB_VARIANT;
156    if (XkbOptionsDflt)	defs->options= XkbOptionsDflt;
157    else		defs->options= XKB_DFLT_KB_OPTIONS;
158    return (rulesDefined?XkbRulesFile:XKB_DFLT_RULES_FILE);
159}
160
161static Bool
162XkbWriteRulesProp(ClientPtr client, pointer closure)
163{
164int 			len,out;
165Atom			name;
166char *			pval;
167
168    if (rulesDefined && (!XkbRulesFile))
169	return False;
170    len= (XkbRulesFile?strlen(XkbRulesFile):strlen(XKB_DFLT_RULES_FILE));
171    len+= (XkbModelUsed?strlen(XkbModelUsed):0);
172    len+= (XkbLayoutUsed?strlen(XkbLayoutUsed):0);
173    len+= (XkbVariantUsed?strlen(XkbVariantUsed):0);
174    len+= (XkbOptionsUsed?strlen(XkbOptionsUsed):0);
175    if (len<1)
176	return True;
177
178    len+= 5; /* trailing NULs */
179
180    name= MakeAtom(_XKB_RF_NAMES_PROP_ATOM,strlen(_XKB_RF_NAMES_PROP_ATOM),1);
181    if (name==None) {
182	ErrorF("Atom error: %s not created\n",_XKB_RF_NAMES_PROP_ATOM);
183	return True;
184    }
185    pval= (char*) ALLOCATE_LOCAL(len);
186    if (!pval) {
187	ErrorF("Allocation error: %s proprerty not created\n",
188						_XKB_RF_NAMES_PROP_ATOM);
189	return True;
190    }
191    out= 0;
192    if (XkbRulesFile) {
193	strcpy(&pval[out],XkbRulesFile);
194	out+= strlen(XkbRulesFile);
195    } else {
196	strcpy(&pval[out],XKB_DFLT_RULES_FILE);
197	out+= strlen(XKB_DFLT_RULES_FILE);
198    }
199    pval[out++]= '\0';
200    if (XkbModelUsed) {
201	strcpy(&pval[out],XkbModelUsed);
202	out+= strlen(XkbModelUsed);
203    }
204    pval[out++]= '\0';
205    if (XkbLayoutUsed) {
206	strcpy(&pval[out],XkbLayoutUsed);
207	out+= strlen(XkbLayoutUsed);
208    }
209    pval[out++]= '\0';
210    if (XkbVariantUsed) {
211	strcpy(&pval[out],XkbVariantUsed);
212	out+= strlen(XkbVariantUsed);
213    }
214    pval[out++]= '\0';
215    if (XkbOptionsUsed) {
216	strcpy(&pval[out],XkbOptionsUsed);
217	out+= strlen(XkbOptionsUsed);
218    }
219    pval[out++]= '\0';
220    if (out!=len) {
221	ErrorF("Internal Error! bad size (%d!=%d) for _XKB_RULES_NAMES\n",
222								out,len);
223    }
224    ChangeWindowProperty(WindowTable[0],name,XA_STRING,8,PropModeReplace,
225							len,pval,True);
226    DEALLOCATE_LOCAL(pval);
227    return True;
228}
229
230static void
231XkbSetRulesUsed(XkbRF_VarDefsPtr defs)
232{
233    if (XkbModelUsed)
234	_XkbFree(XkbModelUsed);
235    XkbModelUsed= (defs->model?_XkbDupString(defs->model):NULL);
236    if (XkbLayoutUsed)
237	_XkbFree(XkbLayoutUsed);
238    XkbLayoutUsed= (defs->layout?_XkbDupString(defs->layout):NULL);
239    if (XkbVariantUsed)
240	_XkbFree(XkbVariantUsed);
241    XkbVariantUsed= (defs->variant?_XkbDupString(defs->variant):NULL);
242    if (XkbOptionsUsed)
243	_XkbFree(XkbOptionsUsed);
244    XkbOptionsUsed= (defs->options?_XkbDupString(defs->options):NULL);
245    if (XkbWantRulesProp)
246	QueueWorkProc(XkbWriteRulesProp,NULL,NULL);
247    return;
248}
249
250_X_EXPORT void
251XkbSetRulesDflts(char *rulesFile,char *model,char *layout,
252					char *variant,char *options)
253{
254    if (XkbRulesFile)
255	_XkbFree(XkbRulesFile);
256    XkbRulesFile= _XkbDupString(rulesFile);
257    rulesDefined= True;
258    if (model) {
259	if (XkbModelDflt)
260	    _XkbFree(XkbModelDflt);
261	XkbModelDflt= _XkbDupString(model);
262    }
263    if (layout) {
264	if (XkbLayoutDflt)
265	    _XkbFree(XkbLayoutDflt);
266	XkbLayoutDflt= _XkbDupString(layout);
267    }
268    if (variant) {
269	if (XkbVariantDflt)
270	    _XkbFree(XkbVariantDflt);
271	XkbVariantDflt= _XkbDupString(variant);
272    }
273    if (options) {
274	if (XkbOptionsDflt)
275	    _XkbFree(XkbOptionsDflt);
276	XkbOptionsDflt= _XkbDupString(options);
277    }
278    return;
279}
280
281/***====================================================================***/
282
283#if defined(luna)
284#define	XKB_DDX_PERMANENT_LOCK	1
285#endif
286
287#include "xkbDflts.h"
288
289static Bool
290XkbInitKeyTypes(XkbDescPtr xkb,SrvXkmInfo *file)
291{
292    if (file->xkbinfo.defined&XkmTypesMask)
293	return True;
294    initTypeNames(NULL);
295    if (XkbAllocClientMap(xkb,XkbKeyTypesMask,num_dflt_types)!=Success)
296	return False;
297    if (XkbCopyKeyTypes(dflt_types,xkb->map->types,num_dflt_types)!=
298    								 Success) {
299	return False;
300    }
301    xkb->map->size_types= xkb->map->num_types= num_dflt_types;
302    return True;
303}
304
305static void
306XkbInitRadioGroups(XkbSrvInfoPtr xkbi,SrvXkmInfo *file)
307{
308    xkbi->nRadioGroups = 0;
309    xkbi->radioGroups = NULL;
310    return;
311}
312
313
314static Status
315XkbInitCompatStructs(XkbDescPtr xkb,SrvXkmInfo *file)
316{
317register int 	i;
318XkbCompatMapPtr	compat;
319
320    if (file->xkbinfo.defined&XkmCompatMapMask)
321	return Success;
322    if (XkbAllocCompatMap(xkb,XkbAllCompatMask,num_dfltSI)!=Success)
323	return BadAlloc;
324    compat = xkb->compat;
325    if (compat->sym_interpret) {
326	compat->num_si = num_dfltSI;
327	memcpy((char *)compat->sym_interpret,(char *)dfltSI,sizeof(dfltSI));
328    }
329    for (i=0;i<XkbNumKbdGroups;i++) {
330	compat->groups[i]= compatMap.groups[i];
331	if (compat->groups[i].vmods!=0) {
332	    unsigned mask;
333	    mask= XkbMaskForVMask(xkb,compat->groups[i].vmods);
334	    compat->groups[i].mask= compat->groups[i].real_mods|mask;
335	}
336	else compat->groups[i].mask= compat->groups[i].real_mods;
337    }
338    return Success;
339}
340
341static void
342XkbInitSemantics(XkbDescPtr xkb,SrvXkmInfo *file)
343{
344    XkbInitKeyTypes(xkb,file);
345    XkbInitCompatStructs(xkb,file);
346    return;
347}
348
349/***====================================================================***/
350
351static Status
352XkbInitNames(XkbSrvInfoPtr xkbi,SrvXkmInfo *file)
353{
354XkbDescPtr	xkb;
355XkbNamesPtr	names;
356Status		rtrn;
357Atom		unknown;
358
359    xkb= xkbi->desc;
360    if ((rtrn=XkbAllocNames(xkb,XkbAllNamesMask,0,0))!=Success)
361	return rtrn;
362    unknown= CREATE_ATOM("unknown");
363    names = xkb->names;
364    if (names->keycodes==None)		names->keycodes= unknown;
365    if (names->geometry==None)		names->geometry= unknown;
366    if (names->phys_symbols==None)	names->phys_symbols= unknown;
367    if (names->symbols==None)		names->symbols= unknown;
368    if (names->types==None)		names->types= unknown;
369    if (names->compat==None)		names->compat= unknown;
370    if ((file->xkbinfo.defined&XkmVirtualModsMask)==0) {
371	if (names->vmods[vmod_NumLock]==None)
372	    names->vmods[vmod_NumLock]= CREATE_ATOM("NumLock");
373	if (names->vmods[vmod_Alt]==None)
374	    names->vmods[vmod_Alt]= CREATE_ATOM("Alt");
375	if (names->vmods[vmod_AltGr]==None)
376	    names->vmods[vmod_AltGr]= CREATE_ATOM("ModeSwitch");
377    }
378
379    if (((file->xkbinfo.defined&XkmIndicatorsMask)==0)||
380	((file->xkbinfo.defined&XkmGeometryMask)==0)) {
381	initIndicatorNames(NULL,xkb);
382	if (names->indicators[LED_CAPS-1]==None)
383	    names->indicators[LED_CAPS-1] = CREATE_ATOM("Caps Lock");
384	if (names->indicators[LED_NUM-1]==None)
385	    names->indicators[LED_NUM-1] = CREATE_ATOM("Num Lock");
386	if (names->indicators[LED_SCROLL-1]==None)
387	    names->indicators[LED_SCROLL-1] = CREATE_ATOM("Scroll Lock");
388#ifdef LED_COMPOSE
389	if (names->indicators[LED_COMPOSE-1]==None)
390	    names->indicators[LED_COMPOSE-1] = CREATE_ATOM("Compose");
391#endif
392    }
393#ifdef DEBUG_RADIO_GROUPS
394    if (names->num_rg<1) {
395	names->radio_groups= (Atom *)_XkbCalloc(RG_COUNT, sizeof(Atom));
396	if (names->radio_groups) {
397	    names->num_rg = RG_COUNT;
398	    names->radio_groups[RG_BOGUS_FUNCTION_GROUP]= CREATE_ATOM("BOGUS");
399	}
400    }
401#endif
402    if (xkb->geom!=NULL)
403	 names->geometry= xkb->geom->name;
404    else names->geometry= unknown;
405    return Success;
406}
407
408static Status
409XkbInitIndicatorMap(XkbSrvInfoPtr xkbi,SrvXkmInfo *file)
410{
411XkbDescPtr		xkb;
412XkbIndicatorPtr		map;
413XkbSrvLedInfoPtr	sli;
414
415    xkb= xkbi->desc;
416    if (XkbAllocIndicatorMaps(xkb)!=Success)
417	return BadAlloc;
418    if ((file->xkbinfo.defined&XkmIndicatorsMask)==0) {
419	map= xkb->indicators;
420	map->phys_indicators = PHYS_LEDS;
421	map->maps[LED_CAPS-1].flags= XkbIM_NoExplicit;
422	map->maps[LED_CAPS-1].which_mods= XkbIM_UseLocked;
423	map->maps[LED_CAPS-1].mods.mask= LockMask;
424	map->maps[LED_CAPS-1].mods.real_mods= LockMask;
425
426	map->maps[LED_NUM-1].flags= XkbIM_NoExplicit;
427	map->maps[LED_NUM-1].which_mods= XkbIM_UseLocked;
428	map->maps[LED_NUM-1].mods.mask= 0;
429	map->maps[LED_NUM-1].mods.real_mods= 0;
430	map->maps[LED_NUM-1].mods.vmods= vmod_NumLockMask;
431
432/* Metro Link */
433	map->maps[LED_SCROLL-1].flags= XkbIM_NoExplicit;
434	map->maps[LED_SCROLL-1].which_mods= XkbIM_UseLocked;
435	map->maps[LED_SCROLL-1].mods.mask= Mod3Mask;
436	map->maps[LED_SCROLL-1].mods.real_mods= Mod3Mask;
437/* Metro Link */
438    }
439    sli= XkbFindSrvLedInfo(xkbi->device,XkbDfltXIClass,XkbDfltXIId,0);
440    if (sli)
441	XkbCheckIndicatorMaps(xkbi->device,sli,XkbAllIndicatorsMask);
442    return Success;
443}
444
445static Status
446XkbInitControls(DeviceIntPtr pXDev,XkbSrvInfoPtr xkbi,SrvXkmInfo *file)
447{
448XkbDescPtr	xkb;
449XkbControlsPtr	ctrls;
450
451    xkb= xkbi->desc;
452    /* 12/31/94 (ef) -- XXX! Should check if controls loaded from file */
453    if (XkbAllocControls(xkb,XkbAllControlsMask)!=Success)
454	FatalError("Couldn't allocate keyboard controls\n");
455    ctrls= xkb->ctrls;
456    if ((file->xkbinfo.defined&XkmSymbolsMask)==0)
457	ctrls->num_groups = 1;
458    ctrls->groups_wrap = XkbSetGroupInfo(1,XkbWrapIntoRange,0);
459    ctrls->internal.mask = 0;
460    ctrls->internal.real_mods = 0;
461    ctrls->internal.vmods = 0;
462    ctrls->ignore_lock.mask = 0;
463    ctrls->ignore_lock.real_mods = 0;
464    ctrls->ignore_lock.vmods = 0;
465    ctrls->enabled_ctrls = XkbAccessXTimeoutMask|XkbRepeatKeysMask|
466				XkbMouseKeysAccelMask|XkbAudibleBellMask|
467				XkbIgnoreGroupLockMask;
468    if (XkbWantAccessX)
469	ctrls->enabled_ctrls|= XkbAccessXKeysMask;
470    AccessXInit(pXDev);
471    return Success;
472}
473
474void
475XkbInitDevice(DeviceIntPtr pXDev)
476{
477int			i;
478XkbSrvInfoPtr		xkbi;
479XkbChangesRec		changes;
480SrvXkmInfo		file;
481unsigned		check;
482XkbEventCauseRec	cause;
483
484    file.dev= pXDev;
485    file.file=NULL;
486    bzero(&file.xkbinfo,sizeof(XkbFileInfo));
487    bzero(&changes,sizeof(XkbChangesRec));
488    pXDev->key->xkbInfo= xkbi= _XkbTypedCalloc(1,XkbSrvInfoRec);
489    if ( xkbi ) {
490	XkbDescPtr	xkb;
491	if ((_XkbInitFileInfo!=NULL)&&(_XkbInitFileInfo->xkb!=NULL)) {
492	    file.xkbinfo= *_XkbInitFileInfo;
493	    xkbi->desc= _XkbInitFileInfo->xkb;
494	    _XkbInitFileInfo= NULL;
495	}
496	else {
497	    xkbi->desc= XkbAllocKeyboard();
498	    if (!xkbi->desc)
499		FatalError("Couldn't allocate keyboard description\n");
500	    xkbi->desc->min_key_code = pXDev->key->curKeySyms.minKeyCode;
501	    xkbi->desc->max_key_code = pXDev->key->curKeySyms.maxKeyCode;
502	}
503	xkb= xkbi->desc;
504	if (xkb->min_key_code == 0)
505	    xkb->min_key_code = pXDev->key->curKeySyms.minKeyCode;
506	if (xkb->max_key_code == 0)
507	    xkb->max_key_code = pXDev->key->curKeySyms.maxKeyCode;
508	if ((pXDev->key->curKeySyms.minKeyCode!=xkbi->desc->min_key_code)||
509	    (pXDev->key->curKeySyms.maxKeyCode!=xkbi->desc->max_key_code)) {
510	    /* 12/9/95 (ef) -- XXX! Maybe we should try to fix up one or */
511	    /*                 the other here, but for now just complain */
512	    /*                 can't just update the core range without */
513	    /*                 reallocating the KeySymsRec (pain)       */
514	    ErrorF("Internal Error!! XKB and core keymap have different range\n");
515	}
516	if (XkbAllocClientMap(xkb,XkbAllClientInfoMask,0)!=Success)
517	    FatalError("Couldn't allocate client map in XkbInitDevice\n");
518	i= XkbNumKeys(xkb)/3+1;
519	if (XkbAllocServerMap(xkb,XkbAllServerInfoMask,i)!=Success)
520	    FatalError("Couldn't allocate server map in XkbInitDevice\n");
521
522	xkbi->dfltPtrDelta=1;
523	xkbi->device = pXDev;
524
525	file.xkbinfo.xkb= xkb;
526	XkbInitSemantics(xkb,&file);
527	XkbInitNames(xkbi,&file);
528	XkbInitRadioGroups(xkbi,&file);
529
530	/* 12/31/94 (ef) -- XXX! Should check if state loaded from file */
531	bzero(&xkbi->state,sizeof(XkbStateRec));
532
533	XkbInitControls(pXDev,xkbi,&file);
534
535	if (file.xkbinfo.defined&XkmSymbolsMask)
536	   memcpy(pXDev->key->modifierMap,xkb->map->modmap,xkb->max_key_code+1);
537	else
538	   memcpy(xkb->map->modmap,pXDev->key->modifierMap,xkb->max_key_code+1);
539
540	XkbInitIndicatorMap(xkbi,&file);
541
542	XkbDDXInitDevice(pXDev);
543
544	if (!(file.xkbinfo.defined&XkmSymbolsMask)) {
545	    XkbUpdateKeyTypesFromCore(pXDev,xkb->min_key_code,XkbNumKeys(xkb),
546								&changes);
547	}
548	else {
549	    XkbUpdateCoreDescription(pXDev,True);
550	}
551	XkbSetCauseUnknown(&cause);
552	XkbUpdateActions(pXDev,xkb->min_key_code, XkbNumKeys(xkb),&changes,
553								&check,&cause);
554        /* For sanity.  The first time the connection
555         * is opened, the client side min and max are set
556         * using QueryMinMaxKeyCodes() which grabs them
557	 * from pXDev.
558	 */
559	pXDev->key->curKeySyms.minKeyCode = xkb->min_key_code;
560	pXDev->key->curKeySyms.maxKeyCode = xkb->max_key_code;
561    }
562    if (file.file!=NULL)
563	fclose(file.file);
564    return;
565}
566
567#if MAP_LENGTH > XkbMaxKeyCount
568#undef  XkbMaxKeyCount
569#define XkbMaxKeyCount MAP_LENGTH
570#endif
571
572_X_EXPORT Bool
573XkbInitKeyboardDeviceStruct(
574    DeviceIntPtr		dev,
575    XkbComponentNamesPtr	names,
576    KeySymsPtr                  pSymsIn,
577    CARD8                       pModsIn[],
578    void                        (*bellProc)(
579        int /*percent*/,
580        DeviceIntPtr /*device*/,
581        pointer /*ctrl*/,
582        int),
583    void                        (*ctrlProc)(
584        DeviceIntPtr /*device*/,
585        KeybdCtrl * /*ctrl*/))
586{
587XkbFileInfo		finfo;
588KeySymsRec		tmpSyms,*pSyms;
589CARD8			tmpMods[XkbMaxLegalKeyCode+1],*pMods;
590char			name[PATH_MAX],*rules;
591Bool			ok=False;
592XkbRF_VarDefsRec	defs;
593
594    if ((dev->key!=NULL)||(dev->kbdfeed!=NULL))
595	return False;
596    pSyms= pSymsIn;
597    pMods= pModsIn;
598    bzero(&defs,sizeof(XkbRF_VarDefsRec));
599    rules= XkbGetRulesDflts(&defs);
600
601    /*
602     * The strings are duplicated because it is not guaranteed that
603     * they are allocated, or that they are allocated for every server
604     * generation. Eventually they will be freed at the end of this
605     * function.
606     */
607    if (names->keymap) names->keymap = _XkbDupString(names->keymap);
608    if (names->keycodes) names->keycodes = _XkbDupString(names->keycodes);
609    if (names->types) names->types = _XkbDupString(names->types);
610    if (names->compat) names->compat = _XkbDupString(names->compat);
611    if (names->geometry) names->geometry = _XkbDupString(names->geometry);
612    if (names->symbols) names->symbols = _XkbDupString(names->symbols);
613
614    if (defs.model && defs.layout && rules) {
615	XkbComponentNamesRec	rNames;
616	bzero(&rNames,sizeof(XkbComponentNamesRec));
617	if (XkbDDXNamesFromRules(dev,rules,&defs,&rNames)) {
618	    if (rNames.keymap) {
619		if (!names->keymap)
620		    names->keymap = rNames.keymap;
621		else _XkbFree(rNames.keymap);
622	    }
623	    if (rNames.keycodes) {
624		if (!names->keycodes)
625		    names->keycodes =  rNames.keycodes;
626		else
627		    _XkbFree(rNames.keycodes);
628	    }
629	    if (rNames.types) {
630		if (!names->types)
631		    names->types = rNames.types;
632		else  _XkbFree(rNames.types);
633	    }
634	    if (rNames.compat) {
635		if (!names->compat)
636		    names->compat =  rNames.compat;
637		else  _XkbFree(rNames.compat);
638	    }
639	    if (rNames.symbols) {
640		if (!names->symbols)
641		    names->symbols =  rNames.symbols;
642		else _XkbFree(rNames.symbols);
643	    }
644	    if (rNames.geometry) {
645		if (!names->geometry)
646		    names->geometry = rNames.geometry;
647		else _XkbFree(rNames.geometry);
648	    }
649	    XkbSetRulesUsed(&defs);
650	}
651    }
652
653    if (names->keymap) {
654        XkbComponentNamesRec	tmpNames;
655	bzero(&tmpNames,sizeof(XkbComponentNamesRec));
656	tmpNames.keymap = names->keymap;
657        ok = (Bool) XkbDDXLoadKeymapByNames(dev,&tmpNames,XkmAllIndicesMask,0,
658					    &finfo,name,PATH_MAX);
659    }
660    if (!(ok && (finfo.xkb!=NULL)))
661        ok = (Bool) XkbDDXLoadKeymapByNames(dev,names,XkmAllIndicesMask,0,
662					    &finfo,name,PATH_MAX);
663
664    if (ok && (finfo.xkb!=NULL)) {
665	XkbDescPtr	xkb;
666	KeyCode		minKC,maxKC;
667
668	xkb= finfo.xkb;
669	minKC= xkb->min_key_code;
670	maxKC= xkb->max_key_code;
671	if (XkbIsLegalKeycode(minKC)&&XkbIsLegalKeycode(maxKC)&&(minKC<=maxKC)&&
672	    ((minKC!=pSyms->minKeyCode)||(maxKC!=pSyms->maxKeyCode))) {
673	    if (xkb->map!=NULL) {
674		KeySym	*inSym,*outSym;
675		int	width= pSymsIn->mapWidth;
676
677		tmpSyms.minKeyCode= minKC;
678		tmpSyms.maxKeyCode= maxKC;
679
680		if (minKC<pSymsIn->minKeyCode)
681		    minKC= pSymsIn->minKeyCode;
682		if (maxKC>pSymsIn->maxKeyCode)
683		    maxKC= pSymsIn->maxKeyCode;
684
685		tmpSyms.mapWidth= width;
686		tmpSyms.map= _XkbTypedCalloc(width*XkbNumKeys(xkb),KeySym);
687		inSym= &pSymsIn->map[(minKC-pSymsIn->minKeyCode)*width];
688		outSym= &tmpSyms.map[(minKC-tmpSyms.minKeyCode)*width];
689		memcpy(outSym,inSym,((maxKC-minKC+1)*width)*sizeof(KeySym));
690		pSyms= &tmpSyms;
691	    }
692	    if ((xkb->map!=NULL)&&(xkb->map->modmap!=NULL)) {
693		bzero(tmpMods,XkbMaxKeyCount);
694		memcpy(tmpMods,xkb->map->modmap,maxKC+1);
695		pMods= tmpMods;
696	    }
697	}
698	_XkbInitFileInfo= &finfo;
699    }
700    else {
701	LogMessage(X_WARNING, "Couldn't load XKB keymap, falling back to pre-XKB keymap\n");
702    }
703    ok= InitKeyboardDeviceStruct((DevicePtr)dev,pSyms,pMods,bellProc,ctrlProc);
704    _XkbInitFileInfo= NULL;
705    if ((pSyms==&tmpSyms)&&(pSyms->map!=NULL)) {
706	_XkbFree(pSyms->map);
707	pSyms->map= NULL;
708    }
709
710    if (names->keymap) _XkbFree(names->keymap);
711    names->keymap = NULL;
712    if (names->keycodes) _XkbFree(names->keycodes);
713    names->keycodes = NULL;
714    if (names->types) _XkbFree(names->types);
715    names->types = NULL;
716    if (names->compat) _XkbFree(names->compat);
717    names->compat = NULL;
718    if (names->geometry) _XkbFree(names->geometry);
719    names->geometry = NULL;
720    if (names->symbols) _XkbFree(names->symbols);
721    names->symbols = NULL;
722
723    return ok;
724}
725
726/***====================================================================***/
727
728	/*
729	 * InitKeyClassDeviceStruct initializes the key class before it
730	 * initializes the keyboard feedback class for a device.
731	 * UpdateActions can't set up the correct autorepeat for keyboard
732	 * initialization because the keyboard feedback isn't created yet.
733	 * Instead, UpdateActions notes the "correct" autorepeat in the
734	 * SrvInfo structure and InitKbdFeedbackClass calls UpdateAutoRepeat
735	 * to apply the computed autorepeat once the feedback class exists.
736	 *
737	 * DIX will apply the changed autorepeat, so there's no need to
738	 * do so here.   This function returns True if both RepeatKeys and
739	 * the core protocol autorepeat ctrls are set (i.e. should use
740	 * software autorepeat), false otherwise.
741	 *
742	 * This function also computes the autorepeat accelerators for the
743	 * default indicator feedback.
744	 */
745int
746XkbFinishDeviceInit(DeviceIntPtr pXDev)
747{
748XkbSrvInfoPtr		xkbi;
749XkbDescPtr		xkb;
750int			softRepeat;
751XkbSrvLedInfoPtr	sli;
752
753    xkbi = NULL;
754    if (pXDev && pXDev->key && pXDev->key->xkbInfo && pXDev->kbdfeed) {
755	xkbi= pXDev->key->xkbInfo;
756	xkb= xkbi->desc;
757	if (pXDev->kbdfeed) {
758	    xkbi->kbdProc= pXDev->kbdfeed->CtrlProc;
759	    pXDev->kbdfeed->CtrlProc= XkbDDXKeybdCtrlProc;
760	}
761	if (pXDev->kbdfeed->ctrl.autoRepeat)
762	    xkb->ctrls->enabled_ctrls|= XkbRepeatKeysMask;
763	softRepeat= (xkb->ctrls->enabled_ctrls&XkbRepeatKeysMask)!=0;
764	if (pXDev->kbdfeed) {
765	    memcpy(pXDev->kbdfeed->ctrl.autoRepeats,
766		   xkb->ctrls->per_key_repeat,XkbPerKeyBitArraySize);
767	    softRepeat= softRepeat&&pXDev->kbdfeed->ctrl.autoRepeat;
768	}
769    }
770    else softRepeat= 0;
771    sli= XkbFindSrvLedInfo(pXDev,XkbDfltXIClass,XkbDfltXIId,0);
772    if (sli && xkbi)
773	XkbCheckIndicatorMaps(xkbi->device,sli,XkbAllIndicatorsMask);
774#ifdef DEBUG
775    else ErrorF("No indicator feedback in XkbFinishInit (shouldn't happen)!\n");
776#endif
777    return softRepeat;
778}
779
780	/*
781	 * Be very careful about what does and doesn't get freed by this
782	 * function.  To reduce fragmentation, XkbInitDevice allocates a
783	 * single huge block per device and divides it up into most of the
784	 * fixed-size structures for the device.   Don't free anything that
785	 * is part of this larger block.
786	 */
787void
788XkbFreeInfo(XkbSrvInfoPtr xkbi)
789{
790    if (xkbi->radioGroups) {
791	_XkbFree(xkbi->radioGroups);
792	xkbi->radioGroups= NULL;
793    }
794    if (xkbi->mouseKeyTimer) {
795	TimerFree(xkbi->mouseKeyTimer);
796	xkbi->mouseKeyTimer= NULL;
797    }
798    if (xkbi->slowKeysTimer) {
799	TimerFree(xkbi->slowKeysTimer);
800	xkbi->slowKeysTimer= NULL;
801    }
802    if (xkbi->bounceKeysTimer) {
803	TimerFree(xkbi->bounceKeysTimer);
804	xkbi->bounceKeysTimer= NULL;
805    }
806    if (xkbi->repeatKeyTimer) {
807	TimerFree(xkbi->repeatKeyTimer);
808	xkbi->repeatKeyTimer= NULL;
809    }
810    if (xkbi->krgTimer) {
811	TimerFree(xkbi->krgTimer);
812	xkbi->krgTimer= NULL;
813    }
814    xkbi->beepType= _BEEP_NONE;
815    if (xkbi->beepTimer) {
816	TimerFree(xkbi->beepTimer);
817	xkbi->beepTimer= NULL;
818    }
819    if (xkbi->desc) {
820	XkbFreeKeyboard(xkbi->desc,XkbAllComponentsMask,True);
821	xkbi->desc= NULL;
822    }
823    _XkbFree(xkbi);
824    return;
825}
826
827/***====================================================================***/
828
829extern int	XkbDfltRepeatDelay;
830extern int	XkbDfltRepeatInterval;
831
832extern unsigned short	XkbDfltAccessXTimeout;
833extern unsigned int	XkbDfltAccessXTimeoutMask;
834extern unsigned int	XkbDfltAccessXFeedback;
835extern unsigned char	XkbDfltAccessXOptions;
836
837int
838XkbProcessArguments(int argc,char *argv[],int i)
839{
840    if (strcmp(argv[i],"-kb")==0) {
841	noXkbExtension= True;
842	return 1;
843    }
844    else if (strcmp(argv[i],"+kb")==0) {
845	noXkbExtension= False;
846	return 1;
847    }
848    else if (strncmp(argv[i], "-xkbdir", 7) == 0) {
849	if(++i < argc) {
850#if !defined(WIN32) && !defined(__CYGWIN__)
851	    if (getuid() != geteuid()) {
852		LogMessage(X_WARNING, "-xkbdir is not available for setuid X servers\n");
853		return -1;
854	    } else
855#endif
856	    {
857		if (strlen(argv[i]) < PATH_MAX) {
858		    XkbBaseDirectory= argv[i];
859		    return 2;
860	        } else {
861		    LogMessage(X_ERROR, "-xkbdir pathname too long\n");
862		    return -1;
863		}
864	    }
865	}
866	else {
867	    return -1;
868	}
869    }
870    else if ((strncmp(argv[i],"-accessx",8)==0)||
871                 (strncmp(argv[i],"+accessx",8)==0)) {
872	int j=1;
873	if (argv[i][0]=='-')
874	    XkbWantAccessX= 0;
875	else {
876	    XkbWantAccessX= 1;
877
878	    if ( ((i+1)<argc) && (isdigit(argv[i+1][0])) ) {
879		XkbDfltAccessXTimeout = atoi(argv[++i]);
880		j++;
881
882		if ( ((i+1)<argc) && (isdigit(argv[i+1][0])) ) {
883		    /*
884		     * presumption that the reasonably useful range of
885		     * values fits in 0..MAXINT since SunOS 4 doesn't
886		     * have strtoul.
887		     */
888		    XkbDfltAccessXTimeoutMask=(unsigned int)
889					      strtol(argv[++i],NULL,16);
890		    j++;
891		}
892		if ( ((i+1)<argc) && (isdigit(argv[i+1][0])) ) {
893		    if (argv[++i][0] == '1' )
894			XkbDfltAccessXFeedback=XkbAccessXFeedbackMask;
895		    else
896			XkbDfltAccessXFeedback=0;
897		    j++;
898		}
899		if ( ((i+1)<argc) && (isdigit(argv[i+1][0])) ) {
900		    XkbDfltAccessXOptions=(unsigned char)
901					   strtol(argv[++i],NULL,16);
902		    j++;
903		}
904	    }
905	}
906	return j;
907    }
908    if ((strcmp(argv[i], "-ardelay") == 0) ||
909        (strcmp (argv[i], "-ar1") == 0)) {	/* -ardelay int */
910	if (++i >= argc) UseMsg ();
911	XkbDfltRepeatDelay = (long)atoi(argv[i]);
912	return 2;
913    }
914    if ((strcmp(argv[i], "-arinterval") == 0) ||
915        (strcmp (argv[i], "-ar2") == 0)) {	/* -arinterval int */
916	if (++i >= argc) UseMsg ();
917	XkbDfltRepeatInterval = (long)atoi(argv[i]);
918	return 2;
919    }
920    return 0;
921}
922
923void
924XkbUseMsg(void)
925{
926    ErrorF("-kb                    disable the X Keyboard Extension\n");
927    ErrorF("+kb                    enable the X Keyboard Extension\n");
928    ErrorF("[+-]accessx [ timeout [ timeout_mask [ feedback [ options_mask] ] ] ]\n");
929    ErrorF("                       enable/disable accessx key sequences\n");
930    ErrorF("-ardelay               set XKB autorepeat delay\n");
931    ErrorF("-arinterval            set XKB autorepeat interval\n");
932}
933