1*4882a593Smuzhiyun /************************************************************
2*4882a593Smuzhiyun Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc.
3*4882a593Smuzhiyun
4*4882a593Smuzhiyun Permission to use, copy, modify, and distribute this
5*4882a593Smuzhiyun software and its documentation for any purpose and without
6*4882a593Smuzhiyun fee is hereby granted, provided that the above copyright
7*4882a593Smuzhiyun notice appear in all copies and that both that copyright
8*4882a593Smuzhiyun notice and this permission notice appear in supporting
9*4882a593Smuzhiyun documentation, and that the name of Silicon Graphics not be
10*4882a593Smuzhiyun used in advertising or publicity pertaining to distribution
11*4882a593Smuzhiyun of the software without specific prior written permission.
12*4882a593Smuzhiyun Silicon Graphics makes no representation about the suitability
13*4882a593Smuzhiyun of this software for any purpose. It is provided "as is"
14*4882a593Smuzhiyun without any express or implied warranty.
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17*4882a593Smuzhiyun SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18*4882a593Smuzhiyun AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19*4882a593Smuzhiyun GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20*4882a593Smuzhiyun DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21*4882a593Smuzhiyun DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22*4882a593Smuzhiyun OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH
23*4882a593Smuzhiyun THE USE OR PERFORMANCE OF THIS SOFTWARE.
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun ********************************************************/
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun #ifdef HAVE_DIX_CONFIG_H
28*4882a593Smuzhiyun #include <dix-config.h>
29*4882a593Smuzhiyun #endif
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun #include <xkb-config.h>
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun #include <stdio.h>
34*4882a593Smuzhiyun #include <ctype.h>
35*4882a593Smuzhiyun #include <X11/X.h>
36*4882a593Smuzhiyun #include <X11/Xos.h>
37*4882a593Smuzhiyun #include <X11/Xproto.h>
38*4882a593Smuzhiyun #include <X11/keysym.h>
39*4882a593Smuzhiyun #include <X11/extensions/XKM.h>
40*4882a593Smuzhiyun #include "inputstr.h"
41*4882a593Smuzhiyun #include "scrnintstr.h"
42*4882a593Smuzhiyun #include "windowstr.h"
43*4882a593Smuzhiyun #define XKBSRV_NEED_FILE_FUNCS
44*4882a593Smuzhiyun #include <xkbsrv.h>
45*4882a593Smuzhiyun #include <X11/extensions/XI.h>
46*4882a593Smuzhiyun #include "xkb.h"
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun #define PRE_ERROR_MSG "\"The XKEYBOARD keymap compiler (xkbcomp) reports:\""
49*4882a593Smuzhiyun #define ERROR_PREFIX "\"> \""
50*4882a593Smuzhiyun #define POST_ERROR_MSG1 "\"Errors from xkbcomp are not fatal to the X server\""
51*4882a593Smuzhiyun #define POST_ERROR_MSG2 "\"End of messages from xkbcomp\""
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun #if defined(WIN32)
54*4882a593Smuzhiyun #define PATHSEPARATOR "\\"
55*4882a593Smuzhiyun #else
56*4882a593Smuzhiyun #define PATHSEPARATOR "/"
57*4882a593Smuzhiyun #endif
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun static unsigned
60*4882a593Smuzhiyun LoadXKM(unsigned want, unsigned need, const char *keymap, XkbDescPtr *xkbRtrn);
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun static void
OutputDirectory(char * outdir,size_t size)63*4882a593Smuzhiyun OutputDirectory(char *outdir, size_t size)
64*4882a593Smuzhiyun {
65*4882a593Smuzhiyun #ifndef WIN32
66*4882a593Smuzhiyun /* Can we write an xkm and then open it too? */
67*4882a593Smuzhiyun if (access(XKM_OUTPUT_DIR, W_OK | X_OK) == 0 &&
68*4882a593Smuzhiyun (strlen(XKM_OUTPUT_DIR) < size)) {
69*4882a593Smuzhiyun (void) strcpy(outdir, XKM_OUTPUT_DIR);
70*4882a593Smuzhiyun }
71*4882a593Smuzhiyun else
72*4882a593Smuzhiyun #else
73*4882a593Smuzhiyun if (strlen(Win32TempDir()) + 1 < size) {
74*4882a593Smuzhiyun (void) strcpy(outdir, Win32TempDir());
75*4882a593Smuzhiyun (void) strcat(outdir, "\\");
76*4882a593Smuzhiyun }
77*4882a593Smuzhiyun else
78*4882a593Smuzhiyun #endif
79*4882a593Smuzhiyun if (strlen("/tmp/") < size) {
80*4882a593Smuzhiyun (void) strcpy(outdir, "/tmp/");
81*4882a593Smuzhiyun }
82*4882a593Smuzhiyun }
83*4882a593Smuzhiyun
84*4882a593Smuzhiyun /**
85*4882a593Smuzhiyun * Callback invoked by XkbRunXkbComp. Write to out to talk to xkbcomp.
86*4882a593Smuzhiyun */
87*4882a593Smuzhiyun typedef void (*xkbcomp_buffer_callback)(FILE *out, void *userdata);
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun /**
90*4882a593Smuzhiyun * Start xkbcomp, let the callback write into xkbcomp's stdin. When done,
91*4882a593Smuzhiyun * return a strdup'd copy of the file name we've written to.
92*4882a593Smuzhiyun */
93*4882a593Smuzhiyun static char *
RunXkbComp(xkbcomp_buffer_callback callback,void * userdata)94*4882a593Smuzhiyun RunXkbComp(xkbcomp_buffer_callback callback, void *userdata)
95*4882a593Smuzhiyun {
96*4882a593Smuzhiyun FILE *out;
97*4882a593Smuzhiyun char *buf = NULL, keymap[PATH_MAX], xkm_output_dir[PATH_MAX];
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun const char *emptystring = "";
100*4882a593Smuzhiyun char *xkbbasedirflag = NULL;
101*4882a593Smuzhiyun const char *xkbbindir = emptystring;
102*4882a593Smuzhiyun const char *xkbbindirsep = emptystring;
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun #ifdef WIN32
105*4882a593Smuzhiyun /* WIN32 has no popen. The input must be stored in a file which is
106*4882a593Smuzhiyun used as input for xkbcomp. xkbcomp does not read from stdin. */
107*4882a593Smuzhiyun char tmpname[PATH_MAX];
108*4882a593Smuzhiyun const char *xkmfile = tmpname;
109*4882a593Smuzhiyun #else
110*4882a593Smuzhiyun const char *xkmfile = "-";
111*4882a593Smuzhiyun #endif
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun snprintf(keymap, sizeof(keymap), "server-%s", display);
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun OutputDirectory(xkm_output_dir, sizeof(xkm_output_dir));
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun #ifdef WIN32
118*4882a593Smuzhiyun strcpy(tmpname, Win32TempDir());
119*4882a593Smuzhiyun strcat(tmpname, "\\xkb_XXXXXX");
120*4882a593Smuzhiyun (void) mktemp(tmpname);
121*4882a593Smuzhiyun #endif
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun if (XkbBaseDirectory != NULL) {
124*4882a593Smuzhiyun if (asprintf(&xkbbasedirflag, "\"-R%s\"", XkbBaseDirectory) == -1)
125*4882a593Smuzhiyun xkbbasedirflag = NULL;
126*4882a593Smuzhiyun }
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun if (XkbBinDirectory != NULL) {
129*4882a593Smuzhiyun int ld = strlen(XkbBinDirectory);
130*4882a593Smuzhiyun int lps = strlen(PATHSEPARATOR);
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun xkbbindir = XkbBinDirectory;
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun if ((ld >= lps) && (strcmp(xkbbindir + ld - lps, PATHSEPARATOR) != 0)) {
135*4882a593Smuzhiyun xkbbindirsep = PATHSEPARATOR;
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun }
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun if (asprintf(&buf,
140*4882a593Smuzhiyun "\"%s%sxkbcomp\" -w %d %s -xkm \"%s\" "
141*4882a593Smuzhiyun "-em1 %s -emp %s -eml %s \"%s%s.xkm\"",
142*4882a593Smuzhiyun xkbbindir, xkbbindirsep,
143*4882a593Smuzhiyun ((xkbDebugFlags < 2) ? 1 :
144*4882a593Smuzhiyun ((xkbDebugFlags > 10) ? 10 : (int) xkbDebugFlags)),
145*4882a593Smuzhiyun xkbbasedirflag ? xkbbasedirflag : "", xkmfile,
146*4882a593Smuzhiyun PRE_ERROR_MSG, ERROR_PREFIX, POST_ERROR_MSG1,
147*4882a593Smuzhiyun xkm_output_dir, keymap) == -1)
148*4882a593Smuzhiyun buf = NULL;
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun free(xkbbasedirflag);
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun if (!buf) {
153*4882a593Smuzhiyun LogMessage(X_ERROR,
154*4882a593Smuzhiyun "XKB: Could not invoke xkbcomp: not enough memory\n");
155*4882a593Smuzhiyun return NULL;
156*4882a593Smuzhiyun }
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun #ifndef WIN32
159*4882a593Smuzhiyun out = Popen(buf, "w");
160*4882a593Smuzhiyun #else
161*4882a593Smuzhiyun out = fopen(tmpname, "w");
162*4882a593Smuzhiyun #endif
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun if (out != NULL) {
165*4882a593Smuzhiyun /* Now write to xkbcomp */
166*4882a593Smuzhiyun (*callback)(out, userdata);
167*4882a593Smuzhiyun
168*4882a593Smuzhiyun #ifndef WIN32
169*4882a593Smuzhiyun if (Pclose(out) == 0)
170*4882a593Smuzhiyun #else
171*4882a593Smuzhiyun if (fclose(out) == 0 && System(buf) >= 0)
172*4882a593Smuzhiyun #endif
173*4882a593Smuzhiyun {
174*4882a593Smuzhiyun if (xkbDebugFlags)
175*4882a593Smuzhiyun DebugF("[xkb] xkb executes: %s\n", buf);
176*4882a593Smuzhiyun free(buf);
177*4882a593Smuzhiyun #ifdef WIN32
178*4882a593Smuzhiyun unlink(tmpname);
179*4882a593Smuzhiyun #endif
180*4882a593Smuzhiyun return xnfstrdup(keymap);
181*4882a593Smuzhiyun }
182*4882a593Smuzhiyun else {
183*4882a593Smuzhiyun LogMessage(X_ERROR, "Error compiling keymap (%s) executing '%s'\n",
184*4882a593Smuzhiyun keymap, buf);
185*4882a593Smuzhiyun }
186*4882a593Smuzhiyun #ifdef WIN32
187*4882a593Smuzhiyun /* remove the temporary file */
188*4882a593Smuzhiyun unlink(tmpname);
189*4882a593Smuzhiyun #endif
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun else {
192*4882a593Smuzhiyun #ifndef WIN32
193*4882a593Smuzhiyun LogMessage(X_ERROR, "XKB: Could not invoke xkbcomp\n");
194*4882a593Smuzhiyun #else
195*4882a593Smuzhiyun LogMessage(X_ERROR, "Could not open file %s\n", tmpname);
196*4882a593Smuzhiyun #endif
197*4882a593Smuzhiyun }
198*4882a593Smuzhiyun free(buf);
199*4882a593Smuzhiyun return NULL;
200*4882a593Smuzhiyun }
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun typedef struct {
203*4882a593Smuzhiyun XkbDescPtr xkb;
204*4882a593Smuzhiyun XkbComponentNamesPtr names;
205*4882a593Smuzhiyun unsigned int want;
206*4882a593Smuzhiyun unsigned int need;
207*4882a593Smuzhiyun } XkbKeymapNamesCtx;
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun static void
xkb_write_keymap_for_names_cb(FILE * out,void * userdata)210*4882a593Smuzhiyun xkb_write_keymap_for_names_cb(FILE *out, void *userdata)
211*4882a593Smuzhiyun {
212*4882a593Smuzhiyun XkbKeymapNamesCtx *ctx = userdata;
213*4882a593Smuzhiyun #ifdef DEBUG
214*4882a593Smuzhiyun if (xkbDebugFlags) {
215*4882a593Smuzhiyun ErrorF("[xkb] XkbDDXCompileKeymapByNames compiling keymap:\n");
216*4882a593Smuzhiyun XkbWriteXKBKeymapForNames(stderr, ctx->names, ctx->xkb, ctx->want, ctx->need);
217*4882a593Smuzhiyun }
218*4882a593Smuzhiyun #endif
219*4882a593Smuzhiyun XkbWriteXKBKeymapForNames(out, ctx->names, ctx->xkb, ctx->want, ctx->need);
220*4882a593Smuzhiyun }
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun static Bool
XkbDDXCompileKeymapByNames(XkbDescPtr xkb,XkbComponentNamesPtr names,unsigned want,unsigned need,char * nameRtrn,int nameRtrnLen)223*4882a593Smuzhiyun XkbDDXCompileKeymapByNames(XkbDescPtr xkb,
224*4882a593Smuzhiyun XkbComponentNamesPtr names,
225*4882a593Smuzhiyun unsigned want,
226*4882a593Smuzhiyun unsigned need, char *nameRtrn, int nameRtrnLen)
227*4882a593Smuzhiyun {
228*4882a593Smuzhiyun char *keymap;
229*4882a593Smuzhiyun Bool rc = FALSE;
230*4882a593Smuzhiyun XkbKeymapNamesCtx ctx = {
231*4882a593Smuzhiyun .xkb = xkb,
232*4882a593Smuzhiyun .names = names,
233*4882a593Smuzhiyun .want = want,
234*4882a593Smuzhiyun .need = need
235*4882a593Smuzhiyun };
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun keymap = RunXkbComp(xkb_write_keymap_for_names_cb, &ctx);
238*4882a593Smuzhiyun
239*4882a593Smuzhiyun if (keymap) {
240*4882a593Smuzhiyun if(nameRtrn)
241*4882a593Smuzhiyun strlcpy(nameRtrn, keymap, nameRtrnLen);
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun free(keymap);
244*4882a593Smuzhiyun rc = TRUE;
245*4882a593Smuzhiyun } else if (nameRtrn)
246*4882a593Smuzhiyun *nameRtrn = '\0';
247*4882a593Smuzhiyun
248*4882a593Smuzhiyun return rc;
249*4882a593Smuzhiyun }
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun typedef struct {
252*4882a593Smuzhiyun const char *keymap;
253*4882a593Smuzhiyun size_t len;
254*4882a593Smuzhiyun } XkbKeymapString;
255*4882a593Smuzhiyun
256*4882a593Smuzhiyun static void
xkb_write_keymap_string_cb(FILE * out,void * userdata)257*4882a593Smuzhiyun xkb_write_keymap_string_cb(FILE *out, void *userdata)
258*4882a593Smuzhiyun {
259*4882a593Smuzhiyun XkbKeymapString *s = userdata;
260*4882a593Smuzhiyun fwrite(s->keymap, s->len, 1, out);
261*4882a593Smuzhiyun }
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun static unsigned int
XkbDDXLoadKeymapFromString(DeviceIntPtr keybd,const char * keymap,int keymap_length,unsigned int want,unsigned int need,XkbDescPtr * xkbRtrn)264*4882a593Smuzhiyun XkbDDXLoadKeymapFromString(DeviceIntPtr keybd,
265*4882a593Smuzhiyun const char *keymap, int keymap_length,
266*4882a593Smuzhiyun unsigned int want,
267*4882a593Smuzhiyun unsigned int need,
268*4882a593Smuzhiyun XkbDescPtr *xkbRtrn)
269*4882a593Smuzhiyun {
270*4882a593Smuzhiyun unsigned int have;
271*4882a593Smuzhiyun char *map_name;
272*4882a593Smuzhiyun XkbKeymapString map = {
273*4882a593Smuzhiyun .keymap = keymap,
274*4882a593Smuzhiyun .len = keymap_length
275*4882a593Smuzhiyun };
276*4882a593Smuzhiyun
277*4882a593Smuzhiyun *xkbRtrn = NULL;
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun map_name = RunXkbComp(xkb_write_keymap_string_cb, &map);
280*4882a593Smuzhiyun if (!map_name) {
281*4882a593Smuzhiyun LogMessage(X_ERROR, "XKB: Couldn't compile keymap\n");
282*4882a593Smuzhiyun return 0;
283*4882a593Smuzhiyun }
284*4882a593Smuzhiyun
285*4882a593Smuzhiyun have = LoadXKM(want, need, map_name, xkbRtrn);
286*4882a593Smuzhiyun free(map_name);
287*4882a593Smuzhiyun
288*4882a593Smuzhiyun return have;
289*4882a593Smuzhiyun }
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun static FILE *
XkbDDXOpenConfigFile(const char * mapName,char * fileNameRtrn,int fileNameRtrnLen)292*4882a593Smuzhiyun XkbDDXOpenConfigFile(const char *mapName, char *fileNameRtrn, int fileNameRtrnLen)
293*4882a593Smuzhiyun {
294*4882a593Smuzhiyun char buf[PATH_MAX], xkm_output_dir[PATH_MAX];
295*4882a593Smuzhiyun FILE *file;
296*4882a593Smuzhiyun
297*4882a593Smuzhiyun buf[0] = '\0';
298*4882a593Smuzhiyun if (mapName != NULL) {
299*4882a593Smuzhiyun OutputDirectory(xkm_output_dir, sizeof(xkm_output_dir));
300*4882a593Smuzhiyun if ((XkbBaseDirectory != NULL) && (xkm_output_dir[0] != '/')
301*4882a593Smuzhiyun #ifdef WIN32
302*4882a593Smuzhiyun && (!isalpha(xkm_output_dir[0]) || xkm_output_dir[1] != ':')
303*4882a593Smuzhiyun #endif
304*4882a593Smuzhiyun ) {
305*4882a593Smuzhiyun if (snprintf(buf, PATH_MAX, "%s/%s%s.xkm", XkbBaseDirectory,
306*4882a593Smuzhiyun xkm_output_dir, mapName) >= PATH_MAX)
307*4882a593Smuzhiyun buf[0] = '\0';
308*4882a593Smuzhiyun }
309*4882a593Smuzhiyun else {
310*4882a593Smuzhiyun if (snprintf(buf, PATH_MAX, "%s%s.xkm", xkm_output_dir, mapName)
311*4882a593Smuzhiyun >= PATH_MAX)
312*4882a593Smuzhiyun buf[0] = '\0';
313*4882a593Smuzhiyun }
314*4882a593Smuzhiyun if (buf[0] != '\0')
315*4882a593Smuzhiyun file = fopen(buf, "rb");
316*4882a593Smuzhiyun else
317*4882a593Smuzhiyun file = NULL;
318*4882a593Smuzhiyun }
319*4882a593Smuzhiyun else
320*4882a593Smuzhiyun file = NULL;
321*4882a593Smuzhiyun if ((fileNameRtrn != NULL) && (fileNameRtrnLen > 0)) {
322*4882a593Smuzhiyun strlcpy(fileNameRtrn, buf, fileNameRtrnLen);
323*4882a593Smuzhiyun }
324*4882a593Smuzhiyun return file;
325*4882a593Smuzhiyun }
326*4882a593Smuzhiyun
327*4882a593Smuzhiyun static unsigned
LoadXKM(unsigned want,unsigned need,const char * keymap,XkbDescPtr * xkbRtrn)328*4882a593Smuzhiyun LoadXKM(unsigned want, unsigned need, const char *keymap, XkbDescPtr *xkbRtrn)
329*4882a593Smuzhiyun {
330*4882a593Smuzhiyun FILE *file;
331*4882a593Smuzhiyun char fileName[PATH_MAX];
332*4882a593Smuzhiyun unsigned missing;
333*4882a593Smuzhiyun
334*4882a593Smuzhiyun file = XkbDDXOpenConfigFile(keymap, fileName, PATH_MAX);
335*4882a593Smuzhiyun if (file == NULL) {
336*4882a593Smuzhiyun LogMessage(X_ERROR, "Couldn't open compiled keymap file %s\n",
337*4882a593Smuzhiyun fileName);
338*4882a593Smuzhiyun return 0;
339*4882a593Smuzhiyun }
340*4882a593Smuzhiyun missing = XkmReadFile(file, need, want, xkbRtrn);
341*4882a593Smuzhiyun if (*xkbRtrn == NULL) {
342*4882a593Smuzhiyun LogMessage(X_ERROR, "Error loading keymap %s\n", fileName);
343*4882a593Smuzhiyun fclose(file);
344*4882a593Smuzhiyun (void) unlink(fileName);
345*4882a593Smuzhiyun return 0;
346*4882a593Smuzhiyun }
347*4882a593Smuzhiyun else {
348*4882a593Smuzhiyun DebugF("Loaded XKB keymap %s, defined=0x%x\n", fileName,
349*4882a593Smuzhiyun (*xkbRtrn)->defined);
350*4882a593Smuzhiyun }
351*4882a593Smuzhiyun fclose(file);
352*4882a593Smuzhiyun (void) unlink(fileName);
353*4882a593Smuzhiyun return (need | want) & (~missing);
354*4882a593Smuzhiyun }
355*4882a593Smuzhiyun
356*4882a593Smuzhiyun unsigned
XkbDDXLoadKeymapByNames(DeviceIntPtr keybd,XkbComponentNamesPtr names,unsigned want,unsigned need,XkbDescPtr * xkbRtrn,char * nameRtrn,int nameRtrnLen)357*4882a593Smuzhiyun XkbDDXLoadKeymapByNames(DeviceIntPtr keybd,
358*4882a593Smuzhiyun XkbComponentNamesPtr names,
359*4882a593Smuzhiyun unsigned want,
360*4882a593Smuzhiyun unsigned need,
361*4882a593Smuzhiyun XkbDescPtr *xkbRtrn, char *nameRtrn, int nameRtrnLen)
362*4882a593Smuzhiyun {
363*4882a593Smuzhiyun XkbDescPtr xkb;
364*4882a593Smuzhiyun
365*4882a593Smuzhiyun *xkbRtrn = NULL;
366*4882a593Smuzhiyun if ((keybd == NULL) || (keybd->key == NULL) ||
367*4882a593Smuzhiyun (keybd->key->xkbInfo == NULL))
368*4882a593Smuzhiyun xkb = NULL;
369*4882a593Smuzhiyun else
370*4882a593Smuzhiyun xkb = keybd->key->xkbInfo->desc;
371*4882a593Smuzhiyun if ((names->keycodes == NULL) && (names->types == NULL) &&
372*4882a593Smuzhiyun (names->compat == NULL) && (names->symbols == NULL) &&
373*4882a593Smuzhiyun (names->geometry == NULL)) {
374*4882a593Smuzhiyun LogMessage(X_ERROR, "XKB: No components provided for device %s\n",
375*4882a593Smuzhiyun keybd->name ? keybd->name : "(unnamed keyboard)");
376*4882a593Smuzhiyun return 0;
377*4882a593Smuzhiyun }
378*4882a593Smuzhiyun else if (!XkbDDXCompileKeymapByNames(xkb, names, want, need,
379*4882a593Smuzhiyun nameRtrn, nameRtrnLen)) {
380*4882a593Smuzhiyun LogMessage(X_ERROR, "XKB: Couldn't compile keymap\n");
381*4882a593Smuzhiyun return 0;
382*4882a593Smuzhiyun }
383*4882a593Smuzhiyun
384*4882a593Smuzhiyun return LoadXKM(want, need, nameRtrn, xkbRtrn);
385*4882a593Smuzhiyun }
386*4882a593Smuzhiyun
387*4882a593Smuzhiyun Bool
XkbDDXNamesFromRules(DeviceIntPtr keybd,const char * rules_name,XkbRF_VarDefsPtr defs,XkbComponentNamesPtr names)388*4882a593Smuzhiyun XkbDDXNamesFromRules(DeviceIntPtr keybd,
389*4882a593Smuzhiyun const char *rules_name,
390*4882a593Smuzhiyun XkbRF_VarDefsPtr defs, XkbComponentNamesPtr names)
391*4882a593Smuzhiyun {
392*4882a593Smuzhiyun char buf[PATH_MAX];
393*4882a593Smuzhiyun FILE *file;
394*4882a593Smuzhiyun Bool complete;
395*4882a593Smuzhiyun XkbRF_RulesPtr rules;
396*4882a593Smuzhiyun
397*4882a593Smuzhiyun if (!rules_name)
398*4882a593Smuzhiyun return FALSE;
399*4882a593Smuzhiyun
400*4882a593Smuzhiyun if (snprintf(buf, PATH_MAX, "%s/rules/%s", XkbBaseDirectory, rules_name)
401*4882a593Smuzhiyun >= PATH_MAX) {
402*4882a593Smuzhiyun LogMessage(X_ERROR, "XKB: Rules name is too long\n");
403*4882a593Smuzhiyun return FALSE;
404*4882a593Smuzhiyun }
405*4882a593Smuzhiyun
406*4882a593Smuzhiyun file = fopen(buf, "r");
407*4882a593Smuzhiyun if (!file) {
408*4882a593Smuzhiyun LogMessage(X_ERROR, "XKB: Couldn't open rules file %s\n", buf);
409*4882a593Smuzhiyun return FALSE;
410*4882a593Smuzhiyun }
411*4882a593Smuzhiyun
412*4882a593Smuzhiyun rules = XkbRF_Create();
413*4882a593Smuzhiyun if (!rules) {
414*4882a593Smuzhiyun LogMessage(X_ERROR, "XKB: Couldn't create rules struct\n");
415*4882a593Smuzhiyun fclose(file);
416*4882a593Smuzhiyun return FALSE;
417*4882a593Smuzhiyun }
418*4882a593Smuzhiyun
419*4882a593Smuzhiyun if (!XkbRF_LoadRules(file, rules)) {
420*4882a593Smuzhiyun LogMessage(X_ERROR, "XKB: Couldn't parse rules file %s\n", rules_name);
421*4882a593Smuzhiyun fclose(file);
422*4882a593Smuzhiyun XkbRF_Free(rules, TRUE);
423*4882a593Smuzhiyun return FALSE;
424*4882a593Smuzhiyun }
425*4882a593Smuzhiyun
426*4882a593Smuzhiyun memset(names, 0, sizeof(*names));
427*4882a593Smuzhiyun complete = XkbRF_GetComponents(rules, defs, names);
428*4882a593Smuzhiyun fclose(file);
429*4882a593Smuzhiyun XkbRF_Free(rules, TRUE);
430*4882a593Smuzhiyun
431*4882a593Smuzhiyun if (!complete)
432*4882a593Smuzhiyun LogMessage(X_ERROR, "XKB: Rules returned no components\n");
433*4882a593Smuzhiyun
434*4882a593Smuzhiyun return complete;
435*4882a593Smuzhiyun }
436*4882a593Smuzhiyun
437*4882a593Smuzhiyun static Bool
XkbRMLVOtoKcCGST(DeviceIntPtr dev,XkbRMLVOSet * rmlvo,XkbComponentNamesPtr kccgst)438*4882a593Smuzhiyun XkbRMLVOtoKcCGST(DeviceIntPtr dev, XkbRMLVOSet * rmlvo,
439*4882a593Smuzhiyun XkbComponentNamesPtr kccgst)
440*4882a593Smuzhiyun {
441*4882a593Smuzhiyun XkbRF_VarDefsRec mlvo;
442*4882a593Smuzhiyun
443*4882a593Smuzhiyun mlvo.model = rmlvo->model;
444*4882a593Smuzhiyun mlvo.layout = rmlvo->layout;
445*4882a593Smuzhiyun mlvo.variant = rmlvo->variant;
446*4882a593Smuzhiyun mlvo.options = rmlvo->options;
447*4882a593Smuzhiyun
448*4882a593Smuzhiyun return XkbDDXNamesFromRules(dev, rmlvo->rules, &mlvo, kccgst);
449*4882a593Smuzhiyun }
450*4882a593Smuzhiyun
451*4882a593Smuzhiyun /**
452*4882a593Smuzhiyun * Compile the given RMLVO keymap and return it. Returns the XkbDescPtr on
453*4882a593Smuzhiyun * success or NULL on failure. If the components compiled are not a superset
454*4882a593Smuzhiyun * or equal to need, the compiliation is treated as failure.
455*4882a593Smuzhiyun */
456*4882a593Smuzhiyun static XkbDescPtr
XkbCompileKeymapForDevice(DeviceIntPtr dev,XkbRMLVOSet * rmlvo,int need)457*4882a593Smuzhiyun XkbCompileKeymapForDevice(DeviceIntPtr dev, XkbRMLVOSet * rmlvo, int need)
458*4882a593Smuzhiyun {
459*4882a593Smuzhiyun XkbDescPtr xkb = NULL;
460*4882a593Smuzhiyun unsigned int provided;
461*4882a593Smuzhiyun XkbComponentNamesRec kccgst = { 0 };
462*4882a593Smuzhiyun char name[PATH_MAX];
463*4882a593Smuzhiyun
464*4882a593Smuzhiyun if (XkbRMLVOtoKcCGST(dev, rmlvo, &kccgst)) {
465*4882a593Smuzhiyun provided =
466*4882a593Smuzhiyun XkbDDXLoadKeymapByNames(dev, &kccgst, XkmAllIndicesMask, need, &xkb,
467*4882a593Smuzhiyun name, PATH_MAX);
468*4882a593Smuzhiyun if ((need & provided) != need) {
469*4882a593Smuzhiyun if (xkb) {
470*4882a593Smuzhiyun XkbFreeKeyboard(xkb, 0, TRUE);
471*4882a593Smuzhiyun xkb = NULL;
472*4882a593Smuzhiyun }
473*4882a593Smuzhiyun }
474*4882a593Smuzhiyun }
475*4882a593Smuzhiyun
476*4882a593Smuzhiyun XkbFreeComponentNames(&kccgst, FALSE);
477*4882a593Smuzhiyun return xkb;
478*4882a593Smuzhiyun }
479*4882a593Smuzhiyun
480*4882a593Smuzhiyun static XkbDescPtr
KeymapOrDefaults(DeviceIntPtr dev,XkbDescPtr xkb)481*4882a593Smuzhiyun KeymapOrDefaults(DeviceIntPtr dev, XkbDescPtr xkb)
482*4882a593Smuzhiyun {
483*4882a593Smuzhiyun XkbRMLVOSet dflts;
484*4882a593Smuzhiyun
485*4882a593Smuzhiyun if (xkb)
486*4882a593Smuzhiyun return xkb;
487*4882a593Smuzhiyun
488*4882a593Smuzhiyun /* we didn't get what we really needed. And that will likely leave
489*4882a593Smuzhiyun * us with a keyboard that doesn't work. Use the defaults instead */
490*4882a593Smuzhiyun LogMessage(X_ERROR, "XKB: Failed to load keymap. Loading default "
491*4882a593Smuzhiyun "keymap instead.\n");
492*4882a593Smuzhiyun
493*4882a593Smuzhiyun XkbGetRulesDflts(&dflts);
494*4882a593Smuzhiyun
495*4882a593Smuzhiyun xkb = XkbCompileKeymapForDevice(dev, &dflts, 0);
496*4882a593Smuzhiyun
497*4882a593Smuzhiyun XkbFreeRMLVOSet(&dflts, FALSE);
498*4882a593Smuzhiyun
499*4882a593Smuzhiyun return xkb;
500*4882a593Smuzhiyun }
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun
503*4882a593Smuzhiyun XkbDescPtr
XkbCompileKeymap(DeviceIntPtr dev,XkbRMLVOSet * rmlvo)504*4882a593Smuzhiyun XkbCompileKeymap(DeviceIntPtr dev, XkbRMLVOSet * rmlvo)
505*4882a593Smuzhiyun {
506*4882a593Smuzhiyun XkbDescPtr xkb;
507*4882a593Smuzhiyun unsigned int need;
508*4882a593Smuzhiyun
509*4882a593Smuzhiyun if (!dev || !rmlvo) {
510*4882a593Smuzhiyun LogMessage(X_ERROR, "XKB: No device or RMLVO specified\n");
511*4882a593Smuzhiyun return NULL;
512*4882a593Smuzhiyun }
513*4882a593Smuzhiyun
514*4882a593Smuzhiyun /* These are the components we really really need */
515*4882a593Smuzhiyun need = XkmSymbolsMask | XkmCompatMapMask | XkmTypesMask |
516*4882a593Smuzhiyun XkmKeyNamesMask | XkmVirtualModsMask;
517*4882a593Smuzhiyun
518*4882a593Smuzhiyun xkb = XkbCompileKeymapForDevice(dev, rmlvo, need);
519*4882a593Smuzhiyun
520*4882a593Smuzhiyun return KeymapOrDefaults(dev, xkb);
521*4882a593Smuzhiyun }
522*4882a593Smuzhiyun
523*4882a593Smuzhiyun XkbDescPtr
XkbCompileKeymapFromString(DeviceIntPtr dev,const char * keymap,int keymap_length)524*4882a593Smuzhiyun XkbCompileKeymapFromString(DeviceIntPtr dev,
525*4882a593Smuzhiyun const char *keymap, int keymap_length)
526*4882a593Smuzhiyun {
527*4882a593Smuzhiyun XkbDescPtr xkb;
528*4882a593Smuzhiyun unsigned int need, provided;
529*4882a593Smuzhiyun
530*4882a593Smuzhiyun if (!dev || !keymap) {
531*4882a593Smuzhiyun LogMessage(X_ERROR, "XKB: No device or keymap specified\n");
532*4882a593Smuzhiyun return NULL;
533*4882a593Smuzhiyun }
534*4882a593Smuzhiyun
535*4882a593Smuzhiyun /* These are the components we really really need */
536*4882a593Smuzhiyun need = XkmSymbolsMask | XkmCompatMapMask | XkmTypesMask |
537*4882a593Smuzhiyun XkmKeyNamesMask | XkmVirtualModsMask;
538*4882a593Smuzhiyun
539*4882a593Smuzhiyun provided =
540*4882a593Smuzhiyun XkbDDXLoadKeymapFromString(dev, keymap, keymap_length,
541*4882a593Smuzhiyun XkmAllIndicesMask, need, &xkb);
542*4882a593Smuzhiyun if ((need & provided) != need) {
543*4882a593Smuzhiyun if (xkb) {
544*4882a593Smuzhiyun XkbFreeKeyboard(xkb, 0, TRUE);
545*4882a593Smuzhiyun xkb = NULL;
546*4882a593Smuzhiyun }
547*4882a593Smuzhiyun }
548*4882a593Smuzhiyun
549*4882a593Smuzhiyun return KeymapOrDefaults(dev, xkb);
550*4882a593Smuzhiyun }
551