1 /*---------------------------------------------------------------------------*
2   Project:  Revolution Low-Level Sync USB keyboard demo
3   File:     kbdLowLevelSync.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: kbdLowLevelSync.c,v $
14   Revision 1.10  2007/10/08 18:44:55  henrch
15   per API change
16 
17   Revision 1.9  2007/10/03 22:48:01  henrch
18   changed to use new KBD / HID lib
19 
20   Revision 1.8  2007/07/13 23:37:18  carlmu
21   Changed from TrySetLeds to KBDSetLedsRetry.
22 
23   Revision 1.7  2007/06/21 22:46:50  carlmu
24   Updated for KBD 1.4 API (changed LED handling).
25 
26   Revision 1.6  2007/05/05 01:56:57  carlmu
27   Changes for 0.8 API
28 
29   Revision 1.5  2007/04/17 23:55:57  carlmu
30   Updated for 0.5 API.
31 
32   Revision 1.4  2007/04/10 18:34:05  carlmu
33   Changed for compatibility with 0.4 API.
34 
35   Revision 1.3  2007/04/02 19:12:17  carlmu
36   Set callback functions modified for new return value.
37 
38   Revision 1.2  2007/03/29 22:38:01  carlmu
39   Added multiple channel support.
40 
41   Revision 1.1  2007/03/28 00:18:25  carlmu
42   Initial version.
43 
44 
45   $NoKeywords: $
46  *---------------------------------------------------------------------------*/
47 
48 /*
49   Example simple keyboard application to output the low-level API HID code
50   to the console.  Uses the synchronous keyboard API.
51  */
52 
53 #include <demo.h>
54 #include <revolution/kbd.h>
55 
56 static u8 __kbd_mem[KBD_MEM_SIZE];
57 
58 
59 //-----------------------------------------------------------------------------
60 
61 #define KBD_CALL(_fn_call)                         \
62   if ((_fn_call) != KBD_SUCCESS) {                 \
63     OSReport ("KBD error: calling %s @ %s:%i\n",   \
64               #_fn_call, __FILE__, __LINE__);      \
65   }
66 
67 //-----------------------------------------------------------------------------
68 
69 static void
kbdAppAttach(KBDDevEvent * kde)70 kbdAppAttach (KBDDevEvent *kde) {
71   OSReport ("kbd app: keyboard added on channel %d\n", kde->channel);
72   // for demo purposes, enable NumLock on newly attached keyboard
73   KBDSetModState(kde->channel, KBD_MS_NUM_LOCK);
74   KBDSetLedsRetry(kde->channel, KBD_LED_NUM_LOCK);
75 }
76 
77 
78 static void
kbdAppDetach(KBDDevEvent * kde)79 kbdAppDetach (KBDDevEvent *kde) {
80   OSReport ("kbd app: keyboard removed on channel %d\n", kde->channel);
81 }
82 
83 
84 static void
kbdAppKeyEvent(KBDKeyEvent * kke)85 kbdAppKeyEvent (KBDKeyEvent *kke) {
86   if (KBD_KEY_MODE_REPEAT(kke->mode)) {
87       return;
88   }
89 
90   if (KBD_KEY_MODE_UP(kke->mode))
91     OSReport ("\t\t\thid code: 0x%02x ^ up (chan %d)\n", kke->hid, kke->channel);
92   else
93     OSReport ("hid code: 0x%02x v down (chan %d)\n", kke->hid, kke->channel);
94 
95   // check for CapsLock, NumLock, or ScrollLock (handle LEDs)
96   if (kke->hid == KBD_HID_Caps_Lock ||
97       kke->hid == KBD_HID_Keypad_Num_Lock ||
98       kke->unicode == KBK_Scroll_Lock) {
99 
100       KBDModState ms;
101       KBDLedState leds;
102 
103       // First compute the new LED state
104       KBDGetModState(kke->channel, &ms);
105 
106       leds = (KBDLedState)
107       (((ms & KBD_MS_NUM_LOCK) == KBD_MS_NUM_LOCK) * KBD_LED_NUM_LOCK |
108        ((ms & KBD_MS_CAPS_LOCK) == KBD_MS_CAPS_LOCK) * KBD_LED_CAPS_LOCK |
109        ((ms & KBD_MS_SCROLL_LOCK) == KBD_MS_SCROLL_LOCK) * KBD_LED_SCROLL_LOCK);
110 
111       KBDSetLedsRetry(kke->channel, leds);
112   }
113 }
114 
115 extern void hid_open_async(void);
116 extern void hid_close_async(void);
117 
main(void)118 int main(void) {
119   KBDKeyEvent kevent;
120   KBDChannel ch;
121   KBDEc      rc;
122 
123   DEMOInit (NULL);
124 
125   hid_open_async();
126 
127   OSReport ("\n\n");
128   OSReport ("************************************************\n");
129   OSReport ("kbdLowLevelSync Low-level Sync keyboard demo\n");
130   OSReport ("************************************************\n");
131   OSReport ("Attach a USB keyboard and press some keys.\n");
132   OSReport ("Use a GameCube controller plugged into port 1.\n");
133   OSReport ("Right Trigger: sleeps for 5 seconds (to test overflow)\n");
134   OSReport ("\n");
135 
136   KBD_CALL (KBDInit(&__kbd_mem, kbdAppAttach, kbdAppDetach, 0));
137 
138   // One of these MUST be called after calling KBDInit.
139   // It's okay to call more than one.
140   KBDInitRegionUS();
141   KBDInitRegionJP();
142   KBDInitRegionEU();
143 
144   while (1) {
145 
146     DEMOPadRead();
147 
148     if ( DEMOPadGetButtonDown(0) & PAD_TRIGGER_R ) {
149       OSSleepSeconds(5);
150     }
151 
152     // poll all keyboard channels
153     for(ch=0; ch<KBD_MAX_CHANNELS; ch++) {
154       KBDChanStatus cstat;
155 
156       // see if keyboard is connected
157       KBD_CALL(KBDGetChannelStatus (ch, &cstat));
158       if (cstat == KBD_CS_OK) {
159 
160     // call KBDGetKey until queue is empty or error
161     do {
162       rc=KBDGetKey(ch, &kevent);
163       if (rc != KBD_SUCCESS) break;
164 
165       if (kevent.hid == KBD_HID_OVERFLOW) {
166         OSReport("KBD queue overflowed!\n");
167         continue;
168       }
169       if (kevent.hid == KBD_HID_NONE) {
170         break;
171       }
172       // process event
173       kbdAppKeyEvent(&kevent);
174     } while (1);
175       }
176     }
177 
178     OSYieldThread();
179 
180   }
181 
182   hid_close_async();
183 
184   OSShutdownSystem(); // Never reached!
185 
186   return 0;
187 }
188 
189 
190