1 /*---------------------------------------------------------------------------*
2 Project: Revolution High-Level USB keyboard demo
3 File: kbdUTF8.c
4
5 Copyright 2007 Nintendo. All rights reserved.
6
7 These coded instructions, statements, and computer programs contain
8 proprietary information of Nintendo of America Inc. and/or Nintendo
9 Company Ltd., and are protected by Federal copyright law. They may
10 not be disclosed to third parties or copied or duplicated in any form,
11 in whole or in part, without the prior written consent of Nintendo.
12
13 $Log: kbdUTF8.c,v $
14 Revision 1.17.6.1 2009/10/14 10:03:27 iwai_yuma
15 Rool back into StackB.
16
17 Revision 1.14 2007/10/08 18:44:55 henrch
18 per API change
19
20 Revision 1.13 2007/10/03 22:48:01 henrch
21 changed to use new KBD / HID lib
22
23 Revision 1.12 2007/07/13 23:37:18 carlmu
24 Changed from TrySetLeds to KBDSetLedsRetry.
25
26 Revision 1.11 2007/07/12 01:37:53 dante.treglia
27 KBD: Removed unsupported languages from typedef enum _KBDCountryCode.
28
29 Revision 1.10 2007/06/21 22:46:50 carlmu
30 Updated for KBD 1.4 API (changed LED handling).
31
32 Revision 1.9 2007/05/29 21:57:50 carlmu
33 Added French Canadian layout to selection.
34 Added Keypad Equals key to output.
35
36 Revision 1.8 2007/05/11 23:09:34 carlmu
37 Added "International" map.
38
39 Revision 1.7 2007/05/05 01:56:57 carlmu
40 Changes for 0.8 API
41
42 Revision 1.6 2007/04/17 23:55:57 carlmu
43 Updated for 0.5 API.
44
45 Revision 1.5 2007/04/10 18:34:05 carlmu
46 Changed for compatibility with 0.4 API.
47
48 Revision 1.4 2007/04/02 19:12:17 carlmu
49 Set callback functions modified for new return value.
50
51 Revision 1.3 2007/03/29 22:36:52 carlmu
52 Added multiple channel support.
53
54 Revision 1.2 2007/03/28 00:19:29 carlmu
55 Added more languages, HID code output.
56
57 Revision 1.1 2007/03/21 18:04:57 carlmu
58 Initial version.
59
60 $NoKeywords: $
61 *---------------------------------------------------------------------------*/
62
63 /*
64 Example keyboard application to convert the high-level API UTF32 unicode
65 output to UTF8.
66 */
67
68 #include <demo.h>
69 #include <revolution/kbd.h>
70 #include <revolution/enc.h>
71
72 //-----------------------------------------------------------------------------
73
74 static u8 __kbd_mem[KBD_MEM_SIZE];
75
76 // List of countries useable in this demo; arbitrary order
77 KBDCountryCode countryList[] = {
78 KBD_CC_UNITED_STATES,
79 KBD_CC_JAPANESE,
80 KBD_CC_INTERNATIONAL,
81 KBD_CC_CANADIAN_BI,
82 KBD_CC_CANADIAN_FR,
83 KBD_CC_DANISH,
84 KBD_CC_FINNISH,
85 KBD_CC_FRENCH,
86 KBD_CC_GERMAN,
87 KBD_CC_GREEK,
88 KBD_CC_ITALIAN,
89 KBD_CC_LATIN_AMERICAN,
90 KBD_CC_NETHERLANDS_DUTCH,
91 KBD_CC_NORWEGIAN,
92 KBD_CC_PORTUGUESE,
93 KBD_CC_SPANISH,
94 KBD_CC_SWEDISH,
95 KBD_CC_UNITED_KINGDOM,
96 };
97
98 #define MAX_CODE (sizeof(countryList)/sizeof(KBDCountryCode))
99
100 // List of countries available in KBD driver; by code order
101 // (Subject to change!)
102 char *countryName[] = {
103 "International",
104 "Canadian_Bi",
105 "Canadian_Fr",
106 "Danish",
107 "Finnish",
108 "French",
109 "German",
110 "Greek",
111 "Italian",
112 "Japanese",
113 "Latin_American",
114 "Netherlands_Dutch",
115 "Norwegian",
116 "Portuguese",
117 "Spanish",
118 "Swedish",
119 "United_Kingdom",
120 "United_States",
121 };
122
123 typedef struct _SpTableEntry {
124 KBDUnicode code;
125 char *name;
126 } SpTableEntry;
127
128 SpTableEntry SpecialTable[] = {
129 KBK_Void, "(void key)",
130 KBK_Error, "(error!)", // should never be output
131 KBK_Backspace, "Backspace",
132 KBK_Tab, "Tab",
133 KBK_Enter, "Enter",
134 KBK_Escape, "Escape",
135 KBK_Space, "Space",
136 KBK_Mod_Shift, "Mod_Shift",
137 KBK_Mod_AltGr, "Mod_AltGr",
138 KBK_Lang_Toggle, "Lang_Toggle",
139 KBK_Num_Lock, "Num_Lock",
140 KBK_Caps_Lock, "Caps_Lock",
141 KBK_Mod_Control, "Mod_Control",
142 KBK_Mod_Alt, "Mod_Alt",
143 KBK_Mod_GUI, "Mod_GUI",
144 KBK_Mod_Extra, "Mod_Extra",
145 KBK_Print_Screen, "Print_Screen",
146 KBK_Scroll_Lock, "Scroll_Lock",
147 KBK_Pause, "Pause",
148 KBK_Application, "Application",
149 KBK_Katakana_Hiragana, "Katakana_Hiragana",
150 KBK_Henkan, "Henkan",
151 KBK_Muhenkan, "Muhenkan",
152 KBK_Kanji, "Kanji",
153 KBK_Katakana, "Katakana",
154 KBK_Hiragana, "Hiragana",
155 KBK_F1, "F1",
156 KBK_F2, "F2",
157 KBK_F3, "F3",
158 KBK_F4, "F4",
159 KBK_F5, "F5",
160 KBK_F6, "F6",
161 KBK_F7, "F7",
162 KBK_F8, "F8",
163 KBK_F9, "F9",
164 KBK_F10, "F10",
165 KBK_F11, "F11",
166 KBK_F12, "F12",
167 KBK_Delete, "Delete",
168 KBK_Insert, "Insert",
169 KBK_End, "End",
170 KBK_Down_Arrow, "Down_Arrow",
171 KBK_Page_Down, "Page_Down",
172 KBK_Left_Arrow, "Left_Arrow",
173 KBK_Right_Arrow, "Right_Arrow",
174 KBK_Home, "Home",
175 KBK_Up_Arrow, "Up_Arrow",
176 KBK_Page_Up, "Page_Up",
177 KBK_Keypad_Delete, "Keypad_Delete",
178 KBK_Keypad_Insert, "Keypad_Insert",
179 KBK_Keypad_End, "Keypad_End",
180 KBK_Keypad_Down_Arrow, "Keypad_Down_Arrow",
181 KBK_Keypad_Page_Down, "Keypad_Page_Down",
182 KBK_Keypad_Left_Arrow, "Keypad_Left_Arrow",
183 KBK_Keypad_Space, "Keypad_Space",
184 KBK_Keypad_Right_Arrow, "Keypad_Right_Arrow",
185 KBK_Keypad_Home, "Keypad_Home",
186 KBK_Keypad_Up_Arrow, "Keypad_Up_Arrow",
187 KBK_Keypad_Page_Up, "Keypad_Page_Up",
188 KBK_Keypad_Comma, "Keypad_Comma",
189 KBK_Keypad_Period, "Keypad_Period",
190 KBK_Keypad_0, "Keypad_0",
191 KBK_Keypad_1, "Keypad_1",
192 KBK_Keypad_2, "Keypad_2",
193 KBK_Keypad_3, "Keypad_3",
194 KBK_Keypad_4, "Keypad_4",
195 KBK_Keypad_5, "Keypad_5",
196 KBK_Keypad_6, "Keypad_6",
197 KBK_Keypad_7, "Keypad_7",
198 KBK_Keypad_8, "Keypad_8",
199 KBK_Keypad_9, "Keypad_9",
200 KBK_Keypad_Slash, "Keypad_Slash",
201 KBK_Keypad_Asterisk, "Keypad_Asterisk",
202 KBK_Keypad_Minus, "Keypad_Minus",
203 KBK_Keypad_Plus, "Keypad_Plus",
204 KBK_Keypad_Equals, "Keypad_Equals",
205 KBK_Keypad_Enter, "Keypad_Enter",
206 };
207
208 #define MAX_SPECIAL (sizeof(SpecialTable)/sizeof(SpTableEntry))
209
210 #define KBD_CALL(_fn_call) \
211 if ((_fn_call) != KBD_SUCCESS) { \
212 OSReport ("KBD error: calling %s @ %s:%i\n", \
213 #_fn_call, __FILE__, __LINE__); \
214 }
215
216 //-----------------------------------------------------------------------------
217
218 u8 language=0;
219
220 static void outputUTF8 (u16 utf16);
221 void outputUTF8Example(void);
222
223 //-----------------------------------------------------------------------------
224
225 static void
kbdAppAttach(KBDDevEvent * kde)226 kbdAppAttach (KBDDevEvent *kde) {
227 OSReport ("kbd app: keyboard added on channel %d\n", kde->channel);
228 // for demo purposes, enable NumLock on newly attached keyboard
229 KBDSetModState(kde->channel, KBD_MS_NUM_LOCK);
230 KBDSetLedsRetry(kde->channel, KBD_LED_NUM_LOCK);
231 }
232
233
234 static void
kbdAppDetach(KBDDevEvent * kde)235 kbdAppDetach (KBDDevEvent *kde) {
236 OSReport ("kbd app: keyboard removed on channel %d\n", kde->channel);
237 }
238
239
240 static void
kbdAppKeyEvent(KBDKeyEvent * kke)241 kbdAppKeyEvent (KBDKeyEvent *kke) {
242 KBDCountryCode country;
243 u32 i;
244
245 // Only report key down events
246 if (KBD_KEY_MODE_UP(kke->mode)) {
247 return;
248 }
249
250 #if 0
251 // filter out unmapped keys
252 if (kke->unicode == KBK_Void) {
253 return;
254 }
255 #endif
256
257 OSReport ("ch %d hid code: 0x%02x v down\n", kke->channel, kke->hid);
258
259 // check for CapsLock, NumLock, or ScrollLock (handle LEDs)
260 if (kke->unicode == KBK_Caps_Lock ||
261 kke->unicode == KBK_Num_Lock ||
262 kke->unicode == KBK_Scroll_Lock) {
263
264 KBDModState ms;
265 KBDLedState leds;
266
267 // First compute the new LED state
268 KBDGetModState(kke->channel, &ms);
269
270 leds = (KBDLedState)
271 (((ms & KBD_MS_NUM_LOCK) == KBD_MS_NUM_LOCK) * KBD_LED_NUM_LOCK |
272 ((ms & KBD_MS_CAPS_LOCK) == KBD_MS_CAPS_LOCK) * KBD_LED_CAPS_LOCK |
273 ((ms & KBD_MS_SCROLL_LOCK) == KBD_MS_SCROLL_LOCK) * KBD_LED_SCROLL_LOCK);
274
275 KBDSetLedsRetry(kke->channel, leds);
276 }
277
278 // Don't report modifier keys by themselves
279 if (KBD_UC_IS_MODIFIER(kke->unicode)) {
280 return;
281 }
282
283 KBD_CALL (KBDGetCountry (kke->channel, &country));
284
285 OSReport("ch %d key: -> ", kke->channel);
286
287 // check for special keys (KBK_F1, KBK_Home, etc.) or for
288 // Ctrl characters (enter, tab, etc.)
289 if (KBD_UC_IS_PRIVATE(kke->unicode) || (kke->unicode <= ' ')) {
290
291 for(i=0; i<MAX_SPECIAL; i++) {
292 if (kke->unicode == SpecialTable[i].code) {
293 OSReport("%s", SpecialTable[i].name);
294 break;
295 }
296 }
297
298 } else { // just a regular Unicode character
299
300 outputUTF8(kke->unicode);
301
302 }
303
304 OSReport (" <-");
305
306 OSReport (" (%s) utf32 unicode: 0x%08x", countryName[country], kke->unicode);
307
308 OSReport (" MS: ");
309
310 if (kke->modState & KBD_MS_SHIFT) OSReport("SHF ");
311 if (kke->modState & KBD_MS_CAPS_LOCK) OSReport("CPL ");
312 if (kke->modState & KBD_MS_NUM_LOCK) OSReport("NML ");
313 if (kke->modState & KBD_MS_CTRL) OSReport("CTL ");
314 if (kke->modState & KBD_MS_ALTGR) OSReport("ATG ");
315 if (kke->modState & KBD_MS_LANG1) OSReport("LA1 ");
316 if (kke->modState & KBD_MS_LANG2) OSReport("LA2 ");
317 if (kke->modState & KBD_MS_ALT) OSReport("ALT ");
318 if (kke->modState & KBD_MS_GUI) OSReport("GUI ");
319 if (kke->modState & KBD_MS_EXTRA) OSReport("EXT ");
320
321 OSReport("\n");
322
323 // For Japanese, handle language change.
324 // (This would normally be done by an IME.)
325 if (kke->unicode == KBK_Katakana_Hiragana) {
326
327 language = (u8) ((language + 1) % 3);
328 kke->modState = (KBDModState) (kke->modState & ~(KBD_MS_HIRAGANA | KBD_MS_KATAKANA));
329
330 switch (language) {
331 case 0:
332 OSReport("Language switched to Romaji\n");
333 KBD_CALL( KBDSetModState(kke->channel, kke->modState) );
334 break;
335 case 1:
336 OSReport("Language switched to Hiragana\n");
337 KBD_CALL( KBDSetModState(kke->channel, (KBDModState) (kke->modState | KBD_MS_HIRAGANA)) );
338 break;
339 case 2:
340 OSReport("Language switched to Katakana\n");
341 KBD_CALL( KBDSetModState(kke->channel, (KBDModState) (kke->modState | KBD_MS_KATAKANA)) );
342 break;
343 }
344 }
345
346 // For Greece, handle language change.
347 if (country == KBD_CC_GREEK) {
348
349 // Look for Alt-Space combination
350 if (kke->unicode == ' ' && ((kke->modState & KBD_MS_ALT)==KBD_MS_ALT)) {
351
352 language = !language;
353 if (language) {
354 KBD_CALL( KBDSetModState(kke->channel, (KBDModState) (kke->modState | KBD_MS_LANG1)) );
355 OSReport("Language switched to Greek\n");
356 } else {
357 KBD_CALL( KBDSetModState(kke->channel, (KBDModState) (kke->modState & ~KBD_MS_LANG1)) );
358 OSReport("Language switched to English\n");
359 }
360 }
361 }
362
363 }
364
365
366 static void
outputUTF8(u16 utf16)367 outputUTF8 (u16 utf16) {
368 s32 utf16_len = 1;
369 u8 utf8[4];
370 s32 utf8_len = 4;
371 u8 b;
372
373 ENCConvertStringUtf16ToUtf8 (&utf8[0],
374 &utf8_len,
375 &utf16,
376 &utf16_len);
377 for (b=0; b<utf8_len; b++) {
378 OSReport ("%c", utf8[b]);
379 }
380 }
381
382
outputUTF8Example(void)383 void outputUTF8Example(void) {
384 OSReport ("If your terminal program is UTF-8 compliant, you will\n");
385 OSReport ("see an Omega symbol between quotes here: \"");
386 outputUTF8(0x03a9);
387 OSReport ("\"\n");
388 OSReport ("and a Hiragana letter A between quotes here: \"");
389 outputUTF8(0x3042);
390 OSReport ("\"\n");
391 }
392
393 static u32 country[KBD_MAX_CHANNELS] = { 0, 0, 0, 0 }; // index into codeList above
394
395 extern void hid_open_async(void);
396 extern void hid_close_async(void);
397
main(void)398 int main(void)
399 {
400 KBDChannel cch = 0; // kbd channel to control
401
402 DEMOInit (NULL);
403
404 hid_open_async();
405
406 // Make a call to ENC lib to get its version output out of the way
407 {
408 u32 in=0;
409 u8 out=0;
410 s32 inlen=1, outlen=0;
411 ENCConvertStringUtf32ToUtf8 (&out, &outlen, &in, &inlen);
412 }
413
414 OSReport ("\n\n");
415 OSReport ("************************************************\n");
416 OSReport ("kbdUTF8 High-level keyboard demo\n");
417 OSReport ("************************************************\n");
418 OSReport ("Attach a USB keyboard and press some keys.\n");
419 OSReport ("Use a GameCube controller plugged into port 1.\n");
420 OSReport ("Button A : set next keyboard country (language)\n");
421 OSReport ("Button B : set previous keyboard country (language)\n");
422 OSReport ("Button X : change channel affected by Button A/B\n");
423 OSReport ("Button Y : output UTF-8 example string\n");
424
425 OSReport ("\n");
426 OSReport ("It is recommended to use a UTF-8 compliant terminal program.\n");
427 outputUTF8Example();
428 OSReport ("\n");
429
430 OSReport ("Country set to %s.\n\n", countryName[countryList[0]]);
431
432 KBD_CALL (KBDInit(&__kbd_mem, kbdAppAttach, kbdAppDetach, kbdAppKeyEvent));
433
434 // One of these MUST be called after calling KBDInit.
435 // It's okay to call more than one.
436 KBDInitRegionUS();
437 KBDInitRegionJP();
438 KBDInitRegionEU();
439
440 do {
441
442 DEMOPadRead();
443
444 if ( (DEMOPadGetButtonDown(0) & PAD_BUTTON_A) ||
445 (DEMOPadGetButtonDown(0) & PAD_BUTTON_B) ) {
446 if (DEMOPadGetButtonDown(0) & PAD_BUTTON_A) {
447 country[cch] = (country[cch]+1) % MAX_CODE;
448 } else {
449 country[cch] = (country[cch]+MAX_CODE-1) % MAX_CODE;
450 }
451 KBD_CALL (KBDSetCountry (cch, countryList[country[cch]]));
452 language = 0;
453 OSReport ("Country switched to %s for channel %d.\n", countryName[countryList[country[cch]]], cch);
454 }
455
456 if ( DEMOPadGetButtonDown(0) & PAD_BUTTON_Y ) {
457 outputUTF8Example();
458 }
459
460 if ( DEMOPadGetButtonDown(0) & PAD_BUTTON_X ) {
461 cch = (KBDChannel) ((cch + 1) % KBD_MAX_CHANNELS);
462 OSReport("Keyboard channel %d selected.\n", cch);
463 }
464
465 OSYieldThread();
466
467 } while (!(DEMOPadGetButtonDown(0) & PAD_BUTTON_MENU));
468
469 OSReport("Shutting down system...\n");
470
471 hid_close_async();
472
473 OSShutdownSystem();
474
475 return 0;
476 }
477