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, see <http://www.gnu.org/licenses/>.
16 * Author: Theppitak Karoonboonyanan <thep@linux.thai.net>
22 #include <gdk/gdkkeysyms.h>
23 #include "gtkimcontextthai.h"
24 #include "thai-charprop.h"
26 static void gtk_im_context_thai_class_init (GtkIMContextThaiClass *class);
27 static void gtk_im_context_thai_init (GtkIMContextThai *im_context_thai);
28 static gboolean gtk_im_context_thai_filter_keypress (GtkIMContext *context,
31 #ifndef GTK_IM_CONTEXT_THAI_NO_FALLBACK
32 static void forget_previous_chars (GtkIMContextThai *context_thai);
33 static void remember_previous_char (GtkIMContextThai *context_thai,
35 #endif /* !GTK_IM_CONTEXT_THAI_NO_FALLBACK */
37 static GObjectClass *parent_class;
39 GType gtk_type_im_context_thai = 0;
42 gtk_im_context_thai_register_type (GTypeModule *type_module)
44 const GTypeInfo im_context_thai_info =
46 sizeof (GtkIMContextThaiClass),
48 (GBaseFinalizeFunc) NULL,
49 (GClassInitFunc) gtk_im_context_thai_class_init,
50 NULL, /* class_finalize */
51 NULL, /* class_data */
52 sizeof (GtkIMContextThai),
54 (GInstanceInitFunc) gtk_im_context_thai_init,
57 gtk_type_im_context_thai =
58 g_type_module_register_type (type_module,
61 &im_context_thai_info, 0);
65 gtk_im_context_thai_class_init (GtkIMContextThaiClass *class)
67 GtkIMContextClass *im_context_class = GTK_IM_CONTEXT_CLASS (class);
69 parent_class = g_type_class_peek_parent (class);
71 im_context_class->filter_keypress = gtk_im_context_thai_filter_keypress;
75 gtk_im_context_thai_init (GtkIMContextThai *context_thai)
77 #ifndef GTK_IM_CONTEXT_THAI_NO_FALLBACK
78 forget_previous_chars (context_thai);
79 #endif /* !GTK_IM_CONTEXT_THAI_NO_FALLBACK */
80 context_thai->isc_mode = ISC_BASICCHECK;
84 gtk_im_context_thai_new (void)
86 GtkIMContextThai *result;
88 result = GTK_IM_CONTEXT_THAI (g_object_new (GTK_TYPE_IM_CONTEXT_THAI, NULL));
90 return GTK_IM_CONTEXT (result);
93 GtkIMContextThaiISCMode
94 gtk_im_context_thai_get_isc_mode (GtkIMContextThai *context_thai)
96 return context_thai->isc_mode;
99 GtkIMContextThaiISCMode
100 gtk_im_context_thai_set_isc_mode (GtkIMContextThai *context_thai,
101 GtkIMContextThaiISCMode mode)
103 GtkIMContextThaiISCMode prev_mode = context_thai->isc_mode;
104 context_thai->isc_mode = mode;
109 is_context_lost_key(guint keyval)
111 return ((keyval & 0xFF00) == 0xFF00) &&
112 (keyval == GDK_KEY_BackSpace ||
113 keyval == GDK_KEY_Tab ||
114 keyval == GDK_KEY_Linefeed ||
115 keyval == GDK_KEY_Clear ||
116 keyval == GDK_KEY_Return ||
117 keyval == GDK_KEY_Pause ||
118 keyval == GDK_KEY_Scroll_Lock ||
119 keyval == GDK_KEY_Sys_Req ||
120 keyval == GDK_KEY_Escape ||
121 keyval == GDK_KEY_Delete ||
122 (GDK_KEY_Home <= keyval && keyval <= GDK_KEY_Begin) || /* IsCursorkey */
123 (GDK_KEY_KP_Space <= keyval && keyval <= GDK_KEY_KP_Delete) || /* IsKeypadKey, non-chars only */
124 (GDK_KEY_Select <= keyval && keyval <= GDK_KEY_Break) || /* IsMiscFunctionKey */
125 (GDK_KEY_F1 <= keyval && keyval <= GDK_KEY_F35)); /* IsFunctionKey */
129 is_context_intact_key(guint keyval)
131 return (((keyval & 0xFF00) == 0xFF00) &&
132 ((GDK_KEY_Shift_L <= keyval && keyval <= GDK_KEY_Hyper_R) || /* IsModifierKey */
133 (keyval == GDK_KEY_Mode_switch) ||
134 (keyval == GDK_KEY_Num_Lock))) ||
135 (((keyval & 0xFE00) == 0xFE00) &&
136 (GDK_KEY_ISO_Lock <= keyval && keyval <= GDK_KEY_ISO_Last_Group_Lock));
140 thai_is_accept (gunichar new_char, gunichar prev_char, gint isc_mode)
144 case ISC_PASSTHROUGH:
148 return TAC_compose_input (prev_char, new_char) != 'R';
152 int op = TAC_compose_input (prev_char, new_char);
153 return op != 'R' && op != 'S';
161 #define thai_is_composible(n,p) (TAC_compose_input ((p), (n)) == 'C')
163 #ifndef GTK_IM_CONTEXT_THAI_NO_FALLBACK
165 forget_previous_chars (GtkIMContextThai *context_thai)
167 memset (context_thai->char_buff, 0, sizeof (context_thai->char_buff));
171 remember_previous_char (GtkIMContextThai *context_thai, gunichar new_char)
173 memmove (context_thai->char_buff + 1, context_thai->char_buff,
174 (GTK_IM_CONTEXT_THAI_BUFF_SIZE - 1) * sizeof (context_thai->char_buff[0]));
175 context_thai->char_buff[0] = new_char;
177 #endif /* !GTK_IM_CONTEXT_THAI_NO_FALLBACK */
180 get_previous_char (GtkIMContextThai *context_thai, gint offset)
185 if (gtk_im_context_get_surrounding ((GtkIMContext *)context_thai,
186 &surrounding, &cursor_index))
192 p = surrounding + cursor_index;
193 for (q = p; offset < 0 && q > surrounding; ++offset)
194 q = g_utf8_prev_char (q);
197 prev_char = g_utf8_get_char_validated (q, p - q);
201 g_free (surrounding);
204 #ifndef GTK_IM_CONTEXT_THAI_NO_FALLBACK
207 offset = -offset - 1;
208 if (0 <= offset && offset < GTK_IM_CONTEXT_THAI_BUFF_SIZE)
209 return context_thai->char_buff[offset];
211 #endif /* !GTK_IM_CONTEXT_THAI_NO_FALLBACK */
217 gtk_im_context_thai_commit_chars (GtkIMContextThai *context_thai,
218 gunichar *s, gsize len)
222 utf8 = g_ucs4_to_utf8 (s, len, NULL, NULL, NULL);
226 g_signal_emit_by_name (context_thai, "commit", utf8);
233 accept_input (GtkIMContextThai *context_thai, gunichar new_char)
235 #ifndef GTK_IM_CONTEXT_THAI_NO_FALLBACK
236 remember_previous_char (context_thai, new_char);
237 #endif /* !GTK_IM_CONTEXT_THAI_NO_FALLBACK */
239 return gtk_im_context_thai_commit_chars (context_thai, &new_char, 1);
243 reorder_input (GtkIMContextThai *context_thai,
244 gunichar prev_char, gunichar new_char)
248 if (!gtk_im_context_delete_surrounding (GTK_IM_CONTEXT (context_thai), -1, 1))
251 #ifndef GTK_IM_CONTEXT_THAI_NO_FALLBACK
252 forget_previous_chars (context_thai);
253 remember_previous_char (context_thai, new_char);
254 remember_previous_char (context_thai, prev_char);
255 #endif /* !GTK_IM_CONTEXT_THAI_NO_FALLBACK */
259 return gtk_im_context_thai_commit_chars (context_thai, buf, 2);
263 replace_input (GtkIMContextThai *context_thai, gunichar new_char)
265 if (!gtk_im_context_delete_surrounding (GTK_IM_CONTEXT (context_thai), -1, 1))
268 #ifndef GTK_IM_CONTEXT_THAI_NO_FALLBACK
269 forget_previous_chars (context_thai);
270 remember_previous_char (context_thai, new_char);
271 #endif /* !GTK_IM_CONTEXT_THAI_NO_FALLBACK */
273 return gtk_im_context_thai_commit_chars (context_thai, &new_char, 1);
277 gtk_im_context_thai_filter_keypress (GtkIMContext *context,
280 GtkIMContextThai *context_thai = GTK_IM_CONTEXT_THAI (context);
281 gunichar prev_char, new_char;
283 GtkIMContextThaiISCMode isc_mode;
285 if (event->type != GDK_KEY_PRESS)
288 if (event->state & (GDK_MODIFIER_MASK
289 & ~(GDK_SHIFT_MASK | GDK_LOCK_MASK | GDK_MOD2_MASK)) ||
290 is_context_lost_key (event->keyval))
292 #ifndef GTK_IM_CONTEXT_THAI_NO_FALLBACK
293 forget_previous_chars (context_thai);
294 #endif /* !GTK_IM_CONTEXT_THAI_NO_FALLBACK */
297 if (event->keyval == 0 || is_context_intact_key (event->keyval))
302 prev_char = get_previous_char (context_thai, -1);
305 new_char = gdk_keyval_to_unicode (event->keyval);
307 isc_mode = gtk_im_context_thai_get_isc_mode (context_thai);
308 if (thai_is_accept (new_char, prev_char, isc_mode))
310 accept_input (context_thai, new_char);
315 gunichar context_char;
317 /* rejected, trying to correct */
318 context_char = get_previous_char (context_thai, -2);
321 if (thai_is_composible (new_char, context_char))
323 if (thai_is_composible (prev_char, new_char))
324 is_reject = !reorder_input (context_thai, prev_char, new_char);
325 else if (thai_is_composible (prev_char, context_char))
326 is_reject = !replace_input (context_thai, new_char);
327 else if ((TAC_char_class (prev_char) == FV1
328 || TAC_char_class (prev_char) == AM)
329 && TAC_char_class (new_char) == TONE)
330 is_reject = !reorder_input (context_thai, prev_char, new_char);
332 else if (thai_is_accept (new_char, context_char, isc_mode))
333 is_reject = !replace_input (context_thai, new_char);
338 /* reject character */