imThaiFlt.c revision 61b2299d
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 if (screc.text->encoding_is_wchar) { 564 c = ucs2tis(screc.text->string.wcs[0]); 565 XFree(screc.text->string.wcs); 566 } else { 567 c = screc.text->string.mbs[0]; 568 XFree(screc.text->string.mbs); 569 } 570 } 571 XFree(screc.text); 572 return c; 573 } else { 574 return (unsigned char) b->mb[b->tree[(ic)->private.local.context].mb]; 575 } 576} 577 578Private unsigned char 579IC_RealDeletePreviousChar(Xic ic) 580{ 581 XICCallback* cb = &ic->core.string_conversion_callback; 582 583 if (cb && cb->callback) { 584 XIMStringConversionCallbackStruct screc; 585 unsigned char c; 586 587 screc.position = 0; 588 screc.direction = XIMBackwardChar; 589 screc.operation = XIMStringConversionSubstitution; 590 screc.factor = 1; 591 screc.text = 0; 592 593 (cb->callback)((XIC)ic, cb->client_data, (XPointer)&screc); 594 if (!screc.text) { return 0; } 595 if ((screc.text->feedback && 596 *screc.text->feedback == XIMStringConversionLeftEdge) || 597 screc.text->length < 1) 598 { 599 c = 0; 600 } else { 601 if (screc.text->encoding_is_wchar) { 602 c = ucs2tis(screc.text->string.wcs[0]); 603 XFree(screc.text->string.wcs); 604 } else { 605 c = screc.text->string.mbs[0]; 606 XFree(screc.text->string.mbs); 607 } 608 } 609 XFree(screc.text); 610 return c; 611 } else { 612 return 0; 613 } 614} 615/* 616 * Input sequence check mode in XIC 617 */ 618#define IC_IscMode(ic) ((ic)->private.local.thai.input_mode) 619 620/* 621 * Max. size of string handled by the two String Lookup functions. 622 */ 623#define STR_LKUP_BUF_SIZE 256 624 625/* 626 * Size of buffer to contain previous locale name. 627 */ 628#define SAV_LOCALE_NAME_SIZE 256 629 630/* 631 * Size of buffer to contain the IM modifier. 632 */ 633#define MAXTHAIIMMODLEN 20 634 635#define AllMods (ShiftMask|LockMask|ControlMask| \ 636 Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask) 637 638 639#define IsISOControlKey(ks) ((ks) >= XK_2 && (ks) <= XK_8) 640 641#define IsValidControlKey(ks) (((((ks)>=XK_A && (ks)<=XK_asciitilde) || \ 642 (ks)==XK_space || (ks)==XK_Delete) && \ 643 ((ks)!=0))) 644 645#define COMPOSE_LED 2 646 647#ifdef UNUSED 648typedef KeySym (*StateProc)( 649 XicThaiPart *thai_part, 650 KeySym symbol, 651 XKeyEvent *event); 652 653 654/* 655 * macros to classify XKeyEvent state field 656 */ 657 658#define IsShift(state) (((state) & ShiftMask) != 0) 659#define IsLock(state) (((state) & LockMask) != 0) 660#define IsControl(state) (((state) & ControlMask) != 0) 661#define IsMod1(state) (((state) & Mod1Mask) != 0) 662#define IsMod2(state) (((state) & Mod2Mask) != 0) 663#define IsMod3(state) (((state) & Mod3Mask) != 0) 664#define IsMod4(state) (((state) & Mod4Mask) != 0) 665#define IsMod5(state) (((state) & Mod5Mask) != 0) 666 667/* 668 * key starts Thai compose sequence (Hex input method) if : 669 */ 670 671#define IsComposeKey(ks, event) \ 672 (( ks==XK_Alt_L && \ 673 IsControl((event)->state) && \ 674 !IsShift((event)->state)) \ 675 ? True : False) 676 677 678/* 679 * State handler to implement the Thai hex input method. 680 */ 681 682Private int const nstate_handlers = 3; 683Private StateProc state_handler[] = { 684 HexIMNormalKey, 685 HexIMFirstComposeKey, 686 HexIMSecondComposeKey 687}; 688 689 690/* 691 * Table for 'Thai Compose' character input. 692 * The current implementation uses latin-1 keysyms. 693 */ 694struct _XMapThaiKey { 695 KeySym from; 696 KeySym to; 697}; 698 699Private struct _XMapThaiKey const ThaiComposeTable[] = { 700 { /* 0xa4 */ XK_currency, /* 0xa5 */ XK_yen }, 701 { /* 0xa2 */ XK_cent, /* 0xa3 */ XK_sterling }, 702 { /* 0xe6 */ XK_ae, /* 0xef */ XK_idiaeresis }, 703 { /* 0xd3 */ XK_Oacute, /* 0xee */ XK_icircumflex }, 704 { /* 0xb9 */ XK_onesuperior, /* 0xfa */ XK_uacute }, 705 { /* 0xd2 */ XK_Ograve, /* 0xe5 */ XK_aring }, 706 { /* 0xbc */ XK_onequarter, /* 0xfb */ XK_ucircumflex }, 707 { XK_VoidSymbol, XK_VoidSymbol } 708}; 709 710struct _XKeytrans { 711 struct _XKeytrans *next;/* next on list */ 712 char *string; /* string to return when the time comes */ 713 int len; /* length of string (since NULL is legit)*/ 714 KeySym key; /* keysym rebound */ 715 unsigned int state; /* modifier state */ 716 KeySym *modifiers; /* modifier keysyms you want */ 717 int mlen; /* length of modifier list */ 718}; 719 720 721/* Convert keysym to 'Thai Compose' keysym */ 722/* The current implementation use latin-1 keysyms */ 723Private Bool 724ThaiComposeConvert( 725 Display *dpy, 726 KeySym insym, 727 KeySym *outsym, KeySym *lower, KeySym *upper) 728{ 729 struct _XMapThaiKey const *table_entry = ThaiComposeTable; 730 731 while (table_entry->from != XK_VoidSymbol) { 732 if (table_entry->from == insym) { 733 *outsym = table_entry->to; 734 *lower = *outsym; 735 *upper = *outsym; 736 return True; 737 } 738 table_entry++; 739 } 740 return False; 741} 742 743Private int 744XThaiTranslateKey( 745 register Display *dpy, 746 KeyCode keycode, 747 register unsigned int modifiers, 748 unsigned int *modifiers_return, 749 KeySym *keysym_return, 750 KeySym *lsym_return, 751 KeySym *usym_return) 752{ 753 int per; 754 register KeySym *syms; 755 KeySym sym = 0, lsym = 0, usym = 0; 756 757 if ((! dpy->keysyms) && (! _XKeyInitialize(dpy))) 758 return 0; 759 *modifiers_return = (ShiftMask|LockMask) | dpy->mode_switch; 760 if (((int)keycode < dpy->min_keycode) || ((int)keycode > dpy->max_keycode)) 761 { 762 *keysym_return = NoSymbol; 763 return 1; 764 } 765 per = dpy->keysyms_per_keycode; 766 syms = &dpy->keysyms[(keycode - dpy->min_keycode) * per]; 767 while ((per > 2) && (syms[per - 1] == NoSymbol)) 768 per--; 769 if ((per > 2) && (modifiers & dpy->mode_switch)) { 770 syms += 2; 771 per -= 2; 772 } 773 if (!(modifiers & ShiftMask) && 774 (!(modifiers & LockMask) || (dpy->lock_meaning == NoSymbol))) { 775 if ((per == 1) || (syms[1] == NoSymbol)) 776 XConvertCase(syms[0], keysym_return, &usym); 777 else { 778 XConvertCase(syms[0], &lsym, &usym); 779 *keysym_return = syms[0]; 780 } 781 } else if (!(modifiers & LockMask) || 782 (dpy->lock_meaning != XK_Caps_Lock)) { 783 if ((per == 1) || ((usym = syms[1]) == NoSymbol)) 784 XConvertCase(syms[0], &lsym, &usym); 785 *keysym_return = usym; 786 } else { 787 if ((per == 1) || ((sym = syms[1]) == NoSymbol)) 788 sym = syms[0]; 789 XConvertCase(sym, &lsym, &usym); 790 if (!(modifiers & ShiftMask) && (sym != syms[0]) && 791 ((sym != usym) || (lsym == usym))) 792 XConvertCase(syms[0], &lsym, &usym); 793 *keysym_return = usym; 794 } 795 /* 796 * ThaiCat keyboard support : 797 * When the Shift and Thai keys are hold for some keys a 'Thai Compose' 798 * character code is generated which is different from column 3 and 799 * 4 of the keymap. 800 * Since we don't know whether ThaiCat keyboard or WTT keyboard is 801 * in use, the same mapping is done for all Thai input. 802 * We just arbitary choose to use column 3 keysyms as the indices of 803 * this mapping. 804 * When the control key is also hold, this mapping has no effect. 805 */ 806 if ((modifiers & Mod1Mask) && 807 (modifiers & ShiftMask) && 808 !(modifiers & ControlMask)) { 809 if (ThaiComposeConvert(dpy, syms[0], &sym, &lsym, &usym)) 810 *keysym_return = sym; 811 } 812 813 if (*keysym_return == XK_VoidSymbol) 814 *keysym_return = NoSymbol; 815 *lsym_return = lsym; 816 *usym_return = usym; 817 return 1; 818} 819 820/* 821 * XThaiTranslateKeySym 822 * 823 * Translate KeySym to TACTIS code output. 824 * The current implementation uses ISO latin-1 keysym. 825 * Should be changed to TACTIS keysyms when they are defined by the 826 * standard. 827 */ 828Private int 829XThaiTranslateKeySym( 830 Display *dpy, 831 register KeySym symbol, 832 register KeySym lsym, 833 register KeySym usym, 834 unsigned int modifiers, 835 unsigned char *buffer, 836 int nbytes) 837{ 838 KeySym ckey = 0; 839 register struct _XKeytrans *p; 840 int length; 841 unsigned long hiBytes; 842 register unsigned char c; 843 844 /* 845 * initialize length = 1 ; 846 */ 847 length = 1; 848 849 if (!symbol) 850 return 0; 851 /* see if symbol rebound, if so, return that string. */ 852 for (p = dpy->key_bindings; p; p = p->next) { 853 if (((modifiers & AllMods) == p->state) && (symbol == p->key)) { 854 length = p->len; 855 if (length > nbytes) length = nbytes; 856 memcpy (buffer, p->string, length); 857 return length; 858 } 859 } 860 /* try to convert to TACTIS, handling control */ 861 hiBytes = symbol >> 8; 862 if (!(nbytes && 863 ((hiBytes == 0) || 864 ((hiBytes == 0xFF) && 865 (((symbol >= XK_BackSpace) && (symbol <= XK_Clear)) || 866 (symbol == XK_Return) || 867 (symbol == XK_Escape) || 868 (symbol == XK_KP_Space) || 869 (symbol == XK_KP_Tab) || 870 (symbol == XK_KP_Enter) || 871 ((symbol >= XK_KP_Multiply) && (symbol <= XK_KP_9)) || 872 (symbol == XK_KP_Equal) || 873 (symbol == XK_Scroll_Lock) || 874#ifdef DXK_PRIVATE /* DEC private keysyms */ 875 (symbol == DXK_Remove) || 876#endif 877 (symbol == NoSymbol) || 878 (symbol == XK_Delete)))))) 879 return 0; 880 881 /* if X keysym, convert to ascii by grabbing low 7 bits */ 882 if (symbol == XK_KP_Space) 883 c = XK_space & 0x7F; /* patch encoding botch */ 884/* not for Thai 885 else if (symbol == XK_hyphen) 886 c = XK_minus & 0xFF; */ /* map to equiv character */ 887 else if (hiBytes == 0xFF) 888 c = symbol & 0x7F; 889 else 890 c = symbol & 0xFF; 891 /* only apply Control key if it makes sense, else ignore it */ 892 if (modifiers & ControlMask) { 893 if (!(IsKeypadKey(lsym) || lsym==XK_Return || lsym==XK_Tab)) { 894 if (IsISOControlKey(lsym)) ckey = lsym; 895 else if (IsISOControlKey(usym)) ckey = usym; 896 else if (lsym == XK_question) ckey = lsym; 897 else if (usym == XK_question) ckey = usym; 898 else if (IsValidControlKey(lsym)) ckey = lsym; 899 else if (IsValidControlKey(usym)) ckey = usym; 900 else length = 0; 901 902 if (length != 0) { 903 if (ckey == XK_2) c = '\000'; 904 else if (ckey >= XK_3 && ckey <= XK_7) 905 c = (char)(ckey-('3'-'\033')); 906 else if (ckey == XK_8) c = '\177'; 907 else if (ckey == XK_Delete) c = '\030'; 908 else if (ckey == XK_question) c = '\037'; 909 else if (ckey == XK_quoteleft) c = '\036'; /* KLee 1/24/91 */ 910 else c = (char)(ckey & 0x1f); 911 } 912 } 913 } 914 /* 915 * ThaiCat has a key that generates two TACTIS codes D1 & E9. 916 * It is represented by the latin-1 keysym XK_thorn (0xfe). 917 * If c is XK_thorn, this key is pressed and it is converted to 918 * 0xd1 0xe9. 919 */ 920 if (c == XK_thorn) { 921 buffer[0] = 0xd1; 922 buffer[1] = 0xe9; 923 buffer[2] = '\0'; 924 return 2; 925 } 926 else { 927 /* Normal case */ 928 buffer[0] = c; 929 buffer[1] = '\0'; 930 return 1; 931 } 932} 933 934/* 935 * given a KeySym, returns the first keycode containing it, if any. 936 */ 937Private CARD8 938FindKeyCode( 939 register Display *dpy, 940 register KeySym code) 941{ 942 943 register KeySym *kmax = dpy->keysyms + 944 (dpy->max_keycode - dpy->min_keycode + 1) * dpy->keysyms_per_keycode; 945 register KeySym *k = dpy->keysyms; 946 while (k < kmax) { 947 if (*k == code) 948 return (((k - dpy->keysyms) / dpy->keysyms_per_keycode) + 949 dpy->min_keycode); 950 k += 1; 951 } 952 return 0; 953} 954 955/* 956 * given a list of modifiers, computes the mask necessary for later matching. 957 * This routine must lookup the key in the Keymap and then search to see 958 * what modifier it is bound to, if any. Sets the AnyModifier bit if it 959 * can't map some keysym to a modifier. 960 */ 961Private void 962ComputeMaskFromKeytrans( 963 Display *dpy, 964 register struct _XKeytrans *p) 965{ 966 register int i; 967 register CARD8 code; 968 register XModifierKeymap *m = dpy->modifiermap; 969 970 p->state = AnyModifier; 971 for (i = 0; i < p->mlen; i++) { 972 /* if not found, then not on current keyboard */ 973 if ((code = FindKeyCode(dpy, p->modifiers[i])) == 0) 974 return; 975 /* code is now the keycode for the modifier you want */ 976 { 977 register int j = m->max_keypermod<<3; 978 979 while ((--j >= 0) && (code != m->modifiermap[j])) 980 ; 981 if (j < 0) 982 return; 983 p->state |= (1<<(j/m->max_keypermod)); 984 } 985 } 986 p->state &= AllMods; 987} 988 989/************************************************************************ 990 * 991 * 992 * Compose handling routines - compose handlers 0,1,2 993 * 994 * 995 ************************************************************************/ 996 997#define NORMAL_KEY_STATE 0 998#define FIRST_COMPOSE_KEY_STATE 1 999#define SECOND_COMPOSE_KEY_STATE 2 1000 1001Private 1002KeySym HexIMNormalKey( 1003 XicThaiPart *thai_part, 1004 KeySym symbol, 1005 XKeyEvent *event) 1006{ 1007 if (IsComposeKey (symbol, event)) /* start compose sequence */ 1008 { 1009 SetLed (event->display,COMPOSE_LED, LedModeOn); 1010 thai_part->comp_state = FIRST_COMPOSE_KEY_STATE; 1011 return NoSymbol; 1012 } 1013 return symbol; 1014} 1015 1016 1017Private 1018KeySym HexIMFirstComposeKey( 1019 XicThaiPart *thai_part, 1020 KeySym symbol, 1021 XKeyEvent *event) 1022{ 1023 if (IsModifierKey (symbol)) return symbol; /* ignore shift etc. */ 1024 if (IsCancelComposeKey (&symbol, event)) /* cancel sequence */ 1025 { 1026 SetLed (event->display,COMPOSE_LED, LedModeOff); 1027 thai_part->comp_state = NORMAL_KEY_STATE; 1028 return symbol; 1029 } 1030 if (IsComposeKey (symbol, event)) /* restart sequence ?? */ 1031 { 1032 return NoSymbol; /* no state change necessary */ 1033 } 1034 1035 thai_part->keysym = symbol; /* save key pressed */ 1036 thai_part->comp_state = SECOND_COMPOSE_KEY_STATE; 1037 return NoSymbol; 1038} 1039 1040Private 1041KeySym HexIMSecondComposeKey( 1042 XicThaiPart *thai_part, 1043 KeySym symbol, 1044 XKeyEvent *event) 1045{ 1046 if (IsModifierKey (symbol)) return symbol; /* ignore shift etc. */ 1047 if (IsComposeKey (symbol, event)) /* restart sequence ? */ 1048 { 1049 thai_part->comp_state =FIRST_COMPOSE_KEY_STATE; 1050 return NoSymbol; 1051 } 1052 SetLed (event->display,COMPOSE_LED, LedModeOff); 1053 if (IsCancelComposeKey (&symbol, event)) /* cancel sequence ? */ 1054 { 1055 thai_part->comp_state = NORMAL_KEY_STATE; 1056 return symbol; 1057 } 1058 1059 if ((symbol = HexIMComposeSequence (thai_part->keysym, symbol)) 1060 ==NoSymbol) 1061 { /* invalid compose sequence */ 1062 XBell(event->display, BellVolume); 1063 } 1064 thai_part->comp_state = NORMAL_KEY_STATE; /* reset to normal state */ 1065 return symbol; 1066} 1067 1068 1069/* 1070 * Interprets two keysyms entered as hex digits and return the Thai keysym 1071 * correspond to the TACTIS code formed. 1072 * The current implementation of this routine returns ISO Latin Keysyms. 1073 */ 1074 1075Private 1076KeySym HexIMComposeSequence(KeySym ks1, KeySym ks2) 1077{ 1078int hi_digit; 1079int lo_digit; 1080int tactis_code; 1081 1082 if ((ks1 >= XK_0) && (ks1 <= XK_9)) 1083 hi_digit = ks1 - XK_0; 1084 else if ((ks1 >= XK_A) && (ks1 <= XK_F)) 1085 hi_digit = ks1 - XK_A + 10; 1086 else if ((ks1 >= XK_a) && (ks1 <= XK_f)) 1087 hi_digit = ks1 - XK_a + 10; 1088 else /* out of range */ 1089 return NoSymbol; 1090 1091 if ((ks2 >= XK_0) && (ks2 <= XK_9)) 1092 lo_digit = ks2 - XK_0; 1093 else if ((ks2 >= XK_A) && (ks2 <= XK_F)) 1094 lo_digit = ks2 - XK_A + 10; 1095 else if ((ks2 >= XK_a) && (ks2 <= XK_f)) 1096 lo_digit = ks2 - XK_a + 10; 1097 else /* out of range */ 1098 return NoSymbol; 1099 1100 tactis_code = hi_digit * 0x10 + lo_digit ; 1101 1102 return (KeySym)tactis_code; 1103 1104} 1105 1106/* 1107 * routine determines 1108 * 1) whether key event should cancel a compose sequence 1109 * 2) whether cancelling key event should be processed or ignored 1110 */ 1111 1112Private 1113int IsCancelComposeKey( 1114 KeySym *symbol, 1115 XKeyEvent *event) 1116{ 1117 if (*symbol==XK_Delete && !IsControl(event->state) && 1118 !IsMod1(event->state)) { 1119 *symbol=NoSymbol; /* cancel compose sequence, and ignore key */ 1120 return True; 1121 } 1122 if (IsComposeKey(*symbol, event)) return False; 1123 return ( 1124 IsControl (event->state) || 1125 IsMod1(event->state) || 1126 IsKeypadKey (*symbol) || 1127 IsFunctionKey (*symbol) || 1128 IsMiscFunctionKey (*symbol) || 1129#ifdef DXK_PRIVATE /* DEC private keysyms */ 1130 *symbol == DXK_Remove || 1131#endif 1132 IsPFKey (*symbol) || 1133 IsCursorKey (*symbol) || 1134 (*symbol >= XK_Tab && *symbol < XK_Multi_key) 1135 ? True : False); /* cancel compose sequence and pass */ 1136 /* cancelling key through */ 1137} 1138 1139 1140/* 1141 * set specified keyboard LED on or off 1142 */ 1143 1144Private 1145void SetLed( 1146 Display *dpy, 1147 int num, 1148 int state) 1149{ 1150 XKeyboardControl led_control; 1151 1152 led_control.led_mode = state; 1153 led_control.led = num; 1154 XChangeKeyboardControl (dpy, KBLed | KBLedMode, &led_control); 1155} 1156#endif 1157 1158/* 1159 * Initialize ISC mode from im modifier 1160 */ 1161Private void InitIscMode(Xic ic) 1162{ 1163 Xim im; 1164 char *im_modifier_name; 1165 1166 /* If already defined, just return */ 1167 1168 if (IC_IscMode(ic)) return; 1169 1170 /* Get IM modifier */ 1171 1172 im = (Xim) XIMOfIC((XIC)ic); 1173 im_modifier_name = im->core.im_name; 1174 1175 /* Match with predefined value, default is Basic Check */ 1176 1177 if (!strncmp(im_modifier_name,"BasicCheck",MAXTHAIIMMODLEN+1)) 1178 IC_IscMode(ic) = WTT_ISC1; 1179 else if (!strncmp(im_modifier_name,"Strict",MAXTHAIIMMODLEN+1)) 1180 IC_IscMode(ic) = WTT_ISC2; 1181 else if (!strncmp(im_modifier_name,"Thaicat",MAXTHAIIMMODLEN+1)) 1182 IC_IscMode(ic) = THAICAT_ISC; 1183 else if (!strncmp(im_modifier_name,"Passthrough",MAXTHAIIMMODLEN+1)) 1184 IC_IscMode(ic) = NOISC; 1185 else 1186 IC_IscMode(ic) = WTT_ISC1; 1187 1188 return; 1189} 1190 1191/* 1192 * Helper functions for _XimThaiFilter() 1193 */ 1194Private Bool 1195ThaiFltAcceptInput(Xic ic, unsigned char new_char, KeySym symbol) 1196{ 1197 DefTreeBase *b = &ic->private.local.base; 1198 b->wc[b->tree[ic->private.local.composed].wc+0] = tis2ucs(new_char); 1199 b->wc[b->tree[ic->private.local.composed].wc+1] = '\0'; 1200 1201 if ((new_char <= 0x1f) || (new_char == 0x7f)) 1202 b->tree[ic->private.local.composed].keysym = symbol; 1203 else 1204 b->tree[ic->private.local.composed].keysym = NoSymbol; 1205 1206 return True; 1207} 1208 1209Private Bool 1210ThaiFltReorderInput(Xic ic, unsigned char previous_char, unsigned char new_char) 1211{ 1212 DefTreeBase *b = &ic->private.local.base; 1213 if (!IC_DeletePreviousChar(ic)) return False; 1214 b->wc[b->tree[ic->private.local.composed].wc+0] = tis2ucs(new_char); 1215 b->wc[b->tree[ic->private.local.composed].wc+1] = tis2ucs(previous_char); 1216 b->wc[b->tree[ic->private.local.composed].wc+2] = '\0'; 1217 1218 b->tree[ic->private.local.composed].keysym = NoSymbol; 1219 1220 return True; 1221} 1222 1223Private Bool 1224ThaiFltReplaceInput(Xic ic, unsigned char new_char, KeySym symbol) 1225{ 1226 DefTreeBase *b = &ic->private.local.base; 1227 if (!IC_DeletePreviousChar(ic)) return False; 1228 b->wc[b->tree[ic->private.local.composed].wc+0] = tis2ucs(new_char); 1229 b->wc[b->tree[ic->private.local.composed].wc+1] = '\0'; 1230 1231 if ((new_char <= 0x1f) || (new_char == 0x7f)) 1232 b->tree[ic->private.local.composed].keysym = symbol; 1233 else 1234 b->tree[ic->private.local.composed].keysym = NoSymbol; 1235 1236 return True; 1237} 1238 1239/* 1240 * Filter function for TACTIS 1241 */ 1242Bool 1243_XimThaiFilter(Display *d, Window w, XEvent *ev, XPointer client_data) 1244{ 1245 Xic ic = (Xic)client_data; 1246 KeySym symbol; 1247 int isc_mode; /* Thai Input Sequence Check mode */ 1248 unsigned char previous_char; /* Last inputted Thai char */ 1249 unsigned char new_char; 1250#ifdef UNUSED 1251 unsigned int modifiers; 1252 KeySym lsym,usym; 1253 int state; 1254 XicThaiPart *thai_part; 1255 char buf[10]; 1256#endif 1257 wchar_t wbuf[10]; 1258 Bool isReject; 1259 DefTreeBase *b = &ic->private.local.base; 1260 1261 if ((ev->type != KeyPress) 1262 || (ev->xkey.keycode == 0)) 1263 return False; 1264 1265 if (!IC_IscMode(ic)) InitIscMode(ic); 1266 1267 XwcLookupString((XIC)ic, &ev->xkey, wbuf, sizeof(wbuf) / sizeof(wbuf[0]), 1268 &symbol, NULL); 1269 1270 if ((ev->xkey.state & (AllMods & ~ShiftMask)) || 1271 ((symbol >> 8 == 0xFF) && 1272 ((XK_BackSpace <= symbol && symbol <= XK_Clear) || 1273 (symbol == XK_Return) || 1274 (symbol == XK_Pause) || 1275 (symbol == XK_Scroll_Lock) || 1276 (symbol == XK_Sys_Req) || 1277 (symbol == XK_Escape) || 1278 (symbol == XK_Delete) || 1279 IsCursorKey(symbol) || 1280 IsKeypadKey(symbol) || 1281 IsMiscFunctionKey(symbol) || 1282 IsFunctionKey(symbol)))) 1283 { 1284 IC_ClearPreviousChar(ic); 1285 return False; 1286 } 1287 if (((symbol >> 8 == 0xFF) && 1288 IsModifierKey(symbol)) || 1289#ifdef XK_XKB_KEYS 1290 ((symbol >> 8 == 0xFE) && 1291 (XK_ISO_Lock <= symbol && symbol <= XK_ISO_Last_Group_Lock)) || 1292#endif 1293 (symbol == NoSymbol)) 1294 { 1295 return False; 1296 } 1297#ifdef UNUSED 1298 if (! XThaiTranslateKey(ev->xkey.display, ev->xkey.keycode, ev->xkey.state, 1299 &modifiers, &symbol, &lsym, &usym)) 1300 return False; 1301 1302 /* 1303 * Hex input method processing 1304 */ 1305 1306 thai_part = &ic->private.local.thai; 1307 state = thai_part->comp_state; 1308 if (state >= 0 && state < nstate_handlers) /* call handler for state */ 1309 { 1310 symbol = (* state_handler[state])(thai_part, symbol, (XKeyEvent *)ev); 1311 } 1312 1313 /* 1314 * Translate KeySym into mb. 1315 */ 1316 count = XThaiTranslateKeySym(ev->xkey.display, symbol, lsym, 1317 usym, ev->xkey.state, buf, 10); 1318 1319 if (!symbol && !count) 1320 return True; 1321 1322 /* Return symbol if cannot convert to character */ 1323 if (!count) 1324 return False; 1325#endif 1326 1327 /* 1328 * Thai Input sequence check 1329 */ 1330 isc_mode = IC_IscMode(ic); 1331 if (!(previous_char = IC_GetPreviousChar(ic))) previous_char = ' '; 1332 new_char = ucs2tis(wbuf[0]); 1333 isReject = True; 1334 if (THAI_isaccepted(new_char, previous_char, isc_mode)) { 1335 ThaiFltAcceptInput(ic, new_char, symbol); 1336 isReject = False; 1337 } else { 1338 unsigned char context_char; 1339 1340 context_char = IC_GetContextChar(ic); 1341 if (context_char) { 1342 if (THAI_iscomposible(new_char, context_char)) { 1343 if (THAI_iscomposible(previous_char, new_char)) { 1344 isReject = !ThaiFltReorderInput(ic, previous_char, new_char); 1345 } else if (THAI_iscomposible(previous_char, context_char)) { 1346 isReject = !ThaiFltReplaceInput(ic, new_char, symbol); 1347 } else if (THAI_chtype(previous_char) == FV1 1348 && THAI_chtype(new_char) == TONE) { 1349 isReject = !ThaiFltReorderInput(ic, previous_char, new_char); 1350 } 1351 } else if (THAI_isaccepted(new_char, context_char, isc_mode)) { 1352 isReject = !ThaiFltReplaceInput(ic, new_char, symbol); 1353 } 1354 } 1355 } 1356 if (isReject) { 1357 /* reject character */ 1358 XBell(ev->xkey.display, BellVolume); 1359 return True; 1360 } 1361 1362 _Xlcwcstombs(ic->core.im->core.lcd, &b->mb[b->tree[ic->private.local.composed].mb], 1363 &b->wc[b->tree[ic->private.local.composed].wc], 10); 1364 1365 _Xlcmbstoutf8(ic->core.im->core.lcd, &b->utf8[b->tree[ic->private.local.composed].utf8], 1366 &b->mb[b->tree[ic->private.local.composed].mb], 10); 1367 1368 /* Remember the last character inputted 1369 * (as fallback in case StringConversionCallback is not provided) 1370 */ 1371 IC_SavePreviousChar(ic, new_char); 1372 1373 ev->xkey.keycode = 0; 1374 XPutBackEvent(d, ev); 1375 return True; 1376} 1377