1 /* GTK - The GIMP Toolkit
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 2 of the License, or (at your option) any later version.
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the
15 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16 * Boston, MA 02111-1307, USA.
18 * Author: Theppitak Karoonboonyanan <thep@linux.thai.net>
24 #include <gdk/gdkkeysyms.h>
25 #include <gdk/gdkkeys.h>
26 #include "gtkimcontextthai.h"
27 #include "thai-charprop.h"
29 static void gtk_im_context_thai_class_init (GtkIMContextThaiClass *class);
30 static void gtk_im_context_thai_init (GtkIMContextThai *im_context_thai);
31 static gboolean gtk_im_context_thai_filter_keypress (GtkIMContext *context,
34 #ifndef GTK_IM_CONTEXT_THAI_NO_FALLBACK
35 static void forget_previous_chars (GtkIMContextThai *context_thai);
36 static void remember_previous_char (GtkIMContextThai *context_thai,
38 #endif /* !GTK_IM_CONTEXT_THAI_NO_FALLBACK */
40 static GObjectClass *parent_class;
42 GType gtk_type_im_context_thai = 0;
45 gtk_im_context_thai_register_type (GTypeModule *type_module)
47 static const GTypeInfo im_context_thai_info =
49 sizeof (GtkIMContextThaiClass),
51 (GBaseFinalizeFunc) NULL,
52 (GClassInitFunc) gtk_im_context_thai_class_init,
53 NULL, /* class_finalize */
54 NULL, /* class_data */
55 sizeof (GtkIMContextThai),
57 (GInstanceInitFunc) gtk_im_context_thai_init,
60 gtk_type_im_context_thai =
61 g_type_module_register_type (type_module,
64 &im_context_thai_info, 0);
68 gtk_im_context_thai_class_init (GtkIMContextThaiClass *class)
70 GtkIMContextClass *im_context_class = GTK_IM_CONTEXT_CLASS (class);
72 parent_class = g_type_class_peek_parent (class);
74 im_context_class->filter_keypress = gtk_im_context_thai_filter_keypress;
78 gtk_im_context_thai_init (GtkIMContextThai *context_thai)
80 #ifndef GTK_IM_CONTEXT_THAI_NO_FALLBACK
81 forget_previous_chars (context_thai);
82 #endif /* !GTK_IM_CONTEXT_THAI_NO_FALLBACK */
83 context_thai->isc_mode = ISC_BASICCHECK;
87 gtk_im_context_thai_new (void)
89 GtkIMContextThai *result;
91 result = GTK_IM_CONTEXT_THAI (g_object_new (GTK_TYPE_IM_CONTEXT_THAI, NULL));
93 return GTK_IM_CONTEXT (result);
96 GtkIMContextThaiISCMode
97 gtk_im_context_thai_get_isc_mode (GtkIMContextThai *context_thai)
99 return context_thai->isc_mode;
102 GtkIMContextThaiISCMode
103 gtk_im_context_thai_set_isc_mode (GtkIMContextThai *context_thai,
104 GtkIMContextThaiISCMode mode)
106 GtkIMContextThaiISCMode prev_mode = context_thai->isc_mode;
107 context_thai->isc_mode = mode;
112 is_context_lost_key(guint keyval)
114 return ((keyval & 0xFF00) == 0xFF00) &&
115 (keyval == GDK_BackSpace ||
117 keyval == GDK_Linefeed ||
118 keyval == GDK_Clear ||
119 keyval == GDK_Return ||
120 keyval == GDK_Pause ||
121 keyval == GDK_Scroll_Lock ||
122 keyval == GDK_Sys_Req ||
123 keyval == GDK_Escape ||
124 keyval == GDK_Delete ||
125 (GDK_Home <= keyval && keyval <= GDK_Begin) || /* IsCursorkey */
126 (GDK_KP_Space <= keyval && keyval <= GDK_KP_Equal) || /* IsKeypadKey */
127 (GDK_Select <= keyval && keyval <= GDK_Break) || /* IsMiscFunctionKey */
128 (GDK_F1 <= keyval && keyval <= GDK_F35)); /* IsFunctionKey */
132 is_context_intact_key(guint keyval)
134 return (((keyval & 0xFF00) == 0xFF00) &&
135 ((GDK_Shift_L <= keyval && keyval <= GDK_Hyper_R) || /* IsModifierKey */
136 (keyval == GDK_Mode_switch) ||
137 (keyval == GDK_Num_Lock))) ||
138 (((keyval & 0xFE00) == 0xFE00) &&
139 (GDK_ISO_Lock <= keyval && keyval <= GDK_ISO_Last_Group_Lock));
143 thai_is_accept (gunichar new_char, gunichar prev_char, gint isc_mode)
147 case ISC_PASSTHROUGH:
151 return TAC_compose_input (prev_char, new_char) != 'R';
155 int op = TAC_compose_input (prev_char, new_char);
156 return op != 'R' && op != 'S';
164 #define thai_is_composible(n,p) (TAC_compose_input ((p), (n)) == 'C')
166 #ifndef GTK_IM_CONTEXT_THAI_NO_FALLBACK
168 forget_previous_chars (GtkIMContextThai *context_thai)
170 memset (context_thai->char_buff, 0, sizeof (context_thai->char_buff));
174 remember_previous_char (GtkIMContextThai *context_thai, gunichar new_char)
176 memmove (context_thai->char_buff + 1, context_thai->char_buff,
177 (GTK_IM_CONTEXT_THAI_BUFF_SIZE - 1) * sizeof (context_thai->char_buff[0]));
178 context_thai->char_buff[0] = new_char;
180 #endif /* !GTK_IM_CONTEXT_THAI_NO_FALLBACK */
183 get_previous_char (GtkIMContextThai *context_thai, gint offset)
188 if (gtk_im_context_get_surrounding ((GtkIMContext *)context_thai,
189 &surrounding, &cursor_index))
195 p = surrounding + cursor_index;
196 for (q = p; offset < 0 && q > surrounding; ++offset)
197 q = g_utf8_prev_char (q);
200 prev_char = g_utf8_get_char_validated (q, p - q);
204 g_free (surrounding);
207 #ifndef GTK_IM_CONTEXT_THAI_NO_FALLBACK
210 offset = -offset - 1;
211 if (0 <= offset && offset < GTK_IM_CONTEXT_THAI_BUFF_SIZE)
212 return context_thai->char_buff[offset];
214 #endif /* !GTK_IM_CONTEXT_THAI_NO_FALLBACK */
220 gtk_im_context_thai_commit_chars (GtkIMContextThai *context_thai,
221 gunichar *s, gsize len)
225 utf8 = g_ucs4_to_utf8 (s, len, NULL, NULL, NULL);
229 g_signal_emit_by_name (context_thai, "commit", utf8);
236 accept_input (GtkIMContextThai *context_thai, gunichar new_char)
238 #ifndef GTK_IM_CONTEXT_THAI_NO_FALLBACK
239 remember_previous_char (context_thai, new_char);
240 #endif /* !GTK_IM_CONTEXT_THAI_NO_FALLBACK */
242 return gtk_im_context_thai_commit_chars (context_thai, &new_char, 1);
246 reorder_input (GtkIMContextThai *context_thai,
247 gunichar prev_char, gunichar new_char)
251 if (!gtk_im_context_delete_surrounding (GTK_IM_CONTEXT (context_thai), -1, 1))
254 #ifndef GTK_IM_CONTEXT_THAI_NO_FALLBACK
255 forget_previous_chars (context_thai);
256 remember_previous_char (context_thai, new_char);
257 remember_previous_char (context_thai, prev_char);
258 #endif /* !GTK_IM_CONTEXT_THAI_NO_FALLBACK */
262 return gtk_im_context_thai_commit_chars (context_thai, buf, 2);
266 replace_input (GtkIMContextThai *context_thai, gunichar new_char)
268 if (!gtk_im_context_delete_surrounding (GTK_IM_CONTEXT (context_thai), -1, 1))
271 #ifndef GTK_IM_CONTEXT_THAI_NO_FALLBACK
272 forget_previous_chars (context_thai);
273 remember_previous_char (context_thai, new_char);
274 #endif /* !GTK_IM_CONTEXT_THAI_NO_FALLBACK */
276 return gtk_im_context_thai_commit_chars (context_thai, &new_char, 1);
280 gtk_im_context_thai_filter_keypress (GtkIMContext *context,
283 GtkIMContextThai *context_thai = GTK_IM_CONTEXT_THAI (context);
284 gunichar prev_char, new_char;
286 GtkIMContextThaiISCMode isc_mode;
288 if (event->type != GDK_KEY_PRESS)
291 if (event->state & (GDK_MODIFIER_MASK & ~GDK_SHIFT_MASK) ||
292 is_context_lost_key (event->keyval))
294 #ifndef GTK_IM_CONTEXT_THAI_NO_FALLBACK
295 forget_previous_chars (context_thai);
296 #endif /* !GTK_IM_CONTEXT_THAI_NO_FALLBACK */
299 if (event->keyval == 0 || is_context_intact_key (event->keyval))
304 prev_char = get_previous_char (context_thai, -1);
307 new_char = gdk_keyval_to_unicode (event->keyval);
309 isc_mode = gtk_im_context_thai_get_isc_mode (context_thai);
310 if (thai_is_accept (new_char, prev_char, isc_mode))
312 accept_input (context_thai, new_char);
317 gunichar context_char;
319 /* rejected, trying to correct */
320 context_char = get_previous_char (context_thai, -2);
323 if (thai_is_composible (new_char, context_char))
325 if (thai_is_composible (prev_char, new_char))
326 is_reject = !reorder_input (context_thai, prev_char, new_char);
327 else if (thai_is_composible (prev_char, context_char))
328 is_reject = !replace_input (context_thai, new_char);
329 else if ((TAC_char_class (prev_char) == FV1
330 || TAC_char_class (prev_char) == AM)
331 && TAC_char_class (new_char) == TONE)
332 is_reject = !reorder_input (context_thai, prev_char, new_char);
334 else if (thai_is_accept (new_char, context_char, isc_mode))
335 is_reject = !replace_input (context_thai, new_char);
340 /* reject character */