1 |
//--------------------------------------------------------------------------- |
2 |
// File name: pad.c |
3 |
//--------------------------------------------------------------------------- |
4 |
#include "launchelf.h" |
5 |
|
6 |
static char padBuf_t[2][256] __attribute__((aligned(64))); |
7 |
struct padButtonStatus buttons_t[2]; |
8 |
u32 padtype_t[2]; |
9 |
u32 paddata, paddata_t[2]; |
10 |
u32 old_pad = 0, old_pad_t[2] = {0, 0}; |
11 |
u32 new_pad, new_pad_t[2]; |
12 |
u32 joy_value = 0; |
13 |
static int test_joy = 0; |
14 |
|
15 |
//--------------------------------------------------------------------------- |
16 |
// read PAD, without KB, and allow no auto-repeat. This is needed in code |
17 |
// that is used regardless of VSync cycles, and where KB is not wanted. |
18 |
//--------------------------------------------------------------------------- |
19 |
int readpad_noKBnoRepeat(void) |
20 |
{ |
21 |
int port, state, ret[2]; |
22 |
|
23 |
for(port=0; port<2; port++){ |
24 |
if((state=padGetState(port, 0))==PAD_STATE_STABLE |
25 |
||(state == PAD_STATE_FINDCTP1)){ |
26 |
//Deal with cases where pad state is valid for padRead |
27 |
ret[port] = padRead(port, 0, &buttons_t[port]); |
28 |
if (ret[port] != 0){ |
29 |
paddata_t[port] = 0xffff ^ buttons_t[port].btns; |
30 |
new_pad_t[port] = paddata_t[port] & ~old_pad_t[port]; |
31 |
old_pad_t[port] = paddata_t[port]; |
32 |
} |
33 |
}else{ |
34 |
//Deal with cases where pad state is not valid for padRead |
35 |
new_pad_t[port]=0; |
36 |
} //ends 'if' testing for state valid for padRead |
37 |
} //ends for |
38 |
new_pad = new_pad_t[0]|new_pad_t[1]; //This has only new button bits |
39 |
paddata = paddata_t[0]|paddata_t[1]; //This has all pressed button bits |
40 |
return (ret[0]|ret[1]); |
41 |
} |
42 |
//------------------------------ |
43 |
//endfunc readpad_noKBnoRepeat |
44 |
//--------------------------------------------------------------------------- |
45 |
// read PAD, but ignore KB. This is needed in code with own KB handlers, |
46 |
// such as the virtual keyboard input routines for 'Rename' and 'New Dir' |
47 |
//--------------------------------------------------------------------------- |
48 |
int readpad_no_KB(void) |
49 |
{ |
50 |
static u64 rpt_time[2]={0,0}; |
51 |
static int rpt_count[2]; |
52 |
int port, state, ret[2]; |
53 |
|
54 |
for(port=0; port<2; port++){ |
55 |
if((state=padGetState(port, 0))==PAD_STATE_STABLE |
56 |
||(state == PAD_STATE_FINDCTP1)){ |
57 |
//Deal with cases where pad state is valid for padRead |
58 |
ret[port] = padRead(port, 0, &buttons_t[port]); |
59 |
if (ret[port] != 0){ |
60 |
paddata_t[port] = 0xffff ^ buttons_t[port].btns; |
61 |
if((padtype_t[port] == 2) && (1 & (test_joy++))){//DualShock && time for joy scan |
62 |
joy_value=0; |
63 |
if(buttons_t[port].rjoy_h >= 0xbf){ |
64 |
paddata_t[port]=PAD_R3_H1; |
65 |
joy_value=buttons_t[port].rjoy_h-0xbf; |
66 |
}else if(buttons_t[port].rjoy_h <= 0x40){ |
67 |
paddata_t[port]=PAD_R3_H0; |
68 |
joy_value=-(buttons_t[port].rjoy_h-0x40); |
69 |
}else if(buttons_t[port].rjoy_v <= 0x40){ |
70 |
paddata_t[port]=PAD_R3_V0; |
71 |
joy_value=-(buttons_t[port].rjoy_v-0x40); |
72 |
}else if(buttons_t[port].rjoy_v >= 0xbf){ |
73 |
paddata_t[port]=PAD_R3_V1; |
74 |
joy_value=buttons_t[port].rjoy_v-0xbf; |
75 |
}else if(buttons_t[port].ljoy_h >= 0xbf){ |
76 |
paddata_t[port]=PAD_L3_H1; |
77 |
joy_value=buttons_t[port].ljoy_h-0xbf; |
78 |
}else if(buttons_t[port].ljoy_h <= 0x40){ |
79 |
paddata_t[port]=PAD_L3_H0; |
80 |
joy_value=-(buttons_t[port].ljoy_h-0x40); |
81 |
}else if(buttons_t[port].ljoy_v <= 0x40){ |
82 |
paddata_t[port]=PAD_L3_V0; |
83 |
joy_value=-(buttons_t[port].ljoy_v-0x40); |
84 |
}else if(buttons_t[port].ljoy_v >= 0xbf){ |
85 |
paddata_t[port]=PAD_L3_V1; |
86 |
joy_value=buttons_t[port].ljoy_v-0xbf; |
87 |
} |
88 |
} |
89 |
new_pad_t[port] = paddata_t[port] & ~old_pad_t[port]; |
90 |
if(old_pad_t[port] == paddata_t[port]){ |
91 |
//no change of pad data |
92 |
if(Timer() > rpt_time[port]){ |
93 |
new_pad_t[port]=paddata_t[port]; //Accept repeated buttons as new |
94 |
rpt_time[port] = Timer() + 40; //Min delay = 40ms => 25Hz repeat |
95 |
if(rpt_count[port]++ < 20) |
96 |
rpt_time[port] += 43; //Early delays = 83ms => 12Hz repeat |
97 |
} |
98 |
}else{ |
99 |
//pad data has changed ! |
100 |
rpt_count[port] = 0; |
101 |
rpt_time[port] = Timer()+400; //Init delay = 400ms |
102 |
old_pad_t[port] = paddata_t[port]; |
103 |
} |
104 |
} |
105 |
}else{ |
106 |
//Deal with cases where pad state is not valid for padRead |
107 |
//NB: This should NOT clear KB repeat test variables |
108 |
new_pad_t[port]=0; |
109 |
//old_pad_t[port]=0; //Clearing this could cause hasty repeats |
110 |
} //ends 'if' testing for state valid for padRead |
111 |
} //ends for |
112 |
new_pad = new_pad_t[0]|new_pad_t[1]; |
113 |
paddata = paddata_t[0]|paddata_t[1]; //This has all pressed button bits |
114 |
return (ret[0]|ret[1]); |
115 |
} |
116 |
//------------------------------ |
117 |
//endfunc readpad_no_KB |
118 |
//--------------------------------------------------------------------------- |
119 |
// simPadKB attempts reading data from a USB keyboard, and map this as a |
120 |
// virtual gamepad. (Very improvised and sloppy, but it should work fine.) |
121 |
//--------------------------------------------------------------------------- |
122 |
int simPadKB(void) |
123 |
{ |
124 |
int ret, command; |
125 |
unsigned char KeyPress; |
126 |
|
127 |
if((!setting->usbkbd_used)||(!PS2KbdRead(&KeyPress))) |
128 |
return 0; |
129 |
if(KeyPress != PS2KBD_ESCAPE_KEY) |
130 |
command = KeyPress; |
131 |
else { |
132 |
PS2KbdRead(&KeyPress); |
133 |
command = 0x100+KeyPress; |
134 |
} |
135 |
ret = 1; //Assume that the entered key is a valid command |
136 |
switch(command) { |
137 |
case 0x11B: //Escape == Triangle |
138 |
new_pad = PAD_TRIANGLE; |
139 |
break; |
140 |
case 0x00A: //Enter == OK |
141 |
if(!swapKeys) |
142 |
new_pad = PAD_CIRCLE; |
143 |
else |
144 |
new_pad = PAD_CROSS; |
145 |
break; |
146 |
case 0x020: //Space == Cancel/Mark |
147 |
if(!swapKeys) |
148 |
new_pad = PAD_CROSS; |
149 |
else |
150 |
new_pad = PAD_CIRCLE; |
151 |
break; |
152 |
case 0x031: //'1' == L1 |
153 |
new_pad = PAD_L1; |
154 |
break; |
155 |
case 0x032: //'2' == L2 |
156 |
new_pad = PAD_L2; |
157 |
break; |
158 |
case 0x033: //'3' == L3 |
159 |
new_pad = PAD_L3; |
160 |
break; |
161 |
case 0x077: //'w' == Up |
162 |
new_pad = PAD_UP; |
163 |
break; |
164 |
case 0x061: //'a' == Left |
165 |
new_pad = PAD_LEFT; |
166 |
break; |
167 |
case 0x073: //'s' == Right |
168 |
new_pad = PAD_RIGHT; |
169 |
break; |
170 |
case 0x07A: //'z' == Down |
171 |
new_pad = PAD_DOWN; |
172 |
break; |
173 |
case 0x030: //'0' == R1 |
174 |
new_pad = PAD_R1; |
175 |
break; |
176 |
case 0x039: //'9' == R2 |
177 |
new_pad = PAD_R2; |
178 |
break; |
179 |
case 0x038: //'8' == R3 |
180 |
new_pad = PAD_R3; |
181 |
break; |
182 |
case 0x069: //'i' == Triangle |
183 |
new_pad = PAD_TRIANGLE; |
184 |
break; |
185 |
case 0x06A: //'j' == Square |
186 |
new_pad = PAD_SQUARE; |
187 |
break; |
188 |
case 0x06B: //'k' == Circle |
189 |
new_pad = PAD_CIRCLE; |
190 |
break; |
191 |
case 0x06D: //'m' == Cross |
192 |
new_pad = PAD_CROSS; |
193 |
break; |
194 |
case 0x101: //F1 == L1 |
195 |
new_pad = PAD_L1; |
196 |
break; |
197 |
case 0x102: //F2 == L2 |
198 |
new_pad = PAD_L2; |
199 |
break; |
200 |
case 0x103: //F3 == L3 |
201 |
new_pad = PAD_L3; |
202 |
break; |
203 |
case 0x12C: //Up == Up |
204 |
new_pad = PAD_UP; |
205 |
break; |
206 |
case 0x12A: //Left == Left |
207 |
new_pad = PAD_LEFT; |
208 |
break; |
209 |
case 0x129: //Right == Right |
210 |
new_pad = PAD_RIGHT; |
211 |
break; |
212 |
case 0x12B: //Down == Down |
213 |
new_pad = PAD_DOWN; |
214 |
break; |
215 |
case 0x123: //Insert == Select |
216 |
new_pad = PAD_SELECT; |
217 |
break; |
218 |
case 0x10C: //F12 == R1 |
219 |
new_pad = PAD_R1; |
220 |
break; |
221 |
case 0x10B: //F11 == R2 |
222 |
new_pad = PAD_R2; |
223 |
break; |
224 |
case 0x10A: //F10 == R3 |
225 |
new_pad = PAD_R3; |
226 |
break; |
227 |
case 0x124: //Home == Triangle |
228 |
new_pad = PAD_TRIANGLE; |
229 |
break; |
230 |
case 0x127: //End == Square |
231 |
new_pad = PAD_SQUARE; |
232 |
break; |
233 |
case 0x125: //PgUp == Circle |
234 |
new_pad = PAD_CIRCLE; |
235 |
break; |
236 |
case 0x128: //PgDn == Cross |
237 |
new_pad = PAD_CROSS; |
238 |
break; |
239 |
case 0x126: //Delete == Start |
240 |
new_pad = PAD_START; |
241 |
break; |
242 |
default: //Unrecognized key => no pad button |
243 |
ret = 0; |
244 |
break; |
245 |
} |
246 |
return ret; |
247 |
} |
248 |
//------------------------------ |
249 |
//endfunc simPadKB |
250 |
//--------------------------------------------------------------------------- |
251 |
// readpad will call readpad_no_KB, and if no new pad buttons are found, it |
252 |
// will also attempt reading data from a USB keyboard, and map this as a |
253 |
// virtual gamepad. (Very improvised and sloppy, but it should work fine.) |
254 |
//--------------------------------------------------------------------------- |
255 |
int readpad(void) |
256 |
{ |
257 |
int ret; |
258 |
|
259 |
if((ret=readpad_no_KB()) && new_pad) |
260 |
return ret; |
261 |
|
262 |
return simPadKB(); |
263 |
} |
264 |
//------------------------------ |
265 |
//endfunc readpad |
266 |
//--------------------------------------------------------------------------- |
267 |
// readpad_noRepeat calls readpad_noKBnoRepeat, and if no new pad buttons are |
268 |
// found, it also attempts reading data from a USB keyboard, and map this as |
269 |
// a virtual gamepad. (Very improvised and sloppy, but it should work fine.) |
270 |
//--------------------------------------------------------------------------- |
271 |
int readpad_noRepeat(void) |
272 |
{ |
273 |
int ret; |
274 |
|
275 |
if((ret=readpad_noKBnoRepeat()) && new_pad) |
276 |
return ret; |
277 |
|
278 |
return simPadKB(); |
279 |
} |
280 |
//------------------------------ |
281 |
//endfunc readpad_noRepeat |
282 |
//--------------------------------------------------------------------------- |
283 |
// Wait for specific PAD, but also accept disconnected state |
284 |
void waitPadReady(int port, int slot) |
285 |
{ |
286 |
int state, lastState; |
287 |
char stateString[16]; |
288 |
|
289 |
state = padGetState(port, slot); |
290 |
lastState = -1; |
291 |
while((state != PAD_STATE_DISCONN) |
292 |
&& (state != PAD_STATE_STABLE) |
293 |
&& (state != PAD_STATE_FINDCTP1)){ |
294 |
if (state != lastState) |
295 |
padStateInt2String(state, stateString); |
296 |
lastState = state; |
297 |
state=padGetState(port, slot); |
298 |
} |
299 |
} |
300 |
//--------------------------------------------------------------------------- |
301 |
// Wait for any PAD, but also accept disconnected states |
302 |
void waitAnyPadReady(void) |
303 |
{ |
304 |
int state_1, state_2; |
305 |
|
306 |
state_1 = padGetState(0, 0); |
307 |
state_2 = padGetState(1, 0); |
308 |
while((state_1 != PAD_STATE_DISCONN) && (state_2 != PAD_STATE_DISCONN) |
309 |
&& (state_1 != PAD_STATE_STABLE) && (state_2 != PAD_STATE_STABLE) |
310 |
&& (state_1 != PAD_STATE_FINDCTP1) && (state_2 != PAD_STATE_FINDCTP1)){ |
311 |
state_1 = padGetState(0, 0); |
312 |
state_2 = padGetState(1, 0); |
313 |
} |
314 |
} |
315 |
//--------------------------------------------------------------------------- |
316 |
// setup PAD |
317 |
int setupPad(void) |
318 |
{ |
319 |
int ret, i, port, state, modes; |
320 |
|
321 |
padInit(0); |
322 |
|
323 |
for(port=0; port<2; port++){ |
324 |
padtype_t[port] = 0; //Assume that we don't have a proper PS2 controller |
325 |
if((ret = padPortOpen(port, 0, &padBuf_t[port][0])) == 0) |
326 |
return 0; |
327 |
waitPadReady(port, 0); |
328 |
state = padGetState(port, 0); |
329 |
if(state != PAD_STATE_DISCONN){ //if anything connected to this port |
330 |
modes = padInfoMode(port, 0, PAD_MODETABLE, -1); |
331 |
if (modes != 0){ //modes != 0, so it may be a dualshock type |
332 |
for(i=0; i<modes; i++){ |
333 |
if (padInfoMode(port, 0, PAD_MODETABLE, i) == PAD_TYPE_DUALSHOCK){ |
334 |
padtype_t[port] = 2; //flag normal PS2 controller |
335 |
break; |
336 |
} |
337 |
} //ends for (modes) |
338 |
} else { //modes == 0, so this is a digital controller |
339 |
padtype_t[port] = 1; //flag digital controller |
340 |
} |
341 |
if(padtype_t[port] == 2) //if DualShock |
342 |
padSetMainMode(port, 0, PAD_MMODE_DUALSHOCK, PAD_MMODE_LOCK); //Set DualShock |
343 |
else //else |
344 |
padSetMainMode(port, 0, PAD_MMODE_DIGITAL, PAD_MMODE_UNLOCK); //Set Digital |
345 |
waitPadReady(port, 0); //Await completion |
346 |
} else { //Nothing is connected to this port |
347 |
padSetMainMode(port, 0, PAD_MMODE_DUALSHOCK, PAD_MMODE_LOCK); //Fake DualShock |
348 |
waitPadReady(port, 0); //Await completion |
349 |
} |
350 |
} //ends for (port) |
351 |
return 1; |
352 |
} |
353 |
//--------------------------------------------------------------------------- |
354 |
// End of file: pad.c |
355 |
//--------------------------------------------------------------------------- |