Apply patch #2998037 from noodlebox:

1) Larger dead zone for analog controls.  Also fixed possible
 issue where negative side of dead zone might not be applied.
 (right bitwise shift applied to negative integers, implementation seems to vary)
2) Analog controls can now be assigned to buttons, and
 non-analog controls can now be assigned to the directional controls.
3) Differentiates between positive and negative movement
 for analog controls.
4) In the GTK and Glade ports, directional buttons can now
 be set independently of their "twins".
5) Hat/POV/D-Pad controls are usable now.
6) Differentiates between multiple controllers.
7) Slightly modified method of storing joypad key codes, in
 a way similar to VBA-M's method of configging controls, though
 I kept the codes as u16's.  The way it's arranged now will allow
 for up to 16 unique joypads, and up to 128 axes, 64 POV hats,
 and 256 Buttons per joypad, which should probably be enough.
 The method of determining a key code is explained in ctrlssdl.cpp.
 Basically, it starts with 0x1000 * joypad_index.
 For buttons, add 0x200 + button_index.
 For hats, add 0x100 + 4 * hat_index + (0, 1, 2, or 3 for R, L, U, D). 
 For axes, add 2 * axis_index + (0 or 1 for negative or positive). 
 Maybe there's a way to get the config file to save these values in
 a hexadecimal representation for easier editing, but I didn't really
 mess with the configs.

So, the reason I decided to try this was that I was having some issues
with my wired XBox 360 controller in the Linux GTK, Glade, and CLI ports
(The controller works fine otherwise).
It seemed to be very sensitive, so it was impossible to "zero" the axes,
which leads to constantly scrolling through menus, etc.  The slightest
touch would trigger the input.  Also wanted to be able to use the D-Pad
and Analog triggers for something useful. The distinction between multiple
"joypads" should also help anyone with any other odd input devices being
recognized, like accelerometers. 

[rm: removed clear_events() from ctrlsdl.cpp since it is unused ]
This commit is contained in:
riccardom 2010-05-09 15:21:17 +00:00
parent fb7ebf22f4
commit d25ec2d119
6 changed files with 144 additions and 178 deletions

View File

