1 /* wiikeyboard.c: routines for dealing with the Wii USB keyboard
2 Copyright (c) 2008 Bjoern Giesler
3
4 $Id: wiikeyboard.c 4109 2009-12-27 06:15:10Z fredm $
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License along
17 with this program; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20 Author contact information:
21
22 E-mail: bjoern@giesler.de
23
24 */
25
26 #define _POSIX_THREADS
27
28 #include <config.h>
29
30 #include <stdio.h>
31 #include <errno.h>
32 #include <string.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <unistd.h>
36
37 #include "display.h"
38 #include "fuse.h"
39 #include "keyboard.h"
40 #include "machine.h"
41 #include "settings.h"
42 #include "snapshot.h"
43 #include "spectrum.h"
44 #include "tape.h"
45 #include "ui/ui.h"
46
47 #include <ogc/lwp.h>
48 #include <ogc/mutex.h>
49 #include <ogc/ipc.h>
50
51 typedef struct {
52 u32 msgtype;
53 u32 unknown1;
54 u8 modifiers;
55 u8 unknown2;
56 u8 keys[6];
57 } wii_kbd_event;
58
59 static s32 kbd = -1;
60
61 static lwp_t kbdthread;
62 static mutex_t kbdmutex;
63 #define QUEUELEN 100
64 static input_event_t queue[QUEUELEN];
65 static int queuepos = 0;
66 static input_event_t releasequeue[QUEUELEN];
67 static int releasequeuepos = 0;
68
69 static int
post_modifier(input_event_t * event,u8 old,u8 new,u8 modifier,input_key spectrum_key)70 post_modifier( input_event_t* event,
71 u8 old, u8 new, u8 modifier, input_key spectrum_key )
72 {
73 if( (old & modifier) && !(new & modifier) ) {
74 event->type = INPUT_EVENT_KEYRELEASE;
75 event->types.key.native_key = modifier;
76 event->types.key.spectrum_key = spectrum_key;
77 return 0;
78 } else if( !(old & modifier) && (new & modifier) ) {
79 event->type = INPUT_EVENT_KEYPRESS;
80 event->types.key.native_key = modifier;
81 event->types.key.spectrum_key = spectrum_key;
82 return 0;
83 }
84
85 return 1;
86 }
87
88 static void*
kbdthread_fn(void * arg)89 kbdthread_fn( void *arg )
90 {
91 wii_kbd_event event, oldevent;
92 int i, j, found;
93
94 memset( &event, 0, sizeof(event) );
95 memset( &oldevent, 0, sizeof(oldevent) );
96
97 while( kbd != -1 ) {
98 IOS_Ioctl( kbd, 0, NULL, 0, &event, sizeof(event) );
99
100 /* skip connect (0) and disconnect (1) events */
101 if( event.msgtype != 2 ) continue;
102
103 input_event_t fuse_event;
104
105 LWP_MutexLock( kbdmutex );
106
107 #define POSTMODIFIER(wiikey, speckey) \
108 if(queuepos < QUEUELEN) \
109 if(post_modifier(queue + queuepos, \
110 oldevent.modifiers, event.modifiers, \
111 wiikey, speckey) == 0) \
112 queuepos++
113
114 POSTMODIFIER( 0x01, INPUT_KEY_Control_L );
115 POSTMODIFIER( 0x02, INPUT_KEY_Shift_L );
116 POSTMODIFIER( 0x04, INPUT_KEY_Alt_L );
117 POSTMODIFIER( 0x08, INPUT_KEY_Super_L );
118 POSTMODIFIER( 0x10, INPUT_KEY_Control_R );
119 POSTMODIFIER( 0x20, INPUT_KEY_Shift_R );
120 POSTMODIFIER( 0x40, INPUT_KEY_Alt_R );
121 POSTMODIFIER( 0x80, INPUT_KEY_Super_R );
122
123 #undef POSTMODIFIER
124
125 /* post keyreleases: old keys that have no new keys */
126 fuse_event.type = INPUT_EVENT_KEYRELEASE;
127 for(i=0; i<6; i++) {
128 if(oldevent.keys[i] == 0) break;
129 found = 0;
130 for( j=0; j<6; j++ ) {
131 if(event.keys[j] == oldevent.keys[i]) {
132 found = 1;
133 break;
134 }
135 }
136 if( !found ) {
137 fuse_event.types.key.spectrum_key = keysyms_remap(oldevent.keys[i]);
138 fuse_event.types.key.native_key = fuse_event.types.key.spectrum_key;
139
140 if( queuepos >= QUEUELEN ) {
141 ui_error( UI_ERROR_WARNING, "%s: keyboard queue full", __func__ );
142 continue;
143 }
144 queue[queuepos++] = fuse_event;
145 continue;
146 }
147 }
148
149 fuse_event.type = INPUT_EVENT_KEYPRESS;
150 for( i=0; i<6; i++ ) {
151 if(event.keys[i] == 0) break;
152 found = 0;
153 for( j=0; j<6; j++ ) {
154 if(oldevent.keys[j] == event.keys[i]) {
155 found = 1;
156 break;
157 }
158 }
159 if( !found ) {
160 fuse_event.types.key.spectrum_key = keysyms_remap( event.keys[i] );
161 fuse_event.types.key.native_key = fuse_event.types.key.spectrum_key;
162
163 if( queuepos >= QUEUELEN ) {
164 ui_error( UI_ERROR_WARNING, "%s: keyboard queue full", __func__ );
165 continue;
166 }
167 queue[queuepos++] = fuse_event;
168 }
169 }
170
171 LWP_MutexUnlock( kbdmutex );
172 oldevent = event;
173 }
174
175 return NULL;
176 }
177
178 int
wiikeyboard_init(void)179 wiikeyboard_init( void )
180 {
181 kbd = IOS_Open( "/dev/usb/kbd", IPC_OPEN_RW );
182 if( kbd < 0 ) return kbd;
183
184 if( LWP_MutexInit(&kbdmutex, 0) != 0 ||
185 LWP_CreateThread(&kbdthread, kbdthread_fn, NULL, NULL, 0, 80) != 0) {
186 IOS_Close(kbd);
187 return 1;
188 }
189
190 return 0;
191 }
192
wiikeyboard_end(void)193 int wiikeyboard_end(void)
194 {
195 if( kbd >= 0 ) IOS_Close(kbd);
196 kbd = -1;
197 return 0;
198 }
199
200 void
keyboard_update(void)201 keyboard_update( void )
202 {
203 int i;
204
205 for( i=0; i<releasequeuepos; i++ ) input_event(&(releasequeue[i]));
206 releasequeuepos = 0;
207
208 LWP_MutexLock( kbdmutex );
209 for(i=0; i<queuepos; i++) {
210 if( queue[i].type == INPUT_EVENT_KEYRELEASE )
211 releasequeue[releasequeuepos++] = queue[i];
212 else
213 input_event( &(queue[i]) );
214 }
215 queuepos = 0;
216 LWP_MutexUnlock( kbdmutex );
217 }
218