imThaiFlt.c revision 61b2299d
11ab64890Smrg/* $Xorg: imThaiFlt.c,v 1.5 2001/02/09 02:03:39 xorgcvs Exp $ */
21ab64890Smrg/***********************************************************
31ab64890Smrg
41ab64890SmrgCopyright 1993, 1998  The Open Group
51ab64890Smrg
61ab64890SmrgPermission to use, copy, modify, distribute, and sell this software and its
71ab64890Smrgdocumentation for any purpose is hereby granted without fee, provided that
81ab64890Smrgthe above copyright notice appear in all copies and that both that
91ab64890Smrgcopyright notice and this permission notice appear in supporting
101ab64890Smrgdocumentation.
111ab64890Smrg
121ab64890SmrgThe above copyright notice and this permission notice shall be included in
131ab64890Smrgall copies or substantial portions of the Software.
141ab64890Smrg
151ab64890SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
161ab64890SmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
171ab64890SmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
181ab64890SmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
191ab64890SmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
201ab64890SmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
211ab64890Smrg
221ab64890SmrgExcept as contained in this notice, the name of The Open Group shall not be
231ab64890Smrgused in advertising or otherwise to promote the sale, use or other dealings
241ab64890Smrgin this Software without prior written authorization from The Open Group.
251ab64890Smrg
261ab64890Smrg
271ab64890SmrgCopyright 1993 by Digital Equipment Corporation, Maynard, Massachusetts.
281ab64890Smrg
291ab64890Smrg                        All Rights Reserved
301ab64890Smrg
3161b2299dSmrgPermission to use, copy, modify, and distribute this software and its
3261b2299dSmrgdocumentation for any purpose and without fee is hereby granted,
331ab64890Smrgprovided that the above copyright notice appear in all copies and that
3461b2299dSmrgboth that copyright notice and this permission notice appear in
351ab64890Smrgsupporting documentation, and that the name of Digital not be
361ab64890Smrgused in advertising or publicity pertaining to distribution of the
3761b2299dSmrgsoftware without specific, written prior permission.
381ab64890Smrg
391ab64890SmrgDIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
401ab64890SmrgALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
411ab64890SmrgDIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
421ab64890SmrgANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
431ab64890SmrgWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
441ab64890SmrgARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
451ab64890SmrgSOFTWARE.
461ab64890Smrg
471ab64890Smrg******************************************************************/
481ab64890Smrg/* $XFree86: xc/lib/X11/imThaiFlt.c,v 3.22tsi Exp $ */
491ab64890Smrg
501ab64890Smrg/*
5161b2299dSmrg**++
5261b2299dSmrg**  FACILITY:
5361b2299dSmrg**
5461b2299dSmrg**      Xlib
5561b2299dSmrg**
5661b2299dSmrg**  ABSTRACT:
5761b2299dSmrg**
581ab64890Smrg**	Thai specific functions.
591ab64890Smrg**	Handles character classifications, composibility checking,
601ab64890Smrg**	Input sequence check and other Thai specific requirements
611ab64890Smrg**	according to WTT specification and DEC extensions.
6261b2299dSmrg**
6361b2299dSmrg**  MODIFICATION HISTORY:
6461b2299dSmrg**
651ab64890Smrg**/
661ab64890Smrg
671ab64890Smrg#ifdef HAVE_CONFIG_H
681ab64890Smrg#include <config.h>
691ab64890Smrg#endif
701ab64890Smrg#include <stdio.h>
711ab64890Smrg#include <X11/Xlib.h>
721ab64890Smrg#include <X11/Xmd.h>
731ab64890Smrg#include <X11/keysym.h>
741ab64890Smrg#include <X11/Xutil.h>
751ab64890Smrg#include "Xlibint.h"
761ab64890Smrg#include "Xlcint.h"
771ab64890Smrg#include "Ximint.h"
781ab64890Smrg#include "XimThai.h"
791ab64890Smrg#include "XlcPubI.h"
801ab64890Smrg
811ab64890Smrg
821ab64890Smrg#define SPACE   32
831ab64890Smrg
841ab64890Smrg/* character classification table */
851ab64890Smrg#define TACTIS_CHARS 256
861ab64890SmrgPrivate
871ab64890Smrgchar const tactis_chtype[TACTIS_CHARS] = {
881ab64890Smrg    CTRL, CTRL, CTRL, CTRL, CTRL, CTRL, CTRL, CTRL,  /*  0 -  7 */
891ab64890Smrg    CTRL, CTRL, CTRL, CTRL, CTRL, CTRL, CTRL, CTRL,  /*  8 - 15 */
901ab64890Smrg    CTRL, CTRL, CTRL, CTRL, CTRL, CTRL, CTRL, CTRL,  /* 16 - 23 */
911ab64890Smrg    CTRL, CTRL, CTRL, CTRL, CTRL, CTRL, CTRL, CTRL,  /* 24 - 31 */
921ab64890Smrg    NON,  NON,  NON,  NON,  NON,  NON,  NON,  NON,   /* 32 - 39 */
931ab64890Smrg    NON,  NON,  NON,  NON,  NON,  NON,  NON,  NON,   /* 40 - 47 */
941ab64890Smrg    NON,  NON,  NON,  NON,  NON,  NON,  NON,  NON,   /* 48 - 55 */
951ab64890Smrg    NON,  NON,  NON,  NON,  NON,  NON,  NON,  NON,   /* 56 - 63 */
961ab64890Smrg    NON,  NON,  NON,  NON,  NON,  NON,  NON,  NON,   /* 64 - 71 */
971ab64890Smrg    NON,  NON,  NON,  NON,  NON,  NON,  NON,  NON,   /* 72 - 79 */
981ab64890Smrg    NON,  NON,  NON,  NON,  NON,  NON,  NON,  NON,   /* 80 - 87 */
991ab64890Smrg    NON,  NON,  NON,  NON,  NON,  NON,  NON,  NON,   /* 88 - 95 */
1001ab64890Smrg    NON,  NON,  NON,  NON,  NON,  NON,  NON,  NON,   /* 96 - 103 */
1011ab64890Smrg    NON,  NON,  NON,  NON,  NON,  NON,  NON,  NON,   /* 104 - 111 */
1021ab64890Smrg    NON,  NON,  NON,  NON,  NON,  NON,  NON,  NON,   /* 112 - 119 */
1031ab64890Smrg    NON,  NON,  NON,  NON,  NON,  NON,  NON,  CTRL,  /* 120 - 127 */
1041ab64890Smrg    CTRL, CTRL, CTRL, CTRL, CTRL, CTRL, CTRL, CTRL,  /* 128 - 135 */
1051ab64890Smrg    CTRL, CTRL, CTRL, CTRL, CTRL, CTRL, CTRL, CTRL,  /* 136 - 143 */
1061ab64890Smrg    CTRL, CTRL, CTRL, CTRL, CTRL, CTRL, CTRL, CTRL,  /* 144 - 151 */
1071ab64890Smrg    CTRL, CTRL, CTRL, CTRL, CTRL, CTRL, CTRL, CTRL,  /* 152 - 159 */
1081ab64890Smrg    NON,  CONS, CONS, CONS, CONS, CONS, CONS, CONS,  /* 160 - 167 */
1091ab64890Smrg    CONS, CONS, CONS, CONS, CONS, CONS, CONS, CONS,  /* 168 - 175 */
1101ab64890Smrg    CONS, CONS, CONS, CONS, CONS, CONS, CONS, CONS,  /* 176 - 183 */
1111ab64890Smrg    CONS, CONS, CONS, CONS, CONS, CONS, CONS, CONS,  /* 184 - 191 */
1121ab64890Smrg    CONS, CONS, CONS, CONS,  FV3, CONS,  FV3, CONS,  /* 192 - 199 */
1131ab64890Smrg    CONS, CONS, CONS, CONS, CONS, CONS, CONS, NON,   /* 200 - 207 */
1141ab64890Smrg    FV1,  AV2,  FV1,  FV1,  AV1,  AV3,  AV2,  AV3,   /* 208 - 215 */
1151ab64890Smrg    BV1,  BV2,  BD,   NON,  NON,  NON,  NON,  NON,   /* 216 - 223 */
1161ab64890Smrg    LV,   LV,   LV,   LV,   LV,   FV2,  NON,  AD2,   /* 224 - 231 */
1171ab64890Smrg    TONE, TONE, TONE, TONE, AD1,  AD1,  AD3,  NON,   /* 232 - 239 */
1181ab64890Smrg    NON,  NON,  NON,  NON,  NON,  NON,  NON,  NON,   /* 240 - 247 */
1191ab64890Smrg    NON,  NON,  NON,  NON,  NON,  NON,  NON,  CTRL   /* 248 - 255 */
1201ab64890Smrg};
1211ab64890Smrg
1221ab64890Smrg/* Composibility checking tables */
1231ab64890Smrg#define NC  0   /* NOT COMPOSIBLE - following char displays in next cell */
1241ab64890Smrg#define CP  1   /* COMPOSIBLE - following char is displayed in the same cell
1251ab64890Smrg                                as leading char, also implies ACCEPT */
1261ab64890Smrg#define XC  3   /* Non-display */
1271ab64890Smrg#define AC  4   /* ACCEPT - display the following char in the next cell */
1281ab64890Smrg#define RJ  5   /* REJECT - discard that following char, ignore it */
1291ab64890Smrg
1301ab64890Smrg#define CH_CLASSES      17  /* 17 classes of chars */
1311ab64890Smrg
1321ab64890SmrgPrivate
1331ab64890Smrgchar const write_rules_lookup[CH_CLASSES][CH_CLASSES] = {
1341ab64890Smrg        /* Table 0: writing/outputing rules */
1351ab64890Smrg        /* row: leading char,  column: following char */
1361ab64890Smrg/* CTRL NON CONS LV FV1 FV2 FV3 BV1 BV2 BD TONE AD1 AD2 AD3 AV1 AV2 AV3 */
1371ab64890Smrg   {XC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC}/*CTRL*/
1381ab64890Smrg  ,{XC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC}/*NON*/
1391ab64890Smrg  ,{XC, NC, NC, NC, NC, NC, NC, CP, CP, CP, CP, CP, CP, CP, CP, CP, CP}/*CONS*/
1401ab64890Smrg  ,{XC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC}/*LV*/
1411ab64890Smrg  ,{XC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC}/*FV1*/
1421ab64890Smrg  ,{XC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC}/*FV2*/
1431ab64890Smrg  ,{XC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC}/*FV3*/
1441ab64890Smrg  ,{XC, NC, NC, NC, NC, NC, NC, NC, NC, NC, CP, CP, NC, NC, NC, NC, NC}/*BV1*/
1451ab64890Smrg  ,{XC, NC, NC, NC, NC, NC, NC, NC, NC, NC, CP, NC, NC, NC, NC, NC, NC}/*BV2*/
1461ab64890Smrg  ,{XC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC}/*BD*/
1471ab64890Smrg  ,{XC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC}/*TONE*/
1481ab64890Smrg  ,{XC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC}/*AD1*/
1491ab64890Smrg  ,{XC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC}/*AD2*/
1501ab64890Smrg  ,{XC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC}/*AD3*/
1511ab64890Smrg  ,{XC, NC, NC, NC, NC, NC, NC, NC, NC, NC, CP, CP, NC, NC, NC, NC, NC}/*AV1*/
1521ab64890Smrg  ,{XC, NC, NC, NC, NC, NC, NC, NC, NC, NC, CP, NC, NC, NC, NC, NC, NC}/*AV2*/
1531ab64890Smrg  ,{XC, NC, NC, NC, NC, NC, NC, NC, NC, NC, CP, NC, CP, NC, NC, NC, NC}/*AV3*/
1541ab64890Smrg};
1551ab64890Smrg
1561ab64890SmrgPrivate
1571ab64890Smrgchar const wtt_isc1_lookup[CH_CLASSES][CH_CLASSES] = {
1581ab64890Smrg      /* Table 1: WTT default input sequence check rules */
1591ab64890Smrg      /* row: leading char,  column: following char */
1601ab64890Smrg/* CTRL NON CONS LV FV1 FV2 FV3 BV1 BV2 BD TONE AD1 AD2 AD3 AV1 AV2 AV3 */
1611ab64890Smrg   {XC, AC, AC, AC, AC, AC, AC, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ}/*CTRL*/
1621ab64890Smrg  ,{XC, AC, AC, AC, AC, AC, AC, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ}/*NON*/
1631ab64890Smrg  ,{XC, AC, AC, AC, AC, AC, AC, CP, CP, CP, CP, CP, CP, CP, CP, CP, CP}/*CONS*/
1641ab64890Smrg  ,{XC, AC, AC, AC, AC, AC, AC, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ}/*LV*/
1651ab64890Smrg  ,{XC, AC, AC, AC, AC, AC, AC, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ}/*FV1*/
1661ab64890Smrg  ,{XC, AC, AC, AC, AC, AC, AC, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ}/*FV2*/
1671ab64890Smrg  ,{XC, AC, AC, AC, AC, AC, AC, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ}/*FV3*/
1681ab64890Smrg  ,{XC, AC, AC, AC, AC, AC, AC, RJ, RJ, RJ, CP, CP, RJ, RJ, RJ, RJ, RJ}/*BV1*/
1691ab64890Smrg  ,{XC, AC, AC, AC, AC, AC, AC, RJ, RJ, RJ, CP, RJ, RJ, RJ, RJ, RJ, RJ}/*BV2*/
1701ab64890Smrg  ,{XC, AC, AC, AC, AC, AC, AC, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ}/*BD*/
1711ab64890Smrg  ,{XC, AC, AC, AC, AC, AC, AC, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ}/*TONE*/
1721ab64890Smrg  ,{XC, AC, AC, AC, AC, AC, AC, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ}/*AD1*/
1731ab64890Smrg  ,{XC, AC, AC, AC, AC, AC, AC, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ}/*AD2*/
1741ab64890Smrg  ,{XC, AC, AC, AC, AC, AC, AC, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ}/*AD3*/
1751ab64890Smrg  ,{XC, AC, AC, AC, AC, AC, AC, RJ, RJ, RJ, CP, CP, RJ, RJ, RJ, RJ, RJ}/*AV1*/
1761ab64890Smrg  ,{XC, AC, AC, AC, AC, AC, AC, RJ, RJ, RJ, CP, RJ, RJ, RJ, RJ, RJ, RJ}/*AV2*/
1771ab64890Smrg  ,{XC, AC, AC, AC, AC, AC, AC, RJ, RJ, RJ, CP, RJ, CP, RJ, RJ, RJ, RJ}/*AV3*/
1781ab64890Smrg};
1791ab64890Smrg
1801ab64890SmrgPrivate
1811ab64890Smrgchar const wtt_isc2_lookup[CH_CLASSES][CH_CLASSES] = {
1821ab64890Smrg      /* Table 2: WTT strict input sequence check rules */
1831ab64890Smrg      /* row: leading char,  column: following char */
1841ab64890Smrg/* CTRL NON CONS LV FV1 FV2 FV3 BV1 BV2 BD TONE AD1 AD2 AD3 AV1 AV2 AV3 */
1851ab64890Smrg   {XC, AC, AC, AC, AC, AC, AC, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ}/*CTRL*/
1861ab64890Smrg  ,{XC, AC, AC, AC, RJ, RJ, AC, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ}/*NON*/
1871ab64890Smrg  ,{XC, AC, AC, AC, AC, RJ, AC, CP, CP, CP, CP, CP, CP, CP, CP, CP, CP}/*CONS*/
1881ab64890Smrg  ,{XC, RJ, AC, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ}/*LV*/
1891ab64890Smrg  ,{XC, AC, AC, AC, AC, RJ, AC, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ}/*FV1*/
1901ab64890Smrg  ,{XC, AC, AC, AC, AC, RJ, AC, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ}/*FV2*/
1911ab64890Smrg  ,{XC, AC, AC, AC, RJ, AC, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ}/*FV3*/
1921ab64890Smrg  ,{XC, AC, AC, AC, AC, RJ, AC, RJ, RJ, RJ, CP, CP, RJ, RJ, RJ, RJ, RJ}/*BV1*/
1931ab64890Smrg  ,{XC, AC, AC, AC, RJ, RJ, AC, RJ, RJ, RJ, CP, RJ, RJ, RJ, RJ, RJ, RJ}/*BV2*/
1941ab64890Smrg  ,{XC, AC, AC, AC, RJ, RJ, AC, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ}/*BD*/
1951ab64890Smrg  ,{XC, AC, AC, AC, AC, AC, AC, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ}/*TONE*/
1961ab64890Smrg  ,{XC, AC, AC, AC, RJ, RJ, AC, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ}/*AD1*/
1971ab64890Smrg  ,{XC, AC, AC, AC, RJ, RJ, AC, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ}/*AD2*/
1981ab64890Smrg  ,{XC, AC, AC, AC, RJ, RJ, AC, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ}/*AD3*/
1991ab64890Smrg  ,{XC, AC, AC, AC, RJ, RJ, AC, RJ, RJ, RJ, CP, CP, RJ, RJ, RJ, RJ, RJ}/*AV1*/
2001ab64890Smrg  ,{XC, AC, AC, AC, RJ, RJ, AC, RJ, RJ, RJ, CP, RJ, RJ, RJ, RJ, RJ, RJ}/*AV2*/
2011ab64890Smrg  ,{XC, AC, AC, AC, RJ, RJ, AC, RJ, RJ, RJ, CP, RJ, CP, RJ, RJ, RJ, RJ}/*AV3*/
2021ab64890Smrg};
2031ab64890Smrg
2041ab64890SmrgPrivate
2051ab64890Smrgchar const thaicat_isc_lookup[CH_CLASSES][CH_CLASSES] = {
2061ab64890Smrg      /* Table 3: Thaicat input sequence check rules */
2071ab64890Smrg      /* row: leading char,  column: following char */
2081ab64890Smrg/* CTRL NON CONS LV FV1 FV2 FV3 BV1 BV2 BD TONE AD1 AD2 AD3 AV1 AV2 AV3 */
2091ab64890Smrg   {XC, AC, AC, AC, AC, AC, AC, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ}/*CTRL*/
2101ab64890Smrg  ,{XC, AC, AC, AC, AC, AC, AC, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ}/*NON*/
2111ab64890Smrg  ,{XC, AC, AC, AC, AC, AC, AC, CP, CP, CP, CP, CP, CP, CP, CP, CP, CP}/*CONS*/
2121ab64890Smrg  ,{XC, AC, AC, AC, AC, AC, AC, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ}/*LV*/
2131ab64890Smrg  ,{XC, AC, AC, AC, AC, AC, AC, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ}/*FV1*/
2141ab64890Smrg  ,{XC, AC, AC, AC, AC, AC, AC, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ}/*FV2*/
2151ab64890Smrg  ,{XC, AC, AC, AC, AC, AC, AC, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ} /*FV3*/
2161ab64890Smrg  ,{XC, AC, AC, AC, AC, AC, AC, RJ, RJ, RJ, CP, CP, RJ, RJ, RJ, RJ, RJ}/*BV1*/
2171ab64890Smrg  ,{XC, AC, AC, AC, AC, AC, AC, RJ, RJ, RJ, CP, RJ, RJ, RJ, RJ, RJ, RJ}/*BV2*/
2181ab64890Smrg  ,{XC, AC, AC, AC, AC, AC, AC, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ}/*BD*/
2191ab64890Smrg  ,{XC, AC, AC, AC, AC, AC, AC, CP, CP, RJ, RJ, RJ, RJ, RJ, CP, CP, CP}/*TONE*/
2201ab64890Smrg  ,{XC, AC, AC, AC, AC, AC, AC, CP, RJ, RJ, RJ, RJ, RJ, RJ, CP, RJ, RJ}/*AD1*/
2211ab64890Smrg  ,{XC, AC, AC, AC, AC, AC, AC, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, CP}/*AD2*/
2221ab64890Smrg  ,{XC, AC, AC, AC, AC, AC, AC, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ, RJ}/*AD3*/
2231ab64890Smrg  ,{XC, AC, AC, AC, AC, AC, AC, RJ, RJ, RJ, CP, CP, RJ, RJ, RJ, RJ, RJ}/*AV1*/
2241ab64890Smrg  ,{XC, AC, AC, AC, AC, AC, AC, RJ, RJ, RJ, CP, RJ, RJ, RJ, RJ, RJ, RJ}/*AV2*/
2251ab64890Smrg  ,{XC, AC, AC, AC, AC, AC, AC, RJ, RJ, RJ, CP, RJ, CP, RJ, RJ, RJ, RJ}/*AV3*/
2261ab64890Smrg};
2271ab64890Smrg
2281ab64890Smrg
2291ab64890Smrg/* returns classification of a char */
2301ab64890SmrgPrivate int
2311ab64890SmrgTHAI_chtype (unsigned char	ch)
2321ab64890Smrg{
2331ab64890Smrg    return tactis_chtype[ch];
2341ab64890Smrg}
2351ab64890Smrg
2361ab64890Smrg#ifdef UNUSED
2371ab64890Smrg/* returns the display level */
2381ab64890SmrgPrivate int
2391ab64890SmrgTHAI_chlevel (unsigned char	ch)
2401ab64890Smrg{
2411ab64890Smrg    int     chlevel;
2421ab64890Smrg
2431ab64890Smrg    switch (tactis_chtype[ch])
2441ab64890Smrg    {
2451ab64890Smrg        case CTRL:
2461ab64890Smrg            chlevel = NON;
2471ab64890Smrg            break;
2481ab64890Smrg        case BV1:
2491ab64890Smrg        case BV2:
2501ab64890Smrg        case BD:
2511ab64890Smrg            chlevel = BELOW;
2521ab64890Smrg            break;
2531ab64890Smrg        case TONE:
2541ab64890Smrg        case AD1:
2551ab64890Smrg        case AD2:
2561ab64890Smrg            chlevel = TOP;
2571ab64890Smrg            break;
2581ab64890Smrg        case AV1:
2591ab64890Smrg        case AV2:
2601ab64890Smrg        case AV3:
2611ab64890Smrg        case AD3:
2621ab64890Smrg            chlevel = ABOVE;
2631ab64890Smrg            break;
2641ab64890Smrg        case NON:
2651ab64890Smrg        case CONS:
2661ab64890Smrg        case LV:
2671ab64890Smrg        case FV1:
2681ab64890Smrg        case FV2:
2691ab64890Smrg        case FV3:
2701ab64890Smrg        default: /* if tactis_chtype is invalid */
2711ab64890Smrg            chlevel = BASE;
2721ab64890Smrg            break;
2731ab64890Smrg    }
2741ab64890Smrg    return chlevel;
2751ab64890Smrg}
2761ab64890Smrg
2771ab64890Smrg
2781ab64890Smrg/* return True if char is non-spacing */
2791ab64890SmrgPrivate Bool
2801ab64890SmrgTHAI_isdead (unsigned char	ch)
2811ab64890Smrg{
2821ab64890Smrg    return ((tactis_chtype[ch] == CTRL) || (tactis_chtype[ch] == BV1) ||
2831ab64890Smrg            (tactis_chtype[ch] == BV2)  || (tactis_chtype[ch] == BD)  ||
2841ab64890Smrg            (tactis_chtype[ch] == TONE) || (tactis_chtype[ch] == AD1) ||
2851ab64890Smrg            (tactis_chtype[ch] == AD2)  || (tactis_chtype[ch] == AD3) ||
2861ab64890Smrg            (tactis_chtype[ch] == AV1)  || (tactis_chtype[ch] == AV2) ||
2871ab64890Smrg            (tactis_chtype[ch] == AV3));
2881ab64890Smrg}
2891ab64890Smrg
2901ab64890Smrg
2911ab64890Smrg/* return True if char is consonant */
2921ab64890SmrgPrivate Bool
2931ab64890SmrgTHAI_iscons (unsigned char	ch)
2941ab64890Smrg{
2951ab64890Smrg    return (tactis_chtype[ch] == CONS);
2961ab64890Smrg}
2971ab64890Smrg
2981ab64890Smrg
2991ab64890Smrg/* return True if char is vowel */
3001ab64890SmrgPrivate Bool
3011ab64890SmrgTHAI_isvowel (unsigned char	ch)
3021ab64890Smrg{
3031ab64890Smrg    return ((tactis_chtype[ch] == LV)  || (tactis_chtype[ch] == FV1) ||
3041ab64890Smrg            (tactis_chtype[ch] == FV2) || (tactis_chtype[ch] == FV3) ||
3051ab64890Smrg            (tactis_chtype[ch] == BV1) || (tactis_chtype[ch] == BV2) ||
3061ab64890Smrg            (tactis_chtype[ch] == AV1) || (tactis_chtype[ch] == AV2) ||
3071ab64890Smrg            (tactis_chtype[ch] == AV3));
3081ab64890Smrg}
3091ab64890Smrg
3101ab64890Smrg
3111ab64890Smrg/* return True if char is tonemark */
3121ab64890SmrgPrivate Bool
3131ab64890SmrgTHAI_istone (unsigned char	ch)
3141ab64890Smrg{
3151ab64890Smrg    return (tactis_chtype[ch] == TONE);
3161ab64890Smrg}
3171ab64890Smrg#endif
3181ab64890Smrg
3191ab64890SmrgPrivate Bool
3201ab64890SmrgTHAI_iscomposible (
32161b2299dSmrg    unsigned char	follow_ch,
3221ab64890Smrg    unsigned char	lead_ch)
3231ab64890Smrg{/* "Can follow_ch be put in the same display cell as lead_ch?" */
3241ab64890Smrg
32561b2299dSmrg    return (write_rules_lookup[THAI_chtype(lead_ch)][THAI_chtype(follow_ch)]
3261ab64890Smrg            == CP);
3271ab64890Smrg}
3281ab64890Smrg
3291ab64890SmrgPrivate Bool
3301ab64890SmrgTHAI_isaccepted (
33161b2299dSmrg    unsigned char	follow_ch,
3321ab64890Smrg    unsigned char	lead_ch,
3331ab64890Smrg    unsigned char	mode)
3341ab64890Smrg{
3351ab64890Smrg    Bool iskeyvalid; /*  means "Can follow_ch be keyed in after lead_ch?" */
3361ab64890Smrg
3371ab64890Smrg    switch (mode)
3381ab64890Smrg    {
3391ab64890Smrg        case WTT_ISC1:
34061b2299dSmrg            iskeyvalid =
3411ab64890Smrg          (wtt_isc1_lookup[THAI_chtype(lead_ch)][THAI_chtype(follow_ch)] != RJ);
3421ab64890Smrg            break;
3431ab64890Smrg        case WTT_ISC2:
34461b2299dSmrg            iskeyvalid =
3451ab64890Smrg          (wtt_isc2_lookup[THAI_chtype(lead_ch)][THAI_chtype(follow_ch)] != RJ);
3461ab64890Smrg            break;
3471ab64890Smrg        case THAICAT_ISC:
3481ab64890Smrg            iskeyvalid =
3491ab64890Smrg       (thaicat_isc_lookup[THAI_chtype(lead_ch)][THAI_chtype(follow_ch)] != RJ);
3501ab64890Smrg            break;
3511ab64890Smrg        default:
3521ab64890Smrg            iskeyvalid = True;
3531ab64890Smrg            break;
3541ab64890Smrg    }
3551ab64890Smrg
3561ab64890Smrg    return iskeyvalid;
3571ab64890Smrg}
3581ab64890Smrg
3591ab64890Smrg#ifdef UNUSED
36061b2299dSmrgPrivate void
3611ab64890SmrgTHAI_apply_write_rules(
36261b2299dSmrg    unsigned char	*instr,
36361b2299dSmrg    unsigned char	*outstr,
36461b2299dSmrg    unsigned char	insert_ch,
3651ab64890Smrg    int 		*num_insert_ch)
3661ab64890Smrg{
3671ab64890Smrg/*
36861b2299dSmrgInput parameters:
3691ab64890Smrg    instr - input string
3701ab64890Smrg    insert_ch specify what char to be added when invalid composition is found
3711ab64890SmrgOutput parameters:
3721ab64890Smrg    outstr - output string after input string has been applied the rules
3731ab64890Smrg    num_insert_ch - number of insert_ch added to outstr.
3741ab64890Smrg*/
3751ab64890Smrg    unsigned char   *lead_ch = NULL, *follow_ch = NULL, *out_ch = NULL;
3761ab64890Smrg
3771ab64890Smrg    *num_insert_ch = 0;
3781ab64890Smrg    lead_ch = follow_ch = instr;
3791ab64890Smrg    out_ch = outstr;
3801ab64890Smrg    if ((*lead_ch == '\0') || !(THAI_find_chtype(instr,DEAD)))
3811ab64890Smrg    {   /* Empty string or can't find any non-spacing char*/
3821ab64890Smrg        strcpy((char *)outstr, (char *)instr);
3831ab64890Smrg    } else { /* String of length >= 1, keep looking */
3841ab64890Smrg        follow_ch++;
3851ab64890Smrg        if (THAI_isdead(*lead_ch)) { /* is first char non-spacing? */
3861ab64890Smrg            *out_ch++ = SPACE;
3871ab64890Smrg            (*num_insert_ch)++;
3881ab64890Smrg        }
3891ab64890Smrg        *out_ch++ = *lead_ch;
3901ab64890Smrg        while (*follow_ch != '\0')  /* more char in string to check */
3911ab64890Smrg        {
39261b2299dSmrg            if (THAI_isdead(*follow_ch) &&
39361b2299dSmrg                 !THAI_iscomposible(*follow_ch,*lead_ch))
3941ab64890Smrg            {
3951ab64890Smrg                *out_ch++ = SPACE;
3961ab64890Smrg                (*num_insert_ch)++;
3971ab64890Smrg            }
3981ab64890Smrg            *out_ch++ = *follow_ch;
3991ab64890Smrg            lead_ch = follow_ch;
4001ab64890Smrg            follow_ch++;
4011ab64890Smrg        }
4021ab64890Smrg        *out_ch = '\0';
4031ab64890Smrg    }
4041ab64890Smrg}
4051ab64890Smrg
40661b2299dSmrgPrivate int
4071ab64890SmrgTHAI_find_chtype (
40861b2299dSmrg    unsigned char	*instr,
4091ab64890Smrg    int		chtype)
4101ab64890Smrg{
4111ab64890Smrg/*
4121ab64890SmrgInput parameters:
4131ab64890Smrg    instr - input string
4141ab64890Smrg    chtype - type of character to look for
4151ab64890SmrgOutput parameters:
4161ab64890Smrg    function returns first position of character with matched chtype
4171ab64890Smrg    function returns -1 if it does not find.
4181ab64890Smrg*/
4191ab64890Smrg    int i = 0, position = -1;
4201ab64890Smrg
4211ab64890Smrg    switch (chtype)
4221ab64890Smrg    {
4231ab64890Smrg        case DEAD:
4241ab64890Smrg            for (i = 0; *instr != '\0' && THAI_isdead(*instr); i++, instr++)
4251ab64890Smrg		;
42661b2299dSmrg            if (*instr != '\0') position = i;
4271ab64890Smrg            break;
4281ab64890Smrg        default:
4291ab64890Smrg            break;
4301ab64890Smrg    }
4311ab64890Smrg    return position;
4321ab64890Smrg}
4331ab64890Smrg
4341ab64890Smrg
43561b2299dSmrgPrivate int
4361ab64890SmrgTHAI_apply_scm(
43761b2299dSmrg    unsigned char	*instr,
43861b2299dSmrg    unsigned char	*outstr,
43961b2299dSmrg    unsigned char	spec_ch,
44061b2299dSmrg    int		num_sp,
4411ab64890Smrg    unsigned char	insert_ch)
4421ab64890Smrg{
4431ab64890Smrg    unsigned char   *scan, *outch;
4441ab64890Smrg    int             i, dead_count, found_count;
4451ab64890Smrg    Bool            isconsecutive;
4461ab64890Smrg
4471ab64890Smrg    scan = instr;
4481ab64890Smrg    outch = outstr;
4491ab64890Smrg    dead_count = found_count = 0;
4501ab64890Smrg    isconsecutive = False;
4511ab64890Smrg    while (*scan != '\0') {
4521ab64890Smrg        if (THAI_isdead(*scan))
4531ab64890Smrg            dead_count++;       /* count number of non-spacing char */
4541ab64890Smrg        if (*scan == spec_ch)
45561b2299dSmrg            if (!isconsecutive)
4561ab64890Smrg                found_count++;      /* count number consecutive spec char found */
4571ab64890Smrg        *outch++ = *scan++;
4581ab64890Smrg        if (found_count == num_sp) {
4591ab64890Smrg            for (i = 0; i < dead_count; i++)
4601ab64890Smrg                *outch++ = insert_ch;
4611ab64890Smrg            dead_count = found_count = 0;
4621ab64890Smrg        }
4631ab64890Smrg    }
4641ab64890Smrg    /* what to return? */
4651ab64890Smrg    return 0; /* probably not right but better than returning garbage */
4661ab64890Smrg}
4671ab64890Smrg
4681ab64890Smrg
4691ab64890Smrg/* The following functions are copied from XKeyBind.c */
4701ab64890Smrg
4711ab64890SmrgPrivate void ComputeMaskFromKeytrans();
4721ab64890SmrgPrivate int IsCancelComposeKey(KeySym *symbol, XKeyEvent *event);
4731ab64890SmrgPrivate void SetLed(Display *dpy, int num, int state);
4741ab64890SmrgPrivate CARD8 FindKeyCode();
4751ab64890Smrg
4761ab64890Smrg
47761b2299dSmrg/* The following functions are specific to this module */
4781ab64890Smrg
4791ab64890SmrgPrivate int XThaiTranslateKey();
4801ab64890SmrgPrivate int XThaiTranslateKeySym();
4811ab64890Smrg
4821ab64890Smrg
4831ab64890SmrgPrivate KeySym HexIMNormalKey(
4841ab64890Smrg    XicThaiPart *thai_part,
4851ab64890Smrg    KeySym symbol,
4861ab64890Smrg    XKeyEvent *event);
4871ab64890SmrgPrivate KeySym HexIMFirstComposeKey(
4881ab64890Smrg    XicThaiPart *thai_part,
4891ab64890Smrg    KeySym symbol,
4901ab64890Smrg    XKeyEvent *event);
4911ab64890SmrgPrivate KeySym HexIMSecondComposeKey(
4921ab64890Smrg    XicThaiPart *thai_part,
4931ab64890Smrg    KeySym symbol
4941ab64890Smrg    XKeyEvent *event);
4951ab64890SmrgPrivate KeySym HexIMComposeSequence(KeySym ks1, KeySym ks2);
4961ab64890SmrgPrivate void InitIscMode(Xic ic);
4971ab64890SmrgPrivate Bool ThaiComposeConvert(
4981ab64890Smrg    Display *dpy,
4991ab64890Smrg    KeySym insym,
5001ab64890Smrg    KeySym *outsym, KeySym *lower, KeySym *upper);
5011ab64890Smrg#endif
5021ab64890Smrg
5031ab64890Smrg/*
5041ab64890Smrg * Definitions
5051ab64890Smrg */
5061ab64890Smrg
5071ab64890Smrg#define BellVolume 		0
5081ab64890Smrg
5091ab64890Smrg#define ucs2tis(wc)  \
5101ab64890Smrg (unsigned char) ( \
5111ab64890Smrg   (0<=(wc)&&(wc)<=0x7F) ? \
5121ab64890Smrg     (wc) : \
5131ab64890Smrg     ((0x0E01<=(wc)&&(wc)<=0x0E5F) ? ((wc)-0x0E00+0xA0) : 0))
5141ab64890Smrg/* "c" is an unsigned char */
5151ab64890Smrg#define tis2ucs(c)  \
5161ab64890Smrg  ( \
5171ab64890Smrg   ((c)<=0x7F) ? \
5181ab64890Smrg     (wchar_t)(c) : \
5191ab64890Smrg     ((0x0A1<=(c)) ? ((wchar_t)(c)-0xA0+0x0E00) : 0))
5201ab64890Smrg
5211ab64890Smrg/*
5221ab64890Smrg * Macros to save and recall last input character in XIC
5231ab64890Smrg */
5241ab64890Smrg#define IC_SavePreviousChar(ic,ch) \
5251ab64890Smrg                ((ic)->private.local.base.mb[(ic)->private.local.base.tree[(ic)->private.local.context].mb] = (char) (ch))
5261ab64890Smrg#define IC_ClearPreviousChar(ic) \
5271ab64890Smrg                ((ic)->private.local.base.mb[(ic)->private.local.base.tree[(ic)->private.local.context].mb] = 0)
5281ab64890Smrg#define IC_GetPreviousChar(ic) \
5291ab64890Smrg		(IC_RealGetPreviousChar(ic,1))
5301ab64890Smrg#define IC_GetContextChar(ic) \
5311ab64890Smrg		(IC_RealGetPreviousChar(ic,2))
5321ab64890Smrg#define IC_DeletePreviousChar(ic) \
5331ab64890Smrg		(IC_RealDeletePreviousChar(ic))
5341ab64890Smrg
5351ab64890SmrgPrivate unsigned char
5361ab64890SmrgIC_RealGetPreviousChar(Xic ic, unsigned short pos)
5371ab64890Smrg{
5381ab64890Smrg    XICCallback* cb = &ic->core.string_conversion_callback;
5391ab64890Smrg    DefTreeBase *b = &ic->private.local.base;
5401ab64890Smrg
5411ab64890Smrg    if (cb && cb->callback) {
5421ab64890Smrg        XIMStringConversionCallbackStruct screc;
5431ab64890Smrg        unsigned char c;
5441ab64890Smrg
5451ab64890Smrg        /* Use a safe value of position = 0 and stretch the range to desired
5461ab64890Smrg         * place, as XIM protocol is unclear here whether it could be negative
5471ab64890Smrg         */
5481ab64890Smrg        screc.position = 0;
5491ab64890Smrg        screc.direction = XIMBackwardChar;
5501ab64890Smrg        screc.operation = XIMStringConversionRetrieval;
5511ab64890Smrg        screc.factor = pos;
5521ab64890Smrg        screc.text = 0;
5531ab64890Smrg
5541ab64890Smrg        (cb->callback)((XIC)ic, cb->client_data, (XPointer)&screc);
5551ab64890Smrg        if (!screc.text)
5561ab64890Smrg            return (unsigned char) b->mb[b->tree[(ic)->private.local.context].mb];
5571ab64890Smrg        if ((screc.text->feedback &&
5581ab64890Smrg             *screc.text->feedback == XIMStringConversionLeftEdge) ||
5591ab64890Smrg            screc.text->length < 1)
5601ab64890Smrg        {
5611ab64890Smrg            c = 0;
5621ab64890Smrg        } else {
5631ab64890Smrg            if (screc.text->encoding_is_wchar) {
5641ab64890Smrg                c = ucs2tis(screc.text->string.wcs[0]);
5651ab64890Smrg                XFree(screc.text->string.wcs);
5661ab64890Smrg            } else {
5671ab64890Smrg                c = screc.text->string.mbs[0];
5681ab64890Smrg                XFree(screc.text->string.mbs);
5691ab64890Smrg            }
5701ab64890Smrg        }
5711ab64890Smrg        XFree(screc.text);
5721ab64890Smrg        return c;
5731ab64890Smrg    } else {
5741ab64890Smrg        return (unsigned char) b->mb[b->tree[(ic)->private.local.context].mb];
5751ab64890Smrg    }
5761ab64890Smrg}
5771ab64890Smrg
5781ab64890SmrgPrivate unsigned char
5791ab64890SmrgIC_RealDeletePreviousChar(Xic ic)
5801ab64890Smrg{
5811ab64890Smrg    XICCallback* cb = &ic->core.string_conversion_callback;
5821ab64890Smrg
5831ab64890Smrg    if (cb && cb->callback) {
5841ab64890Smrg        XIMStringConversionCallbackStruct screc;
5851ab64890Smrg        unsigned char c;
5861ab64890Smrg
5871ab64890Smrg        screc.position = 0;
5881ab64890Smrg        screc.direction = XIMBackwardChar;
5891ab64890Smrg        screc.operation = XIMStringConversionSubstitution;
5901ab64890Smrg        screc.factor = 1;
5911ab64890Smrg        screc.text = 0;
5921ab64890Smrg
5931ab64890Smrg        (cb->callback)((XIC)ic, cb->client_data, (XPointer)&screc);
5941ab64890Smrg        if (!screc.text) { return 0; }
5951ab64890Smrg        if ((screc.text->feedback &&
5961ab64890Smrg             *screc.text->feedback == XIMStringConversionLeftEdge) ||
5971ab64890Smrg            screc.text->length < 1)
5981ab64890Smrg        {
5991ab64890Smrg            c = 0;
6001ab64890Smrg        } else {
6011ab64890Smrg            if (screc.text->encoding_is_wchar) {
6021ab64890Smrg                c = ucs2tis(screc.text->string.wcs[0]);
6031ab64890Smrg                XFree(screc.text->string.wcs);
6041ab64890Smrg            } else {
6051ab64890Smrg                c = screc.text->string.mbs[0];
6061ab64890Smrg                XFree(screc.text->string.mbs);
6071ab64890Smrg            }
6081ab64890Smrg        }
6091ab64890Smrg        XFree(screc.text);
6101ab64890Smrg        return c;
6111ab64890Smrg    } else {
6121ab64890Smrg        return 0;
6131ab64890Smrg    }
6141ab64890Smrg}
6151ab64890Smrg/*
6161ab64890Smrg * Input sequence check mode in XIC
6171ab64890Smrg */
6181ab64890Smrg#define IC_IscMode(ic)		((ic)->private.local.thai.input_mode)
6191ab64890Smrg
6201ab64890Smrg/*
6211ab64890Smrg * Max. size of string handled by the two String Lookup functions.
6221ab64890Smrg */
6231ab64890Smrg#define STR_LKUP_BUF_SIZE	256
6241ab64890Smrg
6251ab64890Smrg/*
6261ab64890Smrg * Size of buffer to contain previous locale name.
6271ab64890Smrg */
6281ab64890Smrg#define SAV_LOCALE_NAME_SIZE	256
6291ab64890Smrg
6301ab64890Smrg/*
6311ab64890Smrg * Size of buffer to contain the IM modifier.
6321ab64890Smrg */
6331ab64890Smrg#define MAXTHAIIMMODLEN 20
6341ab64890Smrg
6351ab64890Smrg#define AllMods (ShiftMask|LockMask|ControlMask| \
6361ab64890Smrg		 Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask)
6371ab64890Smrg
6381ab64890Smrg
6391ab64890Smrg#define IsISOControlKey(ks) ((ks) >= XK_2 && (ks) <= XK_8)
6401ab64890Smrg
6411ab64890Smrg#define IsValidControlKey(ks)   (((((ks)>=XK_A && (ks)<=XK_asciitilde) || \
6421ab64890Smrg                (ks)==XK_space || (ks)==XK_Delete) && \
6431ab64890Smrg                ((ks)!=0)))
6441ab64890Smrg
6451ab64890Smrg#define COMPOSE_LED 2
6461ab64890Smrg
6471ab64890Smrg#ifdef UNUSED
6481ab64890Smrgtypedef KeySym (*StateProc)(
6491ab64890Smrg    XicThaiPart *thai_part,
6501ab64890Smrg    KeySym symbol,
6511ab64890Smrg    XKeyEvent *event);
6521ab64890Smrg
6531ab64890Smrg
6541ab64890Smrg/*
6551ab64890Smrg * macros to classify XKeyEvent state field
6561ab64890Smrg */
6571ab64890Smrg
6581ab64890Smrg#define IsShift(state) (((state) & ShiftMask) != 0)
6591ab64890Smrg#define IsLock(state) (((state) & LockMask) != 0)
6601ab64890Smrg#define IsControl(state) (((state) & ControlMask) != 0)
6611ab64890Smrg#define IsMod1(state) (((state) & Mod1Mask) != 0)
6621ab64890Smrg#define IsMod2(state) (((state) & Mod2Mask) != 0)
6631ab64890Smrg#define IsMod3(state) (((state) & Mod3Mask) != 0)
6641ab64890Smrg#define IsMod4(state) (((state) & Mod4Mask) != 0)
6651ab64890Smrg#define IsMod5(state) (((state) & Mod5Mask) != 0)
6661ab64890Smrg
6671ab64890Smrg/*
6681ab64890Smrg * key starts Thai compose sequence (Hex input method) if :
6691ab64890Smrg */
6701ab64890Smrg
6711ab64890Smrg#define IsComposeKey(ks, event)  \
6721ab64890Smrg	(( ks==XK_Alt_L && 	\
6731ab64890Smrg	   IsControl((event)->state) &&	\
6741ab64890Smrg	   !IsShift((event)->state))	\
6751ab64890Smrg	 ? True : False)
6761ab64890Smrg
6771ab64890Smrg
6781ab64890Smrg/*
6791ab64890Smrg *  State handler to implement the Thai hex input method.
6801ab64890Smrg */
6811ab64890Smrg
6821ab64890SmrgPrivate int const nstate_handlers = 3;
6831ab64890SmrgPrivate StateProc state_handler[] = {
6841ab64890Smrg	HexIMNormalKey,
6851ab64890Smrg	HexIMFirstComposeKey,
6861ab64890Smrg	HexIMSecondComposeKey
6871ab64890Smrg};
6881ab64890Smrg
6891ab64890Smrg
6901ab64890Smrg/*
6911ab64890Smrg *  Table for 'Thai Compose' character input.
6921ab64890Smrg *  The current implementation uses latin-1 keysyms.
6931ab64890Smrg */
6941ab64890Smrgstruct _XMapThaiKey {
6951ab64890Smrg	KeySym from;
6961ab64890Smrg	KeySym to;
6971ab64890Smrg};
6981ab64890Smrg
6991ab64890SmrgPrivate struct _XMapThaiKey const ThaiComposeTable[] = {
7001ab64890Smrg	{ /* 0xa4 */ XK_currency,	/* 0xa5 */ XK_yen },
7011ab64890Smrg	{ /* 0xa2 */ XK_cent,		/* 0xa3 */ XK_sterling },
7021ab64890Smrg	{ /* 0xe6 */ XK_ae,		/* 0xef */ XK_idiaeresis },
7031ab64890Smrg	{ /* 0xd3 */ XK_Oacute,		/* 0xee */ XK_icircumflex },
7041ab64890Smrg	{ /* 0xb9 */ XK_onesuperior,	/* 0xfa */ XK_uacute },
7051ab64890Smrg	{ /* 0xd2 */ XK_Ograve,		/* 0xe5 */ XK_aring },
7061ab64890Smrg	{ /* 0xbc */ XK_onequarter,	/* 0xfb */ XK_ucircumflex },
7071ab64890Smrg	{	     XK_VoidSymbol,		   XK_VoidSymbol }
7081ab64890Smrg};
7091ab64890Smrg
7101ab64890Smrgstruct _XKeytrans {
7111ab64890Smrg	struct _XKeytrans *next;/* next on list */
7121ab64890Smrg	char *string;		/* string to return when the time comes */
7131ab64890Smrg	int len;		/* length of string (since NULL is legit)*/
7141ab64890Smrg	KeySym key;		/* keysym rebound */
7151ab64890Smrg	unsigned int state;	/* modifier state */
7161ab64890Smrg	KeySym *modifiers;	/* modifier keysyms you want */
7171ab64890Smrg	int mlen;		/* length of modifier list */
7181ab64890Smrg};
7191ab64890Smrg
7201ab64890Smrg
7211ab64890Smrg/* Convert keysym to 'Thai Compose' keysym */
7221ab64890Smrg/* The current implementation use latin-1 keysyms */
7231ab64890SmrgPrivate Bool
7241ab64890SmrgThaiComposeConvert(
7251ab64890Smrg    Display *dpy,
7261ab64890Smrg    KeySym insym,
7271ab64890Smrg    KeySym *outsym, KeySym *lower, KeySym *upper)
7281ab64890Smrg{
7291ab64890Smrg    struct _XMapThaiKey const *table_entry = ThaiComposeTable;
7301ab64890Smrg
7311ab64890Smrg    while (table_entry->from != XK_VoidSymbol) {
7321ab64890Smrg	if (table_entry->from == insym) {
7331ab64890Smrg	    *outsym = table_entry->to;
7341ab64890Smrg	    *lower = *outsym;
7351ab64890Smrg	    *upper = *outsym;
7361ab64890Smrg	    return True;
7371ab64890Smrg	}
7381ab64890Smrg	table_entry++;
7391ab64890Smrg    }
7401ab64890Smrg    return False;
7411ab64890Smrg}
7421ab64890Smrg
7431ab64890SmrgPrivate int
7441ab64890SmrgXThaiTranslateKey(
7451ab64890Smrg    register Display *dpy,
7461ab64890Smrg    KeyCode keycode,
7471ab64890Smrg    register unsigned int modifiers,
7481ab64890Smrg    unsigned int *modifiers_return,
7491ab64890Smrg    KeySym *keysym_return,
7501ab64890Smrg    KeySym *lsym_return,
7511ab64890Smrg    KeySym *usym_return)
7521ab64890Smrg{
7531ab64890Smrg    int per;
7541ab64890Smrg    register KeySym *syms;
7551ab64890Smrg    KeySym sym = 0, lsym = 0, usym = 0;
7561ab64890Smrg
7571ab64890Smrg    if ((! dpy->keysyms) && (! _XKeyInitialize(dpy)))
7581ab64890Smrg	return 0;
7591ab64890Smrg    *modifiers_return = (ShiftMask|LockMask) | dpy->mode_switch;
7601ab64890Smrg    if (((int)keycode < dpy->min_keycode) || ((int)keycode > dpy->max_keycode))
7611ab64890Smrg    {
7621ab64890Smrg	*keysym_return = NoSymbol;
7631ab64890Smrg	return 1;
7641ab64890Smrg    }
7651ab64890Smrg    per = dpy->keysyms_per_keycode;
7661ab64890Smrg    syms = &dpy->keysyms[(keycode - dpy->min_keycode) * per];
7671ab64890Smrg    while ((per > 2) && (syms[per - 1] == NoSymbol))
7681ab64890Smrg	per--;
7691ab64890Smrg    if ((per > 2) && (modifiers & dpy->mode_switch)) {
7701ab64890Smrg	syms += 2;
7711ab64890Smrg	per -= 2;
7721ab64890Smrg    }
7731ab64890Smrg    if (!(modifiers & ShiftMask) &&
7741ab64890Smrg	(!(modifiers & LockMask) || (dpy->lock_meaning == NoSymbol))) {
7751ab64890Smrg	if ((per == 1) || (syms[1] == NoSymbol))
7761ab64890Smrg	    XConvertCase(syms[0], keysym_return, &usym);
7771ab64890Smrg	else {
7781ab64890Smrg	    XConvertCase(syms[0], &lsym, &usym);
7791ab64890Smrg	    *keysym_return = syms[0];
7801ab64890Smrg	}
7811ab64890Smrg    } else if (!(modifiers & LockMask) ||
7821ab64890Smrg	       (dpy->lock_meaning != XK_Caps_Lock)) {
7831ab64890Smrg	if ((per == 1) || ((usym = syms[1]) == NoSymbol))
7841ab64890Smrg	    XConvertCase(syms[0], &lsym, &usym);
7851ab64890Smrg	*keysym_return = usym;
7861ab64890Smrg    } else {
7871ab64890Smrg	if ((per == 1) || ((sym = syms[1]) == NoSymbol))
7881ab64890Smrg	    sym = syms[0];
7891ab64890Smrg	XConvertCase(sym, &lsym, &usym);
7901ab64890Smrg	if (!(modifiers & ShiftMask) && (sym != syms[0]) &&
7911ab64890Smrg	    ((sym != usym) || (lsym == usym)))
7921ab64890Smrg	    XConvertCase(syms[0], &lsym, &usym);
7931ab64890Smrg	*keysym_return = usym;
7941ab64890Smrg    }
7951ab64890Smrg    /*
7961ab64890Smrg     * ThaiCat keyboard support :
79761b2299dSmrg     * When the Shift and Thai keys are hold for some keys a 'Thai Compose'
7981ab64890Smrg     * character code is generated which is different from column 3 and
79961b2299dSmrg     * 4 of the keymap.
8001ab64890Smrg     * Since we don't know whether ThaiCat keyboard or WTT keyboard is
8011ab64890Smrg     * in use, the same mapping is done for all Thai input.
80261b2299dSmrg     * We just arbitary choose to use column 3 keysyms as the indices of
8031ab64890Smrg     * this mapping.
8041ab64890Smrg     * When the control key is also hold, this mapping has no effect.
8051ab64890Smrg     */
8061ab64890Smrg    if ((modifiers & Mod1Mask) &&
8071ab64890Smrg	(modifiers & ShiftMask) &&
8081ab64890Smrg	!(modifiers & ControlMask)) {
8091ab64890Smrg	if (ThaiComposeConvert(dpy, syms[0], &sym, &lsym, &usym))
8101ab64890Smrg	    *keysym_return = sym;
8111ab64890Smrg    }
8121ab64890Smrg
8131ab64890Smrg    if (*keysym_return == XK_VoidSymbol)
8141ab64890Smrg	*keysym_return = NoSymbol;
8151ab64890Smrg    *lsym_return = lsym;
8161ab64890Smrg    *usym_return = usym;
8171ab64890Smrg    return 1;
8181ab64890Smrg}
8191ab64890Smrg
82061b2299dSmrg/*
8211ab64890Smrg * XThaiTranslateKeySym
8221ab64890Smrg *
8231ab64890Smrg * Translate KeySym to TACTIS code output.
8241ab64890Smrg * The current implementation uses ISO latin-1 keysym.
8251ab64890Smrg * Should be changed to TACTIS keysyms when they are defined by the
8261ab64890Smrg * standard.
8271ab64890Smrg */
8281ab64890SmrgPrivate int
8291ab64890SmrgXThaiTranslateKeySym(
8301ab64890Smrg    Display *dpy,
8311ab64890Smrg    register KeySym symbol,
8321ab64890Smrg    register KeySym lsym,
8331ab64890Smrg    register KeySym usym,
8341ab64890Smrg    unsigned int modifiers,
8351ab64890Smrg    unsigned char *buffer,
8361ab64890Smrg    int nbytes)
8371ab64890Smrg{
8381ab64890Smrg    KeySym ckey = 0;
83961b2299dSmrg    register struct _XKeytrans *p;
8401ab64890Smrg    int length;
8411ab64890Smrg    unsigned long hiBytes;
8421ab64890Smrg    register unsigned char c;
8431ab64890Smrg
8441ab64890Smrg    /*
8451ab64890Smrg     * initialize length = 1 ;
8461ab64890Smrg     */
8471ab64890Smrg    length = 1;
8481ab64890Smrg
8491ab64890Smrg    if (!symbol)
8501ab64890Smrg	return 0;
8511ab64890Smrg    /* see if symbol rebound, if so, return that string. */
8521ab64890Smrg    for (p = dpy->key_bindings; p; p = p->next) {
8531ab64890Smrg	if (((modifiers & AllMods) == p->state) && (symbol == p->key)) {
8541ab64890Smrg	    length = p->len;
8551ab64890Smrg	    if (length > nbytes) length = nbytes;
8561ab64890Smrg	    memcpy (buffer, p->string, length);
8571ab64890Smrg	    return length;
8581ab64890Smrg	}
8591ab64890Smrg    }
8601ab64890Smrg    /* try to convert to TACTIS, handling control */
8611ab64890Smrg    hiBytes = symbol >> 8;
8621ab64890Smrg    if (!(nbytes &&
8631ab64890Smrg	  ((hiBytes == 0) ||
8641ab64890Smrg	   ((hiBytes == 0xFF) &&
8651ab64890Smrg	    (((symbol >= XK_BackSpace) && (symbol <= XK_Clear)) ||
8661ab64890Smrg	     (symbol == XK_Return) ||
8671ab64890Smrg	     (symbol == XK_Escape) ||
8681ab64890Smrg	     (symbol == XK_KP_Space) ||
8691ab64890Smrg	     (symbol == XK_KP_Tab) ||
8701ab64890Smrg	     (symbol == XK_KP_Enter) ||
8711ab64890Smrg	     ((symbol >= XK_KP_Multiply) && (symbol <= XK_KP_9)) ||
8721ab64890Smrg	     (symbol == XK_KP_Equal) ||
8731ab64890Smrg             (symbol == XK_Scroll_Lock) ||
8741ab64890Smrg#ifdef DXK_PRIVATE /* DEC private keysyms */
8751ab64890Smrg             (symbol == DXK_Remove) ||
8761ab64890Smrg#endif
8771ab64890Smrg             (symbol == NoSymbol) ||
8781ab64890Smrg	     (symbol == XK_Delete))))))
8791ab64890Smrg	return 0;
8801ab64890Smrg
8811ab64890Smrg    /* if X keysym, convert to ascii by grabbing low 7 bits */
8821ab64890Smrg    if (symbol == XK_KP_Space)
8831ab64890Smrg	c = XK_space & 0x7F; /* patch encoding botch */
8841ab64890Smrg/* not for Thai
8851ab64890Smrg    else if (symbol == XK_hyphen)
8861ab64890Smrg	c = XK_minus & 0xFF; */ /* map to equiv character */
8871ab64890Smrg    else if (hiBytes == 0xFF)
8881ab64890Smrg	c = symbol & 0x7F;
8891ab64890Smrg    else
8901ab64890Smrg	c = symbol & 0xFF;
8911ab64890Smrg    /* only apply Control key if it makes sense, else ignore it */
8921ab64890Smrg    if (modifiers & ControlMask) {
8931ab64890Smrg    if (!(IsKeypadKey(lsym) || lsym==XK_Return || lsym==XK_Tab)) {
8941ab64890Smrg        if (IsISOControlKey(lsym)) ckey = lsym;
8951ab64890Smrg        else if (IsISOControlKey(usym)) ckey = usym;
8961ab64890Smrg        else if (lsym == XK_question) ckey = lsym;
8971ab64890Smrg        else if (usym == XK_question) ckey = usym;
8981ab64890Smrg        else if (IsValidControlKey(lsym)) ckey = lsym;
8991ab64890Smrg        else if (IsValidControlKey(usym)) ckey = usym;
9001ab64890Smrg        else length = 0;
9011ab64890Smrg
9021ab64890Smrg        if (length != 0) {
9031ab64890Smrg        if (ckey == XK_2) c = '\000';
9041ab64890Smrg        else if (ckey >= XK_3 && ckey <= XK_7)
9051ab64890Smrg            c = (char)(ckey-('3'-'\033'));
9061ab64890Smrg        else if (ckey == XK_8) c = '\177';
9071ab64890Smrg        else if (ckey == XK_Delete) c = '\030';
9081ab64890Smrg        else if (ckey == XK_question) c = '\037';
9091ab64890Smrg        else if (ckey == XK_quoteleft) c = '\036';  /* KLee 1/24/91 */
9101ab64890Smrg        else c = (char)(ckey & 0x1f);
9111ab64890Smrg        }
9121ab64890Smrg    }
9131ab64890Smrg    }
9141ab64890Smrg    /*
9151ab64890Smrg     *  ThaiCat has a key that generates two TACTIS codes D1 & E9.
91661b2299dSmrg     *  It is represented by the latin-1 keysym XK_thorn (0xfe).
91761b2299dSmrg     *  If c is XK_thorn, this key is pressed and it is converted to
9181ab64890Smrg     *  0xd1 0xe9.
9191ab64890Smrg     */
9201ab64890Smrg    if (c == XK_thorn) {
9211ab64890Smrg	buffer[0] = 0xd1;
9221ab64890Smrg	buffer[1] = 0xe9;
9231ab64890Smrg	buffer[2] = '\0';
9241ab64890Smrg	return 2;
9251ab64890Smrg    }
9261ab64890Smrg    else {
9271ab64890Smrg	/* Normal case */
9281ab64890Smrg        buffer[0] = c;
9291ab64890Smrg	buffer[1] = '\0';
9301ab64890Smrg        return 1;
9311ab64890Smrg    }
9321ab64890Smrg}
9331ab64890Smrg
9341ab64890Smrg/*
9351ab64890Smrg * given a KeySym, returns the first keycode containing it, if any.
9361ab64890Smrg */
9371ab64890SmrgPrivate CARD8
9381ab64890SmrgFindKeyCode(
9391ab64890Smrg    register Display *dpy,
9401ab64890Smrg    register KeySym code)
9411ab64890Smrg{
9421ab64890Smrg
94361b2299dSmrg    register KeySym *kmax = dpy->keysyms +
9441ab64890Smrg	(dpy->max_keycode - dpy->min_keycode + 1) * dpy->keysyms_per_keycode;
9451ab64890Smrg    register KeySym *k = dpy->keysyms;
9461ab64890Smrg    while (k < kmax) {
9471ab64890Smrg	if (*k == code)
9481ab64890Smrg	    return (((k - dpy->keysyms) / dpy->keysyms_per_keycode) +
9491ab64890Smrg		    dpy->min_keycode);
9501ab64890Smrg	k += 1;
9511ab64890Smrg	}
9521ab64890Smrg    return 0;
9531ab64890Smrg}
9541ab64890Smrg
9551ab64890Smrg/*
9561ab64890Smrg * given a list of modifiers, computes the mask necessary for later matching.
9571ab64890Smrg * This routine must lookup the key in the Keymap and then search to see
9581ab64890Smrg * what modifier it is bound to, if any.  Sets the AnyModifier bit if it
9591ab64890Smrg * can't map some keysym to a modifier.
9601ab64890Smrg */
9611ab64890SmrgPrivate void
9621ab64890SmrgComputeMaskFromKeytrans(
9631ab64890Smrg    Display *dpy,
9641ab64890Smrg    register struct _XKeytrans *p)
9651ab64890Smrg{
9661ab64890Smrg    register int i;
9671ab64890Smrg    register CARD8 code;
9681ab64890Smrg    register XModifierKeymap *m = dpy->modifiermap;
9691ab64890Smrg
9701ab64890Smrg    p->state = AnyModifier;
9711ab64890Smrg    for (i = 0; i < p->mlen; i++) {
9721ab64890Smrg	/* if not found, then not on current keyboard */
9731ab64890Smrg	if ((code = FindKeyCode(dpy, p->modifiers[i])) == 0)
9741ab64890Smrg		return;
9751ab64890Smrg	/* code is now the keycode for the modifier you want */
9761ab64890Smrg	{
9771ab64890Smrg	    register int j = m->max_keypermod<<3;
9781ab64890Smrg
9791ab64890Smrg	    while ((--j >= 0) && (code != m->modifiermap[j]))
9801ab64890Smrg		;
9811ab64890Smrg	    if (j < 0)
9821ab64890Smrg		return;
9831ab64890Smrg	    p->state |= (1<<(j/m->max_keypermod));
9841ab64890Smrg	}
9851ab64890Smrg    }
9861ab64890Smrg    p->state &= AllMods;
9871ab64890Smrg}
9881ab64890Smrg
9891ab64890Smrg/************************************************************************
9901ab64890Smrg *
9911ab64890Smrg *
9921ab64890Smrg * Compose handling routines - compose handlers 0,1,2
99361b2299dSmrg *
99461b2299dSmrg *
9951ab64890Smrg ************************************************************************/
9961ab64890Smrg
9971ab64890Smrg#define NORMAL_KEY_STATE 0
9981ab64890Smrg#define FIRST_COMPOSE_KEY_STATE 1
9991ab64890Smrg#define SECOND_COMPOSE_KEY_STATE 2
10001ab64890Smrg
10011ab64890SmrgPrivate
10021ab64890SmrgKeySym HexIMNormalKey(
10031ab64890Smrg    XicThaiPart *thai_part,
10041ab64890Smrg    KeySym symbol,
10051ab64890Smrg    XKeyEvent *event)
10061ab64890Smrg{
10071ab64890Smrg    if (IsComposeKey (symbol, event))	/* start compose sequence	*/
10081ab64890Smrg	{
10091ab64890Smrg	SetLed (event->display,COMPOSE_LED, LedModeOn);
10101ab64890Smrg	thai_part->comp_state = FIRST_COMPOSE_KEY_STATE;
10111ab64890Smrg	return NoSymbol;
10121ab64890Smrg	}
10131ab64890Smrg    return symbol;
10141ab64890Smrg}
10151ab64890Smrg
10161ab64890Smrg
10171ab64890SmrgPrivate
10181ab64890SmrgKeySym HexIMFirstComposeKey(
10191ab64890Smrg    XicThaiPart *thai_part,
10201ab64890Smrg    KeySym symbol,
10211ab64890Smrg    XKeyEvent *event)
10221ab64890Smrg{
10231ab64890Smrg    if (IsModifierKey (symbol)) return symbol; /* ignore shift etc. */
10241ab64890Smrg    if (IsCancelComposeKey (&symbol, event))	/* cancel sequence */
10251ab64890Smrg	{
10261ab64890Smrg	SetLed (event->display,COMPOSE_LED, LedModeOff);
10271ab64890Smrg	thai_part->comp_state = NORMAL_KEY_STATE;
10281ab64890Smrg	return symbol;
10291ab64890Smrg	}
10301ab64890Smrg    if (IsComposeKey (symbol, event))		/* restart sequence ?? */
10311ab64890Smrg	{
10321ab64890Smrg	return NoSymbol;			/* no state change necessary */
10331ab64890Smrg	}
10341ab64890Smrg
10351ab64890Smrg    thai_part->keysym = symbol;		/* save key pressed */
10361ab64890Smrg    thai_part->comp_state = SECOND_COMPOSE_KEY_STATE;
10371ab64890Smrg    return NoSymbol;
10381ab64890Smrg}
10391ab64890Smrg
10401ab64890SmrgPrivate
10411ab64890SmrgKeySym HexIMSecondComposeKey(
10421ab64890Smrg    XicThaiPart *thai_part,
10431ab64890Smrg    KeySym symbol,
10441ab64890Smrg    XKeyEvent *event)
10451ab64890Smrg{
10461ab64890Smrg    if (IsModifierKey (symbol)) return symbol;	/* ignore shift etc. */
10471ab64890Smrg    if (IsComposeKey (symbol, event))		/* restart sequence ? */
10481ab64890Smrg	{
10491ab64890Smrg	thai_part->comp_state =FIRST_COMPOSE_KEY_STATE;
10501ab64890Smrg	return NoSymbol;
10511ab64890Smrg	}
10521ab64890Smrg    SetLed (event->display,COMPOSE_LED, LedModeOff);
10531ab64890Smrg    if (IsCancelComposeKey (&symbol, event))	/* cancel sequence ? */
10541ab64890Smrg	{
10551ab64890Smrg	thai_part->comp_state = NORMAL_KEY_STATE;
10561ab64890Smrg	return symbol;
10571ab64890Smrg	}
10581ab64890Smrg
10591ab64890Smrg    if ((symbol = HexIMComposeSequence (thai_part->keysym, symbol))
10601ab64890Smrg								==NoSymbol)
10611ab64890Smrg	{ /* invalid compose sequence */
10621ab64890Smrg	XBell(event->display, BellVolume);
10631ab64890Smrg	}
10641ab64890Smrg    thai_part->comp_state = NORMAL_KEY_STATE; /* reset to normal state */
10651ab64890Smrg    return symbol;
10661ab64890Smrg}
10671ab64890Smrg
10681ab64890Smrg
10691ab64890Smrg/*
10701ab64890Smrg * Interprets two keysyms entered as hex digits and return the Thai keysym
10711ab64890Smrg * correspond to the TACTIS code formed.
10721ab64890Smrg * The current implementation of this routine returns ISO Latin Keysyms.
10731ab64890Smrg */
10741ab64890Smrg
10751ab64890SmrgPrivate
10761ab64890SmrgKeySym HexIMComposeSequence(KeySym ks1, KeySym ks2)
10771ab64890Smrg{
10781ab64890Smrgint	hi_digit;
10791ab64890Smrgint	lo_digit;
10801ab64890Smrgint	tactis_code;
10811ab64890Smrg
10821ab64890Smrg    if ((ks1 >= XK_0) && (ks1 <= XK_9))
10831ab64890Smrg	hi_digit = ks1 - XK_0;
10841ab64890Smrg    else if ((ks1 >= XK_A) && (ks1 <= XK_F))
10851ab64890Smrg	hi_digit = ks1 - XK_A + 10;
10861ab64890Smrg    else if ((ks1 >= XK_a) && (ks1 <= XK_f))
10871ab64890Smrg	hi_digit = ks1 - XK_a + 10;
10881ab64890Smrg    else	/* out of range */
10891ab64890Smrg	return NoSymbol;
109061b2299dSmrg
10911ab64890Smrg    if ((ks2 >= XK_0) && (ks2 <= XK_9))
10921ab64890Smrg	lo_digit = ks2 - XK_0;
10931ab64890Smrg    else if ((ks2 >= XK_A) && (ks2 <= XK_F))
10941ab64890Smrg	lo_digit = ks2 - XK_A + 10;
10951ab64890Smrg    else if ((ks2 >= XK_a) && (ks2 <= XK_f))
10961ab64890Smrg	lo_digit = ks2 - XK_a + 10;
10971ab64890Smrg    else	/* out of range */
10981ab64890Smrg	return NoSymbol;
10991ab64890Smrg
11001ab64890Smrg    tactis_code = hi_digit * 0x10 + lo_digit ;
11011ab64890Smrg
11021ab64890Smrg    return (KeySym)tactis_code;
11031ab64890Smrg
11041ab64890Smrg}
11051ab64890Smrg
11061ab64890Smrg/*
11071ab64890Smrg * routine determines
11081ab64890Smrg *	1) whether key event should cancel a compose sequence
11091ab64890Smrg *	2) whether cancelling key event should be processed or ignored
11101ab64890Smrg */
11111ab64890Smrg
11121ab64890SmrgPrivate
11131ab64890Smrgint IsCancelComposeKey(
11141ab64890Smrg    KeySym *symbol,
11151ab64890Smrg    XKeyEvent *event)
11161ab64890Smrg{
11171ab64890Smrg    if (*symbol==XK_Delete && !IsControl(event->state) &&
11181ab64890Smrg						!IsMod1(event->state)) {
11191ab64890Smrg	*symbol=NoSymbol;  /* cancel compose sequence, and ignore key */
11201ab64890Smrg	return True;
11211ab64890Smrg    }
11221ab64890Smrg    if (IsComposeKey(*symbol, event)) return False;
11231ab64890Smrg    return (
11241ab64890Smrg	IsControl (event->state) ||
11251ab64890Smrg	IsMod1(event->state) ||
11261ab64890Smrg	IsKeypadKey (*symbol) ||
11271ab64890Smrg	IsFunctionKey (*symbol) ||
11281ab64890Smrg	IsMiscFunctionKey (*symbol) ||
11291ab64890Smrg#ifdef DXK_PRIVATE /* DEC private keysyms */
11301ab64890Smrg	*symbol == DXK_Remove ||
11311ab64890Smrg#endif
11321ab64890Smrg	IsPFKey (*symbol) ||
11331ab64890Smrg	IsCursorKey (*symbol) ||
11341ab64890Smrg	(*symbol >= XK_Tab && *symbol < XK_Multi_key)
11351ab64890Smrg		? True : False);	/* cancel compose sequence and pass */
11361ab64890Smrg					/* cancelling key through	    */
11371ab64890Smrg}
11381ab64890Smrg
11391ab64890Smrg
11401ab64890Smrg/*
11411ab64890Smrg *	set specified keyboard LED on or off
11421ab64890Smrg */
11431ab64890Smrg
11441ab64890SmrgPrivate
11451ab64890Smrgvoid SetLed(
11461ab64890Smrg    Display *dpy,
11471ab64890Smrg    int num,
11481ab64890Smrg    int state)
11491ab64890Smrg{
11501ab64890Smrg    XKeyboardControl led_control;
11511ab64890Smrg
11521ab64890Smrg    led_control.led_mode = state;
11531ab64890Smrg    led_control.led = num;
11541ab64890Smrg    XChangeKeyboardControl (dpy, KBLed | KBLedMode,	&led_control);
11551ab64890Smrg}
11561ab64890Smrg#endif
11571ab64890Smrg
11581ab64890Smrg/*
115961b2299dSmrg * Initialize ISC mode from im modifier
11601ab64890Smrg */
11611ab64890SmrgPrivate void InitIscMode(Xic ic)
11621ab64890Smrg{
11631ab64890Smrg    Xim im;
11641ab64890Smrg    char *im_modifier_name;
11651ab64890Smrg
11661ab64890Smrg    /* If already defined, just return */
11671ab64890Smrg
11681ab64890Smrg    if (IC_IscMode(ic)) return;
11691ab64890Smrg
11701ab64890Smrg    /* Get IM modifier */
11711ab64890Smrg
11721ab64890Smrg    im = (Xim) XIMOfIC((XIC)ic);
11731ab64890Smrg    im_modifier_name = im->core.im_name;
11741ab64890Smrg
11751ab64890Smrg    /* Match with predefined value, default is Basic Check */
11761ab64890Smrg
11771ab64890Smrg    if (!strncmp(im_modifier_name,"BasicCheck",MAXTHAIIMMODLEN+1))
11781ab64890Smrg	IC_IscMode(ic) = WTT_ISC1;
11791ab64890Smrg    else if (!strncmp(im_modifier_name,"Strict",MAXTHAIIMMODLEN+1))
11801ab64890Smrg	IC_IscMode(ic) = WTT_ISC2;
11811ab64890Smrg    else if (!strncmp(im_modifier_name,"Thaicat",MAXTHAIIMMODLEN+1))
11821ab64890Smrg	IC_IscMode(ic) = THAICAT_ISC;
11831ab64890Smrg    else if (!strncmp(im_modifier_name,"Passthrough",MAXTHAIIMMODLEN+1))
11841ab64890Smrg	IC_IscMode(ic) = NOISC;
11851ab64890Smrg    else
11861ab64890Smrg	IC_IscMode(ic) = WTT_ISC1;
11871ab64890Smrg
11881ab64890Smrg    return;
11891ab64890Smrg}
119061b2299dSmrg
11911ab64890Smrg/*
11921ab64890Smrg * Helper functions for _XimThaiFilter()
11931ab64890Smrg */
11941ab64890SmrgPrivate Bool
11951ab64890SmrgThaiFltAcceptInput(Xic ic, unsigned char new_char, KeySym symbol)
11961ab64890Smrg{
11971ab64890Smrg    DefTreeBase *b = &ic->private.local.base;
11981ab64890Smrg    b->wc[b->tree[ic->private.local.composed].wc+0] = tis2ucs(new_char);
11991ab64890Smrg    b->wc[b->tree[ic->private.local.composed].wc+1] = '\0';
12001ab64890Smrg
12011ab64890Smrg    if ((new_char <= 0x1f) || (new_char == 0x7f))
12021ab64890Smrg        b->tree[ic->private.local.composed].keysym = symbol;
12031ab64890Smrg    else
12041ab64890Smrg        b->tree[ic->private.local.composed].keysym = NoSymbol;
12051ab64890Smrg
12061ab64890Smrg    return True;
12071ab64890Smrg}
12081ab64890Smrg
12091ab64890SmrgPrivate Bool
12101ab64890SmrgThaiFltReorderInput(Xic ic, unsigned char previous_char, unsigned char new_char)
12111ab64890Smrg{
12121ab64890Smrg    DefTreeBase *b = &ic->private.local.base;
12131ab64890Smrg    if (!IC_DeletePreviousChar(ic)) return False;
12141ab64890Smrg    b->wc[b->tree[ic->private.local.composed].wc+0] = tis2ucs(new_char);
12151ab64890Smrg    b->wc[b->tree[ic->private.local.composed].wc+1] = tis2ucs(previous_char);
12161ab64890Smrg    b->wc[b->tree[ic->private.local.composed].wc+2] = '\0';
12171ab64890Smrg
12181ab64890Smrg    b->tree[ic->private.local.composed].keysym = NoSymbol;
12191ab64890Smrg
12201ab64890Smrg    return True;
12211ab64890Smrg}
12221ab64890Smrg
12231ab64890SmrgPrivate Bool
12241ab64890SmrgThaiFltReplaceInput(Xic ic, unsigned char new_char, KeySym symbol)
12251ab64890Smrg{
12261ab64890Smrg    DefTreeBase *b = &ic->private.local.base;
12271ab64890Smrg    if (!IC_DeletePreviousChar(ic)) return False;
12281ab64890Smrg    b->wc[b->tree[ic->private.local.composed].wc+0] = tis2ucs(new_char);
12291ab64890Smrg    b->wc[b->tree[ic->private.local.composed].wc+1] = '\0';
12301ab64890Smrg
12311ab64890Smrg    if ((new_char <= 0x1f) || (new_char == 0x7f))
12321ab64890Smrg        b->tree[ic->private.local.composed].keysym = symbol;
12331ab64890Smrg    else
12341ab64890Smrg        b->tree[ic->private.local.composed].keysym = NoSymbol;
12351ab64890Smrg
12361ab64890Smrg    return True;
12371ab64890Smrg}
12381ab64890Smrg
12391ab64890Smrg/*
12401ab64890Smrg * Filter function for TACTIS
12411ab64890Smrg */
12421ab64890SmrgBool
124361b2299dSmrg_XimThaiFilter(Display *d, Window w, XEvent *ev, XPointer client_data)
12441ab64890Smrg{
12451ab64890Smrg    Xic		    ic = (Xic)client_data;
12461ab64890Smrg    KeySym 	    symbol;
12471ab64890Smrg    int 	    isc_mode; /* Thai Input Sequence Check mode */
12481ab64890Smrg    unsigned char   previous_char; /* Last inputted Thai char */
12491ab64890Smrg    unsigned char   new_char;
12501ab64890Smrg#ifdef UNUSED
12511ab64890Smrg    unsigned int    modifiers;
12521ab64890Smrg    KeySym	    lsym,usym;
12531ab64890Smrg    int		    state;
12541ab64890Smrg    XicThaiPart     *thai_part;
12551ab64890Smrg    char	    buf[10];
12561ab64890Smrg#endif
12571ab64890Smrg    wchar_t	    wbuf[10];
12581ab64890Smrg    Bool            isReject;
12591ab64890Smrg    DefTreeBase    *b = &ic->private.local.base;
12601ab64890Smrg
12611ab64890Smrg    if ((ev->type != KeyPress)
12621ab64890Smrg        || (ev->xkey.keycode == 0))
12631ab64890Smrg        return False;
12641ab64890Smrg
12651ab64890Smrg    if (!IC_IscMode(ic)) InitIscMode(ic);
12661ab64890Smrg
12671ab64890Smrg    XwcLookupString((XIC)ic, &ev->xkey, wbuf, sizeof(wbuf) / sizeof(wbuf[0]),
12681ab64890Smrg		    &symbol, NULL);
12691ab64890Smrg
12701ab64890Smrg    if ((ev->xkey.state & (AllMods & ~ShiftMask)) ||
12711ab64890Smrg         ((symbol >> 8 == 0xFF) &&
12721ab64890Smrg         ((XK_BackSpace <= symbol && symbol <= XK_Clear) ||
12731ab64890Smrg           (symbol == XK_Return) ||
12741ab64890Smrg           (symbol == XK_Pause) ||
12751ab64890Smrg           (symbol == XK_Scroll_Lock) ||
12761ab64890Smrg           (symbol == XK_Sys_Req) ||
12771ab64890Smrg           (symbol == XK_Escape) ||
12781ab64890Smrg           (symbol == XK_Delete) ||
12791ab64890Smrg           IsCursorKey(symbol) ||
12801ab64890Smrg           IsKeypadKey(symbol) ||
12811ab64890Smrg           IsMiscFunctionKey(symbol) ||
12821ab64890Smrg           IsFunctionKey(symbol))))
12831ab64890Smrg        {
128461b2299dSmrg            IC_ClearPreviousChar(ic);
12851ab64890Smrg            return False;
12861ab64890Smrg        }
12871ab64890Smrg    if (((symbol >> 8 == 0xFF) &&
12881ab64890Smrg         IsModifierKey(symbol)) ||
12891ab64890Smrg#ifdef XK_XKB_KEYS
12901ab64890Smrg        ((symbol >> 8 == 0xFE) &&
12911ab64890Smrg         (XK_ISO_Lock <= symbol && symbol <= XK_ISO_Last_Group_Lock)) ||
12921ab64890Smrg#endif
12931ab64890Smrg        (symbol == NoSymbol))
12941ab64890Smrg    {
12951ab64890Smrg        return False;
12961ab64890Smrg    }
12971ab64890Smrg#ifdef UNUSED
12981ab64890Smrg    if (! XThaiTranslateKey(ev->xkey.display, ev->xkey.keycode, ev->xkey.state,
12991ab64890Smrg	 		&modifiers, &symbol, &lsym, &usym))
13001ab64890Smrg	return False;
13011ab64890Smrg
13021ab64890Smrg    /*
130361b2299dSmrg     *  Hex input method processing
13041ab64890Smrg     */
13051ab64890Smrg
13061ab64890Smrg    thai_part = &ic->private.local.thai;
13071ab64890Smrg    state = thai_part->comp_state;
13081ab64890Smrg    if (state >= 0 && state < nstate_handlers) /* call handler for state */
13091ab64890Smrg    {
13101ab64890Smrg        symbol = (* state_handler[state])(thai_part, symbol, (XKeyEvent *)ev);
13111ab64890Smrg    }
13121ab64890Smrg
13131ab64890Smrg    /*
13141ab64890Smrg     *  Translate KeySym into mb.
13151ab64890Smrg     */
13161ab64890Smrg    count = XThaiTranslateKeySym(ev->xkey.display, symbol, lsym,
13171ab64890Smrg				usym, ev->xkey.state, buf, 10);
13181ab64890Smrg
13191ab64890Smrg    if (!symbol && !count)
13201ab64890Smrg	return True;
13211ab64890Smrg
13221ab64890Smrg    /* Return symbol if cannot convert to character */
13231ab64890Smrg    if (!count)
13241ab64890Smrg	return False;
13251ab64890Smrg#endif
13261ab64890Smrg
13271ab64890Smrg    /*
13281ab64890Smrg     *  Thai Input sequence check
13291ab64890Smrg     */
13301ab64890Smrg    isc_mode = IC_IscMode(ic);
13311ab64890Smrg    if (!(previous_char = IC_GetPreviousChar(ic))) previous_char = ' ';
13321ab64890Smrg    new_char = ucs2tis(wbuf[0]);
13331ab64890Smrg    isReject = True;
13341ab64890Smrg    if (THAI_isaccepted(new_char, previous_char, isc_mode)) {
13351ab64890Smrg        ThaiFltAcceptInput(ic, new_char, symbol);
13361ab64890Smrg        isReject = False;
13371ab64890Smrg    } else {
13381ab64890Smrg        unsigned char context_char;
13391ab64890Smrg
13401ab64890Smrg        context_char = IC_GetContextChar(ic);
13411ab64890Smrg        if (context_char) {
13421ab64890Smrg            if (THAI_iscomposible(new_char, context_char)) {
13431ab64890Smrg                if (THAI_iscomposible(previous_char, new_char)) {
13441ab64890Smrg                    isReject = !ThaiFltReorderInput(ic, previous_char, new_char);
13451ab64890Smrg                } else if (THAI_iscomposible(previous_char, context_char)) {
13461ab64890Smrg                    isReject = !ThaiFltReplaceInput(ic, new_char, symbol);
13471ab64890Smrg                } else if (THAI_chtype(previous_char) == FV1
13481ab64890Smrg                           && THAI_chtype(new_char) == TONE) {
13491ab64890Smrg                    isReject = !ThaiFltReorderInput(ic, previous_char, new_char);
13501ab64890Smrg                }
13511ab64890Smrg            } else if (THAI_isaccepted(new_char, context_char, isc_mode)) {
13521ab64890Smrg                isReject = !ThaiFltReplaceInput(ic, new_char, symbol);
13531ab64890Smrg            }
13541ab64890Smrg        }
13551ab64890Smrg    }
13561ab64890Smrg    if (isReject) {
13571ab64890Smrg        /* reject character */
13581ab64890Smrg        XBell(ev->xkey.display, BellVolume);
13591ab64890Smrg        return True;
13601ab64890Smrg    }
13611ab64890Smrg
13621ab64890Smrg    _Xlcwcstombs(ic->core.im->core.lcd, &b->mb[b->tree[ic->private.local.composed].mb],
13631ab64890Smrg		 &b->wc[b->tree[ic->private.local.composed].wc], 10);
13641ab64890Smrg
13651ab64890Smrg    _Xlcmbstoutf8(ic->core.im->core.lcd, &b->utf8[b->tree[ic->private.local.composed].utf8],
13661ab64890Smrg		  &b->mb[b->tree[ic->private.local.composed].mb], 10);
13671ab64890Smrg
13681ab64890Smrg    /* Remember the last character inputted
13691ab64890Smrg     * (as fallback in case StringConversionCallback is not provided)
13701ab64890Smrg     */
13711ab64890Smrg    IC_SavePreviousChar(ic, new_char);
13721ab64890Smrg
13731ab64890Smrg    ev->xkey.keycode = 0;
13741ab64890Smrg    XPutBackEvent(d, ev);
13751ab64890Smrg    return True;
13761ab64890Smrg}
1377