1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2 -*- */
2 /* IM-JA Japanese Input Method Module for GTK-2.0
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 *
19 * Authors: Botond Botyanszki <boti@rocketmail.com>
20 *
21 */
22
23 #include <stdio.h>
24 #include <string.h>
25 #include <gtk/gtk.h>
26 #include <gdk/gdkkeysyms.h>
27
28
29 #include "im-ja.h"
30 #include "im-ja-impl.h"
31 #include "error.h"
32 #include "common.h"
33 #include "romakana.h"
34 #include "hiragana-convtable.h"
35 #include "zenkaku-convtable.h"
36 #include "halfkata-convtable.h"
37
38 extern IMJAConfig cfg;
39
40 /* * * * * * * * * * * * * * * * */
41
im_ja_kana_convert_tailing_n(IMJAContext * cn)42 gboolean im_ja_kana_convert_tailing_n(IMJAContext *cn) {
43 if (strlen(cn->preedit_buf) == 0) return FALSE;
44 if (cn->preedit_buf[strlen(cn->preedit_buf) - 1] == 'n') {
45 cn->preedit_buf[strlen(cn->preedit_buf) - 1] = 0;
46 switch (cn->input_method) {
47 case IM_JA_HIRAGANA_INPUT:
48 g_strlcat(cn->preedit_buf, "\xE3\x82\x93", BUFFERSIZE);
49 break;
50 case IM_JA_KATAKANA_INPUT:
51 g_strlcat(cn->preedit_buf, "\xE3\x83\xB3", BUFFERSIZE);
52 break;
53 case IM_JA_HALFKATA_INPUT:
54 g_strlcat(cn->preedit_buf, "\xEF\xBE\x9D", BUFFERSIZE);
55 break;
56 }
57 return TRUE;
58 }
59 return FALSE;
60 }
61
62
im_ja_kana_commit_converted(IMJAContext * cn,gchar * kanastr)63 void im_ja_kana_commit_converted(IMJAContext *cn, gchar *kanastr) {
64 gchar *lastkana;
65
66 /* Find any converted char */
67 if (strlen(kanastr) == 0) return;
68 lastkana = kanastr + strlen(kanastr);
69
70 while (isJPChar(g_utf8_get_char(g_utf8_prev_char(lastkana))) == FALSE) {
71 lastkana = g_utf8_prev_char(lastkana);
72 if (lastkana == kanastr) break;
73 }
74
75 /* IM_JA_DEBUG("lastkana: %s, kanastr: %s\n", lastkana, kanastr); */
76
77 if (lastkana == kanastr + strlen(kanastr)) {
78 g_strlcpy(cn->preedit_buf, kanastr, BUFFERSIZE);
79 im_ja_commit(cn);
80 im_ja_context_reset(cn);
81 }
82 else {
83 if (lastkana != kanastr) {
84 g_strlcpy(cn->preedit_buf, kanastr, BUFFERSIZE);
85 cn->preedit_buf[lastkana - kanastr] = 0;
86 im_ja_commit(cn);
87 }
88 /* copy new string back to preedit buffer */
89 g_strlcpy(cn->preedit_buf, lastkana, BUFFERSIZE);
90 cn->cursor_char_pos = g_utf8_strlen(cn->preedit_buf, -1);
91 *lastkana = 0;
92 }
93 }
94
95
im_ja_kana_filter_keypress(IMJAContext * cn,GdkEventKey * key)96 gboolean im_ja_kana_filter_keypress(IMJAContext *cn, GdkEventKey *key) {
97 gchar *tmpstr;
98
99 if (key->type == GDK_KEY_RELEASE) {
100 return FALSE;
101 }
102 if (key->keyval == GDK_space) {
103 /* g_strlcat(cn->preedit_buf, " ", BUFFERSIZE); */
104 gtk_im_context_reset(GTK_IM_CONTEXT(cn));
105 g_strlcat(cn->preedit_buf, " ", BUFFERSIZE);
106 im_ja_commit(cn); /* Insert a space */
107 /* FIXME: maybe this should be zenkaku space //ascii & unicode zenkaku diff: 65248 */
108 return TRUE;
109 }
110
111 if (key->keyval == GDK_BackSpace) {
112 if (strlen(cn->preedit_buf) > 0) {
113 buffer_delchar(cn->preedit_buf);
114 im_ja_preedit_changed(cn);
115 return TRUE;
116 }
117 return FALSE;
118 }
119
120 if ((key->keyval == GDK_Return) || (ishotkey(key, COMMIT_PREEDIT, &cfg) == TRUE)) {
121 if (strlen(cn->preedit_buf) == 0) return FALSE;
122 im_ja_kana_convert_tailing_n(cn);
123 if (g_utf8_validate(cn->preedit_buf, -1, NULL) != TRUE) {
124 printf("Cannot commit. utf8_validate failed: %s\n", cn->preedit_buf);
125 }
126 else im_ja_commit(cn);
127 im_ja_on_reset(cn);
128 return TRUE;
129 }
130
131 if (im_ja_is_printable_key(key) == TRUE) {
132 gchar utf8strg[7];
133 gchar *tmpeuc;
134 int utf8strg_end;
135
136 utf8strg_end = g_unichar_to_utf8(gdk_keyval_to_unicode(key->keyval), utf8strg);
137 utf8strg[utf8strg_end] = 0;
138 tmpeuc = utf82euc(utf8strg);
139 if ((unsigned int)tmpeuc[0] > 128) {
140 g_free(tmpeuc);
141 IM_JA_DEBUG("*ERROR* non-ascii input\n");
142 im_ja_input_utf8(cn, utf8strg);
143 return TRUE;
144 }
145 g_free(tmpeuc);
146
147 g_strlcat(cn->preedit_buf, utf8strg, BUFFERSIZE);
148
149 tmpstr = roma2kana(cn->preedit_buf, cn->input_method);
150 IM_JA_DEBUG("converted \"%s\" to \"%s\"\n", cn->preedit_buf, tmpstr);
151 im_ja_kana_commit_converted(cn, tmpstr);
152 g_free(tmpstr);
153
154 if (g_utf8_validate(cn->preedit_buf, -1, NULL) != TRUE) {
155 printf("utf8_validate failed: %s\n", cn->preedit_buf);
156 }
157 im_ja_preedit_changed(cn);
158 return TRUE;
159 }
160
161 return FALSE;
162 }
163
g_strrncmp(gchar * s1,size_t s1len,gchar * s2,size_t s2len)164 int g_strrncmp(gchar* s1, size_t s1len, gchar* s2, size_t s2len) {
165
166 if( s1len > s2len ) s1 += s1len-s2len;
167 return strncmp(s1, s2, s2len);
168 }
169
170
171 /* Convert romaji to kana. Returns the kana string */
roma2kana(gchar * romastr,gint input_method)172 gchar *roma2kana(gchar *romastr, gint input_method) {
173 gchar *result = NULL;
174 gchar *tmpstr = NULL;
175 romapair *romatable = NULL;
176 gint i = 0, s1len, s2len;
177
178 if (romastr == NULL) return NULL;
179 if (*romastr == '\0') return NULL;
180
181 s1len = strlen(romastr);
182
183 switch (input_method) {
184 case IM_JA_HIRAGANA_INPUT:
185 case IM_JA_KATAKANA_INPUT:
186 romatable = hiraganatable;
187 break;
188 case IM_JA_HALFKATA_INPUT:
189 romatable = halfkatatable;
190 break;
191 case IM_JA_ZENKAKU_INPUT:
192 romatable = zenkakutable;
193 break;
194 }
195
196 for (i = 0; ; i++) {
197 romapair rp = romatable[i];
198 if (rp.kana[0] == '0' && rp.roma[0] == '0') break;
199 s2len = strlen(rp.roma);
200 /* Compare end of input and string in kana table */
201 if (g_strrncmp(romastr, s1len, rp.roma, s2len) == 0) {
202 result = g_new0(gchar, BUFFERSIZE);
203 strncat(result, romastr, s1len - s2len);
204 g_strlcat(result, rp.kana, BUFFERSIZE);
205
206 if (input_method == IM_JA_KATAKANA_INPUT) {
207 tmpstr = result;
208 result = hira2kata(tmpstr);
209 g_free(tmpstr);
210 }
211 return result;
212 }
213 }
214 return g_strdup(romastr); /* no change */
215 }
216
roma2kana_i(gchar * romastr,gint * index,gint input_method)217 gchar *roma2kana_i(gchar *romastr, gint *index, gint input_method)
218 {
219 gchar *result = NULL;
220 gchar *tmpstr = NULL;
221 gint i = 0,s1len,s2len;
222 romapair *romatable = NULL;
223
224 if (romastr == NULL)
225 return NULL;
226
227 result = g_new0(gchar, BUFFERSIZE);
228
229 if (*romastr == '\0')
230 return result;
231
232 s1len = *index;
233
234 switch (input_method) {
235 case IM_JA_HIRAGANA_INPUT:
236 case IM_JA_KATAKANA_INPUT:
237 romatable = hiraganatable;
238 break;
239 case IM_JA_HALFKATA_INPUT:
240 romatable = halfkatatable;
241 break;
242 case IM_JA_ZENKAKU_INPUT:
243 romatable = zenkakutable;
244 break;
245 }
246
247 for (i = 0; ; i++)
248 {
249 romapair rp = romatable[i];
250 if (rp.kana[0] == '0' && rp.roma[0] == '0')
251 break;
252
253 s2len = strlen(rp.roma);
254
255 /* Compare offset of input and string in kana table */
256 if(g_strrncmp(romastr, s1len, rp.roma,s2len) == 0 )
257 {
258 *index += strlen(rp.kana) - s2len;
259 strncat(result, romastr, s1len - s2len );
260 g_strlcat(result, rp.kana, BUFFERSIZE);
261 g_strlcat(result, romastr+s1len, BUFFERSIZE);
262 if (input_method == IM_JA_KATAKANA_INPUT) {
263 tmpstr = result;
264 result = hira2kata(tmpstr);
265 g_free(tmpstr);
266 }
267 return result;
268 }
269 }
270
271 /* no change */
272 g_strlcat(result, romastr, BUFFERSIZE);
273 return result;
274 }
275
276
roma2kana_i_lastpass(gchar * romastr,gint * index,gint input_method)277 gchar *roma2kana_i_lastpass(gchar *romastr, gint *index, gint input_method)
278 /* IMHO the cursor position change should be done in canna_rk.c
279 depending on the return value of this function. See e.g
280 im_ja_wnn_convert_tailing_n() or im_ja_kana_convert_tailing_n()
281 */
282 {
283 gchar *result = NULL;
284 gchar *subst_str = NULL;
285 gchar *pattern="n";
286 gint s1len;
287
288 if (romastr == NULL)
289 return NULL;
290
291 result = g_new0(gchar, BUFFERSIZE);
292
293 if (*romastr == '\0')
294 return result;
295
296 s1len = *index;
297
298 switch (input_method) {
299 case IM_JA_HIRAGANA_INPUT:
300 subst_str = "\xE3\x82\x93";
301 break;
302 case IM_JA_KATAKANA_INPUT:
303 subst_str = "\xE3\x83\xB3";
304 break;
305 case IM_JA_HALFKATA_INPUT:
306 subst_str = "\xEF\xBE\x9D";
307 break;
308 }
309
310 /* Compare offset of input and string in kana table */
311 if(g_strrncmp(romastr, s1len, pattern, 1) == 0 )
312 {
313 *index += 3 - 1;
314 strncat(result, romastr, s1len - 1 );
315 g_strlcat(result, subst_str, BUFFERSIZE);
316 g_strlcat(result, romastr+s1len, BUFFERSIZE);
317 return result;
318 }
319
320 /* no change */
321 g_strlcat(result, romastr, BUFFERSIZE);
322 return result;
323 }
324
325