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