514 lines
13 KiB
C++
514 lines
13 KiB
C++
/* joysdl.c - this file is part of DeSmuME
|
|
*
|
|
* Copyright (C) 2007 Pascal Giard
|
|
*
|
|
* Author: Pascal Giard <evilynux@gmail.com>
|
|
*
|
|
* This file is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This file is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; see the file COPYING. If not, write to
|
|
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
* Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
#include "ctrlssdl.h"
|
|
#include "saves.h"
|
|
#include "SPU.h"
|
|
|
|
u16 keyboard_cfg[NB_KEYS];
|
|
u16 joypad_cfg[NB_KEYS];
|
|
u16 nbr_joy;
|
|
mouse_status mouse;
|
|
|
|
extern volatile BOOL execute;
|
|
|
|
static SDL_Joystick **open_joysticks = NULL;
|
|
|
|
/* Keypad key names */
|
|
const char *key_names[NB_KEYS] =
|
|
{
|
|
"A", "B", "Select", "Start",
|
|
"Right", "Left", "Up", "Down",
|
|
"R", "L", "X", "Y",
|
|
"Debug", "Boost"
|
|
};
|
|
|
|
/* Default joypad configuration */
|
|
const u16 default_joypad_cfg[NB_KEYS] =
|
|
{ 1, // A
|
|
0, // B
|
|
5, // select
|
|
8, // start
|
|
256, // Right -- Start cheating abit...
|
|
256, // Left
|
|
512, // Up
|
|
512, // Down -- End of cheating.
|
|
7, // R
|
|
6, // L
|
|
4, // X
|
|
3, // Y
|
|
-1, // DEBUG
|
|
-1 // BOOST
|
|
};
|
|
|
|
const u16 plain_keyboard_cfg[NB_KEYS] =
|
|
{
|
|
'x', // A
|
|
'z', // B
|
|
'y', // select
|
|
'u', // start
|
|
'l', // Right
|
|
'j', // Left
|
|
'i', // Up
|
|
'k', // Down
|
|
'w', // R
|
|
'q', // L
|
|
's', // X
|
|
'a', // Y
|
|
'p', // DEBUG
|
|
'o' // BOOST
|
|
};
|
|
|
|
/* Load default joystick and keyboard configurations */
|
|
void load_default_config(const u16 kbCfg[])
|
|
{
|
|
memcpy(keyboard_cfg, kbCfg, sizeof(keyboard_cfg));
|
|
memcpy(joypad_cfg, default_joypad_cfg, sizeof(joypad_cfg));
|
|
}
|
|
|
|
/* Initialize joysticks */
|
|
BOOL init_joy( void) {
|
|
int i;
|
|
BOOL joy_init_good = TRUE;
|
|
|
|
set_joy_keys(default_joypad_cfg);
|
|
|
|
if(SDL_InitSubSystem(SDL_INIT_JOYSTICK) == -1)
|
|
{
|
|
fprintf(stderr, "Error trying to initialize joystick support: %s\n",
|
|
SDL_GetError());
|
|
return FALSE;
|
|
}
|
|
|
|
nbr_joy = SDL_NumJoysticks();
|
|
|
|
if ( nbr_joy > 0) {
|
|
printf("Found %d joysticks\n", nbr_joy);
|
|
open_joysticks =
|
|
(SDL_Joystick**)calloc( sizeof ( SDL_Joystick *), nbr_joy);
|
|
|
|
if ( open_joysticks != NULL) {
|
|
for (i = 0; i < nbr_joy; i++)
|
|
{
|
|
SDL_Joystick * joy = SDL_JoystickOpen(i);
|
|
printf("Joystick %d %s\n", i, SDL_JoystickName(i));
|
|
printf("Axes: %d\n", SDL_JoystickNumAxes(joy));
|
|
printf("Buttons: %d\n", SDL_JoystickNumButtons(joy));
|
|
printf("Trackballs: %d\n", SDL_JoystickNumBalls(joy));
|
|
printf("Hats: %d\n\n", SDL_JoystickNumHats(joy));
|
|
}
|
|
}
|
|
else {
|
|
joy_init_good = FALSE;
|
|
}
|
|
}
|
|
|
|
return joy_init_good;
|
|
}
|
|
|
|
/* Set all buttons at once */
|
|
void set_joy_keys(const u16 joyCfg[])
|
|
{
|
|
memcpy(joypad_cfg, joyCfg, sizeof(joypad_cfg));
|
|
}
|
|
|
|
/* Set all buttons at once */
|
|
void set_kb_keys(const u16 kbCfg[])
|
|
{
|
|
memcpy(keyboard_cfg, kbCfg, sizeof(keyboard_cfg));
|
|
}
|
|
|
|
/* Unload joysticks */
|
|
void uninit_joy( void)
|
|
{
|
|
int i;
|
|
|
|
if ( open_joysticks != NULL) {
|
|
for (i = 0; i < SDL_NumJoysticks(); i++) {
|
|
SDL_JoystickClose( open_joysticks[i]);
|
|
}
|
|
|
|
free( open_joysticks);
|
|
}
|
|
|
|
open_joysticks = NULL;
|
|
SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
|
|
}
|
|
|
|
/* Return keypad vector with given key set to 1 */
|
|
u16 lookup_joy_key (u16 keyval) {
|
|
int i;
|
|
u16 Key = 0;
|
|
for(i = 0; i < NB_KEYS; i++)
|
|
if(keyval == joypad_cfg[i]) break;
|
|
if(i < NB_KEYS) Key = KEYMASK_(i);
|
|
return Key;
|
|
}
|
|
|
|
/* Return keypad vector with given key set to 1 */
|
|
u16 lookup_key (u16 keyval) {
|
|
int i;
|
|
u16 Key = 0;
|
|
for(i = 0; i < NB_KEYS; i++)
|
|
if(keyval == keyboard_cfg[i]) break;
|
|
if(i < NB_KEYS) Key = KEYMASK_(i);
|
|
return Key;
|
|
}
|
|
|
|
/* Empty SDL Events' queue */
|
|
static void clear_events( void)
|
|
{
|
|
SDL_Event event;
|
|
/* IMPORTANT: Reenable joystick events iif needed. */
|
|
if(SDL_JoystickEventState(SDL_QUERY) == SDL_IGNORE)
|
|
SDL_JoystickEventState(SDL_ENABLE);
|
|
|
|
/* There's an event waiting to be processed? */
|
|
while (SDL_PollEvent(&event))
|
|
{
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/* Get and set a new joystick key */
|
|
u16 get_set_joy_key(int index) {
|
|
BOOL done = FALSE;
|
|
SDL_Event event;
|
|
u16 key = joypad_cfg[index];
|
|
|
|
/* Enable joystick events if needed */
|
|
if( SDL_JoystickEventState(SDL_QUERY) == SDL_IGNORE )
|
|
SDL_JoystickEventState(SDL_ENABLE);
|
|
|
|
while(SDL_WaitEvent(&event) && !done)
|
|
{
|
|
switch(event.type)
|
|
{
|
|
case SDL_JOYBUTTONDOWN:
|
|
printf( "Got joykey: %d\n", event.jbutton.button );
|
|
key = event.jbutton.button;
|
|
done = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if( SDL_JoystickEventState(SDL_QUERY) == SDL_ENABLE )
|
|
SDL_JoystickEventState(SDL_IGNORE);
|
|
joypad_cfg[index] = key;
|
|
|
|
return key;
|
|
}
|
|
|
|
/* Reset corresponding key and its twin axis key */
|
|
static u16 get_joy_axis_twin(u16 key)
|
|
{
|
|
switch(key)
|
|
{
|
|
case KEYMASK_( KEY_RIGHT-1 ):
|
|
return KEYMASK_( KEY_LEFT-1 );
|
|
case KEYMASK_( KEY_UP-1 ):
|
|
return KEYMASK_( KEY_DOWN-1 );
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/* Get and set a new joystick axis */
|
|
void get_set_joy_axis(int index, int index_o) {
|
|
BOOL done = FALSE;
|
|
SDL_Event event;
|
|
u16 key = joypad_cfg[index];
|
|
|
|
/* Clear events */
|
|
clear_events();
|
|
/* Enable joystick events if needed */
|
|
if( SDL_JoystickEventState(SDL_QUERY) == SDL_IGNORE )
|
|
SDL_JoystickEventState(SDL_ENABLE);
|
|
|
|
while(SDL_WaitEvent(&event) && !done)
|
|
{
|
|
switch(event.type)
|
|
{
|
|
case SDL_JOYAXISMOTION:
|
|
/* Discriminate small movements */
|
|
if( (event.jaxis.value >> 5) != 0 )
|
|
{
|
|
key = JOY_AXIS_(event.jaxis.axis);
|
|
done = TRUE;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
if( SDL_JoystickEventState(SDL_QUERY) == SDL_ENABLE )
|
|
SDL_JoystickEventState(SDL_IGNORE);
|
|
/* Update configuration */
|
|
joypad_cfg[index] = key;
|
|
joypad_cfg[index_o] = joypad_cfg[index];
|
|
}
|
|
|
|
static signed long
|
|
screen_to_touch_range_x( signed long scr_x, float size_ratio) {
|
|
signed long touch_x = (signed long)((float)scr_x * size_ratio);
|
|
|
|
return touch_x;
|
|
}
|
|
|
|
static signed long
|
|
screen_to_touch_range_y( signed long scr_y, float size_ratio) {
|
|
signed long touch_y = (signed long)((float)scr_y * size_ratio);
|
|
|
|
return touch_y;
|
|
}
|
|
|
|
/* Set mouse coordinates */
|
|
void set_mouse_coord(signed long x,signed long y)
|
|
{
|
|
if(x<0) x = 0; else if(x>255) x = 255;
|
|
if(y<0) y = 0; else if(y>192) y = 192;
|
|
mouse.x = x;
|
|
mouse.y = y;
|
|
}
|
|
|
|
/* Update NDS keypad */
|
|
void update_keypad(u16 keys)
|
|
{
|
|
#ifdef WORDS_BIGENDIAN
|
|
ARM9Mem.ARM9_REG[0x130] = ~keys & 0xFF;
|
|
ARM9Mem.ARM9_REG[0x131] = (~keys >> 8) & 0x3;
|
|
MMU.ARM7_REG[0x130] = ~keys & 0xFF;
|
|
MMU.ARM7_REG[0x131] = (~keys >> 8) & 0x3;
|
|
#else
|
|
((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] = ~keys & 0x3FF;
|
|
((u16 *)MMU.ARM7_REG)[0x130>>1] = ~keys & 0x3FF;
|
|
#endif
|
|
/* Update X and Y buttons */
|
|
MMU.ARM7_REG[0x136] = ( ~( keys >> 10) & 0x3 ) | (MMU.ARM7_REG[0x136] & ~0x3);
|
|
}
|
|
|
|
/* Retrieve current NDS keypad */
|
|
u16 get_keypad( void)
|
|
{
|
|
u16 keypad;
|
|
keypad = ~MMU.ARM7_REG[0x136];
|
|
keypad = (keypad & 0x3) << 10;
|
|
#ifdef WORDS_BIGENDIAN
|
|
keypad |= ~(ARM9Mem.ARM9_REG[0x130] | (ARM9Mem.ARM9_REG[0x131] << 8)) & 0x3FF;
|
|
#else
|
|
keypad |= ~((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] & 0x3FF;
|
|
#endif
|
|
return keypad;
|
|
}
|
|
|
|
/*
|
|
* The internal joystick events processing function
|
|
*/
|
|
static int
|
|
do_process_joystick_events( u16 *keypad, SDL_Event *event) {
|
|
int processed = 1;
|
|
u16 key;
|
|
|
|
switch ( event->type)
|
|
{
|
|
/* Joystick axis motion
|
|
Note: button constants have a 1bit offset. */
|
|
case SDL_JOYAXISMOTION:
|
|
key = lookup_joy_key( JOY_AXIS_(event->jaxis.axis) );
|
|
if( key == 0 ) break; /* Not an axis of interest? */
|
|
|
|
/* Axis is back to initial position */
|
|
if( event->jaxis.value == 0 )
|
|
RM_KEY( *keypad, key | get_joy_axis_twin(key) );
|
|
/* Key should have been down but its currently set to up? */
|
|
else if( (event->jaxis.value > 0) &&
|
|
(key == KEYMASK_( KEY_UP-1 )) )
|
|
key = KEYMASK_( KEY_DOWN-1 );
|
|
/* Key should have been left but its currently set to right? */
|
|
else if( (event->jaxis.value < 0) &&
|
|
(key == KEYMASK_( KEY_RIGHT-1 )) )
|
|
key = KEYMASK_( KEY_LEFT-1 );
|
|
|
|
/* Remove some sensitivity before checking if different than zero...
|
|
Fixes some badly behaving joypads [like one of mine]. */
|
|
if( (event->jaxis.value >> 5) != 0 )
|
|
ADD_KEY( *keypad, key );
|
|
break;
|
|
|
|
/* Joystick button pressed */
|
|
/* FIXME: Add support for BOOST */
|
|
case SDL_JOYBUTTONDOWN:
|
|
key = lookup_joy_key( event->jbutton.button );
|
|
ADD_KEY( *keypad, key );
|
|
break;
|
|
|
|
/* Joystick button released */
|
|
case SDL_JOYBUTTONUP:
|
|
key = lookup_joy_key(event->jbutton.button);
|
|
RM_KEY( *keypad, key );
|
|
break;
|
|
|
|
default:
|
|
processed = 0;
|
|
break;
|
|
}
|
|
|
|
return processed;
|
|
}
|
|
|
|
/*
|
|
* Process only the joystick events
|
|
*/
|
|
void
|
|
process_joystick_events( u16 *keypad) {
|
|
SDL_Event event;
|
|
|
|
/* IMPORTANT: Reenable joystick events iif needed. */
|
|
if(SDL_JoystickEventState(SDL_QUERY) == SDL_IGNORE)
|
|
SDL_JoystickEventState(SDL_ENABLE);
|
|
|
|
/* There's an event waiting to be processed? */
|
|
while (SDL_PollEvent(&event))
|
|
{
|
|
do_process_joystick_events( keypad, &event);
|
|
}
|
|
}
|
|
|
|
u16 shift_pressed;
|
|
|
|
/* Manage input events */
|
|
int
|
|
process_ctrls_events( u16 *keypad,
|
|
void (*external_videoResizeFn)( u16 width, u16 height),
|
|
float nds_screen_size_ratio)
|
|
{
|
|
u16 key;
|
|
int cause_quit = 0;
|
|
SDL_Event event;
|
|
|
|
/* IMPORTANT: Reenable joystick events iif needed. */
|
|
if(SDL_JoystickEventState(SDL_QUERY) == SDL_IGNORE)
|
|
SDL_JoystickEventState(SDL_ENABLE);
|
|
|
|
/* There's an event waiting to be processed? */
|
|
while (SDL_PollEvent(&event))
|
|
{
|
|
if ( !do_process_joystick_events( keypad, &event)) {
|
|
switch (event.type)
|
|
{
|
|
case SDL_VIDEORESIZE:
|
|
if ( external_videoResizeFn != NULL) {
|
|
external_videoResizeFn( event.resize.w, event.resize.h);
|
|
}
|
|
break;
|
|
|
|
case SDL_KEYDOWN:
|
|
switch(event.key.keysym.sym){
|
|
case SDLK_LSHIFT:
|
|
shift_pressed |= 1;
|
|
break;
|
|
case SDLK_RSHIFT:
|
|
shift_pressed |= 2;
|
|
break;
|
|
default:
|
|
key = lookup_key(event.key.keysym.sym);
|
|
ADD_KEY( *keypad, key );
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case SDL_KEYUP:
|
|
switch(event.key.keysym.sym){
|
|
case SDLK_LSHIFT:
|
|
shift_pressed &= ~1;
|
|
break;
|
|
case SDLK_RSHIFT:
|
|
shift_pressed &= ~2;
|
|
break;
|
|
|
|
case SDLK_F1:
|
|
case SDLK_F2:
|
|
case SDLK_F3:
|
|
case SDLK_F4:
|
|
case SDLK_F5:
|
|
case SDLK_F6:
|
|
case SDLK_F7:
|
|
case SDLK_F8:
|
|
case SDLK_F9:
|
|
case SDLK_F10:
|
|
int prevexec;
|
|
prevexec = execute;
|
|
execute = FALSE;
|
|
SPU_Pause(1);
|
|
if(!shift_pressed){
|
|
loadstate_slot(event.key.keysym.sym - SDLK_F1 + 1);
|
|
}else{
|
|
savestate_slot(event.key.keysym.sym - SDLK_F1 + 1);
|
|
}
|
|
execute = prevexec;
|
|
SPU_Pause(!execute);
|
|
break;
|
|
default:
|
|
key = lookup_key(event.key.keysym.sym);
|
|
RM_KEY( *keypad, key );
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case SDL_MOUSEBUTTONDOWN:
|
|
if(event.button.button==1)
|
|
mouse.down = TRUE;
|
|
|
|
case SDL_MOUSEMOTION:
|
|
if(!mouse.down)
|
|
break;
|
|
else {
|
|
signed long scaled_x =
|
|
screen_to_touch_range_x( event.button.x,
|
|
nds_screen_size_ratio);
|
|
signed long scaled_y =
|
|
screen_to_touch_range_y( event.button.y,
|
|
nds_screen_size_ratio);
|
|
|
|
if( scaled_y >= 192)
|
|
set_mouse_coord( scaled_x, scaled_y - 192);
|
|
}
|
|
break;
|
|
|
|
case SDL_MOUSEBUTTONUP:
|
|
if(mouse.down) mouse.click = TRUE;
|
|
mouse.down = FALSE;
|
|
break;
|
|
|
|
case SDL_QUIT:
|
|
cause_quit = 1;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return cause_quit;
|
|
}
|
|
|