1 /*
2 * Author: Yoichiro Ueno (ueno@cs.titech.ac.jp)
3 *
4 * Copyright (C) 1991, 1992, Yoichiro Ueno.
5 *
6 * Permission to use, copy, modify, and distribute this software and
7 * its documentation for any purpose is hereby granted by the Author without
8 * fee, provided that the above copyright notice appear in all copies and
9 * that both the copyright notice and this permission notice appear in
10 * supporting documentation, and that the name of the Author not be used
11 * in advertising or publicity pertaining to distribution of the software
12 * without specific, written prior permission. The Author makes no
13 * representations about the suitability of this software for any purpose.
14 * It is provided "as is" without express or implied warranty.
15 *
16 * THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
20 * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
21 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
22 * PERFORMANCE OF THIS SOFTWARE.
23 *
24 * @(#)$Header: /mm2/home/cvs/bc-src/tgif/convkinput.c,v 1.2 2009/09/28 22:39:48 william Exp $
25 */
26
27 #ifndef _NO_KINPUT
28
29 #define _INCLUDE_FROM_CONVKINPUT_C_
30
31 #include "tgifdefs.h"
32
33 #include "choice.e"
34 #include "convkinput.e"
35 #include "dialog.e"
36 #include "msg.e"
37 #include "strtbl.e"
38 #include "text.e"
39
40 /* from kinput2/include/ConvProto.h */
41 #define CONV_ATTR(code,len) ((unsigned long)((code)<<16)+(len))
42 #define CONVATTR_INDIRECT 1
43 #define CONVATTR_SPOT_LOCATION 3
44 #define CONVATTR_INPUT_STYLE 128
45 #define CONVARG_OVERTHESPOT 4L
46
47 #define CONV_OFF 0
48 #define WAIT_CONV_ON 1
49 #define CONV_ON 2
50 #define WAIT_CONV_OFF 3
51
52 #define KANJI0 0
53 #define KANJI1 1
54 #define KANJI2 2
55 #define KANJI3 3
56 #define KANJI4 4
57 #define KANJI5 5
58
59 #define LATIN 0
60 #define ESC 1
61 #define ESC_24 2
62 #define ESC_28 3
63 #define ESC_GL 4
64 #define ESC_GR 5
65 #define KANJI_GL 6
66 #define KANJI_GR 7
67
68 /* do not translate -- program constants */
69 #define KINPUT2_SELECTION "_JAPANESE_CONVERSION"
70 #define KINPUT_SELECTION "JAPANESE_CONVERSION"
71 #define TARGET "COMPOUND_TEXT"
72 #define CONV_REQUEST "CONVERSION_REQUEST"
73 #define CONV_NOTIFY "CONVERSION_NOTIFY"
74 #define CONV_END "CONVERSION_END"
75 #define CONV_END_REQ "CONVERSION_END_REQUEST"
76
77 static int conv_mode = CONV_OFF;
78 static Atom conv_selection = None;
79 static Window conv_owner_win = None;
80 static Atom conv_target = None;
81 static Atom conv_property = None;
82 static Atom conv_req = None;
83 static Atom conv_notify = None;
84 static Atom conv_end = None;
85 static Atom conv_end_req = None;
86
87 static Atom conv_attr = None;
88 static Atom conv_attr_notify = None;
89
90 static Window conv_win = None;
91
92 int imProtocol = IM_NONE;
93 int copyAndPasteJIS = FALSE;
94 char kinputConvSelName[MAXSTRING] = KINPUT2_SELECTION;
95
96 static int kinputConvOverSpot = 0;
97
KinputSetConvOverSpot(nConvOverSpot)98 void KinputSetConvOverSpot(nConvOverSpot)
99 int nConvOverSpot;
100 {
101 kinputConvOverSpot = nConvOverSpot;
102 }
103
104 /* for over-the-spot: from convlib.c in kinput2/client */
KinputTellCursorPosition(dpy,win,x,y)105 void KinputTellCursorPosition(dpy, win, x, y)
106 Display *dpy;
107 Window win;
108 int x, y;
109 {
110 Window owner_win;
111 char msg[80];
112 char * str1;
113 XClientMessageEvent xcme;
114 unsigned long data[4];
115 int len = 0;
116
117 if(imProtocol != IM_KINPUT)
118 return;
119
120 if (conv_attr == None || conv_attr_notify == None)
121 return;
122
123 #if 0
124 switch(conv_mode) {
125 case WAIT_CONV_ON :
126 Msg(TgLoadString(STID_WAIT_FOR_START_CONV));
127 return;
128 case WAIT_CONV_OFF :
129 case CONV_OFF :
130 return;
131 }
132 #endif
133
134 if((owner_win = XGetSelectionOwner(dpy, conv_selection))
135 == None) {
136 str1 = XGetAtomName(dpy, conv_selection);
137 sprintf(msg, TgLoadString(STID_NO_NAMED_SELECTION_OWNER), str1);
138 Msg(msg);
139 XFree(str1);
140 conv_owner_win = None;
141 conv_mode = CONV_OFF;
142 return;
143 }
144
145 if(conv_owner_win != owner_win)
146 return;
147
148 data[len++] = CONV_ATTR(CONVATTR_SPOT_LOCATION, 1);
149 data[len++] = (x << 16) | (y & 0xffff);
150
151 data[len++] = CONV_ATTR(CONVATTR_INPUT_STYLE, 1);
152 data[len++] = CONVARG_OVERTHESPOT;
153
154 XChangeProperty(dpy, win,
155 conv_attr, conv_attr, 32,
156 PropModeReplace, (unsigned char *)data, len);
157
158 xcme.type = ClientMessage;
159 xcme.display = dpy;
160 xcme.window = owner_win;
161 xcme.message_type = conv_attr_notify;
162 xcme.format = 32;
163 xcme.data.l[0] = conv_selection;
164 xcme.data.l[1] = win;
165 xcme.data.l[2] = CONV_ATTR(CONVATTR_INDIRECT, 1);
166 xcme.data.l[3] = conv_attr;
167 if (XSendEvent(dpy, owner_win, False, NoEventMask, (XEvent *)&xcme)
168 == 0) {
169 MsgBox(TgLoadString(STID_FAIL_TO_CHANGE_CONV_PROP), TOOL_NAME, INFO_MB);
170 return;
171 }
172 }
173
174 static
InternAtom(dpy,name)175 Atom InternAtom(dpy, name)
176 Display *dpy;
177 char * name;
178 {
179 Atom ret;
180 char msg[80];
181
182 if((ret = XInternAtom(dpy, name, False)) == None) {
183 sprintf(msg, TgLoadString(STID_FAIL_TO_INTERN_NAMED_ATOM),
184 name);
185 MsgBox(msg, TOOL_NAME, INFO_MB);
186 }
187
188 return ret;
189 }
190
KinputBeginConversion(dpy,win)191 void KinputBeginConversion (dpy, win)
192 Display *dpy;
193 Window win;
194 {
195 XClientMessageEvent xcme;
196 Window owner_win;
197 char msg[80];
198 char * str1;
199 int curX, curY;
200
201 if(imProtocol != IM_KINPUT)
202 return;
203
204 #ifdef DEBUG /* debug, do not translate */
205 fprintf(stderr, "KinputBeginConversion() : %d\n", conv_mode);
206 #endif
207 if(curChoice != DRAWTEXT || !textCursorShown)
208 return;
209
210 if(conv_selection == None &&
211 (conv_selection = InternAtom(dpy, kinputConvSelName)) == None)
212 return;
213
214 if(conv_target == None && (conv_target = InternAtom(dpy, TARGET)) == None)
215 return;
216
217 #if 1 /* which better? */
218 if(conv_mode == CONV_OFF)
219 #else
220 if(conv_mode != CONV_ON)
221 #endif
222 conv_property = None;
223
224 if(conv_req == None && (conv_req = InternAtom(dpy, CONV_REQUEST)) == None)
225 return;
226
227 if(conv_notify == None &&
228 (conv_notify = InternAtom(dpy, CONV_NOTIFY)) == None)
229 return;
230
231 if(conv_end == None && (conv_end = InternAtom(dpy, CONV_END)) == None)
232 return;
233
234 if(conv_end_req == None &&
235 (conv_end_req = InternAtom(dpy, CONV_END_REQ)) == None)
236 return;
237
238 if (kinputConvOverSpot) {
239 if(conv_attr == None &&
240 (conv_attr = InternAtom(dpy, "CONVERSION_ATTRIBUTE")) == None)
241 return;
242
243 if(conv_attr_notify == None &&
244 (conv_attr_notify = InternAtom(dpy, "CONVERSION_ATTRIBUTE_NOTIFY")) == None)
245 return;
246 }
247
248 if((owner_win = XGetSelectionOwner(dpy, conv_selection))
249 == None) {
250 str1 = XGetAtomName(dpy, conv_selection);
251 sprintf(msg, TgLoadString(STID_NO_NAMED_SELECTION_OWNER), str1);
252 MsgBox(msg, TOOL_NAME, INFO_MB);
253 XFree(str1);
254 conv_owner_win = None;
255 conv_mode = CONV_OFF;
256 #ifdef DEBUG /* debug, do not translate */
257 fprintf(stderr, "0x%08x\n", owner_win);
258 #endif
259 return;
260 }
261 #ifdef DEBUG /* debug, do not translate */
262 fprintf(stderr, "0x%08x\n", owner_win);
263 #endif
264
265 switch(conv_mode) {
266 case WAIT_CONV_ON :
267 Msg(TgLoadString(STID_WAIT_FOR_START_CONV));
268 return;
269 case CONV_ON :
270 if (conv_owner_win == owner_win)
271 return;
272 break;
273 }
274
275 xcme.type = ClientMessage;
276 xcme.display = dpy;
277 xcme.window = owner_win;
278 xcme.message_type = conv_req;
279 xcme.format = 32;
280 xcme.data.l[0] = conv_selection;
281 xcme.data.l[1] = win;
282 xcme.data.l[2] = conv_target;
283 xcme.data.l[3] = conv_property;
284 xcme.data.l[4] = conv_attr;
285 if(XSendEvent(dpy, owner_win, False, NoEventMask, (XEvent *)&xcme)
286 == 0) {
287 MsgBox(TgLoadString(STID_FAIL_TO_CONNECT_TO_OWNER), TOOL_NAME,
288 INFO_MB);
289 return;
290 }
291
292 conv_owner_win = owner_win;
293 conv_mode = WAIT_CONV_ON;
294
295 TellTextCursorPosition(&curX, &curY);
296 KinputTellCursorPosition(dpy, win, curX, curY);
297 }
298
KinputCheckClientMessage(dpy,win,xclient)299 void KinputCheckClientMessage (dpy, win, xclient)
300 Display *dpy;
301 Window win;
302 XClientMessageEvent * xclient;
303 {
304 if(imProtocol != IM_KINPUT)
305 return;
306
307 if(xclient->message_type == conv_notify) {
308 #ifdef DEBUG /* debug, do not translate */
309 fprintf(stderr, "KinputCheckClientMessage() : conv_notify : %d\n", conv_mode);
310 #endif
311 if( conv_mode != WAIT_CONV_ON ||
312 xclient->window != win ||
313 xclient->format != 32 ||
314 xclient->data.l[0] != conv_selection) {
315 return;
316 }
317 if( xclient->data.l[2] == None ||
318 xclient->data.l[1] != conv_target) {
319 conv_mode = CONV_OFF;
320 return;
321 }
322 conv_mode = CONV_ON;
323 conv_property = xclient->data.l[2];
324 conv_win = xclient->data.l[3];
325 }
326 else if(xclient->message_type == conv_end) {
327 #ifdef DEBUG /* debug, do not translate */
328 fprintf(stderr, "KinputCheckClientMessage() : conv_end : %d\n", conv_mode);
329 #endif
330 if((conv_mode != WAIT_CONV_OFF && conv_mode != CONV_ON) ||
331 xclient->window != win ||
332 xclient->format != 32 ||
333 xclient->data.l[0] != conv_selection ||
334 (xclient->data.l[1] != conv_owner_win &&
335 xclient->data.l[1] != conv_win)) {
336 return;
337 }
338 conv_mode = CONV_OFF;
339 }
340 }
341
CvtCompoundTextToEuc(dst,src)342 void CvtCompoundTextToEuc(dst, src)
343 register char * dst;
344 register char * src;
345 {
346 int status;
347
348 status = LATIN;
349
350 while(*src != '\0') {
351 switch(status) {
352 case LATIN :
353 if(*src == '\033')
354 status = ESC;
355 else
356 *dst++= *src;
357 break;
358 case ESC :
359 if(*src == '$')
360 status = ESC_24;
361 else if(*src == '(')
362 status = ESC_28;
363 else {
364 status = LATIN;
365 *dst++= *src;
366 }
367 break;
368 case ESC_28 :
369 if(*src == 'B' || *src == 'J') /* noda */
370 status = LATIN;
371 else {
372 status = LATIN;
373 *dst++= *src;
374 }
375 break;
376 case ESC_24 :
377 if(*src == '(')
378 status = ESC_GL;
379 else if(*src == ')')
380 status = ESC_GR;
381 else {
382 status = LATIN;
383 *dst++= *src;
384 }
385 break;
386 case ESC_GL :
387 if(*src == 'B' || *src == '@')
388 status = KANJI_GL;
389 else {
390 status = LATIN;
391 *dst++= *src;
392 }
393 break;
394 case ESC_GR :
395 if(*src == 'B' || *src == '@')
396 status = KANJI_GR;
397 else {
398 status = LATIN;
399 *dst++= *src;
400 }
401 break;
402 case KANJI_GL :
403 if(*src == '\033')
404 status = ESC;
405 else
406 if((*src & 0xff) < ' ')
407 *dst++= *src;
408 else
409 *dst++= (*src | 0x80);
410 break;
411 case KANJI_GR :
412 if(*src == '\033')
413 status = ESC;
414 else
415 *dst++= *src;
416 break;
417 default :
418 status = LATIN;
419 break;
420 }
421 src ++;
422 }
423
424 *dst = '\0';
425 }
426
427 static
CvtCompoundTextToEuc_N(src,items)428 char* CvtCompoundTextToEuc_N(src, items)
429 char * src;
430 int items;
431 {
432 char *dst;
433 if ((dst = (char *)malloc(sizeof(*src) * (items + 1))) != NULL) {
434 strncpy(dst, src, items);
435 dst[items] = '\0';
436 CvtCompoundTextToEuc(dst, dst);
437 return dst;
438 } else {
439 FailAllocMessage();
440 return NULL;
441 }
442 }
443
KinputCheckConvProperty(dpy,win,xprop)444 char* KinputCheckConvProperty (dpy, win, xprop)
445 Display *dpy;
446 Window win;
447 XPropertyEvent * xprop;
448 {
449 Atom act_target;
450 int act_format;
451 unsigned long nitems;
452 unsigned long remain_bytes;
453 unsigned char * data;
454 char * stmp;
455
456 if(imProtocol != IM_KINPUT)
457 return NULL;
458
459 if( xprop->window != win ||
460 xprop->atom != conv_property ||
461 xprop->state != PropertyNewValue ||
462 conv_mode != CONV_ON) {
463 return NULL;
464 }
465
466 if(XGetWindowProperty(dpy, win, conv_property,
467 0, MAXSTRING/sizeof(long),
468 True, conv_target, &act_target, &act_format,
469 &nitems, &remain_bytes, &data) != Success) {
470 MsgBox(TgLoadString(STID_FAIL_TO_GET_WIN_PROP), TOOL_NAME,
471 INFO_MB);
472 return NULL;
473 }
474 if (remain_bytes > 0)
475 XDeleteProperty(dpy, win, conv_property);
476
477 if(act_target == None || conv_target != act_target)
478 return NULL;
479 if(act_format != 8) {
480 XFree(data);
481 return NULL;
482 }
483
484 stmp = CvtCompoundTextToEuc_N((char*)data, nitems);
485
486 XFree(data);
487 return stmp;
488 }
489
KinputEndConversion(dpy,win)490 void KinputEndConversion (dpy, win)
491 Display *dpy;
492 Window win;
493 {
494 Window owner_win;
495 char msg[80];
496 char * str1;
497 XClientMessageEvent xcme;
498
499 if(imProtocol != IM_KINPUT)
500 return;
501
502 #ifdef DEBUG /* debug, do not translate */
503 fprintf(stderr, "KinputEndConversion() : %d\n", conv_mode);
504 #endif
505 switch(conv_mode) {
506 case WAIT_CONV_ON :
507 Msg(TgLoadString(STID_WAIT_FOR_START_CONV));
508 return;
509 case WAIT_CONV_OFF :
510 case CONV_OFF :
511 return;
512 }
513
514 if((owner_win = XGetSelectionOwner(dpy, conv_selection))
515 == None) {
516 str1 = XGetAtomName(dpy, conv_selection);
517 sprintf(msg, TgLoadString(STID_NO_NAMED_SELECTION_OWNER), str1);
518 MsgBox(msg, TOOL_NAME, INFO_MB);
519 XFree(str1);
520 conv_owner_win = None;
521 conv_mode = CONV_OFF;
522 #ifdef DEBUG /* debug, do not translate */
523 fprintf(stderr, "0x%08x\n", owner_win);
524 #endif
525 return;
526 }
527 #ifdef DEBUG /* debug, do not translate */
528 fprintf(stderr, "0x%08x\n", owner_win);
529 #endif
530
531 if(conv_owner_win != owner_win) {
532 conv_mode = CONV_OFF;
533 return;
534 }
535
536 xcme.type = ClientMessage;
537 xcme.display = dpy;
538 xcme.window = owner_win;
539 xcme.message_type = conv_end_req;
540 xcme.format = 32;
541 xcme.data.l[0] = conv_selection;
542 xcme.data.l[1] = win;
543 if(XSendEvent(dpy, owner_win, False, NoEventMask, (XEvent *)&xcme)
544 == 0) {
545 MsgBox(TgLoadString(STID_FAIL_TO_DISCONNECT_FROM_OWNER),
546 TOOL_NAME, INFO_MB);
547 conv_mode = CONV_OFF;
548 return;
549 }
550
551 conv_mode = WAIT_CONV_OFF;
552 }
553
CvtJisToEuc(dst,src)554 void CvtJisToEuc(dst, src)
555 register char * dst;
556 register char * src;
557 {
558 register int kanjiMode;
559 register int len;
560
561 kanjiMode = KANJI0;
562 len = 0;
563
564 while(*src != '\0') {
565 switch(kanjiMode) {
566 case KANJI0 :
567 if(*src == '\033')
568 kanjiMode = KANJI1;
569 else
570 *dst ++ = *src;
571 break;
572 case KANJI1 :
573 if(*src == '$')
574 kanjiMode = KANJI2;
575 else
576 kanjiMode = KANJI0;
577 break;
578 case KANJI2 :
579 if(*src == '@' || *src == 'B') {
580 len = 0;
581 kanjiMode = KANJI3;
582 }
583 else
584 kanjiMode = KANJI0;
585 break;
586 case KANJI3 :
587 if(*src == '\033')
588 kanjiMode = KANJI4;
589 else {
590 len ++;
591 if(*(src + 1) != '\033' || (len & 1) == 0)
592 *dst ++ = (*src | 0x80);
593 }
594 break;
595 case KANJI4 :
596 if(*src == '(')
597 kanjiMode = KANJI5;
598 else {
599 len = 0;
600 kanjiMode = KANJI3;
601 }
602 break;
603 case KANJI5 :
604 if(*src == 'J' || *src == 'B')
605 kanjiMode = KANJI0;
606 else {
607 len = 0;
608 kanjiMode = KANJI3;
609 }
610 break;
611 default :
612 break;
613 }
614 src ++;
615 }
616
617 *dst = '\0';
618 }
619
CvtEucToJis(dst,src)620 int CvtEucToJis(dst, src)
621 register char *dst;
622 register char *src;
623 {
624 int status;
625 int len;
626
627 status = LATIN;
628 len = 0;
629
630 while(*src != '\0') {
631 switch(status) {
632 case LATIN :
633 while((*src & 0x80) == 0 && *src != '\0') {
634 if(dst)
635 *dst ++ = *src;
636 src ++;
637 len ++;
638 }
639 status = KANJI_GR;
640 break;
641 case KANJI_GR :
642 if(dst) {
643 *dst ++ = '\033';
644 *dst ++ = '$';
645 *dst ++ = 'B';
646 }
647 len += 3;
648 while((*src & 0x80) == 0x80 && *src != '\0') {
649 if(dst)
650 *dst ++ = *src & 0x7f;
651 src ++;
652 len ++;
653 }
654 if(dst) {
655 *dst ++ = '\033';
656 *dst ++ = '(';
657 *dst ++ = 'B';
658 }
659 len += 3;
660 status = LATIN;
661 break;
662 default :
663 break;
664 }
665 }
666
667 if(dst)
668 *dst = '\0';
669
670 return len;
671 }
672
673 #endif /* ~_NO_KINPUT */
674
675