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 "gtkimcontextthai.h"
26 #include "thai-charprop.h"
28 static void gtk_im_context_thai_class_init (GtkIMContextThaiClass *class);
29 static void gtk_im_context_thai_init (GtkIMContextThai *im_context_thai);
30 static gboolean gtk_im_context_thai_filter_keypress (GtkIMContext *context,
33 #ifndef GTK_IM_CONTEXT_THAI_NO_FALLBACK
34 static void forget_previous_chars (GtkIMContextThai *context_thai);
35 static void remember_previous_char (GtkIMContextThai *context_thai,
37 #endif /* !GTK_IM_CONTEXT_THAI_NO_FALLBACK */
39 static GObjectClass *parent_class;
41 GType gtk_type_im_context_thai = 0;
44 gtk_im_context_thai_register_type (GTypeModule *type_module)
46 static const GTypeInfo im_context_thai_info =
48 sizeof (GtkIMContextThaiClass),
50 (GBaseFinalizeFunc) NULL,
51 (GClassInitFunc) gtk_im_context_thai_class_init,
52 NULL, /* class_finalize */
53 NULL, /* class_data */
54 sizeof (GtkIMContextThai),
56 (GInstanceInitFunc) gtk_im_context_thai_init,
59 gtk_type_im_context_thai =
60 g_type_module_register_type (type_module,
63 &im_context_thai_info, 0);
67 gtk_im_context_thai_class_init (GtkIMContextThaiClass *class)
69 GtkIMContextClass *im_context_class = GTK_IM_CONTEXT_CLASS (class);
71 parent_class = g_type_class_peek_parent (class);
73 im_context_class->filter_keypress = gtk_im_context_thai_filter_keypress;
77 gtk_im_context_thai_init (GtkIMContextThai *context_thai)
79 #ifndef GTK_IM_CONTEXT_THAI_NO_FALLBACK
80 forget_previous_chars (context_thai);
81 #endif /* !GTK_IM_CONTEXT_THAI_NO_FALLBACK */
82 context_thai->isc_mode = ISC_BASICCHECK;
86 gtk_im_context_thai_new (void)
88 GtkIMContextThai *result;
90 result = GTK_IM_CONTEXT_THAI (g_object_new (GTK_TYPE_IM_CONTEXT_THAI, NULL));
92 return GTK_IM_CONTEXT (result);
95 GtkIMContextThaiISCMode
96 gtk_im_context_thai_get_isc_mode (GtkIMContextThai *context_thai)
98 return context_thai->isc_mode;
101 GtkIMContextThaiISCMode
102 gtk_im_context_thai_set_isc_mode (GtkIMContextThai *context_thai,
103 GtkIMContextThaiISCMode mode)
105 GtkIMContextThaiISCMode prev_mode = context_thai->isc_mode;
106 context_thai->isc_mode = mode;
111 is_context_lost_key(guint keyval)
113 return ((keyval & 0xFF00) == 0xFF00) &&
114 (keyval == GDK_BackSpace ||
116 keyval == GDK_Linefeed ||
117 keyval == GDK_Clear ||
118 keyval == GDK_Return ||
119 keyval == GDK_Pause ||
120 keyval == GDK_Scroll_Lock ||
121 keyval == GDK_Sys_Req ||
122 keyval == GDK_Escape ||
123 keyval == GDK_Delete ||
124 (GDK_Home <= keyval && keyval <= GDK_Begin) || /* IsCursorkey */
125 (GDK_KP_Space <= keyval && keyval <= GDK_KP_Delete) || /* IsKeypadKey, non-chars only */
126 (GDK_Select <= keyval && keyval <= GDK_Break) || /* IsMiscFunctionKey */
127 (GDK_F1 <= keyval && keyval <= GDK_F35)); /* IsFunctionKey */
131 is_context_intact_key(guint keyval)
133 return (((keyval & 0xFF00) == 0xFF00) &&
134 ((GDK_Shift_L <= keyval && keyval <= GDK_Hyper_R) || /* IsModifierKey */
135 (keyval == GDK_Mode_switch) ||
136 (keyval == GDK_Num_Lock))) ||
137 (((keyval & 0xFE00) == 0xFE00) &&
138 (GDK_ISO_Lock <= keyval && keyval <= GDK_ISO_Last_Group_Lock));
142 thai_is_accept (gunichar new_char, gunichar prev_char, gint isc_mode)
146 case ISC_PASSTHROUGH:
150 return TAC_compose_input (prev_char, new_char) != 'R';
154 int op = TAC_compose_input (prev_char, new_char);
155 return op != 'R' && op != 'S';
163 #define thai_is_composible(n,p) (TAC_compose_input ((p), (n)) == 'C')
165 #ifndef GTK_IM_CONTEXT_THAI_NO_FALLBACK
167 forget_previous_chars (GtkIMContextThai *context_thai)
169 memset (context_thai->char_buff, 0, sizeof (context_thai->char_buff));
173 remember_previous_char (GtkIMContextThai *context_thai, gunichar new_char)
175 memmove (context_thai->char_buff + 1, context_thai->char_buff,
176 (GTK_IM_CONTEXT_THAI_BUFF_SIZE - 1) * sizeof (context_thai->char_buff[0]));
177 context_thai->char_buff[0] = new_char;
179 #endif /* !GTK_IM_CONTEXT_THAI_NO_FALLBACK */
182 get_previous_char (GtkIMContextThai *context_thai, gint offset)
187 if (gtk_im_context_get_surrounding ((GtkIMContext *)context_thai,
188 &surrounding, &cursor_index))
194 p = surrounding + cursor_index;
195 for (q = p; offset < 0 && q > surrounding; ++offset)
196 q = g_utf8_prev_char (q);
199 prev_char = g_utf8_get_char_validated (q, p - q);
203 g_free (surrounding);
206 #ifndef GTK_IM_CONTEXT_THAI_NO_FALLBACK
209 offset = -offset - 1;
210 if (0 <= offset && offset < GTK_IM_CONTEXT_THAI_BUFF_SIZE)
211 return context_thai->char_buff[offset];
213 #endif /* !GTK_IM_CONTEXT_THAI_NO_FALLBACK */
219 gtk_im_context_thai_commit_chars (GtkIMContextThai *context_thai,
220 gunichar *s, gsize len)
224 utf8 = g_ucs4_to_utf8 (s, len, NULL, NULL, NULL);
228 g_signal_emit_by_name (context_thai, "commit", utf8);
235 accept_input (GtkIMContextThai *context_thai, gunichar new_char)
237 #ifndef GTK_IM_CONTEXT_THAI_NO_FALLBACK
238 remember_previous_char (context_thai, new_char);
239 #endif /* !GTK_IM_CONTEXT_THAI_NO_FALLBACK */
241 return gtk_im_context_thai_commit_chars (context_thai, &new_char, 1);
245 reorder_input (GtkIMContextThai *context_thai,
246 gunichar prev_char, gunichar new_char)
250 if (!gtk_im_context_delete_surrounding (GTK_IM_CONTEXT (context_thai), -1, 1))
253 #ifndef GTK_IM_CONTEXT_THAI_NO_FALLBACK
254 forget_previous_chars (context_thai);
255 remember_previous_char (context_thai, new_char);
256 remember_previous_char (context_thai, prev_char);
257 #endif /* !GTK_IM_CONTEXT_THAI_NO_FALLBACK */
261 return gtk_im_context_thai_commit_chars (context_thai, buf, 2);
265 replace_input (GtkIMContextThai *context_thai, gunichar new_char)
267 if (!gtk_im_context_delete_surrounding (GTK_IM_CONTEXT (context_thai), -1, 1))
270 #ifndef GTK_IM_CONTEXT_THAI_NO_FALLBACK
271 forget_previous_chars (context_thai);
272 remember_previous_char (context_thai, new_char);
273 #endif /* !GTK_IM_CONTEXT_THAI_NO_FALLBACK */
275 return gtk_im_context_thai_commit_chars (context_thai, &new_char, 1);
279 gtk_im_context_thai_filter_keypress (GtkIMContext *context,
282 GtkIMContextThai *context_thai = GTK_IM_CONTEXT_THAI (context);
283 gunichar prev_char, new_char;
285 GtkIMContextThaiISCMode isc_mode;
287 if (event->type != GDK_KEY_PRESS)
290 if (event->state & (GDK_MODIFIER_MASK
291 & ~(GDK_SHIFT_MASK | GDK_LOCK_MASK | GDK_MOD2_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 */