| 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 |
//--------------------------------------------------------------------------- |