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