xref: /OK3568_Linux_fs/external/xserver/xkb/ddxLoad.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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