desmume/src/ctrlssdl.cpp

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;
}