1 /******************************************************************
2
3 Copyright 1994, 1995 by Sun Microsystems, Inc.
4 Copyright 1993, 1994 by Hewlett-Packard Company
5
6 Permission to use, copy, modify, distribute, and sell this software
7 and its documentation for any purpose is hereby granted without fee,
8 provided that the above copyright notice appear in all copies and
9 that both that copyright notice and this permission notice appear
10 in supporting documentation, and that the name of Sun Microsystems, Inc.
11 and Hewlett-Packard not be used in advertising or publicity pertaining to
12 distribution of the software without specific, written prior permission.
13 Sun Microsystems, Inc. and Hewlett-Packard make no representations about
14 the suitability of this software for any purpose. It is provided "as is"
15 without express or implied warranty.
16
17 SUN MICROSYSTEMS INC. AND HEWLETT-PACKARD COMPANY DISCLAIMS ALL
18 WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
19 WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
20 SUN MICROSYSTEMS, INC. AND HEWLETT-PACKARD COMPANY BE LIABLE FOR ANY
21 SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
22 RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
23 CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
24 IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
25
26 Author: Hidetoshi Tajima(tajima@Eng.Sun.COM) Sun Microsystems, Inc.
27
28 ******************************************************************/
29 #include <stdio.h>
30 #include <X11/Xlocale.h>
31 #include <X11/Xlib.h>
32 #include <X11/Xutil.h>
33 #include <X11/keysym.h>
34 #include <X11/Ximd/IMdkit.h>
35 #include <X11/Ximd/Xi18n.h>
36
37 #define DEFAULT_IMNAME "sampleIM"
38 #define DEFAULT_LOCALE "zh_TW,ja_JP"
39
40 /* flags for debugging */
41 Bool use_trigger = True; /* Dynamic Event Flow is default */
42 Bool use_offkey = False; /* Register OFF Key for Dynamic Event Flow */
43 Bool use_tcp = False; /* Using TCP/IP Transport or not */
44 Bool use_local = False; /* Using Unix domain Tranport or not */
45 long filter_mask = KeyPressMask;
46
47 /* Supported Inputstyles */
48 static XIMStyle Styles[] = {
49 XIMPreeditCallbacks|XIMStatusCallbacks,
50 XIMPreeditPosition|XIMStatusArea,
51 XIMPreeditPosition|XIMStatusNothing,
52 XIMPreeditArea|XIMStatusArea,
53 XIMPreeditNothing|XIMStatusNothing,
54 0
55 };
56
57 /* Trigger Keys List */
58 static XIMTriggerKey Trigger_Keys[] = {
59 {XK_space, ShiftMask, ShiftMask},
60 {0L, 0L, 0L}
61 };
62
63 /* Conversion Keys List */
64 static XIMTriggerKey Conversion_Keys[] = {
65 {XK_k, ControlMask, ControlMask},
66 {0L, 0L, 0L}
67 };
68
69 /* Forward Keys List */
70 static XIMTriggerKey Forward_Keys[] = {
71 {XK_Return, 0, 0},
72 {XK_Tab, 0, 0},
73 {0L, 0L, 0L}
74 };
75
76 /* Supported Taiwanese Encodings */
77 static XIMEncoding zhEncodings[] = {
78 "COMPOUND_TEXT",
79 NULL
80 };
81
MyGetICValuesHandler(ims,call_data)82 MyGetICValuesHandler(ims, call_data)
83 XIMS ims;
84 IMChangeICStruct *call_data;
85 {
86 GetIC(call_data);
87 return True;
88 }
89
MySetICValuesHandler(ims,call_data)90 MySetICValuesHandler(ims, call_data)
91 XIMS ims;
92 IMChangeICStruct *call_data;
93 {
94 SetIC(call_data);
95 return True;
96 }
97
MyOpenHandler(ims,call_data)98 MyOpenHandler(ims, call_data)
99 XIMS ims;
100 IMOpenStruct *call_data;
101 {
102 #ifdef DEBUG
103 printf("new_client lang = %s\n", call_data->lang.name);
104 printf(" connect_id = 0x%x\n", (int)call_data->connect_id);
105 #endif
106 return True;
107 }
108
MyCloseHandler(ims,call_data)109 MyCloseHandler(ims, call_data)
110 XIMS ims;
111 IMOpenStruct *call_data;
112 {
113 #ifdef DEBUG
114 printf("closing connect_id 0x%x\n", (int)call_data->connect_id);
115 #endif
116 return True;
117 }
118
MyCreateICHandler(ims,call_data)119 MyCreateICHandler(ims, call_data)
120 XIMS ims;
121 IMChangeICStruct *call_data;
122 {
123 CreateIC(call_data);
124 return True;
125 }
126
MyDestroyICHandler(ims,call_data)127 MyDestroyICHandler(ims, call_data)
128 XIMS ims;
129 IMChangeICStruct *call_data;
130 {
131 DestroyIC(call_data);
132 return True;
133 }
134
135 #define STRBUFLEN 64
IsKey(ims,call_data,trigger)136 IsKey(ims, call_data, trigger)
137 XIMS ims;
138 IMForwardEventStruct *call_data;
139 XIMTriggerKey *trigger; /* Searching for these keys */
140 {
141 char strbuf[STRBUFLEN];
142 KeySym keysym;
143 int i;
144 int modifier;
145 int modifier_mask;
146 XKeyEvent *kev;
147
148 memset(strbuf, 0, STRBUFLEN);
149 kev = (XKeyEvent*)&call_data->event;
150 XLookupString(kev, strbuf, STRBUFLEN, &keysym, NULL);
151
152 for (i = 0; trigger[i].keysym != 0; i++) {
153 modifier = trigger[i].modifier;
154 modifier_mask = trigger[i].modifier_mask;
155 if (((KeySym)trigger[i].keysym == keysym)
156 && ((kev->state & modifier_mask) == modifier))
157 return True;
158 }
159 return False;
160 }
161
ProcessKey(ims,call_data)162 ProcessKey(ims, call_data)
163 XIMS ims;
164 IMForwardEventStruct *call_data;
165 {
166 char strbuf[STRBUFLEN];
167 KeySym keysym;
168 XKeyEvent *kev;
169 int count;
170
171 fprintf(stderr, "Processing \n");
172 memset(strbuf, 0, STRBUFLEN);
173 kev = (XKeyEvent*)&call_data->event;
174 count = XLookupString(kev, strbuf, STRBUFLEN, &keysym, NULL);
175
176 if (count > 0) {
177 fprintf(stdout, "[%s] ", strbuf);
178 }
179 }
180
MyForwardEventHandler(ims,call_data)181 MyForwardEventHandler(ims, call_data)
182 XIMS ims;
183 IMForwardEventStruct *call_data;
184 {
185 /* Lookup KeyPress Events only */
186 fprintf(stderr, "ForwardEventHandler\n");
187 if (call_data->event.type != KeyPress) {
188 fprintf(stderr, "bogus event type, ignored\n");
189 return True;
190 }
191
192 /* In case of Static Event Flow */
193 if (!use_trigger) {
194 static Bool preedit_state_flag = False;
195 if (IsKey(ims, call_data, Trigger_Keys)) {
196 preedit_state_flag = !preedit_state_flag;
197 return True;
198 }
199 }
200
201 /* In case of Dynamic Event Flow without registering OFF keys,
202 the end of preediting must be notified from IMserver to
203 IMlibrary. */
204 if (use_trigger && !use_offkey) {
205 if (IsKey(ims, call_data, Trigger_Keys)) {
206 return IMPreeditEnd(ims, (XPointer)call_data);
207 }
208 }
209 if (IsKey(ims, call_data, Conversion_Keys)) {
210 XTextProperty tp;
211 Display *display = ims->core.display;
212 /* char *text = "�o�O�@�� IM ���A��������"; */
213 char *text = "���üy";
214 char **list_return; /* [20]; */
215 int count_return; /* [20]; */
216
217 fprintf(stderr, "matching ctrl-k...\n");
218 XmbTextListToTextProperty(display, (char **)&text, 1,
219 XCompoundTextStyle,
220 &tp);
221
222 ((IMCommitStruct*)call_data)->flag |= XimLookupChars;
223 ((IMCommitStruct*)call_data)->commit_string = (char *)tp.value;
224 fprintf(stderr, "commiting string...(%s)\n", tp.value);
225 IMCommitString(ims, (XPointer)call_data);
226 #if 0
227 XmbTextPropertyToTextList(display, &tp, &list_return, &count_return);
228 fprintf(stderr, "converted back: %s\n", *list_return);
229 #endif
230 XFree(tp.value);
231 fprintf(stderr, "survived so far..\n");
232 }
233 else if (IsKey(ims, call_data, Forward_Keys)) {
234 IMForwardEventStruct forward_ev = *((IMForwardEventStruct *)call_data);
235
236 fprintf(stderr, "TAB and RETURN forwarded...\n");
237 IMForwardEvent(ims, (XPointer)&forward_ev);
238 } else {
239 ProcessKey(ims, call_data);
240 }
241 return True;
242 }
243
MyTriggerNotifyHandler(ims,call_data)244 MyTriggerNotifyHandler(ims, call_data)
245 XIMS ims;
246 IMTriggerNotifyStruct *call_data;
247 {
248 if (call_data->flag == 0) { /* on key */
249 /* Here, the start of preediting is notified from IMlibrary, which
250 is the only way to start preediting in case of Dynamic Event
251 Flow, because ON key is mandatary for Dynamic Event Flow. */
252 return True;
253 } else if (use_offkey && call_data->flag == 1) { /* off key */
254 /* Here, the end of preediting is notified from the IMlibrary, which
255 happens only if OFF key, which is optional for Dynamic Event Flow,
256 has been registered by IMOpenIM or IMSetIMValues, otherwise,
257 the end of preediting must be notified from the IMserver to the
258 IMlibrary. */
259 return True;
260 } else {
261 /* never happens */
262 return False;
263 }
264 }
265
MyPreeditStartReplyHandler(ims,call_data)266 MyPreeditStartReplyHandler(ims, call_data)
267 XIMS ims;
268 IMPreeditCBStruct *call_data;
269 {
270 }
271
MyPreeditCaretReplyHandler(ims,call_data)272 MyPreeditCaretReplyHandler(ims, call_data)
273 XIMS ims;
274 IMPreeditCBStruct *call_data;
275 {
276 }
277
MyProtoHandler(ims,call_data)278 MyProtoHandler(ims, call_data)
279 XIMS ims;
280 IMProtocol *call_data;
281 {
282 switch (call_data->major_code) {
283 case XIM_OPEN:
284 fprintf(stderr, "XIM_OPEN:\n");
285 return MyOpenHandler(ims, call_data);
286 case XIM_CLOSE:
287 fprintf(stderr, "XIM_CLOSE:\n");
288 return MyCloseHandler(ims, call_data);
289 case XIM_CREATE_IC:
290 fprintf(stderr, "XIM_CREATE_IC:\n");
291 return MyCreateICHandler(ims, call_data);
292 case XIM_DESTROY_IC:
293 fprintf(stderr, "XIM_DESTROY_IC.\n");
294 return MyDestroyICHandler(ims, call_data);
295 case XIM_SET_IC_VALUES:
296 fprintf(stderr, "XIM_SET_IC_VALUES:\n");
297 return MySetICValuesHandler(ims, call_data);
298 case XIM_GET_IC_VALUES:
299 fprintf(stderr, "XIM_GET_IC_VALUES:\n");
300 return MyGetICValuesHandler(ims, call_data);
301 case XIM_FORWARD_EVENT:
302 return MyForwardEventHandler(ims, call_data);
303 case XIM_SET_IC_FOCUS:
304 fprintf(stderr, "XIM_SET_IC_FOCUS()\n");
305 return True;
306 case XIM_UNSET_IC_FOCUS:
307 fprintf(stderr, "XIM_UNSET_IC_FOCUS:\n");
308 return True;
309 case XIM_RESET_IC:
310 fprintf(stderr, "XIM_RESET_IC_FOCUS:\n");
311 return True;
312 case XIM_TRIGGER_NOTIFY:
313 fprintf(stderr, "XIM_TRIGGER_NOTIFY:\n");
314 return MyTriggerNotifyHandler(ims, call_data);
315 case XIM_PREEDIT_START_REPLY:
316 fprintf(stderr, "XIM_PREEDIT_START_REPLY:\n");
317 return MyPreeditStartReplyHandler(ims, call_data);
318 case XIM_PREEDIT_CARET_REPLY:
319 fprintf(stderr, "XIM_PREEDIT_CARET_REPLY:\n");
320 return MyPreeditCaretReplyHandler(ims, call_data);
321 default:
322 fprintf(stderr, "Unknown IMDKit Protocol message type\n");
323 break;
324 }
325 }
326
MyXEventHandler(im_window,event)327 void MyXEventHandler(im_window, event)
328 Window im_window;
329 XEvent *event;
330 {
331 fprintf(stderr, "Local Event\n");
332 switch (event->type) {
333 case DestroyNotify:
334 break;
335 case ButtonPress:
336 switch (event->xbutton.button) {
337 case Button3:
338 if (event->xbutton.window == im_window)
339 goto Exit;
340 break;
341 }
342 default:
343 break;
344 }
345 return;
346 Exit:
347 XDestroyWindow(event->xbutton.display, im_window);
348 exit(0);
349 }
350
main(argc,argv)351 main(argc, argv)
352 int argc;
353 char **argv;
354 {
355 char *display_name = NULL;
356 Display *dpy;
357 char *imname = NULL;
358 XIMS ims;
359 XIMStyles *input_styles, *styles2;
360 XIMTriggerKeys *on_keys, *trigger2;
361 XIMEncodings *encodings, *encoding2;
362 Window im_window;
363 register int i;
364 char transport[80]; /* enough */
365
366 for (i = 1; i < argc; i++) {
367 if (!strcmp(argv[i], "-name")) {
368 imname = argv[++i];
369 } else if (!strcmp(argv[i], "-display")) {
370 display_name = argv[++i];
371 } else if (!strcmp(argv[i], "-dynamic")) {
372 use_trigger = True;
373 } else if (!strcmp(argv[i], "-static")) {
374 use_trigger = False;
375 } else if (!strcmp(argv[i], "-tcp")) {
376 use_tcp = True;
377 } else if (!strcmp(argv[i], "-local")) {
378 use_local = True;
379 } else if (!strcmp(argv[i], "-offkey")) {
380 use_offkey = True;
381 } else if (!strcmp(argv[i], "-kl")) {
382 filter_mask = (KeyPressMask|KeyReleaseMask);
383 }
384 }
385 if (!imname) imname = DEFAULT_IMNAME;
386
387 setlocale(LC_CTYPE, "zh_TW");
388 if ((dpy = XOpenDisplay(display_name)) == NULL) {
389 fprintf(stderr, "Can't Open Display: %s\n", display_name);
390 exit(1);
391 }
392 im_window = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy),
393 0, 700, 400, 800-700,
394 0, WhitePixel(dpy, DefaultScreen(dpy)),
395 WhitePixel(dpy, DefaultScreen(dpy)));
396
397 if (im_window == (Window)NULL) {
398 fprintf(stderr, "Can't Create Window\n");
399 exit(1);
400 }
401 XStoreName(dpy, im_window, "sampleIM");
402 XSetTransientForHint(dpy, im_window, im_window);
403
404 if ((input_styles = (XIMStyles *)malloc(sizeof(XIMStyles))) == NULL) {
405 fprintf(stderr, "Can't allocate\n");
406 exit(1);
407 }
408 input_styles->count_styles = sizeof(Styles)/sizeof(XIMStyle) - 1;
409 input_styles->supported_styles = Styles;
410
411 if ((on_keys = (XIMTriggerKeys *)
412 malloc(sizeof(XIMTriggerKeys))) == NULL) {
413 fprintf(stderr, "Can't allocate\n");
414 exit(1);
415 }
416 on_keys->count_keys = sizeof(Trigger_Keys)/sizeof(XIMTriggerKey) - 1;
417 on_keys->keylist = Trigger_Keys;
418
419 if ((encodings = (XIMEncodings *)malloc(sizeof(XIMEncodings))) == NULL) {
420 fprintf(stderr, "Can't allocate\n");
421 exit(1);
422 }
423 encodings->count_encodings = sizeof(zhEncodings)/sizeof(XIMEncoding) - 1;
424 encodings->supported_encodings = zhEncodings;
425
426 if (use_local) {
427 char hostname[64];
428 char *address = "/tmp/.ximsock";
429
430 gethostname(hostname, 64);
431 sprintf(transport, "local/%s:%s", hostname, address);
432 } else if (use_tcp) {
433 char hostname[64];
434 int port_number = 9010;
435
436 gethostname(hostname, 64);
437 sprintf(transport, "tcp/%s:%d", hostname, port_number);
438 } else {
439 strcpy(transport, "X/");
440 }
441
442 ims = IMOpenIM(dpy,
443 IMModifiers, "Xi18n",
444 IMServerWindow, im_window,
445 IMServerName, imname,
446 IMLocale, DEFAULT_LOCALE,
447 IMServerTransport, transport,
448 IMInputStyles, input_styles,
449 NULL);
450 if (ims == (XIMS)NULL) {
451 fprintf(stderr, "Can't Open Input Method Service:\n");
452 fprintf(stderr, "\tInput Method Name :%s\n", imname);
453 fprintf(stderr, "\tTranport Address:%s\n", transport);
454 exit(1);
455 }
456 if (use_trigger) {
457 if (use_offkey)
458 IMSetIMValues(ims,
459 IMOnKeysList, on_keys,
460 IMOffKeysList, on_keys,
461 NULL);
462 else
463 IMSetIMValues(ims,
464 IMOnKeysList, on_keys,
465 NULL);
466 }
467 IMSetIMValues(ims,
468 IMEncodingList, encodings,
469 IMProtocolHandler, MyProtoHandler,
470 IMFilterEventMask, filter_mask,
471 NULL);
472 IMGetIMValues(ims,
473 IMInputStyles, &styles2,
474 IMOnKeysList, &trigger2,
475 IMOffKeysList, &trigger2,
476 IMEncodingList, &encoding2,
477 NULL);
478 XSelectInput(dpy, im_window, StructureNotifyMask|ButtonPressMask);
479 XMapWindow(dpy, im_window);
480 XFlush(dpy); /* necessary flush for tcp/ip connection */
481
482 for (;;) {
483 XEvent event;
484 XNextEvent(dpy, &event);
485 if (XFilterEvent(&event, None) == True) {
486 fprintf(stderr, "window %ld\n",event.xany.window);
487 continue;
488 }
489 MyXEventHandler(im_window, &event);
490 }
491 }
492