Bug Summary

File:modules/im/ximcp/imThaiFlt.c
Location:line 596, column 46
Description:Dereference of null pointer

Annotated Source Code

1/***********************************************************
2
3Copyright 1993, 1998 The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included in
12all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21Except as contained in this notice, the name of The Open Group shall not be
22used in advertising or otherwise to promote the sale, use or other dealings
23in this Software without prior written authorization from The Open Group.
24
25
26Copyright 1993 by Digital Equipment Corporation, Maynard, Massachusetts.
27
28 All Rights Reserved
29
30Permission to use, copy, modify, and distribute this software and its
31documentation for any purpose and without fee is hereby granted,
32provided that the above copyright notice appear in all copies and that
33both that copyright notice and this permission notice appear in
34supporting documentation, and that the name of Digital not be
35used in advertising or publicity pertaining to distribution of the
36software without specific, written prior permission.
37
38DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
39ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
40DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
41ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
42WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
43ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
44SOFTWARE.
45
46******************************************************************/
47
48/*
49**++
50** FACILITY:
51**
52** Xlib
53**
54** ABSTRACT:
55**
56** Thai specific functions.
57** Handles character classifications, composibility checking,
58** Input sequence check and other Thai specific requirements
59** according to WTT specification and DEC extensions.
60**
61** MODIFICATION HISTORY:
62**
63**/
64
65#ifdef HAVE_CONFIG_H1
66#include <config.h>
67#endif
68#include <stdio.h>
69#include <X11/Xlib.h>
70#include <X11/Xmd.h>
71#include <X11/keysym.h>
72#include <X11/Xutil.h>
73#include "Xlibint.h"
74#include "Xlcint.h"
75#include "Ximint.h"
76#include "XimThai.h"
77#include "XlcPubI.h"
78
79
80#define SPACE32 32
81
82/* character classification table */
83#define TACTIS_CHARS256 256
84Privatestatic
85char const tactis_chtype[TACTIS_CHARS256] = {
86 CTRL0, CTRL0, CTRL0, CTRL0, CTRL0, CTRL0, CTRL0, CTRL0, /* 0 - 7 */
87 CTRL0, CTRL0, CTRL0, CTRL0, CTRL0, CTRL0, CTRL0, CTRL0, /* 8 - 15 */
88 CTRL0, CTRL0, CTRL0, CTRL0, CTRL0, CTRL0, CTRL0, CTRL0, /* 16 - 23 */
89 CTRL0, CTRL0, CTRL0, CTRL0, CTRL0, CTRL0, CTRL0, CTRL0, /* 24 - 31 */
90 NON1, NON1, NON1, NON1, NON1, NON1, NON1, NON1, /* 32 - 39 */
91 NON1, NON1, NON1, NON1, NON1, NON1, NON1, NON1, /* 40 - 47 */
92 NON1, NON1, NON1, NON1, NON1, NON1, NON1, NON1, /* 48 - 55 */
93 NON1, NON1, NON1, NON1, NON1, NON1, NON1, NON1, /* 56 - 63 */
94 NON1, NON1, NON1, NON1, NON1, NON1, NON1, NON1, /* 64 - 71 */
95 NON1, NON1, NON1, NON1, NON1, NON1, NON1, NON1, /* 72 - 79 */
96 NON1, NON1, NON1, NON1, NON1, NON1, NON1, NON1, /* 80 - 87 */
97 NON1, NON1, NON1, NON1, NON1, NON1, NON1, NON1, /* 88 - 95 */
98 NON1, NON1, NON1, NON1, NON1, NON1, NON1, NON1, /* 96 - 103 */
99 NON1, NON1, NON1, NON1, NON1, NON1, NON1, NON1, /* 104 - 111 */
100 NON1, NON1, NON1, NON1, NON1, NON1, NON1, NON1, /* 112 - 119 */
101 NON1, NON1, NON1, NON1, NON1, NON1, NON1, CTRL0, /* 120 - 127 */
102 CTRL0, CTRL0, CTRL0, CTRL0, CTRL0, CTRL0, CTRL0, CTRL0, /* 128 - 135 */
103 CTRL0, CTRL0, CTRL0, CTRL0, CTRL0, CTRL0, CTRL0, CTRL0, /* 136 - 143 */
104 CTRL0, CTRL0, CTRL0, CTRL0, CTRL0, CTRL0, CTRL0, CTRL0, /* 144 - 151 */
105 CTRL0, CTRL0, CTRL0, CTRL0, CTRL0, CTRL0, CTRL0, CTRL0, /* 152 - 159 */
106 NON1, CONS2, CONS2, CONS2, CONS2, CONS2, CONS2, CONS2, /* 160 - 167 */
107 CONS2, CONS2, CONS2, CONS2, CONS2, CONS2, CONS2, CONS2, /* 168 - 175 */
108 CONS2, CONS2, CONS2, CONS2, CONS2, CONS2, CONS2, CONS2, /* 176 - 183 */
109 CONS2, CONS2, CONS2, CONS2, CONS2, CONS2, CONS2, CONS2, /* 184 - 191 */
110 CONS2, CONS2, CONS2, CONS2, FV36, CONS2, FV36, CONS2, /* 192 - 199 */
111 CONS2, CONS2, CONS2, CONS2, CONS2, CONS2, CONS2, NON1, /* 200 - 207 */
112 FV14, AV215, FV14, FV14, AV114, AV316, AV215, AV316, /* 208 - 215 */
113 BV17, BV28, BD9, NON1, NON1, NON1, NON1, NON1, /* 216 - 223 */
114 LV3, LV3, LV3, LV3, LV3, FV25, NON1, AD212, /* 224 - 231 */
115 TONE10, TONE10, TONE10, TONE10, AD111, AD111, AD313, NON1, /* 232 - 239 */
116 NON1, NON1, NON1, NON1, NON1, NON1, NON1, NON1, /* 240 - 247 */
117 NON1, NON1, NON1, NON1, NON1, NON1, NON1, CTRL0 /* 248 - 255 */
118};
119
120/* Composibility checking tables */
121#define NC0 0 /* NOT COMPOSIBLE - following char displays in next cell */
122#define CP1 1 /* COMPOSIBLE - following char is displayed in the same cell
123 as leading char, also implies ACCEPT */
124#define XC3 3 /* Non-display */
125#define AC4 4 /* ACCEPT - display the following char in the next cell */
126#define RJ5 5 /* REJECT - discard that following char, ignore it */
127
128#define CH_CLASSES17 17 /* 17 classes of chars */
129
130Privatestatic
131char const write_rules_lookup[CH_CLASSES17][CH_CLASSES17] = {
132 /* Table 0: writing/outputing rules */
133 /* row: leading char, column: following char */
134/* CTRL NON CONS LV FV1 FV2 FV3 BV1 BV2 BD TONE AD1 AD2 AD3 AV1 AV2 AV3 */
135 {XC3, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0}/*CTRL*/
136 ,{XC3, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0}/*NON*/
137 ,{XC3, NC0, NC0, NC0, NC0, NC0, NC0, CP1, CP1, CP1, CP1, CP1, CP1, CP1, CP1, CP1, CP1}/*CONS*/
138 ,{XC3, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0}/*LV*/
139 ,{XC3, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0}/*FV1*/
140 ,{XC3, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0}/*FV2*/
141 ,{XC3, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0}/*FV3*/
142 ,{XC3, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, CP1, CP1, NC0, NC0, NC0, NC0, NC0}/*BV1*/
143 ,{XC3, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, CP1, NC0, NC0, NC0, NC0, NC0, NC0}/*BV2*/
144 ,{XC3, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0}/*BD*/
145 ,{XC3, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0}/*TONE*/
146 ,{XC3, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0}/*AD1*/
147 ,{XC3, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0}/*AD2*/
148 ,{XC3, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0}/*AD3*/
149 ,{XC3, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, CP1, CP1, NC0, NC0, NC0, NC0, NC0}/*AV1*/
150 ,{XC3, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, CP1, NC0, NC0, NC0, NC0, NC0, NC0}/*AV2*/
151 ,{XC3, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, NC0, CP1, NC0, CP1, NC0, NC0, NC0, NC0}/*AV3*/
152};
153
154Privatestatic
155char const wtt_isc1_lookup[CH_CLASSES17][CH_CLASSES17] = {
156 /* Table 1: WTT default input sequence check rules */
157 /* row: leading char, column: following char */
158/* CTRL NON CONS LV FV1 FV2 FV3 BV1 BV2 BD TONE AD1 AD2 AD3 AV1 AV2 AV3 */
159 {XC3, AC4, AC4, AC4, AC4, AC4, AC4, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5}/*CTRL*/
160 ,{XC3, AC4, AC4, AC4, AC4, AC4, AC4, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5}/*NON*/
161 ,{XC3, AC4, AC4, AC4, AC4, AC4, AC4, CP1, CP1, CP1, CP1, CP1, CP1, CP1, CP1, CP1, CP1}/*CONS*/
162 ,{XC3, AC4, AC4, AC4, AC4, AC4, AC4, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5}/*LV*/
163 ,{XC3, AC4, AC4, AC4, AC4, AC4, AC4, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5}/*FV1*/
164 ,{XC3, AC4, AC4, AC4, AC4, AC4, AC4, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5}/*FV2*/
165 ,{XC3, AC4, AC4, AC4, AC4, AC4, AC4, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5}/*FV3*/
166 ,{XC3, AC4, AC4, AC4, AC4, AC4, AC4, RJ5, RJ5, RJ5, CP1, CP1, RJ5, RJ5, RJ5, RJ5, RJ5}/*BV1*/
167 ,{XC3, AC4, AC4, AC4, AC4, AC4, AC4, RJ5, RJ5, RJ5, CP1, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5}/*BV2*/
168 ,{XC3, AC4, AC4, AC4, AC4, AC4, AC4, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5}/*BD*/
169 ,{XC3, AC4, AC4, AC4, AC4, AC4, AC4, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5}/*TONE*/
170 ,{XC3, AC4, AC4, AC4, AC4, AC4, AC4, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5}/*AD1*/
171 ,{XC3, AC4, AC4, AC4, AC4, AC4, AC4, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5}/*AD2*/
172 ,{XC3, AC4, AC4, AC4, AC4, AC4, AC4, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5}/*AD3*/
173 ,{XC3, AC4, AC4, AC4, AC4, AC4, AC4, RJ5, RJ5, RJ5, CP1, CP1, RJ5, RJ5, RJ5, RJ5, RJ5}/*AV1*/
174 ,{XC3, AC4, AC4, AC4, AC4, AC4, AC4, RJ5, RJ5, RJ5, CP1, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5}/*AV2*/
175 ,{XC3, AC4, AC4, AC4, AC4, AC4, AC4, RJ5, RJ5, RJ5, CP1, RJ5, CP1, RJ5, RJ5, RJ5, RJ5}/*AV3*/
176};
177
178Privatestatic
179char const wtt_isc2_lookup[CH_CLASSES17][CH_CLASSES17] = {
180 /* Table 2: WTT strict input sequence check rules */
181 /* row: leading char, column: following char */
182/* CTRL NON CONS LV FV1 FV2 FV3 BV1 BV2 BD TONE AD1 AD2 AD3 AV1 AV2 AV3 */
183 {XC3, AC4, AC4, AC4, AC4, AC4, AC4, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5}/*CTRL*/
184 ,{XC3, AC4, AC4, AC4, RJ5, RJ5, AC4, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5}/*NON*/
185 ,{XC3, AC4, AC4, AC4, AC4, RJ5, AC4, CP1, CP1, CP1, CP1, CP1, CP1, CP1, CP1, CP1, CP1}/*CONS*/
186 ,{XC3, RJ5, AC4, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5}/*LV*/
187 ,{XC3, AC4, AC4, AC4, AC4, RJ5, AC4, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5}/*FV1*/
188 ,{XC3, AC4, AC4, AC4, AC4, RJ5, AC4, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5}/*FV2*/
189 ,{XC3, AC4, AC4, AC4, RJ5, AC4, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5}/*FV3*/
190 ,{XC3, AC4, AC4, AC4, AC4, RJ5, AC4, RJ5, RJ5, RJ5, CP1, CP1, RJ5, RJ5, RJ5, RJ5, RJ5}/*BV1*/
191 ,{XC3, AC4, AC4, AC4, RJ5, RJ5, AC4, RJ5, RJ5, RJ5, CP1, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5}/*BV2*/
192 ,{XC3, AC4, AC4, AC4, RJ5, RJ5, AC4, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5}/*BD*/
193 ,{XC3, AC4, AC4, AC4, AC4, AC4, AC4, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5}/*TONE*/
194 ,{XC3, AC4, AC4, AC4, RJ5, RJ5, AC4, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5}/*AD1*/
195 ,{XC3, AC4, AC4, AC4, RJ5, RJ5, AC4, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5}/*AD2*/
196 ,{XC3, AC4, AC4, AC4, RJ5, RJ5, AC4, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5}/*AD3*/
197 ,{XC3, AC4, AC4, AC4, RJ5, RJ5, AC4, RJ5, RJ5, RJ5, CP1, CP1, RJ5, RJ5, RJ5, RJ5, RJ5}/*AV1*/
198 ,{XC3, AC4, AC4, AC4, RJ5, RJ5, AC4, RJ5, RJ5, RJ5, CP1, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5}/*AV2*/
199 ,{XC3, AC4, AC4, AC4, RJ5, RJ5, AC4, RJ5, RJ5, RJ5, CP1, RJ5, CP1, RJ5, RJ5, RJ5, RJ5}/*AV3*/
200};
201
202Privatestatic
203char const thaicat_isc_lookup[CH_CLASSES17][CH_CLASSES17] = {
204 /* Table 3: Thaicat input sequence check rules */
205 /* row: leading char, column: following char */
206/* CTRL NON CONS LV FV1 FV2 FV3 BV1 BV2 BD TONE AD1 AD2 AD3 AV1 AV2 AV3 */
207 {XC3, AC4, AC4, AC4, AC4, AC4, AC4, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5}/*CTRL*/
208 ,{XC3, AC4, AC4, AC4, AC4, AC4, AC4, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5}/*NON*/
209 ,{XC3, AC4, AC4, AC4, AC4, AC4, AC4, CP1, CP1, CP1, CP1, CP1, CP1, CP1, CP1, CP1, CP1}/*CONS*/
210 ,{XC3, AC4, AC4, AC4, AC4, AC4, AC4, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5}/*LV*/
211 ,{XC3, AC4, AC4, AC4, AC4, AC4, AC4, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5}/*FV1*/
212 ,{XC3, AC4, AC4, AC4, AC4, AC4, AC4, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5}/*FV2*/
213 ,{XC3, AC4, AC4, AC4, AC4, AC4, AC4, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5} /*FV3*/
214 ,{XC3, AC4, AC4, AC4, AC4, AC4, AC4, RJ5, RJ5, RJ5, CP1, CP1, RJ5, RJ5, RJ5, RJ5, RJ5}/*BV1*/
215 ,{XC3, AC4, AC4, AC4, AC4, AC4, AC4, RJ5, RJ5, RJ5, CP1, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5}/*BV2*/
216 ,{XC3, AC4, AC4, AC4, AC4, AC4, AC4, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5}/*BD*/
217 ,{XC3, AC4, AC4, AC4, AC4, AC4, AC4, CP1, CP1, RJ5, RJ5, RJ5, RJ5, RJ5, CP1, CP1, CP1}/*TONE*/
218 ,{XC3, AC4, AC4, AC4, AC4, AC4, AC4, CP1, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, CP1, RJ5, RJ5}/*AD1*/
219 ,{XC3, AC4, AC4, AC4, AC4, AC4, AC4, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, CP1}/*AD2*/
220 ,{XC3, AC4, AC4, AC4, AC4, AC4, AC4, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5}/*AD3*/
221 ,{XC3, AC4, AC4, AC4, AC4, AC4, AC4, RJ5, RJ5, RJ5, CP1, CP1, RJ5, RJ5, RJ5, RJ5, RJ5}/*AV1*/
222 ,{XC3, AC4, AC4, AC4, AC4, AC4, AC4, RJ5, RJ5, RJ5, CP1, RJ5, RJ5, RJ5, RJ5, RJ5, RJ5}/*AV2*/
223 ,{XC3, AC4, AC4, AC4, AC4, AC4, AC4, RJ5, RJ5, RJ5, CP1, RJ5, CP1, RJ5, RJ5, RJ5, RJ5}/*AV3*/
224};
225
226
227/* returns classification of a char */
228Privatestatic int
229THAI_chtype (unsigned char ch)
230{
231 return tactis_chtype[ch];
232}
233
234#ifdef UNUSED
235/* returns the display level */
236Privatestatic int
237THAI_chlevel (unsigned char ch)
238{
239 int chlevel;
240
241 switch (tactis_chtype[ch])
242 {
243 case CTRL0:
244 chlevel = NON1;
245 break;
246 case BV17:
247 case BV28:
248 case BD9:
249 chlevel = BELOW4;
250 break;
251 case TONE10:
252 case AD111:
253 case AD212:
254 chlevel = TOP1;
255 break;
256 case AV114:
257 case AV215:
258 case AV316:
259 case AD313:
260 chlevel = ABOVE2;
261 break;
262 case NON1:
263 case CONS2:
264 case LV3:
265 case FV14:
266 case FV25:
267 case FV36:
268 default: /* if tactis_chtype is invalid */
269 chlevel = BASE3;
270 break;
271 }
272 return chlevel;
273}
274
275
276/* return True if char is non-spacing */
277Privatestatic Boolint
278THAI_isdead (unsigned char ch)
279{
280 return ((tactis_chtype[ch] == CTRL0) || (tactis_chtype[ch] == BV17) ||
281 (tactis_chtype[ch] == BV28) || (tactis_chtype[ch] == BD9) ||
282 (tactis_chtype[ch] == TONE10) || (tactis_chtype[ch] == AD111) ||
283 (tactis_chtype[ch] == AD212) || (tactis_chtype[ch] == AD313) ||
284 (tactis_chtype[ch] == AV114) || (tactis_chtype[ch] == AV215) ||
285 (tactis_chtype[ch] == AV316));
286}
287
288
289/* return True if char is consonant */
290Privatestatic Boolint
291THAI_iscons (unsigned char ch)
292{
293 return (tactis_chtype[ch] == CONS2);
294}
295
296
297/* return True if char is vowel */
298Privatestatic Boolint
299THAI_isvowel (unsigned char ch)
300{
301 return ((tactis_chtype[ch] == LV3) || (tactis_chtype[ch] == FV14) ||
302 (tactis_chtype[ch] == FV25) || (tactis_chtype[ch] == FV36) ||
303 (tactis_chtype[ch] == BV17) || (tactis_chtype[ch] == BV28) ||
304 (tactis_chtype[ch] == AV114) || (tactis_chtype[ch] == AV215) ||
305 (tactis_chtype[ch] == AV316));
306}
307
308
309/* return True if char is tonemark */
310Privatestatic Boolint
311THAI_istone (unsigned char ch)
312{
313 return (tactis_chtype[ch] == TONE10);
314}
315#endif
316
317Privatestatic Boolint
318THAI_iscomposible (
319 unsigned char follow_ch,
320 unsigned char lead_ch)
321{/* "Can follow_ch be put in the same display cell as lead_ch?" */
322
323 return (write_rules_lookup[THAI_chtype(lead_ch)][THAI_chtype(follow_ch)]
324 == CP1);
325}
326
327Privatestatic Boolint
328THAI_isaccepted (
329 unsigned char follow_ch,
330 unsigned char lead_ch,
331 unsigned char mode)
332{
333 Boolint iskeyvalid; /* means "Can follow_ch be keyed in after lead_ch?" */
334
335 switch (mode)
336 {
337 case WTT_ISC11:
338 iskeyvalid =
339 (wtt_isc1_lookup[THAI_chtype(lead_ch)][THAI_chtype(follow_ch)] != RJ5);
340 break;
341 case WTT_ISC22:
342 iskeyvalid =
343 (wtt_isc2_lookup[THAI_chtype(lead_ch)][THAI_chtype(follow_ch)] != RJ5);
344 break;
345 case THAICAT_ISC3:
346 iskeyvalid =
347 (thaicat_isc_lookup[THAI_chtype(lead_ch)][THAI_chtype(follow_ch)] != RJ5);
348 break;
349 default:
350 iskeyvalid = True1;
351 break;
352 }
353
354 return iskeyvalid;
355}
356
357#ifdef UNUSED
358Privatestatic void
359THAI_apply_write_rules(
360 unsigned char *instr,
361 unsigned char *outstr,
362 unsigned char insert_ch,
363 int *num_insert_ch)
364{
365/*
366Input parameters:
367 instr - input string
368 insert_ch specify what char to be added when invalid composition is found
369Output parameters:
370 outstr - output string after input string has been applied the rules
371 num_insert_ch - number of insert_ch added to outstr.
372*/
373 unsigned char *lead_ch = NULL((void*)0), *follow_ch = NULL((void*)0), *out_ch = NULL((void*)0);
374
375 *num_insert_ch = 0;
376 lead_ch = follow_ch = instr;
377 out_ch = outstr;
378 if ((*lead_ch == '\0') || !(THAI_find_chtype(instr,DEAD17)))
379 { /* Empty string or can't find any non-spacing char*/
380 strcpy((char *)outstr, (char *)instr);
381 } else { /* String of length >= 1, keep looking */
382 follow_ch++;
383 if (THAI_isdead(*lead_ch)) { /* is first char non-spacing? */
384 *out_ch++ = SPACE32;
385 (*num_insert_ch)++;
386 }
387 *out_ch++ = *lead_ch;
388 while (*follow_ch != '\0') /* more char in string to check */
389 {
390 if (THAI_isdead(*follow_ch) &&
391 !THAI_iscomposible(*follow_ch,*lead_ch))
392 {
393 *out_ch++ = SPACE32;
394 (*num_insert_ch)++;
395 }
396 *out_ch++ = *follow_ch;
397 lead_ch = follow_ch;
398 follow_ch++;
399 }
400 *out_ch = '\0';
401 }
402}
403
404Privatestatic int
405THAI_find_chtype (
406 unsigned char *instr,
407 int chtype)
408{
409/*
410Input parameters:
411 instr - input string
412 chtype - type of character to look for
413Output parameters:
414 function returns first position of character with matched chtype
415 function returns -1 if it does not find.
416*/
417 int i = 0, position = -1;
418
419 switch (chtype)
420 {
421 case DEAD17:
422 for (i = 0; *instr != '\0' && THAI_isdead(*instr); i++, instr++)
423 ;
424 if (*instr != '\0') position = i;
425 break;
426 default:
427 break;
428 }
429 return position;
430}
431
432
433Privatestatic int
434THAI_apply_scm(
435 unsigned char *instr,
436 unsigned char *outstr,
437 unsigned char spec_ch,
438 int num_sp,
439 unsigned char insert_ch)
440{
441 unsigned char *scan, *outch;
442 int i, dead_count, found_count;
443 Boolint isconsecutive;
444
445 scan = instr;
446 outch = outstr;
447 dead_count = found_count = 0;
448 isconsecutive = False0;
449 while (*scan != '\0') {
450 if (THAI_isdead(*scan))
451 dead_count++; /* count number of non-spacing char */
452 if (*scan == spec_ch)
453 if (!isconsecutive)
454 found_count++; /* count number consecutive spec char found */
455 *outch++ = *scan++;
456 if (found_count == num_sp) {
457 for (i = 0; i < dead_count; i++)
458 *outch++ = insert_ch;
459 dead_count = found_count = 0;
460 }
461 }
462 /* what to return? */
463 return 0; /* probably not right but better than returning garbage */
464}
465
466
467/* The following functions are copied from XKeyBind.c */
468
469Privatestatic void ComputeMaskFromKeytrans();
470Privatestatic int IsCancelComposeKey(KeySym *symbol, XKeyEvent *event);
471Privatestatic void SetLed(Display *dpy, int num, int state);
472Privatestatic CARD8 FindKeyCode();
473
474
475/* The following functions are specific to this module */
476
477Privatestatic int XThaiTranslateKey();
478Privatestatic int XThaiTranslateKeySym();
479
480
481Privatestatic KeySym HexIMNormalKey(
482 XicThaiPart *thai_part,
483 KeySym symbol,
484 XKeyEvent *event);
485Privatestatic KeySym HexIMFirstComposeKey(
486 XicThaiPart *thai_part,
487 KeySym symbol,
488 XKeyEvent *event);
489Privatestatic KeySym HexIMSecondComposeKey(
490 XicThaiPart *thai_part,
491 KeySym symbol
492 XKeyEvent *event);
493Privatestatic KeySym HexIMComposeSequence(KeySym ks1, KeySym ks2);
494Privatestatic void InitIscMode(Xic ic);
495Privatestatic Boolint ThaiComposeConvert(
496 Display *dpy,
497 KeySym insym,
498 KeySym *outsym, KeySym *lower, KeySym *upper);
499#endif
500
501/*
502 * Definitions
503 */
504
505#define BellVolume0 0
506
507#define ucs2tis(wc)(unsigned char) ( (0<=(wc)&&(wc)<=0x7F) ? (wc) :
((0x0E01<=(wc)&&(wc)<=0x0E5F) ? ((wc)-0x0E00 +
0xA0) : 0))
\
508 (unsigned char) ( \
509 (0<=(wc)&&(wc)<=0x7F) ? \
510 (wc) : \
511 ((0x0E01<=(wc)&&(wc)<=0x0E5F) ? ((wc)-0x0E00+0xA0) : 0))
512/* "c" is an unsigned char */
513#define tis2ucs(c)( ((c)<=0x7F) ? (wchar_t)(c) : ((0x0A1<=(c)) ? ((wchar_t
)(c)-0xA0 +0x0E00) : 0))
\
514 ( \
515 ((c)<=0x7F) ? \
516 (wchar_t)(c) : \
517 ((0x0A1<=(c)) ? ((wchar_t)(c)-0xA0+0x0E00) : 0))
518
519/*
520 * Macros to save and recall last input character in XIC
521 */
522#define IC_SavePreviousChar(ic,ch)((ic)->private.local.base.mb[(ic)->private.local.base.tree
[(ic)->private.local.context].mb] = (char) (ch))
\
523 ((ic)->private.local.base.mb[(ic)->private.local.base.tree[(ic)->private.local.context].mb] = (char) (ch))
524#define IC_ClearPreviousChar(ic)((ic)->private.local.base.mb[(ic)->private.local.base.tree
[(ic)->private.local.context].mb] = 0)
\
525 ((ic)->private.local.base.mb[(ic)->private.local.base.tree[(ic)->private.local.context].mb] = 0)
526#define IC_GetPreviousChar(ic)(IC_RealGetPreviousChar(ic,1)) \
527 (IC_RealGetPreviousChar(ic,1))
528#define IC_GetContextChar(ic)(IC_RealGetPreviousChar(ic,2)) \
529 (IC_RealGetPreviousChar(ic,2))
530#define IC_DeletePreviousChar(ic)(IC_RealDeletePreviousChar(ic)) \
531 (IC_RealDeletePreviousChar(ic))
532
533Privatestatic unsigned char
534IC_RealGetPreviousChar(Xic ic, unsigned short pos)
535{
536 XICCallback* cb = &ic->core.string_conversion_callback;
537 DefTreeBase *b = &ic->private.local.base;
538
539 if (cb && cb->callback) {
1
Taking false branch
540 XIMStringConversionCallbackStruct screc;
541 unsigned char c;
542
543 /* Use a safe value of position = 0 and stretch the range to desired
544 * place, as XIM protocol is unclear here whether it could be negative
545 */
546 screc.position = 0;
547 screc.direction = XIMBackwardChar;
548 screc.operation = XIMStringConversionRetrieval(0x0002);
549 screc.factor = pos;
550 screc.text = 0;
551
552 (cb->callback)((XIC)ic, cb->client_data, (XPointer)&screc);
553 if (!screc.text)
554 return (unsigned char) b->mb[b->tree[(ic)->private.local.context].mb];
555 if ((screc.text->feedback &&
556 *screc.text->feedback == XIMStringConversionLeftEdge(0x00000001)) ||
557 screc.text->length < 1)
558 {
559 c = 0;
560 } else {
561 Xim im;
562 XlcConv conv;
563 int from_left;
564 int to_left;
565 char *from_buf;
566 char *to_buf;
567
568 im = (Xim) XIMOfIC((XIC)ic);
569 if (screc.text->encoding_is_wchar) {
570 conv = _XlcOpenConverter(im->core.lcd, XlcNWideChar"wideChar",
571 im->core.lcd, XlcNCharSet"charSet");
572 from_buf = (char *) screc.text->string.wcs;
573 from_left = screc.text->length * sizeof(wchar_t);
574 } else {
575 conv = _XlcOpenConverter(im->core.lcd, XlcNMultiByte"multiByte",
576 im->core.lcd, XlcNCharSet"charSet");
577 from_buf = screc.text->string.mbs;
578 from_left = screc.text->length;
579 }
580 to_buf = (char *)&c;
581 to_left = 1;
582
583 _XlcResetConverter(conv);
584 if (_XlcConvert(conv, (XPointer *)&from_buf, &from_left,
585 (XPointer *)&to_buf, &to_left, NULL((void*)0), 0) < 0)
586 {
587 c = (unsigned char) b->mb[b->tree[(ic)->private.local.context].mb];
588 }
589 _XlcCloseConverter(conv);
590
591 XFree(screc.text->string.mbs);
592 }
593 XFree(screc.text);
594 return c;
595 } else {
596 return (unsigned char) b->mb[b->tree[(ic)->private.local.context].mb];
2
Dereference of null pointer
597 }
598}
599
600Privatestatic unsigned char
601IC_RealDeletePreviousChar(Xic ic)
602{
603 XICCallback* cb = &ic->core.string_conversion_callback;
604
605 if (cb && cb->callback) {
606 XIMStringConversionCallbackStruct screc;
607 unsigned char c;
608
609 screc.position = 0;
610 screc.direction = XIMBackwardChar;
611 screc.operation = XIMStringConversionSubstitution(0x0001);
612 screc.factor = 1;
613 screc.text = 0;
614
615 (cb->callback)((XIC)ic, cb->client_data, (XPointer)&screc);
616 if (!screc.text) { return 0; }
617 if ((screc.text->feedback &&
618 *screc.text->feedback == XIMStringConversionLeftEdge(0x00000001)) ||
619 screc.text->length < 1)
620 {
621 c = 0;
622 } else {
623 if (screc.text->encoding_is_wchar) {
624 c = ucs2tis(screc.text->string.wcs[0])(unsigned char) ( (0<=(screc.text->string.wcs[0])&&
(screc.text->string.wcs[0])<=0x7F) ? (screc.text->string
.wcs[0]) : ((0x0E01<=(screc.text->string.wcs[0])&&
(screc.text->string.wcs[0])<=0x0E5F) ? ((screc.text->
string.wcs[0])-0x0E00 +0xA0) : 0))
;
625 XFree(screc.text->string.wcs);
626 } else {
627 c = screc.text->string.mbs[0];
628 XFree(screc.text->string.mbs);
629 }
630 }
631 XFree(screc.text);
632 return c;
633 } else {
634 return 0;
635 }
636}
637/*
638 * Input sequence check mode in XIC
639 */
640#define IC_IscMode(ic)((ic)->private.local.thai.input_mode) ((ic)->private.local.thai.input_mode)
641
642/*
643 * Max. size of string handled by the two String Lookup functions.
644 */
645#define STR_LKUP_BUF_SIZE256 256
646
647/*
648 * Size of buffer to contain previous locale name.
649 */
650#define SAV_LOCALE_NAME_SIZE256 256
651
652/*
653 * Size of buffer to contain the IM modifier.
654 */
655#define MAXTHAIIMMODLEN20 20
656
657#define AllMods((1<<0)|(1<<1)|(1<<2)| (1<<3)|(1<<
4)|(1<<5)|(1<<6)|(1<<7))
(ShiftMask(1<<0)|LockMask(1<<1)|ControlMask(1<<2)| \
658 Mod1Mask(1<<3)|Mod2Mask(1<<4)|Mod3Mask(1<<5)|Mod4Mask(1<<6)|Mod5Mask(1<<7))
659
660
661#define IsISOControlKey(ks)((ks) >= 0x0032 && (ks) <= 0x0038) ((ks) >= XK_20x0032 && (ks) <= XK_80x0038)
662
663#define IsValidControlKey(ks)(((((ks)>=0x0041 && (ks)<=0x007e) || (ks)==0x0020
|| (ks)==0xffff) && ((ks)!=0)))
(((((ks)>=XK_A0x0041 && (ks)<=XK_asciitilde0x007e) || \
664 (ks)==XK_space0x0020 || (ks)==XK_Delete0xffff) && \
665 ((ks)!=0)))
666
667#define COMPOSE_LED2 2
668
669#ifdef UNUSED
670typedef KeySym (*StateProc)(
671 XicThaiPart *thai_part,
672 KeySym symbol,
673 XKeyEvent *event);
674
675
676/*
677 * macros to classify XKeyEvent state field
678 */
679
680#define IsShift(state) (((state) & ShiftMask(1<<0)) != 0)
681#define IsLock(state) (((state) & LockMask(1<<1)) != 0)
682#define IsControl(state) (((state) & ControlMask(1<<2)) != 0)
683#define IsMod1(state) (((state) & Mod1Mask(1<<3)) != 0)
684#define IsMod2(state) (((state) & Mod2Mask(1<<4)) != 0)
685#define IsMod3(state) (((state) & Mod3Mask(1<<5)) != 0)
686#define IsMod4(state) (((state) & Mod4Mask(1<<6)) != 0)
687#define IsMod5(state) (((state) & Mod5Mask(1<<7)) != 0)
688
689/*
690 * key starts Thai compose sequence (Hex input method) if :
691 */
692
693#define IsComposeKey(ks, event) \
694 (( ks==XK_Alt_L0xffe9 && \
695 IsControl((event)->state) && \
696 !IsShift((event)->state)) \
697 ? True1 : False0)
698
699
700/*
701 * State handler to implement the Thai hex input method.
702 */
703
704Privatestatic int const nstate_handlers = 3;
705Privatestatic StateProc state_handler[] = {
706 HexIMNormalKey,
707 HexIMFirstComposeKey,
708 HexIMSecondComposeKey
709};
710
711
712/*
713 * Table for 'Thai Compose' character input.
714 * The current implementation uses latin-1 keysyms.
715 */
716struct _XMapThaiKey {
717 KeySym from;
718 KeySym to;
719};
720
721Privatestatic struct _XMapThaiKey const ThaiComposeTable[] = {
722 { /* 0xa4 */ XK_currency0x00a4, /* 0xa5 */ XK_yen0x00a5 },
723 { /* 0xa2 */ XK_cent0x00a2, /* 0xa3 */ XK_sterling0x00a3 },
724 { /* 0xe6 */ XK_ae0x00e6, /* 0xef */ XK_idiaeresis0x00ef },
725 { /* 0xd3 */ XK_Oacute0x00d3, /* 0xee */ XK_icircumflex0x00ee },
726 { /* 0xb9 */ XK_onesuperior0x00b9, /* 0xfa */ XK_uacute0x00fa },
727 { /* 0xd2 */ XK_Ograve0x00d2, /* 0xe5 */ XK_aring0x00e5 },
728 { /* 0xbc */ XK_onequarter0x00bc, /* 0xfb */ XK_ucircumflex0x00fb },
729 { XK_VoidSymbol0xffffff, XK_VoidSymbol0xffffff }
730};
731
732struct _XKeytrans {
733 struct _XKeytrans *next;/* next on list */
734 char *string; /* string to return when the time comes */
735 int len; /* length of string (since NULL is legit)*/
736 KeySym key; /* keysym rebound */
737 unsigned int state; /* modifier state */
738 KeySym *modifiers; /* modifier keysyms you want */
739 int mlen; /* length of modifier list */
740};
741
742
743/* Convert keysym to 'Thai Compose' keysym */
744/* The current implementation use latin-1 keysyms */
745Privatestatic Boolint
746ThaiComposeConvert(
747 Display *dpy,
748 KeySym insym,
749 KeySym *outsym, KeySym *lower, KeySym *upper)
750{
751 struct _XMapThaiKey const *table_entry = ThaiComposeTable;
752
753 while (table_entry->from != XK_VoidSymbol0xffffff) {
754 if (table_entry->from == insym) {
755 *outsym = table_entry->to;
756 *lower = *outsym;
757 *upper = *outsym;
758 return True1;
759 }
760 table_entry++;
761 }
762 return False0;
763}
764
765Privatestatic int
766XThaiTranslateKey(
767 register Display *dpy,
768 KeyCode keycode,
769 register unsigned int modifiers,
770 unsigned int *modifiers_return,
771 KeySym *keysym_return,
772 KeySym *lsym_return,
773 KeySym *usym_return)
774{
775 int per;
776 register KeySym *syms;
777 KeySym sym = 0, lsym = 0, usym = 0;
778
779 if ((! dpy->keysyms) && (! _XKeyInitialize(dpy)))
780 return 0;
781 *modifiers_return = (ShiftMask(1<<0)|LockMask(1<<1)) | dpy->mode_switch;
782 if (((int)keycode < dpy->min_keycode) || ((int)keycode > dpy->max_keycode))
783 {
784 *keysym_return = NoSymbol0L;
785 return 1;
786 }
787 per = dpy->keysyms_per_keycode;
788 syms = &dpy->keysyms[(keycode - dpy->min_keycode) * per];
789 while ((per > 2) && (syms[per - 1] == NoSymbol0L))
790 per--;
791 if ((per > 2) && (modifiers & dpy->mode_switch)) {
792 syms += 2;
793 per -= 2;
794 }
795 if (!(modifiers & ShiftMask(1<<0)) &&
796 (!(modifiers & LockMask(1<<1)) || (dpy->lock_meaning == NoSymbol0L))) {
797 if ((per == 1) || (syms[1] == NoSymbol0L))
798 XConvertCase(syms[0], keysym_return, &usym);
799 else {
800 XConvertCase(syms[0], &lsym, &usym);
801 *keysym_return = syms[0];
802 }
803 } else if (!(modifiers & LockMask(1<<1)) ||
804 (dpy->lock_meaning != XK_Caps_Lock0xffe5)) {
805 if ((per == 1) || ((usym = syms[1]) == NoSymbol0L))
806 XConvertCase(syms[0], &lsym, &usym);
807 *keysym_return = usym;
808 } else {
809 if ((per == 1) || ((sym = syms[1]) == NoSymbol0L))
810 sym = syms[0];
811 XConvertCase(sym, &lsym, &usym);
812 if (!(modifiers & ShiftMask(1<<0)) && (sym != syms[0]) &&
813 ((sym != usym) || (lsym == usym)))
814 XConvertCase(syms[0], &lsym, &usym);
815 *keysym_return = usym;
816 }
817 /*
818 * ThaiCat keyboard support :
819 * When the Shift and Thai keys are hold for some keys a 'Thai Compose'
820 * character code is generated which is different from column 3 and
821 * 4 of the keymap.
822 * Since we don't know whether ThaiCat keyboard or WTT keyboard is
823 * in use, the same mapping is done for all Thai input.
824 * We just arbitary choose to use column 3 keysyms as the indices of
825 * this mapping.
826 * When the control key is also hold, this mapping has no effect.
827 */
828 if ((modifiers & Mod1Mask(1<<3)) &&
829 (modifiers & ShiftMask(1<<0)) &&
830 !(modifiers & ControlMask(1<<2))) {
831 if (ThaiComposeConvert(dpy, syms[0], &sym, &lsym, &usym))
832 *keysym_return = sym;
833 }
834
835 if (*keysym_return == XK_VoidSymbol0xffffff)
836 *keysym_return = NoSymbol0L;
837 *lsym_return = lsym;
838 *usym_return = usym;
839 return 1;
840}
841
842/*
843 * XThaiTranslateKeySym
844 *
845 * Translate KeySym to TACTIS code output.
846 * The current implementation uses ISO latin-1 keysym.
847 * Should be changed to TACTIS keysyms when they are defined by the
848 * standard.
849 */
850Privatestatic int
851XThaiTranslateKeySym(
852 Display *dpy,
853 register KeySym symbol,
854 register KeySym lsym,
855 register KeySym usym,
856 unsigned int modifiers,
857 unsigned char *buffer,
858 int nbytes)
859{
860 KeySym ckey = 0;
861 register struct _XKeytrans *p;
862 int length;
863 unsigned long hiBytes;
864 register unsigned char c;
865
866 /*
867 * initialize length = 1 ;
868 */
869 length = 1;
870
871 if (!symbol)
872 return 0;
873 /* see if symbol rebound, if so, return that string. */
874 for (p = dpy->key_bindings; p; p = p->next) {
875 if (((modifiers & AllMods((1<<0)|(1<<1)|(1<<2)| (1<<3)|(1<<
4)|(1<<5)|(1<<6)|(1<<7))
) == p->state) && (symbol == p->key)) {
876 length = p->len;
877 if (length > nbytes) length = nbytes;
878 memcpy (buffer, p->string, length);
879 return length;
880 }
881 }
882 /* try to convert to TACTIS, handling control */
883 hiBytes = symbol >> 8;
884 if (!(nbytes &&
885 ((hiBytes == 0) ||
886 ((hiBytes == 0xFF) &&
887 (((symbol >= XK_BackSpace0xff08) && (symbol <= XK_Clear0xff0b)) ||
888 (symbol == XK_Return0xff0d) ||
889 (symbol == XK_Escape0xff1b) ||
890 (symbol == XK_KP_Space0xff80) ||
891 (symbol == XK_KP_Tab0xff89) ||
892 (symbol == XK_KP_Enter0xff8d) ||
893 ((symbol >= XK_KP_Multiply0xffaa) && (symbol <= XK_KP_90xffb9)) ||
894 (symbol == XK_KP_Equal0xffbd) ||
895 (symbol == XK_Scroll_Lock0xff14) ||
896#ifdef DXK_PRIVATE /* DEC private keysyms */
897 (symbol == DXK_Remove) ||
898#endif
899 (symbol == NoSymbol0L) ||
900 (symbol == XK_Delete0xffff))))))
901 return 0;
902
903 /* if X keysym, convert to ascii by grabbing low 7 bits */
904 if (symbol == XK_KP_Space0xff80)
905 c = XK_space0x0020 & 0x7F; /* patch encoding botch */
906/* not for Thai
907 else if (symbol == XK_hyphen)
908 c = XK_minus & 0xFF; */ /* map to equiv character */
909 else if (hiBytes == 0xFF)
910 c = symbol & 0x7F;
911 else
912 c = symbol & 0xFF;
913 /* only apply Control key if it makes sense, else ignore it */
914 if (modifiers & ControlMask(1<<2)) {
915 if (!(IsKeypadKey(lsym)(((KeySym)(lsym) >= 0xff80) && ((KeySym)(lsym) <=
0xffbd))
|| lsym==XK_Return0xff0d || lsym==XK_Tab0xff09)) {
916 if (IsISOControlKey(lsym)((lsym) >= 0x0032 && (lsym) <= 0x0038)) ckey = lsym;
917 else if (IsISOControlKey(usym)((usym) >= 0x0032 && (usym) <= 0x0038)) ckey = usym;
918 else if (lsym == XK_question0x003f) ckey = lsym;
919 else if (usym == XK_question0x003f) ckey = usym;
920 else if (IsValidControlKey(lsym)(((((lsym)>=0x0041 && (lsym)<=0x007e) || (lsym)
==0x0020 || (lsym)==0xffff) && ((lsym)!=0)))
) ckey = lsym;
921 else if (IsValidControlKey(usym)(((((usym)>=0x0041 && (usym)<=0x007e) || (usym)
==0x0020 || (usym)==0xffff) && ((usym)!=0)))
) ckey = usym;
922 else length = 0;
923
924 if (length != 0) {
925 if (ckey == XK_20x0032) c = '\000';
926 else if (ckey >= XK_30x0033 && ckey <= XK_70x0037)
927 c = (char)(ckey-('3'-'\033'));
928 else if (ckey == XK_80x0038) c = '\177';
929 else if (ckey == XK_Delete0xffff) c = '\030';
930 else if (ckey == XK_question0x003f) c = '\037';
931 else if (ckey == XK_quoteleft0x0060) c = '\036'; /* KLee 1/24/91 */
932 else c = (char)(ckey & 0x1f);
933 }
934 }
935 }
936 /*
937 * ThaiCat has a key that generates two TACTIS codes D1 & E9.
938 * It is represented by the latin-1 keysym XK_thorn (0xfe).
939 * If c is XK_thorn, this key is pressed and it is converted to
940 * 0xd1 0xe9.
941 */
942 if (c == XK_thorn0x00fe) {
943 buffer[0] = 0xd1;
944 buffer[1] = 0xe9;
945 buffer[2] = '\0';
946 return 2;
947 }
948 else {
949 /* Normal case */
950 buffer[0] = c;
951 buffer[1] = '\0';
952 return 1;
953 }
954}
955
956/*
957 * given a KeySym, returns the first keycode containing it, if any.
958 */
959Privatestatic CARD8
960FindKeyCode(
961 register Display *dpy,
962 register KeySym code)
963{
964
965 register KeySym *kmax = dpy->keysyms +
966 (dpy->max_keycode - dpy->min_keycode + 1) * dpy->keysyms_per_keycode;
967 register KeySym *k = dpy->keysyms;
968 while (k < kmax) {
969 if (*k == code)
970 return (((k - dpy->keysyms) / dpy->keysyms_per_keycode) +
971 dpy->min_keycode);
972 k += 1;
973 }
974 return 0;
975}
976
977/*
978 * given a list of modifiers, computes the mask necessary for later matching.
979 * This routine must lookup the key in the Keymap and then search to see
980 * what modifier it is bound to, if any. Sets the AnyModifier bit if it
981 * can't map some keysym to a modifier.
982 */
983Privatestatic void
984ComputeMaskFromKeytrans(
985 Display *dpy,
986 register struct _XKeytrans *p)
987{
988 register int i;
989 register CARD8 code;
990 register XModifierKeymap *m = dpy->modifiermap;
991
992 p->state = AnyModifier(1<<15);
993 for (i = 0; i < p->mlen; i++) {
994 /* if not found, then not on current keyboard */
995 if ((code = FindKeyCode(dpy, p->modifiers[i])) == 0)
996 return;
997 /* code is now the keycode for the modifier you want */
998 {
999 register int j = m->max_keypermod<<3;
1000
1001 while ((--j >= 0) && (code != m->modifiermap[j]))
1002 ;
1003 if (j < 0)
1004 return;
1005 p->state |= (1<<(j/m->max_keypermod));
1006 }
1007 }
1008 p->state &= AllMods((1<<0)|(1<<1)|(1<<2)| (1<<3)|(1<<
4)|(1<<5)|(1<<6)|(1<<7))
;
1009}
1010
1011/************************************************************************
1012 *
1013 *
1014 * Compose handling routines - compose handlers 0,1,2
1015 *
1016 *
1017 ************************************************************************/
1018
1019#define NORMAL_KEY_STATE 0
1020#define FIRST_COMPOSE_KEY_STATE 1
1021#define SECOND_COMPOSE_KEY_STATE 2
1022
1023Privatestatic
1024KeySym HexIMNormalKey(
1025 XicThaiPart *thai_part,
1026 KeySym symbol,
1027 XKeyEvent *event)
1028{
1029 if (IsComposeKey (symbol, event)) /* start compose sequence */
1030 {
1031 SetLed (event->display,COMPOSE_LED2, LedModeOn1);
1032 thai_part->comp_state = FIRST_COMPOSE_KEY_STATE;
1033 return NoSymbol0L;
1034 }
1035 return symbol;
1036}
1037
1038
1039Privatestatic
1040KeySym HexIMFirstComposeKey(
1041 XicThaiPart *thai_part,
1042 KeySym symbol,
1043 XKeyEvent *event)
1044{
1045 if (IsModifierKey (symbol)((((KeySym)(symbol) >= 0xffe1) && ((KeySym)(symbol
) <= 0xffee)) || (((KeySym)(symbol) >= 0xfe01) &&
((KeySym)(symbol) <= 0xfe13)) || ((KeySym)(symbol) == 0xff7e
) || ((KeySym)(symbol) == 0xff7f))
) return symbol; /* ignore shift etc. */
1046 if (IsCancelComposeKey (&symbol, event)) /* cancel sequence */
1047 {
1048 SetLed (event->display,COMPOSE_LED2, LedModeOff0);
1049 thai_part->comp_state = NORMAL_KEY_STATE;
1050 return symbol;
1051 }
1052 if (IsComposeKey (symbol, event)) /* restart sequence ?? */
1053 {
1054 return NoSymbol0L; /* no state change necessary */
1055 }
1056
1057 thai_part->keysym = symbol; /* save key pressed */
1058 thai_part->comp_state = SECOND_COMPOSE_KEY_STATE;
1059 return NoSymbol0L;
1060}
1061
1062Privatestatic
1063KeySym HexIMSecondComposeKey(
1064 XicThaiPart *thai_part,
1065 KeySym symbol,
1066 XKeyEvent *event)
1067{
1068 if (IsModifierKey (symbol)((((KeySym)(symbol) >= 0xffe1) && ((KeySym)(symbol
) <= 0xffee)) || (((KeySym)(symbol) >= 0xfe01) &&
((KeySym)(symbol) <= 0xfe13)) || ((KeySym)(symbol) == 0xff7e
) || ((KeySym)(symbol) == 0xff7f))
) return symbol; /* ignore shift etc. */
1069 if (IsComposeKey (symbol, event)) /* restart sequence ? */
1070 {
1071 thai_part->comp_state =FIRST_COMPOSE_KEY_STATE;
1072 return NoSymbol0L;
1073 }
1074 SetLed (event->display,COMPOSE_LED2, LedModeOff0);
1075 if (IsCancelComposeKey (&symbol, event)) /* cancel sequence ? */
1076 {
1077 thai_part->comp_state = NORMAL_KEY_STATE;
1078 return symbol;
1079 }
1080
1081 if ((symbol = HexIMComposeSequence (thai_part->keysym, symbol))
1082 ==NoSymbol0L)
1083 { /* invalid compose sequence */
1084 XBell(event->display, BellVolume0);
1085 }
1086 thai_part->comp_state = NORMAL_KEY_STATE; /* reset to normal state */
1087 return symbol;
1088}
1089
1090
1091/*
1092 * Interprets two keysyms entered as hex digits and return the Thai keysym
1093 * correspond to the TACTIS code formed.
1094 * The current implementation of this routine returns ISO Latin Keysyms.
1095 */
1096
1097Privatestatic
1098KeySym HexIMComposeSequence(KeySym ks1, KeySym ks2)
1099{
1100int hi_digit;
1101int lo_digit;
1102int tactis_code;
1103
1104 if ((ks1 >= XK_00x0030) && (ks1 <= XK_90x0039))
1105 hi_digit = ks1 - XK_00x0030;
1106 else if ((ks1 >= XK_A0x0041) && (ks1 <= XK_F0x0046))
1107 hi_digit = ks1 - XK_A0x0041 + 10;
1108 else if ((ks1 >= XK_a0x0061) && (ks1 <= XK_f0x0066))
1109 hi_digit = ks1 - XK_a0x0061 + 10;
1110 else /* out of range */
1111 return NoSymbol0L;
1112
1113 if ((ks2 >= XK_00x0030) && (ks2 <= XK_90x0039))
1114 lo_digit = ks2 - XK_00x0030;
1115 else if ((ks2 >= XK_A0x0041) && (ks2 <= XK_F0x0046))
1116 lo_digit = ks2 - XK_A0x0041 + 10;
1117 else if ((ks2 >= XK_a0x0061) && (ks2 <= XK_f0x0066))
1118 lo_digit = ks2 - XK_a0x0061 + 10;
1119 else /* out of range */
1120 return NoSymbol0L;
1121
1122 tactis_code = hi_digit * 0x10 + lo_digit ;
1123
1124 return (KeySym)tactis_code;
1125
1126}
1127
1128/*
1129 * routine determines
1130 * 1) whether key event should cancel a compose sequence
1131 * 2) whether cancelling key event should be processed or ignored
1132 */
1133
1134Privatestatic
1135int IsCancelComposeKey(
1136 KeySym *symbol,
1137 XKeyEvent *event)
1138{
1139 if (*symbol==XK_Delete0xffff && !IsControl(event->state) &&
1140 !IsMod1(event->state)) {
1141 *symbol=NoSymbol0L; /* cancel compose sequence, and ignore key */
1142 return True1;
1143 }
1144 if (IsComposeKey(*symbol, event)) return False0;
1145 return (
1146 IsControl (event->state) ||
1147 IsMod1(event->state) ||
1148 IsKeypadKey (*symbol)(((KeySym)(*symbol) >= 0xff80) && ((KeySym)(*symbol
) <= 0xffbd))
||
1149 IsFunctionKey (*symbol)(((KeySym)(*symbol) >= 0xffbe) && ((KeySym)(*symbol
) <= 0xffe0))
||
1150 IsMiscFunctionKey (*symbol)(((KeySym)(*symbol) >= 0xff60) && ((KeySym)(*symbol
) <= 0xff6b))
||
1151#ifdef DXK_PRIVATE /* DEC private keysyms */
1152 *symbol == DXK_Remove ||
1153#endif
1154 IsPFKey (*symbol)(((KeySym)(*symbol) >= 0xff91) && ((KeySym)(*symbol
) <= 0xff94))
||
1155 IsCursorKey (*symbol)(((KeySym)(*symbol) >= 0xff50) && ((KeySym)(*symbol
) < 0xff60))
||
1156 (*symbol >= XK_Tab0xff09 && *symbol < XK_Multi_key0xff20)
1157 ? True1 : False0); /* cancel compose sequence and pass */
1158 /* cancelling key through */
1159}
1160
1161
1162/*
1163 * set specified keyboard LED on or off
1164 */
1165
1166Privatestatic
1167void SetLed(
1168 Display *dpy,
1169 int num,
1170 int state)
1171{
1172 XKeyboardControl led_control;
1173
1174 led_control.led_mode = state;
1175 led_control.led = num;
1176 XChangeKeyboardControl (dpy, KBLed(1L<<4) | KBLedMode(1L<<5), &led_control);
1177}
1178#endif
1179
1180/*
1181 * Initialize ISC mode from im modifier
1182 */
1183Privatestatic void InitIscMode(Xic ic)
1184{
1185 Xim im;
1186 char *im_modifier_name;
1187
1188 /* If already defined, just return */
1189
1190 if (IC_IscMode(ic)((ic)->private.local.thai.input_mode)) return;
1191
1192 /* Get IM modifier */
1193
1194 im = (Xim) XIMOfIC((XIC)ic);
1195 im_modifier_name = im->core.im_name;
1196
1197 /* Match with predefined value, default is Basic Check */
1198
1199 if (!strncmp(im_modifier_name,"BasicCheck",MAXTHAIIMMODLEN20+1))
1200 IC_IscMode(ic)((ic)->private.local.thai.input_mode) = WTT_ISC11;
1201 else if (!strncmp(im_modifier_name,"Strict",MAXTHAIIMMODLEN20+1))
1202 IC_IscMode(ic)((ic)->private.local.thai.input_mode) = WTT_ISC22;
1203 else if (!strncmp(im_modifier_name,"Thaicat",MAXTHAIIMMODLEN20+1))
1204 IC_IscMode(ic)((ic)->private.local.thai.input_mode) = THAICAT_ISC3;
1205 else if (!strncmp(im_modifier_name,"Passthrough",MAXTHAIIMMODLEN20+1))
1206 IC_IscMode(ic)((ic)->private.local.thai.input_mode) = NOISC255;
1207 else
1208 IC_IscMode(ic)((ic)->private.local.thai.input_mode) = WTT_ISC11;
1209
1210 return;
1211}
1212
1213/*
1214 * Helper functions for _XimThaiFilter()
1215 */
1216Privatestatic Boolint
1217ThaiFltAcceptInput(Xic ic, unsigned char new_char, KeySym symbol)
1218{
1219 DefTreeBase *b = &ic->private.local.base;
1220 b->wc[b->tree[ic->private.local.composed].wc+0] = tis2ucs(new_char)( ((new_char)<=0x7F) ? (wchar_t)(new_char) : ((0x0A1<=(
new_char)) ? ((wchar_t)(new_char)-0xA0 +0x0E00) : 0))
;
1221 b->wc[b->tree[ic->private.local.composed].wc+1] = '\0';
1222
1223 if ((new_char <= 0x1f) || (new_char == 0x7f))
1224 b->tree[ic->private.local.composed].keysym = symbol;
1225 else
1226 b->tree[ic->private.local.composed].keysym = NoSymbol0L;
1227
1228 return True1;
1229}
1230
1231Privatestatic Boolint
1232ThaiFltReorderInput(Xic ic, unsigned char previous_char, unsigned char new_char)
1233{
1234 DefTreeBase *b = &ic->private.local.base;
1235 if (!IC_DeletePreviousChar(ic)(IC_RealDeletePreviousChar(ic))) return False0;
1236 b->wc[b->tree[ic->private.local.composed].wc+0] = tis2ucs(new_char)( ((new_char)<=0x7F) ? (wchar_t)(new_char) : ((0x0A1<=(
new_char)) ? ((wchar_t)(new_char)-0xA0 +0x0E00) : 0))
;
1237 b->wc[b->tree[ic->private.local.composed].wc+1] = tis2ucs(previous_char)( ((previous_char)<=0x7F) ? (wchar_t)(previous_char) : ((0x0A1
<=(previous_char)) ? ((wchar_t)(previous_char)-0xA0 +0x0E00
) : 0))
;
1238 b->wc[b->tree[ic->private.local.composed].wc+2] = '\0';
1239
1240 b->tree[ic->private.local.composed].keysym = NoSymbol0L;
1241
1242 return True1;
1243}
1244
1245Privatestatic Boolint
1246ThaiFltReplaceInput(Xic ic, unsigned char new_char, KeySym symbol)
1247{
1248 DefTreeBase *b = &ic->private.local.base;
1249 if (!IC_DeletePreviousChar(ic)(IC_RealDeletePreviousChar(ic))) return False0;
1250 b->wc[b->tree[ic->private.local.composed].wc+0] = tis2ucs(new_char)( ((new_char)<=0x7F) ? (wchar_t)(new_char) : ((0x0A1<=(
new_char)) ? ((wchar_t)(new_char)-0xA0 +0x0E00) : 0))
;
1251 b->wc[b->tree[ic->private.local.composed].wc+1] = '\0';
1252
1253 if ((new_char <= 0x1f) || (new_char == 0x7f))
1254 b->tree[ic->private.local.composed].keysym = symbol;
1255 else
1256 b->tree[ic->private.local.composed].keysym = NoSymbol0L;
1257
1258 return True1;
1259}
1260
1261Privatestatic unsigned
1262NumLockMask(Display *d)
1263{
1264 int i;
1265 XModifierKeymap *map;
1266 KeyCode numlock_keycode = XKeysymToKeycode (d, XK_Num_Lock0xff7f);
1267 if (numlock_keycode == NoSymbol0L)
1268 return 0;
1269
1270 map = XGetModifierMapping (d);
1271 if (!map)
1272 return 0;
1273
1274 for (i = 0; i < 8; i++) {
1275 if (map->modifiermap[map->max_keypermod * i] == numlock_keycode) {
1276 XFreeModifiermap(map);
1277 return 1 << i;
1278 }
1279 }
1280 XFreeModifiermap(map);
1281 return 0;
1282}
1283
1284/*
1285 * Filter function for TACTIS
1286 */
1287Boolint
1288_XimThaiFilter(Display *d, Window w, XEvent *ev, XPointer client_data)
1289{
1290 Xic ic = (Xic)client_data;
1291 KeySym symbol;
1292 int isc_mode; /* Thai Input Sequence Check mode */
1293 unsigned char previous_char; /* Last inputted Thai char */
1294 unsigned char new_char;
1295#ifdef UNUSED
1296 unsigned int modifiers;
1297 KeySym lsym,usym;
1298 int state;
1299 XicThaiPart *thai_part;
1300 char buf[10];
1301#endif
1302 wchar_t wbuf[10];
1303 Boolint isReject;
1304 DefTreeBase *b = &ic->private.local.base;
1305
1306 if ((ev->type != KeyPress2)
1307 || (ev->xkey.keycode == 0))
1308 return False0;
1309
1310 if (!IC_IscMode(ic)((ic)->private.local.thai.input_mode)) InitIscMode(ic);
1311
1312 XwcLookupString((XIC)ic, &ev->xkey, wbuf, sizeof(wbuf) / sizeof(wbuf[0]),
1313 &symbol, NULL((void*)0));
1314
1315 if ((ev->xkey.state & (AllMods((1<<0)|(1<<1)|(1<<2)| (1<<3)|(1<<
4)|(1<<5)|(1<<6)|(1<<7))
& ~(ShiftMask(1<<0)|LockMask(1<<1)|NumLockMask(d)))) ||
1316 ((symbol >> 8 == 0xFF) &&
1317 ((XK_BackSpace0xff08 <= symbol && symbol <= XK_Clear0xff0b) ||
1318 (symbol == XK_Return0xff0d) ||
1319 (symbol == XK_Pause0xff13) ||
1320 (symbol == XK_Scroll_Lock0xff14) ||
1321 (symbol == XK_Sys_Req0xff15) ||
1322 (symbol == XK_Escape0xff1b) ||
1323 (symbol == XK_Delete0xffff) ||
1324 IsCursorKey(symbol)(((KeySym)(symbol) >= 0xff50) && ((KeySym)(symbol)
< 0xff60))
||
1325 IsKeypadKey(symbol)(((KeySym)(symbol) >= 0xff80) && ((KeySym)(symbol)
<= 0xffbd))
||
1326 IsMiscFunctionKey(symbol)(((KeySym)(symbol) >= 0xff60) && ((KeySym)(symbol)
<= 0xff6b))
||
1327 IsFunctionKey(symbol)(((KeySym)(symbol) >= 0xffbe) && ((KeySym)(symbol)
<= 0xffe0))
)))
1328 {
1329 IC_ClearPreviousChar(ic)((ic)->private.local.base.mb[(ic)->private.local.base.tree
[(ic)->private.local.context].mb] = 0)
;
1330 return False0;
1331 }
1332 if (((symbol >> 8 == 0xFF) &&
1333 IsModifierKey(symbol)((((KeySym)(symbol) >= 0xffe1) && ((KeySym)(symbol
) <= 0xffee)) || (((KeySym)(symbol) >= 0xfe01) &&
((KeySym)(symbol) <= 0xfe13)) || ((KeySym)(symbol) == 0xff7e
) || ((KeySym)(symbol) == 0xff7f))
) ||
1334#ifdef XK_XKB_KEYS
1335 ((symbol >> 8 == 0xFE) &&
1336 (XK_ISO_Lock0xfe01 <= symbol && symbol <= XK_ISO_Last_Group_Lock0xfe0f)) ||
1337#endif
1338 (symbol == NoSymbol0L))
1339 {
1340 return False0;
1341 }
1342#ifdef UNUSED
1343 if (! XThaiTranslateKey(ev->xkey.display, ev->xkey.keycode, ev->xkey.state,
1344 &modifiers, &symbol, &lsym, &usym))
1345 return False0;
1346
1347 /*
1348 * Hex input method processing
1349 */
1350
1351 thai_part = &ic->private.local.thai;
1352 state = thai_part->comp_state;
1353 if (state >= 0 && state < nstate_handlers) /* call handler for state */
1354 {
1355 symbol = (* state_handler[state])(thai_part, symbol, (XKeyEvent *)ev);
1356 }
1357
1358 /*
1359 * Translate KeySym into mb.
1360 */
1361 count = XThaiTranslateKeySym(ev->xkey.display, symbol, lsym,
1362 usym, ev->xkey.state, buf, 10);
1363
1364 if (!symbol && !count)
1365 return True1;
1366
1367 /* Return symbol if cannot convert to character */
1368 if (!count)
1369 return False0;
1370#endif
1371
1372 /*
1373 * Thai Input sequence check
1374 */
1375 isc_mode = IC_IscMode(ic)((ic)->private.local.thai.input_mode);
1376 if (!(previous_char = IC_GetPreviousChar(ic)(IC_RealGetPreviousChar(ic,1)))) previous_char = ' ';
1377 new_char = ucs2tis(wbuf[0])(unsigned char) ( (0<=(wbuf[0])&&(wbuf[0])<=0x7F
) ? (wbuf[0]) : ((0x0E01<=(wbuf[0])&&(wbuf[0])<=
0x0E5F) ? ((wbuf[0])-0x0E00 +0xA0) : 0))
;
1378 isReject = True1;
1379 if (THAI_isaccepted(new_char, previous_char, isc_mode)) {
1380 ThaiFltAcceptInput(ic, new_char, symbol);
1381 isReject = False0;
1382 } else {
1383 unsigned char context_char;
1384
1385 context_char = IC_GetContextChar(ic)(IC_RealGetPreviousChar(ic,2));
1386 if (context_char) {
1387 if (THAI_iscomposible(new_char, context_char)) {
1388 if (THAI_iscomposible(previous_char, new_char)) {
1389 isReject = !ThaiFltReorderInput(ic, previous_char, new_char);
1390 } else if (THAI_iscomposible(previous_char, context_char)) {
1391 isReject = !ThaiFltReplaceInput(ic, new_char, symbol);
1392 } else if (THAI_chtype(previous_char) == FV14
1393 && THAI_chtype(new_char) == TONE10) {
1394 isReject = !ThaiFltReorderInput(ic, previous_char, new_char);
1395 }
1396 } else if (THAI_isaccepted(new_char, context_char, isc_mode)) {
1397 isReject = !ThaiFltReplaceInput(ic, new_char, symbol);
1398 }
1399 }
1400 }
1401 if (isReject) {
1402 /* reject character */
1403 XBell(ev->xkey.display, BellVolume0);
1404 return True1;
1405 }
1406
1407 _Xlcwcstombs(ic->core.im->core.lcd, &b->mb[b->tree[ic->private.local.composed].mb],
1408 &b->wc[b->tree[ic->private.local.composed].wc], 10);
1409
1410 _Xlcmbstoutf8(ic->core.im->core.lcd, &b->utf8[b->tree[ic->private.local.composed].utf8],
1411 &b->mb[b->tree[ic->private.local.composed].mb], 10);
1412
1413 /* Remember the last character inputted
1414 * (as fallback in case StringConversionCallback is not provided)
1415 */
1416 IC_SavePreviousChar(ic, new_char)((ic)->private.local.base.mb[(ic)->private.local.base.tree
[(ic)->private.local.context].mb] = (char) (new_char))
;
1417
1418 ev->xkey.keycode = 0;
1419 XPutBackEvent(d, ev);
1420 return True1;
1421}