imThaiFlt.c revision e9628295
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    else if (hiBytes == 0xFF)
9071ab64890Smrg	c = symbol & 0x7F;
9081ab64890Smrg    else
9091ab64890Smrg	c = symbol & 0xFF;
910e9628295Smrg
9111ab64890Smrg    /* only apply Control key if it makes sense, else ignore it */
9121ab64890Smrg    if (modifiers & ControlMask) {
9131ab64890Smrg    if (!(IsKeypadKey(lsym) || lsym==XK_Return || lsym==XK_Tab)) {
9141ab64890Smrg        if (IsISOControlKey(lsym)) ckey = lsym;
9151ab64890Smrg        else if (IsISOControlKey(usym)) ckey = usym;
9161ab64890Smrg        else if (lsym == XK_question) ckey = lsym;
9171ab64890Smrg        else if (usym == XK_question) ckey = usym;
9181ab64890Smrg        else if (IsValidControlKey(lsym)) ckey = lsym;
9191ab64890Smrg        else if (IsValidControlKey(usym)) ckey = usym;
9201ab64890Smrg        else length = 0;
9211ab64890Smrg
9221ab64890Smrg        if (length != 0) {
9231ab64890Smrg        if (ckey == XK_2) c = '\000';
9241ab64890Smrg        else if (ckey >= XK_3 && ckey <= XK_7)
9251ab64890Smrg            c = (char)(ckey-('3'-'\033'));
9261ab64890Smrg        else if (ckey == XK_8) c = '\177';
9271ab64890Smrg        else if (ckey == XK_Delete) c = '\030';
9281ab64890Smrg        else if (ckey == XK_question) c = '\037';
9291ab64890Smrg        else if (ckey == XK_quoteleft) c = '\036';  /* KLee 1/24/91 */
9301ab64890Smrg        else c = (char)(ckey & 0x1f);
9311ab64890Smrg        }
9321ab64890Smrg    }
9331ab64890Smrg    }
9341ab64890Smrg    /*
9351ab64890Smrg     *  ThaiCat has a key that generates two TACTIS codes D1 & E9.
93661b2299dSmrg     *  It is represented by the latin-1 keysym XK_thorn (0xfe).
93761b2299dSmrg     *  If c is XK_thorn, this key is pressed and it is converted to
9381ab64890Smrg     *  0xd1 0xe9.
9391ab64890Smrg     */
9401ab64890Smrg    if (c == XK_thorn) {
9411ab64890Smrg	buffer[0] = 0xd1;
9421ab64890Smrg	buffer[1] = 0xe9;
9431ab64890Smrg	buffer[2] = '\0';
9441ab64890Smrg	return 2;
9451ab64890Smrg    }
9461ab64890Smrg    else {
9471ab64890Smrg	/* Normal case */
9481ab64890Smrg        buffer[0] = c;
9491ab64890Smrg	buffer[1] = '\0';
9501ab64890Smrg        return 1;
9511ab64890Smrg    }
9521ab64890Smrg}
9531ab64890Smrg
9541ab64890Smrg/*
9551ab64890Smrg * given a KeySym, returns the first keycode containing it, if any.
9561ab64890Smrg */
957eb411b4bSmrgstatic CARD8
9581ab64890SmrgFindKeyCode(
9591ab64890Smrg    register Display *dpy,
9601ab64890Smrg    register KeySym code)
9611ab64890Smrg{
9621ab64890Smrg
96361b2299dSmrg    register KeySym *kmax = dpy->keysyms +
9641ab64890Smrg	(dpy->max_keycode - dpy->min_keycode + 1) * dpy->keysyms_per_keycode;
9651ab64890Smrg    register KeySym *k = dpy->keysyms;
9661ab64890Smrg    while (k < kmax) {
9671ab64890Smrg	if (*k == code)
9681ab64890Smrg	    return (((k - dpy->keysyms) / dpy->keysyms_per_keycode) +
9691ab64890Smrg		    dpy->min_keycode);
9701ab64890Smrg	k += 1;
9711ab64890Smrg	}
9721ab64890Smrg    return 0;
9731ab64890Smrg}
9741ab64890Smrg
9751ab64890Smrg/*
9761ab64890Smrg * given a list of modifiers, computes the mask necessary for later matching.
9771ab64890Smrg * This routine must lookup the key in the Keymap and then search to see
9781ab64890Smrg * what modifier it is bound to, if any.  Sets the AnyModifier bit if it
9791ab64890Smrg * can't map some keysym to a modifier.
9801ab64890Smrg */
981eb411b4bSmrgstatic void
9821ab64890SmrgComputeMaskFromKeytrans(
9831ab64890Smrg    Display *dpy,
9841ab64890Smrg    register struct _XKeytrans *p)
9851ab64890Smrg{
9861ab64890Smrg    register int i;
9871ab64890Smrg    register CARD8 code;
9881ab64890Smrg    register XModifierKeymap *m = dpy->modifiermap;
9891ab64890Smrg
9901ab64890Smrg    p->state = AnyModifier;
9911ab64890Smrg    for (i = 0; i < p->mlen; i++) {
9921ab64890Smrg	/* if not found, then not on current keyboard */
9931ab64890Smrg	if ((code = FindKeyCode(dpy, p->modifiers[i])) == 0)
9941ab64890Smrg		return;
9951ab64890Smrg	/* code is now the keycode for the modifier you want */
9961ab64890Smrg	{
9971ab64890Smrg	    register int j = m->max_keypermod<<3;
9981ab64890Smrg
9991ab64890Smrg	    while ((--j >= 0) && (code != m->modifiermap[j]))
10001ab64890Smrg		;
10011ab64890Smrg	    if (j < 0)
10021ab64890Smrg		return;
10031ab64890Smrg	    p->state |= (1<<(j/m->max_keypermod));
10041ab64890Smrg	}
10051ab64890Smrg    }
10061ab64890Smrg    p->state &= AllMods;
10071ab64890Smrg}
10081ab64890Smrg
10091ab64890Smrg/************************************************************************
10101ab64890Smrg *
10111ab64890Smrg *
10121ab64890Smrg * Compose handling routines - compose handlers 0,1,2
101361b2299dSmrg *
101461b2299dSmrg *
10151ab64890Smrg ************************************************************************/
10161ab64890Smrg
10171ab64890Smrg#define NORMAL_KEY_STATE 0
10181ab64890Smrg#define FIRST_COMPOSE_KEY_STATE 1
10191ab64890Smrg#define SECOND_COMPOSE_KEY_STATE 2
10201ab64890Smrg
1021eb411b4bSmrgstatic
10221ab64890SmrgKeySym HexIMNormalKey(
10231ab64890Smrg    XicThaiPart *thai_part,
10241ab64890Smrg    KeySym symbol,
10251ab64890Smrg    XKeyEvent *event)
10261ab64890Smrg{
10271ab64890Smrg    if (IsComposeKey (symbol, event))	/* start compose sequence	*/
10281ab64890Smrg	{
10291ab64890Smrg	SetLed (event->display,COMPOSE_LED, LedModeOn);
10301ab64890Smrg	thai_part->comp_state = FIRST_COMPOSE_KEY_STATE;
10311ab64890Smrg	return NoSymbol;
10321ab64890Smrg	}
10331ab64890Smrg    return symbol;
10341ab64890Smrg}
10351ab64890Smrg
10361ab64890Smrg
1037eb411b4bSmrgstatic
10381ab64890SmrgKeySym HexIMFirstComposeKey(
10391ab64890Smrg    XicThaiPart *thai_part,
10401ab64890Smrg    KeySym symbol,
10411ab64890Smrg    XKeyEvent *event)
10421ab64890Smrg{
10431ab64890Smrg    if (IsModifierKey (symbol)) return symbol; /* ignore shift etc. */
10441ab64890Smrg    if (IsCancelComposeKey (&symbol, event))	/* cancel sequence */
10451ab64890Smrg	{
10461ab64890Smrg	SetLed (event->display,COMPOSE_LED, LedModeOff);
10471ab64890Smrg	thai_part->comp_state = NORMAL_KEY_STATE;
10481ab64890Smrg	return symbol;
10491ab64890Smrg	}
10501ab64890Smrg    if (IsComposeKey (symbol, event))		/* restart sequence ?? */
10511ab64890Smrg	{
10521ab64890Smrg	return NoSymbol;			/* no state change necessary */
10531ab64890Smrg	}
10541ab64890Smrg
10551ab64890Smrg    thai_part->keysym = symbol;		/* save key pressed */
10561ab64890Smrg    thai_part->comp_state = SECOND_COMPOSE_KEY_STATE;
10571ab64890Smrg    return NoSymbol;
10581ab64890Smrg}
10591ab64890Smrg
1060eb411b4bSmrgstatic
10611ab64890SmrgKeySym HexIMSecondComposeKey(
10621ab64890Smrg    XicThaiPart *thai_part,
10631ab64890Smrg    KeySym symbol,
10641ab64890Smrg    XKeyEvent *event)
10651ab64890Smrg{
10661ab64890Smrg    if (IsModifierKey (symbol)) return symbol;	/* ignore shift etc. */
10671ab64890Smrg    if (IsComposeKey (symbol, event))		/* restart sequence ? */
10681ab64890Smrg	{
10691ab64890Smrg	thai_part->comp_state =FIRST_COMPOSE_KEY_STATE;
10701ab64890Smrg	return NoSymbol;
10711ab64890Smrg	}
10721ab64890Smrg    SetLed (event->display,COMPOSE_LED, LedModeOff);
10731ab64890Smrg    if (IsCancelComposeKey (&symbol, event))	/* cancel sequence ? */
10741ab64890Smrg	{
10751ab64890Smrg	thai_part->comp_state = NORMAL_KEY_STATE;
10761ab64890Smrg	return symbol;
10771ab64890Smrg	}
10781ab64890Smrg
10791ab64890Smrg    if ((symbol = HexIMComposeSequence (thai_part->keysym, symbol))
10801ab64890Smrg								==NoSymbol)
10811ab64890Smrg	{ /* invalid compose sequence */
10821ab64890Smrg	XBell(event->display, BellVolume);
10831ab64890Smrg	}
10841ab64890Smrg    thai_part->comp_state = NORMAL_KEY_STATE; /* reset to normal state */
10851ab64890Smrg    return symbol;
10861ab64890Smrg}
10871ab64890Smrg
10881ab64890Smrg
10891ab64890Smrg/*
10901ab64890Smrg * Interprets two keysyms entered as hex digits and return the Thai keysym
10911ab64890Smrg * correspond to the TACTIS code formed.
10921ab64890Smrg * The current implementation of this routine returns ISO Latin Keysyms.
10931ab64890Smrg */
10941ab64890Smrg
1095eb411b4bSmrgstatic
10961ab64890SmrgKeySym HexIMComposeSequence(KeySym ks1, KeySym ks2)
10971ab64890Smrg{
10981ab64890Smrgint	hi_digit;
10991ab64890Smrgint	lo_digit;
11001ab64890Smrgint	tactis_code;
11011ab64890Smrg
11021ab64890Smrg    if ((ks1 >= XK_0) && (ks1 <= XK_9))
11031ab64890Smrg	hi_digit = ks1 - XK_0;
11041ab64890Smrg    else if ((ks1 >= XK_A) && (ks1 <= XK_F))
11051ab64890Smrg	hi_digit = ks1 - XK_A + 10;
11061ab64890Smrg    else if ((ks1 >= XK_a) && (ks1 <= XK_f))
11071ab64890Smrg	hi_digit = ks1 - XK_a + 10;
11081ab64890Smrg    else	/* out of range */
11091ab64890Smrg	return NoSymbol;
111061b2299dSmrg
11111ab64890Smrg    if ((ks2 >= XK_0) && (ks2 <= XK_9))
11121ab64890Smrg	lo_digit = ks2 - XK_0;
11131ab64890Smrg    else if ((ks2 >= XK_A) && (ks2 <= XK_F))
11141ab64890Smrg	lo_digit = ks2 - XK_A + 10;
11151ab64890Smrg    else if ((ks2 >= XK_a) && (ks2 <= XK_f))
11161ab64890Smrg	lo_digit = ks2 - XK_a + 10;
11171ab64890Smrg    else	/* out of range */
11181ab64890Smrg	return NoSymbol;
11191ab64890Smrg
11201ab64890Smrg    tactis_code = hi_digit * 0x10 + lo_digit ;
11211ab64890Smrg
11221ab64890Smrg    return (KeySym)tactis_code;
11231ab64890Smrg
11241ab64890Smrg}
11251ab64890Smrg
11261ab64890Smrg/*
11271ab64890Smrg * routine determines
11281ab64890Smrg *	1) whether key event should cancel a compose sequence
11291ab64890Smrg *	2) whether cancelling key event should be processed or ignored
11301ab64890Smrg */
11311ab64890Smrg
1132eb411b4bSmrgstatic
11331ab64890Smrgint IsCancelComposeKey(
11341ab64890Smrg    KeySym *symbol,
11351ab64890Smrg    XKeyEvent *event)
11361ab64890Smrg{
11371ab64890Smrg    if (*symbol==XK_Delete && !IsControl(event->state) &&
11381ab64890Smrg						!IsMod1(event->state)) {
11391ab64890Smrg	*symbol=NoSymbol;  /* cancel compose sequence, and ignore key */
11401ab64890Smrg	return True;
11411ab64890Smrg    }
11421ab64890Smrg    if (IsComposeKey(*symbol, event)) return False;
11431ab64890Smrg    return (
11441ab64890Smrg	IsControl (event->state) ||
11451ab64890Smrg	IsMod1(event->state) ||
11461ab64890Smrg	IsKeypadKey (*symbol) ||
11471ab64890Smrg	IsFunctionKey (*symbol) ||
11481ab64890Smrg	IsMiscFunctionKey (*symbol) ||
11491ab64890Smrg#ifdef DXK_PRIVATE /* DEC private keysyms */
11501ab64890Smrg	*symbol == DXK_Remove ||
11511ab64890Smrg#endif
11521ab64890Smrg	IsPFKey (*symbol) ||
11531ab64890Smrg	IsCursorKey (*symbol) ||
11541ab64890Smrg	(*symbol >= XK_Tab && *symbol < XK_Multi_key)
11551ab64890Smrg		? True : False);	/* cancel compose sequence and pass */
11561ab64890Smrg					/* cancelling key through	    */
11571ab64890Smrg}
11581ab64890Smrg
11591ab64890Smrg
11601ab64890Smrg/*
11611ab64890Smrg *	set specified keyboard LED on or off
11621ab64890Smrg */
11631ab64890Smrg
1164eb411b4bSmrgstatic
11651ab64890Smrgvoid SetLed(
11661ab64890Smrg    Display *dpy,
11671ab64890Smrg    int num,
11681ab64890Smrg    int state)
11691ab64890Smrg{
11701ab64890Smrg    XKeyboardControl led_control;
11711ab64890Smrg
11721ab64890Smrg    led_control.led_mode = state;
11731ab64890Smrg    led_control.led = num;
11741ab64890Smrg    XChangeKeyboardControl (dpy, KBLed | KBLedMode,	&led_control);
11751ab64890Smrg}
11761ab64890Smrg#endif
11771ab64890Smrg
11781ab64890Smrg/*
117961b2299dSmrg * Initialize ISC mode from im modifier
11801ab64890Smrg */
1181eb411b4bSmrgstatic void InitIscMode(Xic ic)
11821ab64890Smrg{
11831ab64890Smrg    Xim im;
11841ab64890Smrg    char *im_modifier_name;
11851ab64890Smrg
11861ab64890Smrg    /* If already defined, just return */
11871ab64890Smrg
11881ab64890Smrg    if (IC_IscMode(ic)) return;
11891ab64890Smrg
11901ab64890Smrg    /* Get IM modifier */
11911ab64890Smrg
11921ab64890Smrg    im = (Xim) XIMOfIC((XIC)ic);
11931ab64890Smrg    im_modifier_name = im->core.im_name;
11941ab64890Smrg
11951ab64890Smrg    /* Match with predefined value, default is Basic Check */
11961ab64890Smrg
11971ab64890Smrg    if (!strncmp(im_modifier_name,"BasicCheck",MAXTHAIIMMODLEN+1))
11981ab64890Smrg	IC_IscMode(ic) = WTT_ISC1;
11991ab64890Smrg    else if (!strncmp(im_modifier_name,"Strict",MAXTHAIIMMODLEN+1))
12001ab64890Smrg	IC_IscMode(ic) = WTT_ISC2;
12011ab64890Smrg    else if (!strncmp(im_modifier_name,"Thaicat",MAXTHAIIMMODLEN+1))
12021ab64890Smrg	IC_IscMode(ic) = THAICAT_ISC;
12031ab64890Smrg    else if (!strncmp(im_modifier_name,"Passthrough",MAXTHAIIMMODLEN+1))
12041ab64890Smrg	IC_IscMode(ic) = NOISC;
12051ab64890Smrg    else
12061ab64890Smrg	IC_IscMode(ic) = WTT_ISC1;
12071ab64890Smrg
12081ab64890Smrg    return;
12091ab64890Smrg}
121061b2299dSmrg
12111ab64890Smrg/*
12121ab64890Smrg * Helper functions for _XimThaiFilter()
12131ab64890Smrg */
1214eb411b4bSmrgstatic Bool
12151ab64890SmrgThaiFltAcceptInput(Xic ic, unsigned char new_char, KeySym symbol)
12161ab64890Smrg{
12171ab64890Smrg    DefTreeBase *b = &ic->private.local.base;
12181ab64890Smrg    b->wc[b->tree[ic->private.local.composed].wc+0] = tis2ucs(new_char);
12191ab64890Smrg    b->wc[b->tree[ic->private.local.composed].wc+1] = '\0';
12201ab64890Smrg
12211ab64890Smrg    if ((new_char <= 0x1f) || (new_char == 0x7f))
12221ab64890Smrg        b->tree[ic->private.local.composed].keysym = symbol;
12231ab64890Smrg    else
12241ab64890Smrg        b->tree[ic->private.local.composed].keysym = NoSymbol;
12251ab64890Smrg
12261ab64890Smrg    return True;
12271ab64890Smrg}
12281ab64890Smrg
1229eb411b4bSmrgstatic Bool
12301ab64890SmrgThaiFltReorderInput(Xic ic, unsigned char previous_char, unsigned char new_char)
12311ab64890Smrg{
12321ab64890Smrg    DefTreeBase *b = &ic->private.local.base;
12331ab64890Smrg    if (!IC_DeletePreviousChar(ic)) return False;
12341ab64890Smrg    b->wc[b->tree[ic->private.local.composed].wc+0] = tis2ucs(new_char);
12351ab64890Smrg    b->wc[b->tree[ic->private.local.composed].wc+1] = tis2ucs(previous_char);
12361ab64890Smrg    b->wc[b->tree[ic->private.local.composed].wc+2] = '\0';
12371ab64890Smrg
12381ab64890Smrg    b->tree[ic->private.local.composed].keysym = NoSymbol;
12391ab64890Smrg
12401ab64890Smrg    return True;
12411ab64890Smrg}
12421ab64890Smrg
1243eb411b4bSmrgstatic Bool
12441ab64890SmrgThaiFltReplaceInput(Xic ic, unsigned char new_char, KeySym symbol)
12451ab64890Smrg{
12461ab64890Smrg    DefTreeBase *b = &ic->private.local.base;
12471ab64890Smrg    if (!IC_DeletePreviousChar(ic)) return False;
12481ab64890Smrg    b->wc[b->tree[ic->private.local.composed].wc+0] = tis2ucs(new_char);
12491ab64890Smrg    b->wc[b->tree[ic->private.local.composed].wc+1] = '\0';
12501ab64890Smrg
12511ab64890Smrg    if ((new_char <= 0x1f) || (new_char == 0x7f))
12521ab64890Smrg        b->tree[ic->private.local.composed].keysym = symbol;
12531ab64890Smrg    else
12541ab64890Smrg        b->tree[ic->private.local.composed].keysym = NoSymbol;
12551ab64890Smrg
12561ab64890Smrg    return True;
12571ab64890Smrg}
12581ab64890Smrg
1259eb411b4bSmrgstatic unsigned
12602e9c7c8cSmrgNumLockMask(Display *d)
12612e9c7c8cSmrg{
12622e9c7c8cSmrg    int i;
126357f47464Smrg    XModifierKeymap *map;
12642e9c7c8cSmrg    KeyCode numlock_keycode = XKeysymToKeycode (d, XK_Num_Lock);
12652e9c7c8cSmrg    if (numlock_keycode == NoSymbol)
12662e9c7c8cSmrg        return 0;
12672e9c7c8cSmrg
126857f47464Smrg    map = XGetModifierMapping (d);
126957f47464Smrg    if (!map)
127057f47464Smrg        return 0;
127157f47464Smrg
12722e9c7c8cSmrg    for (i = 0; i < 8; i++) {
127357f47464Smrg        if (map->modifiermap[map->max_keypermod * i] == numlock_keycode) {
127457f47464Smrg            XFreeModifiermap(map);
12752e9c7c8cSmrg            return 1 << i;
127657f47464Smrg        }
12772e9c7c8cSmrg    }
127857f47464Smrg    XFreeModifiermap(map);
12792e9c7c8cSmrg    return 0;
12802e9c7c8cSmrg}
12812e9c7c8cSmrg
12821ab64890Smrg/*
12831ab64890Smrg * Filter function for TACTIS
12841ab64890Smrg */
12851ab64890SmrgBool
128661b2299dSmrg_XimThaiFilter(Display *d, Window w, XEvent *ev, XPointer client_data)
12871ab64890Smrg{
12881ab64890Smrg    Xic		    ic = (Xic)client_data;
12891ab64890Smrg    KeySym 	    symbol;
12901ab64890Smrg    int 	    isc_mode; /* Thai Input Sequence Check mode */
12911ab64890Smrg    unsigned char   previous_char; /* Last inputted Thai char */
12921ab64890Smrg    unsigned char   new_char;
12931ab64890Smrg#ifdef UNUSED
12941ab64890Smrg    unsigned int    modifiers;
12951ab64890Smrg    KeySym	    lsym,usym;
12961ab64890Smrg    int		    state;
12971ab64890Smrg    XicThaiPart     *thai_part;
12981ab64890Smrg    char	    buf[10];
12991ab64890Smrg#endif
13001ab64890Smrg    wchar_t	    wbuf[10];
13011ab64890Smrg    Bool            isReject;
13021ab64890Smrg    DefTreeBase    *b = &ic->private.local.base;
13031ab64890Smrg
13041ab64890Smrg    if ((ev->type != KeyPress)
13051ab64890Smrg        || (ev->xkey.keycode == 0))
13061ab64890Smrg        return False;
13071ab64890Smrg
13081ab64890Smrg    if (!IC_IscMode(ic)) InitIscMode(ic);
13091ab64890Smrg
13101ab64890Smrg    XwcLookupString((XIC)ic, &ev->xkey, wbuf, sizeof(wbuf) / sizeof(wbuf[0]),
13111ab64890Smrg		    &symbol, NULL);
13121ab64890Smrg
13132e9c7c8cSmrg    if ((ev->xkey.state & (AllMods & ~(ShiftMask|LockMask|NumLockMask(d)))) ||
13141ab64890Smrg         ((symbol >> 8 == 0xFF) &&
13151ab64890Smrg         ((XK_BackSpace <= symbol && symbol <= XK_Clear) ||
13161ab64890Smrg           (symbol == XK_Return) ||
13171ab64890Smrg           (symbol == XK_Pause) ||
13181ab64890Smrg           (symbol == XK_Scroll_Lock) ||
13191ab64890Smrg           (symbol == XK_Sys_Req) ||
13201ab64890Smrg           (symbol == XK_Escape) ||
13211ab64890Smrg           (symbol == XK_Delete) ||
13221ab64890Smrg           IsCursorKey(symbol) ||
13231ab64890Smrg           IsKeypadKey(symbol) ||
13241ab64890Smrg           IsMiscFunctionKey(symbol) ||
13251ab64890Smrg           IsFunctionKey(symbol))))
13261ab64890Smrg        {
132761b2299dSmrg            IC_ClearPreviousChar(ic);
13281ab64890Smrg            return False;
13291ab64890Smrg        }
13301ab64890Smrg    if (((symbol >> 8 == 0xFF) &&
13311ab64890Smrg         IsModifierKey(symbol)) ||
13321ab64890Smrg#ifdef XK_XKB_KEYS
13331ab64890Smrg        ((symbol >> 8 == 0xFE) &&
13341ab64890Smrg         (XK_ISO_Lock <= symbol && symbol <= XK_ISO_Last_Group_Lock)) ||
13351ab64890Smrg#endif
13361ab64890Smrg        (symbol == NoSymbol))
13371ab64890Smrg    {
13381ab64890Smrg        return False;
13391ab64890Smrg    }
13401ab64890Smrg#ifdef UNUSED
13411ab64890Smrg    if (! XThaiTranslateKey(ev->xkey.display, ev->xkey.keycode, ev->xkey.state,
13421ab64890Smrg	 		&modifiers, &symbol, &lsym, &usym))
13431ab64890Smrg	return False;
13441ab64890Smrg
13451ab64890Smrg    /*
134661b2299dSmrg     *  Hex input method processing
13471ab64890Smrg     */
13481ab64890Smrg
13491ab64890Smrg    thai_part = &ic->private.local.thai;
13501ab64890Smrg    state = thai_part->comp_state;
13511ab64890Smrg    if (state >= 0 && state < nstate_handlers) /* call handler for state */
13521ab64890Smrg    {
13531ab64890Smrg        symbol = (* state_handler[state])(thai_part, symbol, (XKeyEvent *)ev);
13541ab64890Smrg    }
13551ab64890Smrg
13561ab64890Smrg    /*
13571ab64890Smrg     *  Translate KeySym into mb.
13581ab64890Smrg     */
13591ab64890Smrg    count = XThaiTranslateKeySym(ev->xkey.display, symbol, lsym,
13601ab64890Smrg				usym, ev->xkey.state, buf, 10);
13611ab64890Smrg
13621ab64890Smrg    if (!symbol && !count)
13631ab64890Smrg	return True;
13641ab64890Smrg
13651ab64890Smrg    /* Return symbol if cannot convert to character */
13661ab64890Smrg    if (!count)
13671ab64890Smrg	return False;
13681ab64890Smrg#endif
13691ab64890Smrg
13701ab64890Smrg    /*
13711ab64890Smrg     *  Thai Input sequence check
13721ab64890Smrg     */
13731ab64890Smrg    isc_mode = IC_IscMode(ic);
13741ab64890Smrg    if (!(previous_char = IC_GetPreviousChar(ic))) previous_char = ' ';
13751ab64890Smrg    new_char = ucs2tis(wbuf[0]);
13761ab64890Smrg    isReject = True;
13771ab64890Smrg    if (THAI_isaccepted(new_char, previous_char, isc_mode)) {
13781ab64890Smrg        ThaiFltAcceptInput(ic, new_char, symbol);
13791ab64890Smrg        isReject = False;
13801ab64890Smrg    } else {
13811ab64890Smrg        unsigned char context_char;
13821ab64890Smrg
13831ab64890Smrg        context_char = IC_GetContextChar(ic);
13841ab64890Smrg        if (context_char) {
13851ab64890Smrg            if (THAI_iscomposible(new_char, context_char)) {
13861ab64890Smrg                if (THAI_iscomposible(previous_char, new_char)) {
13871ab64890Smrg                    isReject = !ThaiFltReorderInput(ic, previous_char, new_char);
13881ab64890Smrg                } else if (THAI_iscomposible(previous_char, context_char)) {
13891ab64890Smrg                    isReject = !ThaiFltReplaceInput(ic, new_char, symbol);
13901ab64890Smrg                } else if (THAI_chtype(previous_char) == FV1
13911ab64890Smrg                           && THAI_chtype(new_char) == TONE) {
13921ab64890Smrg                    isReject = !ThaiFltReorderInput(ic, previous_char, new_char);
13931ab64890Smrg                }
13941ab64890Smrg            } else if (THAI_isaccepted(new_char, context_char, isc_mode)) {
13951ab64890Smrg                isReject = !ThaiFltReplaceInput(ic, new_char, symbol);
13961ab64890Smrg            }
13971ab64890Smrg        }
13981ab64890Smrg    }
13991ab64890Smrg    if (isReject) {
14001ab64890Smrg        /* reject character */
14011ab64890Smrg        XBell(ev->xkey.display, BellVolume);
14021ab64890Smrg        return True;
14031ab64890Smrg    }
14041ab64890Smrg
14051ab64890Smrg    _Xlcwcstombs(ic->core.im->core.lcd, &b->mb[b->tree[ic->private.local.composed].mb],
14061ab64890Smrg		 &b->wc[b->tree[ic->private.local.composed].wc], 10);
14071ab64890Smrg
14081ab64890Smrg    _Xlcmbstoutf8(ic->core.im->core.lcd, &b->utf8[b->tree[ic->private.local.composed].utf8],
14091ab64890Smrg		  &b->mb[b->tree[ic->private.local.composed].mb], 10);
14101ab64890Smrg
14111ab64890Smrg    /* Remember the last character inputted
14121ab64890Smrg     * (as fallback in case StringConversionCallback is not provided)
14131ab64890Smrg     */
14141ab64890Smrg    IC_SavePreviousChar(ic, new_char);
14151ab64890Smrg
14161ab64890Smrg    ev->xkey.keycode = 0;
14171ab64890Smrg    XPutBackEvent(d, ev);
14181ab64890Smrg    return True;
14191ab64890Smrg}
1420