@ -46,22 +46,35 @@ const char *key_names[NB_KEYS] =
"Debug", "Boost"
};
/* Joypad Key Codes -- 4-digit Hexadecimal number
* 1st digit: device ID (0 is first joypad, 1 is second, etc.)
* 2nd digit: 0 - Axis, 1 - Hat/POV/D-Pad, 2 - Button
* 3rd & 4th digit: (depends on input type)
* Negative Axis - 2 * axis index
* Positive Axis - 2 * axis index + 1
* Hat Right - 4 * hat index
* Hat Left - 4 * hat index + 1
* Hat Up - 4 * hat index + 2
* Hat Down - 4 * hat index + 3
* Button - button index
*/
/* 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
{ 0x0201, // A
0x0200, // B
0x0205, // select
0x0208, // start
0x0001, // Right
0x0000, // Left
0x0002, // Up
0x0003, // Down
0x0207, // R
0x0206, // L
0x0204, // X
0x0203, // Y
0xFFFF, // DEBUG
0xFFFF // BOOST
};
const u16 plain_keyboard_cfg[NB_KEYS] =
@ -184,22 +197,6 @@ u16 lookup_key (u16 keyval) {
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 pressed joystick key */
u16 get_joy_key(int index) {
BOOL done = FALSE;
@ -215,10 +212,49 @@ u16 get_joy_key(int index) {
switch(event.type)
{
case SDL_JOYBUTTONDOWN:
printf( "Got joykey: %d\n", event.jbutton.button );
key = event.jbutton.button;
printf( "Device: %d; Button: %d\n", event.jbutton.which, event.jbutton.button );
key = ((event.jbutton.which & 15) << 12) | JOY_BUTTON << 8 | (event.jbutton.button & 255);
done = TRUE;
break;
case SDL_JOYAXISMOTION:
/* Dead zone of 50% */
if( (abs(event.jaxis.value) >> 14) != 0 )
{
key = ((event.jaxis.which & 15) << 12) | JOY_AXIS << 8 | ((event.jaxis.axis & 127) << 1);
if (event.jaxis.value > 0) {
printf( "Device: %d; Axis: %d (+)\n", event.jaxis.which, event.jaxis.axis );
key |= 1;
}
else
printf( "Device: %d; Axis: %d (-)\n", event.jaxis.which, event.jaxis.axis );
done = TRUE;
}
break;
case SDL_JOYHATMOTION:
/* Diagonal positions will be treated as two separate keys being activated, rather than a single diagonal key. */
/* JOY_HAT_* are sequential integers, rather than a bitmask */
if (event.jhat.value != SDL_HAT_CENTERED) {
key = ((event.jhat.which & 15) << 12) | JOY_HAT << 8 | ((event.jhat.hat & 63) << 2);
/* Can't just use a switch here because SDL_HAT_* make up a bitmask. We only want one of these when assigning keys. */
if ((event.jhat.value & SDL_HAT_UP) != 0) {
key |= JOY_HAT_UP;
printf( "Device: %d; Hat: %d (Up)\n", event.jhat.which, event.jhat.hat );
}
else if ((event.jhat.value & SDL_HAT_RIGHT) != 0) {
key |= JOY_HAT_RIGHT;
printf( "Device: %d; Hat: %d (Right)\n", event.jhat.which, event.jhat.hat );
}
else if ((event.jhat.value & SDL_HAT_DOWN) != 0) {
key |= JOY_HAT_DOWN;
printf( "Device: %d; Hat: %d (Down)\n", event.jhat.which, event.jhat.hat );
}
else if ((event.jhat.value & SDL_HAT_LEFT) != 0) {
key |= JOY_HAT_LEFT;
printf( "Device: %d; Hat: %d (Left)\n", event.jhat.which, event.jhat.hat );
}
done = TRUE;
}
break;
}
}
@ -235,61 +271,6 @@ u16 get_set_joy_key(int index) {
return joypad_cfg[index];
}
/* 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 a new joystick axis */
u16 get_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);
return key;
}
/* Get and set a new joystick axis */
void get_set_joy_axis(int index, int index_o) {
u16 key = get_joy_axis(index, index_o);
/* 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);
@ -355,45 +336,84 @@ u16 get_keypad( void)
static int
do_process_joystick_events( u16 *keypad, SDL_Event *event) {
int processed = 1;
u16 key_code;
u16 key;
u16 key_o;
u16 key_u;
u16 key_r;
u16 key_d;
u16 key_l;
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? */
key_code = ((event->jaxis.which & 15) << 12) | JOY_AXIS << 8 | ((event->jaxis.axis & 127) << 1);
if( (abs(event->jaxis.value) >> 14) != 0 )
{
if (event->jaxis.value > 0)
key_code |= 1;
key = lookup_joy_key( key_code );
key_o = lookup_joy_key( key_code ^ 1 );
if (key != 0)
ADD_KEY( *keypad, key );
if (key_o != 0)
RM_KEY( *keypad, key_o );
}
else
{
// Axis is zeroed
key = lookup_joy_key( key_code );
key_o = lookup_joy_key( key_code ^ 1 );
if (key != 0)
RM_KEY( *keypad, key );
if (key_o != 0)
RM_KEY( *keypad, key_o );
}
break;
/* 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 );
case SDL_JOYHATMOTION:
/* Diagonal positions will be treated as two separate keys being activated, rather than a single diagonal key. */
/* JOY_HAT_* are sequential integers, rather than a bitmask */
key_code = ((event->jhat.which & 15) << 12) | JOY_HAT << 8 | ((event->jhat.hat & 63) << 2);
key_u = lookup_joy_key( key_code | JOY_HAT_UP );
key_r = lookup_joy_key( key_code | JOY_HAT_RIGHT );
key_d = lookup_joy_key( key_code | JOY_HAT_DOWN );
key_l = lookup_joy_key( key_code | JOY_HAT_LEFT );
if ((key_u != 0) && ((event->jhat.value & SDL_HAT_UP) != 0))
ADD_KEY( *keypad, key_u );
else if (key_u != 0)
RM_KEY( *keypad, key_u );
if ((key_r != 0) && ((event->jhat.value & SDL_HAT_RIGHT) != 0))
ADD_KEY( *keypad, key_r );
else if (key_r != 0)
RM_KEY( *keypad, key_r );
if ((key_d != 0) && ((event->jhat.value & SDL_HAT_DOWN) != 0))
ADD_KEY( *keypad, key_d );
else if (key_d != 0)
RM_KEY( *keypad, key_d );
if ((key_l != 0) && ((event->jhat.value & SDL_HAT_LEFT) != 0))
ADD_KEY( *keypad, key_l );
else if (key_l != 0)
RM_KEY( *keypad, key_l );
break;
/* Joystick button pressed */
/* FIXME: Add support for BOOST */
case SDL_JOYBUTTONDOWN:
key = lookup_joy_key( event->jbutton.button );
ADD_KEY( *keypad, key );
key_code = ((event->jbutton.which & 15) << 12) | JOY_BUTTON << 8 | (event->jbutton.button & 255);
key = lookup_joy_key( key_code );
if (key != 0)
ADD_KEY( *keypad, key );
break;
/* Joystick button released */
case SDL_JOYBUTTONUP:
key = lookup_joy_key(event->jbutton.button);
RM_KEY( *keypad, key );
key_code = ((event->jbutton.which & 15) << 12) | JOY_BUTTON << 8 | (event->jbutton.button & 255);
key = lookup_joy_key( key_code );
if (key != 0)
RM_KEY( *keypad, key );
break;
default:

View File

@ -35,7 +35,15 @@
#define ADD_KEY(keypad,key) ( (keypad) |= (key) )
#define RM_KEY(keypad,key) ( (keypad) &= ~(key) )
#define KEYMASK_(k) (1 << (k))
#define JOY_AXIS_(k) (((k)+1) << 8)
#define JOY_AXIS 0
#define JOY_HAT 1
#define JOY_BUTTON 2
#define JOY_HAT_RIGHT 0
#define JOY_HAT_LEFT 1
#define JOY_HAT_UP 2
#define JOY_HAT_DOWN 3
#define NB_KEYS 14
#define KEY_NONE 0
@ -95,8 +103,6 @@ void set_joy_keys(const u16 joyCfg[]);
void set_kb_keys(const u16 kbCfg[]);
u16 get_joy_key(int index);
u16 get_set_joy_key(int index);
u16 get_joy_axis(int index, int index_opp);
void get_set_joy_axis(int index, int index_opp);
void update_keypad(u16 keys);
u16 get_keypad( void);
u16 lookup_key (u16 keyval);

View File

@ -386,37 +386,6 @@ static void ask_joy_key(GtkButton*b, int key)
gtk_widget_hide((GtkWidget*)dlg);
}
/* Joystick configuration / Key definition */
static void ask_joy_axis(u8 key, u8 opposite_key)
{
char text[50];
char current_button[50], opposite_button[50];
GtkWidget * dlg;
GtkButton * btn;
key--; /* remove 1 to get index */
opposite_key--;
snprintf(current_button, 50, "button_joy_%s",key_names[key]);
snprintf(opposite_button, 50, "button_joy_%s",key_names[opposite_key]);
dlg = (GtkWidget*)glade_xml_get_widget(xml, "wJoyDlg");
gtk_widget_show(dlg);
/* Need to force event processing. Otherwise, popup won't show up. */
while ( gtk_events_pending() ) gtk_main_iteration();
get_set_joy_axis(key, opposite_key);
snprintf(text, 50, "%s : %d",key_names[key],joypad_cfg[key]);
btn = (GtkButton*)glade_xml_get_widget(xml, current_button);
gtk_button_set_label(btn,text);
snprintf(text, 50, "%s : %d",key_names[opposite_key],joypad_cfg[opposite_key]);
btn = (GtkButton*)glade_xml_get_widget(xml, opposite_button);
gtk_button_set_label(btn,text);
gtk_widget_hide((GtkWidget*)dlg);
}
/* Bind a keyboard key to a keypad key */
void on_button_kb_key_clicked (GtkButton *b, gpointer user_data)
{
@ -424,13 +393,6 @@ void on_button_kb_key_clicked (GtkButton *b, gpointer user_data)
ask( b, key );
}
/* Bind a joystick axis to a keypad directionnal pad */
void on_button_joy_axis_clicked (GtkButton *b, gpointer user_data)
{
int key = dyn_CAST( int, user_data );
ask_joy_axis( key, key+1 );
}
/* Bind a joystick button to a keypad key */
void on_button_joy_key_clicked (GtkButton *b, gpointer user_data)
{

View File

@ -46,7 +46,6 @@ G_MODULE_EXPORT void on_wKeybConfDlg_response (GtkDialog *dialog, gint arg1, gp
G_MODULE_EXPORT void on_button_kb_key_clicked (GtkButton *button, gpointer user_data);
/* Joystick configuration / Key definition */
G_MODULE_EXPORT void on_button_joy_axis_clicked (GtkButton *button, gpointer user_data);
G_MODULE_EXPORT void on_button_joy_key_clicked (GtkButton *button, gpointer user_data);
}

View File

@ -2121,7 +2121,7 @@ Contributors:
<property name="use_underline">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
<signal name="clicked" handler="on_button_joy_axis_clicked" object="%d:7" last_modification_time="Tue, 13 Feb 2007 07:13:04 GMT"/>
<signal name="clicked" handler="on_button_joy_key_clicked" object="%d:7" last_modification_time="Tue, 13 Feb 2007 07:13:04 GMT"/>
</widget>
<packing>
<property name="left_attach">1</property>
@ -2141,7 +2141,7 @@ Contributors:
<property name="use_underline">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
<signal name="clicked" handler="on_button_joy_axis_clicked" object="%d:7" last_modification_time="Tue, 13 Feb 2007 07:13:14 GMT"/>
<signal name="clicked" handler="on_button_joy_key_clicked" object="%d:8" last_modification_time="Tue, 13 Feb 2007 07:13:14 GMT"/>
</widget>
<packing>
<property name="left_attach">1</property>
@ -2161,7 +2161,7 @@ Contributors:
<property name="use_underline">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
<signal name="clicked" handler="on_button_joy_axis_clicked" object="%d:5" last_modification_time="Tue, 13 Feb 2007 07:13:29 GMT"/>
<signal name="clicked" handler="on_button_joy_key_clicked" object="%d:6" last_modification_time="Tue, 13 Feb 2007 07:13:29 GMT"/>
</widget>
<packing>
<property name="left_attach">0</property>
@ -2181,7 +2181,7 @@ Contributors:
<property name="use_underline">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
<signal name="clicked" handler="on_button_joy_axis_clicked" object="%d:5" last_modification_time="Tue, 13 Feb 2007 07:13:42 GMT"/>
<signal name="clicked" handler="on_button_joy_key_clicked" object="%d:5" last_modification_time="Tue, 13 Feb 2007 07:13:42 GMT"/>
</widget>
<packing>
<property name="left_attach">2</property>

View File

@ -1402,19 +1402,7 @@ static void AcceptNewJoyKey(GtkWidget *w, GdkEventFocus *e, struct modify_key_ct
{
gchar *YouPressed;
switch (ctx->key_id) {
case KEY_RIGHT:
case KEY_LEFT:
ctx->mk_key_chosen = get_joy_axis(KEY_LEFT, KEY_RIGHT);
break;
case KEY_UP:
case KEY_DOWN:
ctx->mk_key_chosen = get_joy_axis(KEY_UP, KEY_DOWN);
break;
default:
ctx->mk_key_chosen = get_joy_key(ctx->key_id);
break;
}
ctx->mk_key_chosen = get_joy_key(ctx->key_id);
YouPressed = g_strdup_printf("You pressed : %d\nClick OK to keep this key.", ctx->mk_key_chosen);
gtk_label_set(GTK_LABEL(ctx->label), YouPressed);
@ -1450,16 +1438,7 @@ static void Modify_JoyKey(GtkWidget* widget, gpointer data)
switch(gtk_dialog_run(GTK_DIALOG(mkDialog))) {
case GTK_RESPONSE_OK:
switch (ctx.key_id) {
case KEY_RIGHT:
case KEY_LEFT:
Keypad_Temp[KEY_RIGHT-1] = Keypad_Temp[KEY_LEFT-1] = ctx.mk_key_chosen;
case KEY_UP:
case KEY_DOWN:
Keypad_Temp[KEY_UP-1] = Keypad_Temp[KEY_DOWN-1] = ctx.mk_key_chosen;
default:
Keypad_Temp[Key] = ctx.mk_key_chosen;
}
Keypad_Temp[Key] = ctx.mk_key_chosen;
Key_Label = g_strdup_printf("%s (%d)", key_names[Key], Keypad_Temp[Key]);
gtk_button_set_label(GTK_BUTTON(widget), Key_Label);
g_free(Key_Label);