1 /*
2
3 Copyright (c) 2007-2013 uim Project https://github.com/uim/uim
4
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions
9 are met:
10
11 1. Redistributions of source code must retain the above copyright
12 notice, this list of conditions and the following disclaimer.
13 2. Redistributions in binary form must reproduce the above copyright
14 notice, this list of conditions and the following disclaimer in the
15 documentation and/or other materials provided with the distribution.
16 3. Neither the name of authors nor the names of its contributors
17 may be used to endorse or promote products derived from this software
18 without specific prior written permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
21 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
24 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 SUCH DAMAGE.
31
32 */
33
34 #include <string.h>
35
36 #include <X11/XKBlib.h>
37
38 #include "uim-scm.h"
39 #include "uim-scm-abbrev.h"
40 #include "dynlib.h"
41 #include "uim-x-util.h"
42
43 static XkbDescPtr xkb = NULL;
44
45 static uim_lisp
xkb_set_display(uim_lisp lisp_display)46 xkb_set_display(uim_lisp lisp_display)
47 {
48 Display *c_display = (Display *)C_PTR(lisp_display);
49
50 if (! XkbQueryExtension(c_display, NULL, NULL, NULL, NULL, NULL))
51 return uim_scm_f();
52 if (xkb != NULL) XkbFreeKeyboard(xkb, XkbAllComponentsMask, True);
53 if ((xkb = XkbAllocKeyboard()) == NULL) return uim_scm_f();
54 xkb->dpy = c_display;
55
56 return uim_scm_t();
57 }
58
59 static uim_lisp
xkb_levels(XkbDescPtr xkb,KeyCode kc,int group)60 xkb_levels(XkbDescPtr xkb, KeyCode kc, int group)
61 {
62 int l, nlevels = XkbKeyGroupWidth(xkb, kc, group);
63 uim_lisp levels = uim_scm_null();
64
65 for (l = nlevels - 1; l >= 0; l--) {
66 int ukey = uim_x_keysym2ukey(XkbKeySymEntry(xkb, kc, l, group));
67 levels = CONS(MAKE_INT(ukey), levels);
68 }
69
70 return levels;
71 }
72
73 static uim_lisp
xkb_groups(XkbDescPtr xkb,KeyCode kc)74 xkb_groups(XkbDescPtr xkb, KeyCode kc)
75 {
76 char name[XkbKeyNameLength + 1];
77 int g, ngroups;
78 uim_lisp groups;
79
80 name[XkbKeyNameLength] = '\0';
81 strncpy(name, xkb->names->keys[kc].name, XkbKeyNameLength);
82 if (name[0] == '\0') return uim_scm_f();
83
84 ngroups = XkbKeyNumGroups(xkb, kc);
85 if (ngroups == 0) return uim_scm_f();
86 groups = uim_scm_null();
87 for (g = ngroups - 1; g >= 0; g--)
88 groups = CONS(xkb_levels(xkb, kc, g), groups);
89
90 return CONS(MAKE_INT(kc), CONS(MAKE_SYM(name), groups));
91 }
92
93 static uim_lisp
xkb_lib_display_readyp(void)94 xkb_lib_display_readyp(void)
95 {
96 return MAKE_BOOL(xkb != NULL && xkb->dpy != NULL);
97 }
98
99 /*
100 * returns a list of which each element is of the form
101 *
102 * (xkeycode xkbname group1 group2 ...)
103 *
104 * in which each of groupn is a list of keysyms at different shift
105 * levels available in the group, and xkbname, a scheme symbol, is a
106 * symbolic key name as returned by XKB. Keysyms are returned after
107 * being converted to uim keys which can differ from X keysyms.
108 */
109 static uim_lisp
xkb_lib_get_map(void)110 xkb_lib_get_map(void)
111 {
112 int kc;
113 uim_lisp map;
114
115 if (xkb == NULL || xkb->dpy == NULL) return uim_scm_f();
116
117 if (XkbGetUpdatedMap(xkb->dpy, XkbAllClientInfoMask, xkb) != Success)
118 return uim_scm_f();
119 if (XkbGetNames(xkb->dpy, XkbKeyNamesMask, xkb) != Success)
120 return uim_scm_f();
121
122 map = uim_scm_null();
123 for (kc = xkb->max_key_code; kc >= xkb->min_key_code; kc--) {
124 uim_lisp groups = xkb_groups(xkb, kc);
125 if (TRUEP(groups)) map = CONS(groups, map);
126 }
127
128 return map;
129 }
130
131 static uim_lisp
xkb_lib_get_groups_wrap_control(void)132 xkb_lib_get_groups_wrap_control(void)
133 {
134 unsigned char ngroups;
135
136 if (xkb == NULL || xkb->dpy == NULL) return uim_scm_f();
137
138 if (XkbGetControls(xkb->dpy, XkbGroupsWrapMask, xkb) != Success)
139 return uim_scm_f();
140 ngroups = xkb->ctrls->num_groups;
141
142 switch (xkb->ctrls->groups_wrap & (3L << 6)) {
143 case XkbWrapIntoRange:
144 return LIST2(MAKE_SYM("wrap-into-range"), MAKE_INT(ngroups));
145 case XkbClampIntoRange:
146 return LIST2(MAKE_SYM("clamp-into-range"), MAKE_INT(ngroups));
147 case XkbRedirectIntoRange:
148 return LIST2(MAKE_INT(xkb->ctrls->groups_wrap & 0xf),
149 MAKE_INT(ngroups));
150 default:
151 return uim_scm_f();
152 }
153 }
154
155 static uim_lisp
xkb_lib_get_group(void)156 xkb_lib_get_group(void)
157 {
158 XkbStateRec state;
159
160 if (xkb == NULL || xkb->dpy == NULL) return uim_scm_f();
161 if (XkbGetState(xkb->dpy, XkbUseCoreKbd, &state) != Success)
162 return uim_scm_f();
163
164 return MAKE_INT(state.group);
165 }
166
167 static uim_lisp
xkb_open_display(void)168 xkb_open_display(void)
169 {
170 Display *display = XkbOpenDisplay(NULL, NULL, NULL, NULL, NULL, NULL);
171 if (display == NULL) return uim_scm_f();
172 return MAKE_PTR(display);
173 }
174
175 void
uim_dynlib_instance_init(void)176 uim_dynlib_instance_init(void)
177 {
178 uim_scm_init_proc0("xkb-lib-display-ready?", xkb_lib_display_readyp);
179 uim_scm_init_proc0("xkb-lib-get-map", xkb_lib_get_map);
180 uim_scm_init_proc0("xkb-lib-get-groups-wrap-control",
181 xkb_lib_get_groups_wrap_control);
182 uim_scm_init_proc0("xkb-lib-get-group", xkb_lib_get_group);
183
184 uim_scm_init_proc1("%xkb-set-display", xkb_set_display);
185 uim_scm_init_proc0("%xkb-open-display", xkb_open_display);
186 }
187
188 void
uim_dynlib_instance_quit(void)189 uim_dynlib_instance_quit(void)
190 {
191 if (xkb != NULL) XkbFreeKeyboard(xkb, XkbAllComponentsMask, True);
192 xkb = NULL;
193 }
194