/*---------------------------------------------------------------------------* Project: Revolution KPR Key Processing demo File: kprdemo.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: kprdemo.c,v $ Revision 1.12.2.1 2009/10/14 10:04:01 iwai_yuma Rool back into StackB. Revision 1.10 2007/10/08 19:20:19 henrch changed per KBD api Revision 1.9 2007/07/13 23:42:26 carlmu Added instruction output for Greek layout language change. Revision 1.8 2007/07/13 23:38:50 carlmu Changed from TrySetLeds to KBDSetLedsRetry. Revision 1.7 2007/07/12 01:37:58 dante.treglia KBD: Removed unsupported languages from typedef enum _KBDCountryCode. Revision 1.6 2007/06/21 22:47:09 carlmu Updated for KBD 1.4 API (changed LED handling). Revision 1.5 2007/05/29 21:59:19 carlmu Added French Canadian layout to selection. Added Keypad Equals key to output. Revision 1.4 2007/05/11 23:13:41 carlmu Added "International" map. Added region initializers for KPR. Revision 1.3 2007/05/05 01:57:21 carlmu Changes for 0.8 API Revision 1.2 2007/05/01 20:42:48 carlmu Checks for control characters entered using Alt+keypad. Revision 1.1 2007/04/25 19:00:58 carlmu Initial version. $NoKeywords: $ *---------------------------------------------------------------------------*/ /* Example KPR application to show how to use Key Processing library. */ #include #include #include #include extern void hid_open_async(void); extern void hid_close_async(void); // Decide if an 8-bit Unicode character is a control character #define UNICODE_IS_CONTROL(uc) ((uc)<32 || ((uc)>=128 && (uc)<=159)) //----------------------------------------------------------------------------- static 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!)", // should never be output 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; KPRQueue kprq[KBD_MAX_CHANNELS]; 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; u16 utf16; // Only report key down events (exception is Alt key going up) if (KBD_KEY_MODE_UP(kke->mode) && kke->unicode != KBK_Mod_Alt) { return; } // filter out unmapped keys if (kke->unicode == KBK_Void) { return; } // If Alt key went up, need to send a NULL to the KPR queue if (KBD_KEY_MODE_UP(kke->mode) && kke->unicode == KBK_Mod_Alt) { kke->unicode = 0; } // 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; } // check for special keys (KBK_F1, KBK_Home, etc.) or for // Ctrl characters (enter, tab, etc.). // Alt+keypad keys shouldn't be filtered, though. if (KBD_UC_IS_PRIVATE(kke->unicode) && !(KBD_MS_IS_NUMLOCK(kke->modState) && KBD_UC_IS_KP_NUM_UL_KEY(kke->unicode))) { for(i=0; iunicode == SpecialTable[i].code) { OSReport("%s\n", SpecialTable[i].name); break; } } } else { // just a regular Unicode character (or Alt+keypad key) // If Alt+keypad key, convert to Keypad number range if (KBD_UC_IS_KP_NUM_UL_KEY(kke->unicode)) { kke->unicode = KBD_KP_NUM_UL_KEY_TO_KP_NUM_NL_KEY(kke->unicode); } // Send the key to the processing queue KPRPutChar( &kprq[kke->channel], kke->unicode ); // See what comes out; may be more than 1 character. while ( (utf16 = KPRGetChar( &kprq[kke->channel] )) != 0 ) { // User may have used Alt+Keypad to enter a control character if (UNICODE_IS_CONTROL(utf16)) { OSReport("\\%d", utf16); } else { outputUTF8(utf16); } OSReport("\n"); } } // For Japanese, handle language change. // (This would normally be done by an IME.) // Keep keyboard in Romaji mode, but now just change the processing mode. if (kke->unicode == KBK_Katakana_Hiragana) { language = (u8) ((language + 1) % 3); switch (language) { case 0: OSReport("Language switched to Romaji\n"); KPRSetMode(&kprq[kke->channel], KPR_MODE_ALT_KEYPAD); break; case 1: OSReport("Language switched to Hiragana\n"); KPRSetMode(&kprq[kke->channel], (KPRMode) (KPR_MODE_JP_ROMAJI_HIRAGANA | KPR_MODE_ALT_KEYPAD)); break; case 2: OSReport("Language switched to Katakana\n"); KPRSetMode(&kprq[kke->channel], (KPRMode) (KPR_MODE_JP_ROMAJI_KATAKANA | KPR_MODE_ALT_KEYPAD)); break; } } // For Greece, handle language change. KBD_CALL (KBDGetCountry (kke->channel, &country)); 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