/*---------------------------------------------------------------------------* Project: Revolution High-Level Sync USB keyboard demo File: kbdUTF8Sync.c Copyright 2007 Nintendo. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. $Log: kbdUTF8Sync.c,v $ Revision 1.13 2007/10/08 18:44:55 henrch per API change Revision 1.12 2007/10/03 22:48:01 henrch changed to use new KBD / HID lib Revision 1.11 2007/07/13 23:37:18 carlmu Changed from TrySetLeds to KBDSetLedsRetry. Revision 1.10 2007/07/12 01:37:53 dante.treglia KBD: Removed unsupported languages from typedef enum _KBDCountryCode. Revision 1.9 2007/06/21 22:46:50 carlmu Updated for KBD 1.4 API (changed LED handling). Revision 1.8 2007/05/29 21:57:50 carlmu Added French Canadian layout to selection. Added Keypad Equals key to output. Revision 1.7 2007/05/11 23:09:34 carlmu Added "International" map. Revision 1.6 2007/05/05 01:56:57 carlmu Changes for 0.8 API Revision 1.5 2007/04/17 23:55:57 carlmu Updated for 0.5 API. Revision 1.4 2007/04/10 18:34:05 carlmu Changed for compatibility with 0.4 API. Revision 1.3 2007/04/02 19:12:17 carlmu Set callback functions modified for new return value. Revision 1.2 2007/03/29 22:36:11 carlmu Added multiple channel support. Revision 1.1 2007/03/28 00:18:25 carlmu Initial version. $NoKeywords: $ *---------------------------------------------------------------------------*/ /* Example keyboard application to convert the high-level API UTF32 unicode output to UTF8. Uses the synchronous keyboard API. */ #include #include #include static u8 __kbd_mem[KBD_MEM_SIZE]; //----------------------------------------------------------------------------- // List of countries useable in this demo; arbitrary order KBDCountryCode countryList[] = { KBD_CC_UNITED_STATES, KBD_CC_JAPANESE, KBD_CC_INTERNATIONAL, KBD_CC_CANADIAN_BI, KBD_CC_CANADIAN_FR, KBD_CC_DANISH, KBD_CC_FINNISH, KBD_CC_FRENCH, KBD_CC_GERMAN, KBD_CC_GREEK, KBD_CC_ITALIAN, KBD_CC_LATIN_AMERICAN, KBD_CC_NETHERLANDS_DUTCH, KBD_CC_NORWEGIAN, KBD_CC_PORTUGUESE, KBD_CC_SPANISH, KBD_CC_SWEDISH, KBD_CC_UNITED_KINGDOM, }; #define MAX_CODE (sizeof(countryList)/sizeof(KBDCountryCode)) // List of countries available in KBD driver; by code order // (Subject to change!) char *countryName[] = { "International", "Canadian_Bi", "Canadian_Fr", "Danish", "Finnish", "French", "German", "Greek", "Italian", "Japanese", "Latin_American", "Netherlands_Dutch", "Norwegian", "Portuguese", "Spanish", "Swedish", "United_Kingdom", "United_States", }; typedef struct _SpTableEntry { KBDUnicode code; char *name; } SpTableEntry; SpTableEntry SpecialTable[] = { KBK_Void, "(void key)", KBK_Error, "(error!)", KBK_Backspace, "Backspace", KBK_Tab, "Tab", KBK_Enter, "Enter", KBK_Escape, "Escape", KBK_Space, "Space", KBK_Mod_Shift, "Mod_Shift", KBK_Mod_AltGr, "Mod_AltGr", KBK_Lang_Toggle, "Lang_Toggle", KBK_Num_Lock, "Num_Lock", KBK_Caps_Lock, "Caps_Lock", KBK_Mod_Control, "Mod_Control", KBK_Mod_Alt, "Mod_Alt", KBK_Mod_GUI, "Mod_GUI", KBK_Mod_Extra, "Mod_Extra", KBK_Print_Screen, "Print_Screen", KBK_Scroll_Lock, "Scroll_Lock", KBK_Pause, "Pause", KBK_Application, "Application", KBK_Katakana_Hiragana, "Katakana_Hiragana", KBK_Henkan, "Henkan", KBK_Muhenkan, "Muhenkan", KBK_Kanji, "Kanji", KBK_Katakana, "Katakana", KBK_Hiragana, "Hiragana", KBK_F1, "F1", KBK_F2, "F2", KBK_F3, "F3", KBK_F4, "F4", KBK_F5, "F5", KBK_F6, "F6", KBK_F7, "F7", KBK_F8, "F8", KBK_F9, "F9", KBK_F10, "F10", KBK_F11, "F11", KBK_F12, "F12", KBK_Delete, "Delete", KBK_Insert, "Insert", KBK_End, "End", KBK_Down_Arrow, "Down_Arrow", KBK_Page_Down, "Page_Down", KBK_Left_Arrow, "Left_Arrow", KBK_Right_Arrow, "Right_Arrow", KBK_Home, "Home", KBK_Up_Arrow, "Up_Arrow", KBK_Page_Up, "Page_Up", KBK_Keypad_Delete, "Keypad_Delete", KBK_Keypad_Insert, "Keypad_Insert", KBK_Keypad_End, "Keypad_End", KBK_Keypad_Down_Arrow, "Keypad_Down_Arrow", KBK_Keypad_Page_Down, "Keypad_Page_Down", KBK_Keypad_Left_Arrow, "Keypad_Left_Arrow", KBK_Keypad_Space, "Keypad_Space", KBK_Keypad_Right_Arrow, "Keypad_Right_Arrow", KBK_Keypad_Home, "Keypad_Home", KBK_Keypad_Up_Arrow, "Keypad_Up_Arrow", KBK_Keypad_Page_Up, "Keypad_Page_Up", KBK_Keypad_Comma, "Keypad_Comma", KBK_Keypad_Period, "Keypad_Period", KBK_Keypad_0, "Keypad_0", KBK_Keypad_1, "Keypad_1", KBK_Keypad_2, "Keypad_2", KBK_Keypad_3, "Keypad_3", KBK_Keypad_4, "Keypad_4", KBK_Keypad_5, "Keypad_5", KBK_Keypad_6, "Keypad_6", KBK_Keypad_7, "Keypad_7", KBK_Keypad_8, "Keypad_8", KBK_Keypad_9, "Keypad_9", KBK_Keypad_Slash, "Keypad_Slash", KBK_Keypad_Asterisk, "Keypad_Asterisk", KBK_Keypad_Minus, "Keypad_Minus", KBK_Keypad_Plus, "Keypad_Plus", KBK_Keypad_Equals, "Keypad_Equals", KBK_Keypad_Enter, "Keypad_Enter", }; #define MAX_SPECIAL (sizeof(SpecialTable)/sizeof(SpTableEntry)) #define KBD_CALL(_fn_call) \ if ((_fn_call) != KBD_SUCCESS) { \ OSReport ("KBD error: calling %s @ %s:%i\n", \ #_fn_call, __FILE__, __LINE__); \ } //----------------------------------------------------------------------------- u8 language=0; static void outputUTF8 (u16 utf16); void outputUTF8Example(void); //----------------------------------------------------------------------------- static void kbdAppAttach (KBDDevEvent *kde) { OSReport ("kbd app: keyboard added on channel %d\n", kde->channel); // for demo purposes, enable NumLock on newly attached keyboard KBDSetModState(kde->channel, KBD_MS_NUM_LOCK); KBDSetLedsRetry(kde->channel, KBD_LED_NUM_LOCK); } static void kbdAppDetach (KBDDevEvent *kde) { OSReport ("kbd app: keyboard removed on channel %d\n", kde->channel); } static void kbdAppKeyEvent (KBDKeyEvent *kke) { KBDCountryCode country; u32 i; // Only report key down events if (KBD_KEY_MODE_UP(kke->mode)) { return; } #if 0 // filter out unmapped keys if (kke->unicode == KBK_Void) { return; } #endif OSReport ("ch %d hid code: 0x%02x v down\n", kke->channel, kke->hid); // check for CapsLock, NumLock, or ScrollLock (handle LEDs) if (kke->unicode == KBK_Caps_Lock || kke->unicode == KBK_Num_Lock || kke->unicode == KBK_Scroll_Lock) { KBDModState ms; KBDLedState leds; // First compute the new LED state KBDGetModState(kke->channel, &ms); leds = (KBDLedState) (((ms & KBD_MS_NUM_LOCK) == KBD_MS_NUM_LOCK) * KBD_LED_NUM_LOCK | ((ms & KBD_MS_CAPS_LOCK) == KBD_MS_CAPS_LOCK) * KBD_LED_CAPS_LOCK | ((ms & KBD_MS_SCROLL_LOCK) == KBD_MS_SCROLL_LOCK) * KBD_LED_SCROLL_LOCK); KBDSetLedsRetry(kke->channel, leds); } // Don't report modifier keys by themselves if (KBD_UC_IS_MODIFIER(kke->unicode)) { return; } KBD_CALL (KBDGetCountry (kke->channel, &country)); OSReport("ch %d key: -> ", kke->channel); // check for special keys (KBK_F1, KBK_Home, etc.) or for // Ctrl characters (enter, tab, etc.) if (KBD_UC_IS_PRIVATE(kke->unicode) || (kke->unicode <= ' ')) { for(i=0; iunicode == SpecialTable[i].code) { OSReport("%s", SpecialTable[i].name); break; } } } else { // just a regular Unicode character outputUTF8(kke->unicode); } OSReport (" <-"); OSReport (" (%s) utf32 unicode: 0x%08x", countryName[country], kke->unicode); OSReport (" MS: "); if (kke->modState & KBD_MS_SHIFT) OSReport("SHF "); if (kke->modState & KBD_MS_CAPS_LOCK) OSReport("CPL "); if (kke->modState & KBD_MS_NUM_LOCK) OSReport("NML "); if (kke->modState & KBD_MS_CTRL) OSReport("CTL "); if (kke->modState & KBD_MS_ALTGR) OSReport("ATG "); if (kke->modState & KBD_MS_LANG1) OSReport("LA1 "); if (kke->modState & KBD_MS_LANG2) OSReport("LA2 "); if (kke->modState & KBD_MS_ALT) OSReport("ALT "); if (kke->modState & KBD_MS_GUI) OSReport("GUI "); if (kke->modState & KBD_MS_EXTRA) OSReport("EXT "); OSReport("\n"); // For Japanese, handle language change. // (This would normally be done by an IME.) if (kke->unicode == KBK_Katakana_Hiragana) { language = (u8) ((language + 1) % 3); kke->modState = (KBDModState) (kke->modState & ~(KBD_MS_HIRAGANA | KBD_MS_KATAKANA)); switch (language) { case 0: OSReport("Language switched to Romaji\n"); KBD_CALL( KBDSetModState(kke->channel, kke->modState) ); break; case 1: OSReport("Language switched to Hiragana\n"); KBD_CALL( KBDSetModState(kke->channel, (KBDModState) (kke->modState | KBD_MS_HIRAGANA)) ); break; case 2: OSReport("Language switched to Katakana\n"); KBD_CALL( KBDSetModState(kke->channel, (KBDModState) (kke->modState | KBD_MS_KATAKANA)) ); break; } } // For Greece, handle language change. if (country == KBD_CC_GREEK) { // Look for Alt-Space combination if (kke->unicode == ' ' && ((kke->modState & KBD_MS_ALT)==KBD_MS_ALT)) { language = !language; if (language) { KBD_CALL( KBDSetModState(kke->channel, (KBDModState) (kke->modState | KBD_MS_LANG1)) ); OSReport("Language switched to Greek\n"); } else { KBD_CALL( KBDSetModState(kke->channel, (KBDModState) (kke->modState & ~KBD_MS_LANG1)) ); OSReport("Language switched to English\n"); } } } } static void outputUTF8 (u16 utf16) { s32 utf16_len = 1; u8 utf8[4]; s32 utf8_len = 4; u8 b; ENCConvertStringUtf16ToUtf8 (&utf8[0], &utf8_len, &utf16, &utf16_len); for (b=0; b