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