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