grafX2/input.c
Adrien Destugues 1cf83a2ed7 Fixed various aspects of the gp2x button handling :
- Default button mapping so you can at least click on the buttons
- Keep button press and button release in sync, so you use the same button for the same thing
- Fix display of the buttons

I noticed that ALT is interfering with the buttons names. Maybe we are using too much bits. CTRL and SHIFT work fine.
Also, the gp2x builds start by default in windowed mode at 640x480. This means the screen is hardware scaled down... that makes the program almost unusable, you have to go to the screen menu and switch to a more useable resolution. Finally, all the softscaled modes should be disabled, because the hardware scaler does its work very well :)


git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@844 416bcca6-2ee7-4201-b75f-2eb2f807beb1
2009-06-06 21:57:29 +00:00

773 lines
22 KiB
C
Raw Blame History

/* Grafx2 - The Ultimate 256-color bitmap paint program
Copyright 2009 Franck Charlet
Copyright 2007 Adrien Destugues
Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud)
Grafx2 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; version 2
of the License.
Grafx2 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 Grafx2; if not, see <http://www.gnu.org/licenses/>
*/
#include <SDL.h>
#include "global.h"
#include "keyboard.h"
#include "sdlscreen.h"
#include "windows.h"
#include "errors.h"
#include "misc.h"
#include "input.h"
void Handle_window_resize(SDL_ResizeEvent event);
void Handle_window_exit(SDL_QuitEvent event);
byte Directional_up;
byte Directional_up_right;
byte Directional_right;
byte Directional_down_right;
byte Directional_down;
byte Directional_down_left;
byte Directional_left;
byte Directional_up_left;
long Directional_delay;
long Directional_last_move;
long Directional_step;
short Mouse_count; // Number of mouse movements received in the current Get_input()
word Input_new_mouse_X;
word Input_new_mouse_Y;
byte Input_new_mouse_K;
byte Mouse_mode = 0; ///< Mouse mode = 0:normal, 1:emulated with custom sensitivity.
short Mouse_virtual_x_position;
short Mouse_virtual_y_position;
short Mouse_virtual_width;
short Mouse_virtual_height;
// TODO: move to config
#ifdef __GP2X__
short Joybutton_shift=GP2X_BUTTON_L; // Button number that serves as a "shift" modifier
short Joybutton_control=GP2X_BUTTON_R; // Button number that serves as a "ctrl" modifier
short Joybutton_alt=GP2X_BUTTON_CLICK; // Button number that serves as a "alt" modifier
short Joybutton_left_click=GP2X_BUTTON_B; // Button number that serves as left click
short Joybutton_right_click=GP2X_BUTTON_Y; // Button number that serves as right-click
#else
short Joybutton_shift=-1; // Button number that serves as a "shift" modifier
short Joybutton_control=-1; // Button number that serves as a "ctrl" modifier
short Joybutton_alt=-1; // Button number that serves as a "alt" modifier
short Joybutton_left_click=0; // Button number that serves as left click
short Joybutton_right_click=0; // Button number that serves as right-click
#endif
int Is_shortcut(word Key, word function)
{
if (Key == 0)
return 0;
if (function & 0x100)
{
if (Buttons_Pool[function&0xFF].Left_shortcut[0]==Key)
return 1;
if (Buttons_Pool[function&0xFF].Left_shortcut[1]==Key)
return 1;
return 0;
}
if (function & 0x200)
{
if (Buttons_Pool[function&0xFF].Right_shortcut[0]==Key)
return 1;
if (Buttons_Pool[function&0xFF].Right_shortcut[1]==Key)
return 1;
return 0;
}
if(Key == Config_Key[function][0])
return 1;
if(Key == Config_Key[function][1])
return 1;
return 0;
}
// Called each time there is a cursor move, either triggered by mouse or keyboard shortcuts
int Move_cursor_with_constraints()
{
int feedback=0;
byte bl=0;//BL va indiquer si on doit corriger la position du curseur
// Clip mouse to the editing area. There can be a border when using big
// pixels, if the SDL screen dimensions are not factors of the pixel size.
if (Input_new_mouse_Y>=Screen_height)
{
Input_new_mouse_Y=Screen_height-1;
bl=1;
}
if (Input_new_mouse_X>=Screen_width)
{
Input_new_mouse_X=Screen_width-1;
bl=1;
}
//Gestion "avanc<6E>e" du curseur: interdire la descente du curseur dans le
//menu lorsqu'on est en train de travailler dans l'image
if (Operation_stack_size != 0)
{
//Si le curseur ne se trouve plus dans l'image
if(Menu_Y<=Input_new_mouse_Y)
{
//On bloque le curseur en fin d'image
bl++;
Input_new_mouse_Y=Menu_Y-1; //La ligne !!au-dessus!! du menu
}
if(Main_magnifier_mode)
{
if(Operation_in_magnifier==0)
{
if(Input_new_mouse_X>=Main_separator_position)
{
bl++;
Input_new_mouse_X=Main_separator_position-1;
}
}
else
{
if(Input_new_mouse_X<Main_X_zoom)
{
bl++;
Input_new_mouse_X=Main_X_zoom;
}
}
}
}
if ((Input_new_mouse_X != Mouse_X) ||
(Input_new_mouse_Y != Mouse_Y) ||
(Input_new_mouse_K != Mouse_K))
{
if ((Input_new_mouse_K != Mouse_K))
feedback=1;
Hide_cursor(); // On efface le curseur AVANT de le d<>placer...
if (Input_new_mouse_X != Mouse_X || Input_new_mouse_Y != Mouse_Y)
{
Mouse_X=Input_new_mouse_X;
Mouse_Y=Input_new_mouse_Y;
if (bl)
Set_mouse_position();
}
Mouse_K=Input_new_mouse_K;
Compute_paintbrush_coordinates();
Display_cursor();
Mouse_count++;
if (Mouse_count>Config.Mouse_merge_movement)
feedback=1;
}
return feedback;
}
// Inhibits a key shortcut if it's disallowed during an operation.
dword Inhibit_shortcut(dword key)
{
if (Operation_stack_size!=0 && key != 0)
{
//Enfin, on inhibe les touches (sauf si c'est un changement de couleur
//ou de taille de pinceau lors d'une des operations suivantes:
//OPERATION_CONTINUOUS_DRAW, OPERATION_DISCONTINUOUS_DRAW, OPERATION_AIRBRUSH)
if(Allow_color_change_during_operation)
{
//A ce stade l<>, on sait qu'on est dans une des 3 op<6F>rations
//supportant le changement de couleur ou de taille de pinceau.
if(
(!Is_shortcut(key,SPECIAL_NEXT_FORECOLOR)) &&
(!Is_shortcut(key,SPECIAL_PREVIOUS_FORECOLOR)) &&
(!Is_shortcut(key,SPECIAL_NEXT_BACKCOLOR)) &&
(!Is_shortcut(key,SPECIAL_PREVIOUS_BACKCOLOR)) &&
(!Is_shortcut(key,SPECIAL_SMALLER_PAINTBRUSH)) &&
(!Is_shortcut(key,SPECIAL_BIGGER_PAINTBRUSH)) &&
(!Is_shortcut(key,SPECIAL_NEXT_USER_FORECOLOR)) &&
(!Is_shortcut(key,SPECIAL_PREVIOUS_USER_FORECOLOR)) &&
(!Is_shortcut(key,SPECIAL_NEXT_USER_BACKCOLOR)) &&
(!Is_shortcut(key,SPECIAL_PREVIOUS_USER_BACKCOLOR))
)
{
key=0;
}
}
else key = 0;
}
return key;
}
// WM events management
void Handle_window_resize(SDL_ResizeEvent event)
{
Resize_width = event.w;
Resize_height = event.h;
}
void Handle_window_exit(__attribute__((unused)) SDL_QuitEvent event)
{
Quit_is_required = 1;
}
// Mouse events management
int Handle_mouse_move(SDL_MouseMotionEvent event)
{
if (Mouse_mode == 0)
{
Input_new_mouse_X = event.x/Pixel_width;
Input_new_mouse_Y = event.y/Pixel_height;
}
else
{
Mouse_virtual_x_position += event.xrel * 12 / Config.Mouse_sensitivity_index_x;
// Clip
if (Mouse_virtual_x_position > Mouse_virtual_width)
Mouse_virtual_x_position = Mouse_virtual_width;
else if (Mouse_virtual_x_position < 0)
Mouse_virtual_x_position = 0;
Mouse_virtual_y_position += event.yrel * 12 / Config.Mouse_sensitivity_index_y;
// Clip
if (Mouse_virtual_y_position > Mouse_virtual_height)
Mouse_virtual_y_position = Mouse_virtual_height;
else if (Mouse_virtual_y_position < 0)
Mouse_virtual_y_position = 0;
Input_new_mouse_X = Mouse_virtual_x_position / 12 / Pixel_width;
Input_new_mouse_Y = Mouse_virtual_y_position / 12 / Pixel_height;
}
return Move_cursor_with_constraints();
}
int Handle_mouse_click(SDL_MouseButtonEvent event)
{
switch(event.button)
{
case SDL_BUTTON_LEFT:
Input_new_mouse_K |= 1;
break;
case SDL_BUTTON_RIGHT:
Input_new_mouse_K |= 2;
break;
case SDL_BUTTON_MIDDLE:
Key = Inhibit_shortcut(KEY_MOUSEMIDDLE|Key_modifiers(SDL_GetModState()));
// TODO: repeat system maybe?
return 0;
case SDL_BUTTON_WHEELUP:
Key = Inhibit_shortcut(KEY_MOUSEWHEELUP|Key_modifiers(SDL_GetModState()));
return 0;
case SDL_BUTTON_WHEELDOWN:
Key = Inhibit_shortcut(KEY_MOUSEWHEELDOWN|Key_modifiers(SDL_GetModState()));
return 0;
default:
return 0;
}
return Move_cursor_with_constraints();
}
int Handle_mouse_release(SDL_MouseButtonEvent event)
{
switch(event.button)
{
case SDL_BUTTON_LEFT:
Input_new_mouse_K &= ~1;
break;
case SDL_BUTTON_RIGHT:
Input_new_mouse_K &= ~2;
break;
}
return Move_cursor_with_constraints();
}
// Keyboard management
int Handle_key_press(SDL_KeyboardEvent event)
{
//Appui sur une touche du clavier
Key = Keysym_to_keycode(event.keysym);
Key_ANSI = Keysym_to_ANSI(event.keysym);
if(Is_shortcut(Key,SPECIAL_MOUSE_UP))
{
Directional_up=1;
return 0;
}
else if(Is_shortcut(Key,SPECIAL_MOUSE_DOWN))
{
Directional_down=1;
return 0;
}
else if(Is_shortcut(Key,SPECIAL_MOUSE_LEFT))
{
Directional_left=1;
return 0;
}
else if(Is_shortcut(Key,SPECIAL_MOUSE_RIGHT))
{
Directional_right=1;
return 0;
}
else if(Is_shortcut(Key,SPECIAL_CLICK_LEFT))
{
Input_new_mouse_K=1;
return Move_cursor_with_constraints();
}
else if(Is_shortcut(Key,SPECIAL_CLICK_RIGHT))
{
Input_new_mouse_K=2;
return Move_cursor_with_constraints();
}
Key = Inhibit_shortcut(Key);
return 0;
}
int Release_control(int key_code, int modifier)
{
if(key_code == (Config_Key[SPECIAL_MOUSE_UP][0]&0x0FFF) || (Config_Key[SPECIAL_MOUSE_UP][0]&modifier) ||
key_code == (Config_Key[SPECIAL_MOUSE_UP][1]&0x0FFF) || (Config_Key[SPECIAL_MOUSE_UP][1]&modifier))
{
Directional_up=0;
}
if(key_code == (Config_Key[SPECIAL_MOUSE_DOWN][0]&0x0FFF) || (Config_Key[SPECIAL_MOUSE_DOWN][0]&modifier) ||
key_code == (Config_Key[SPECIAL_MOUSE_DOWN][1]&0x0FFF) || (Config_Key[SPECIAL_MOUSE_DOWN][1]&modifier))
{
Directional_down=0;
}
if(key_code == (Config_Key[SPECIAL_MOUSE_LEFT][0]&0x0FFF) || (Config_Key[SPECIAL_MOUSE_LEFT][0]&modifier) ||
key_code == (Config_Key[SPECIAL_MOUSE_LEFT][1]&0x0FFF) || (Config_Key[SPECIAL_MOUSE_LEFT][1]&modifier))
{
Directional_left=0;
}
if(key_code == (Config_Key[SPECIAL_MOUSE_RIGHT][0]&0x0FFF) || (Config_Key[SPECIAL_MOUSE_RIGHT][0]&modifier) ||
key_code == (Config_Key[SPECIAL_MOUSE_RIGHT][1]&0x0FFF) || (Config_Key[SPECIAL_MOUSE_RIGHT][1]&modifier))
{
Directional_right=0;
}
if(key_code == (Config_Key[SPECIAL_CLICK_LEFT][0]&0x0FFF) || (Config_Key[SPECIAL_CLICK_LEFT][0]&modifier) ||
key_code == (Config_Key[SPECIAL_CLICK_LEFT][1]&0x0FFF) || (Config_Key[SPECIAL_CLICK_LEFT][1]&modifier))
{
Input_new_mouse_K &= ~1;
return Move_cursor_with_constraints();
}
if(key_code == (Config_Key[SPECIAL_CLICK_RIGHT][0]&0x0FFF) || (Config_Key[SPECIAL_CLICK_RIGHT][0]&modifier) ||
key_code == (Config_Key[SPECIAL_CLICK_RIGHT][1]&0x0FFF) || (Config_Key[SPECIAL_CLICK_RIGHT][1]&modifier))
{
Input_new_mouse_K &= ~2;
return Move_cursor_with_constraints();
}
// Other keys don't need to be released : they are handled as "events" and procesed only once.
// These clicks are apart because they need to be continuous (ie move while key pressed)
// We are relying on "hardware" keyrepeat to achieve that.
return 0;
}
int Handle_key_release(SDL_KeyboardEvent event)
{
int modifier;
int released_key = Keysym_to_keycode(event.keysym) & 0x0FFF;
switch(event.keysym.sym)
{
case SDLK_RSHIFT:
case SDLK_LSHIFT:
modifier=MOD_SHIFT;
break;
case SDLK_RCTRL:
case SDLK_LCTRL:
modifier=MOD_CTRL;
break;
case SDLK_RALT:
case SDLK_LALT:
case SDLK_MODE:
modifier=MOD_ALT;
break;
case SDLK_RMETA:
case SDLK_LMETA:
modifier=MOD_META;
break;
default:
modifier=0;
}
return Release_control(released_key, modifier);
}
// Joystick management
int Handle_joystick_press(SDL_JoyButtonEvent event)
{
if (event.button == Joybutton_shift)
{
SDL_SetModState(SDL_GetModState() | KMOD_SHIFT);
return 0;
}
if (event.button == Joybutton_control)
{
SDL_SetModState(SDL_GetModState() | KMOD_CTRL);
return 0;
}
if (event.button == Joybutton_alt)
{
SDL_SetModState(SDL_GetModState() | (KMOD_ALT|KMOD_META));
return 0;
}
if (event.button == Joybutton_left_click)
{
Input_new_mouse_K=1;
return Move_cursor_with_constraints();
}
if (event.button == Joybutton_right_click)
{
Input_new_mouse_K=2;
return Move_cursor_with_constraints();
}
#ifdef __GP2X__
switch(event.button)
{
#ifndef NO_JOYCURSOR
case GP2X_BUTTON_UP:
Directional_up=1;
break;
case GP2X_BUTTON_UPRIGHT:
Directional_up_right=1;
break;
case GP2X_BUTTON_RIGHT:
Directional_right=1;
break;
case GP2X_BUTTON_DOWNRIGHT:
Directional_down_right=1;
break;
case GP2X_BUTTON_DOWN:
Directional_down=1;
break;
case GP2X_BUTTON_DOWNLEFT:
Directional_down_left=1;
break;
case GP2X_BUTTON_LEFT:
Directional_left=1;
break;
case GP2X_BUTTON_UPLEFT:
Directional_up_left=1;
break;
#endif
default:
break;
}
#endif
Key = (KEY_JOYBUTTON+event.button)|Key_modifiers(SDL_GetModState());
// TODO: systeme de r<>p<EFBFBD>tition
return Move_cursor_with_constraints();
}
int Handle_joystick_release(SDL_JoyButtonEvent event)
{
if (event.button == Joybutton_shift)
{
SDL_SetModState(SDL_GetModState() & ~KMOD_SHIFT);
return Release_control(0,MOD_SHIFT);
}
if (event.button == Joybutton_control)
{
SDL_SetModState(SDL_GetModState() & ~KMOD_CTRL);
return Release_control(0,MOD_CTRL);
}
if (event.button == Joybutton_alt)
{
SDL_SetModState(SDL_GetModState() & ~(KMOD_ALT|KMOD_META));
return Release_control(0,MOD_ALT);
}
if (event.button == Joybutton_left_click)
{
Input_new_mouse_K &= ~1;
return Move_cursor_with_constraints();
}
if (event.button == Joybutton_right_click)
{
Input_new_mouse_K &= ~2;
return Move_cursor_with_constraints();
}
#ifdef __GP2X__
switch(event.button)
{
case GP2X_BUTTON_UP:
Directional_up=0;
break;
case GP2X_BUTTON_UPRIGHT:
Directional_up_right=0;
break;
case GP2X_BUTTON_RIGHT:
Directional_right=0;
break;
case GP2X_BUTTON_DOWNRIGHT:
Directional_down_right=0;
break;
case GP2X_BUTTON_DOWN:
Directional_down=0;
break;
case GP2X_BUTTON_DOWNLEFT:
Directional_down_left=0;
break;
case GP2X_BUTTON_LEFT:
Directional_left=0;
break;
case GP2X_BUTTON_UPLEFT:
Directional_up_left=0;
break;
}
#endif
return Move_cursor_with_constraints();
}
void Handle_joystick_movement(SDL_JoyAxisEvent event)
{
#ifndef NO_JOYCURSOR
if (event.axis==0) // X
{
Directional_right=Directional_left=0;
if (event.value<-1000)
{
Directional_left=1;
}
else if (event.value>1000)
Directional_right=1;
}
else if (event.axis==1) // Y
{
Directional_up=Directional_down=0;
if (event.value<-1000)
{
Directional_up=1;
}
else if (event.value>1000)
Directional_down=1;
}
#endif
}
// Attempts to move the mouse cursor by the given deltas (may be more than 1 pixel at a time)
int Cursor_displace(short delta_x, short delta_y)
{
short x=Input_new_mouse_X;
short y=Input_new_mouse_Y;
if(Main_magnifier_mode && Input_new_mouse_Y < Menu_Y && Input_new_mouse_X > Main_separator_position)
{
// Cursor in zoomed area
if (delta_x<0)
Input_new_mouse_X = Max(Main_separator_position, x-Main_magnifier_factor);
else if (delta_x>0)
Input_new_mouse_X = Min(Screen_width-1, x+Main_magnifier_factor);
if (delta_y<0)
Input_new_mouse_Y = Max(0, y-Main_magnifier_factor);
else if (delta_y>0)
Input_new_mouse_Y = Min(Screen_height-1, y+Main_magnifier_factor);
}
else
{
if (delta_x<0)
Input_new_mouse_X = Max(0, x+delta_x);
else if (delta_x>0)
Input_new_mouse_X = Min(Screen_width-1, x+delta_x);
if (delta_y<0)
Input_new_mouse_Y = Max(0, y+delta_y);
else if (delta_y>0)
Input_new_mouse_Y = Min(Screen_height-1, y+delta_y);
}
return Move_cursor_with_constraints();
}
// Main input handling function
int Get_input(void)
{
SDL_Event event;
int user_feedback_required = 0; // Flag qui indique si on doit arr<72>ter de traiter les <20>v<EFBFBD>nements ou si on peut enchainer
Key_ANSI = 0;
Key = 0;
Mouse_count=0;
// Process as much events as possible without redrawing the screen.
// This mostly allows us to merge mouse events for people with an high
// resolution mouse
while( (!user_feedback_required) && SDL_PollEvent(&event)) // Try to cumulate for a full VBL except if there is a required feedback
{
switch(event.type)
{
case SDL_VIDEORESIZE:
Handle_window_resize(event.resize);
user_feedback_required = 1;
break;
case SDL_QUIT:
Handle_window_exit(event.quit);
user_feedback_required = 1;
break;
case SDL_MOUSEMOTION:
user_feedback_required = Handle_mouse_move(event.motion);
break;
case SDL_MOUSEBUTTONDOWN:
Handle_mouse_click(event.button);
user_feedback_required = 1;
break;
case SDL_MOUSEBUTTONUP:
Handle_mouse_release(event.button);
user_feedback_required = 1;
break;
case SDL_KEYDOWN:
Handle_key_press(event.key);
user_feedback_required = 1;
break;
case SDL_KEYUP:
Handle_key_release(event.key);
break;
case SDL_JOYBUTTONUP:
Handle_joystick_release(event.jbutton);
user_feedback_required = 1;
break;
case SDL_JOYBUTTONDOWN:
Handle_joystick_press(event.jbutton);
user_feedback_required = 1;
break;
case SDL_JOYAXISMOTION:
Handle_joystick_movement(event.jaxis);
break;
default:
// DEBUG("Unhandled SDL event number : ",event.type);
break;
}
}
// Directional controller
if (!(Directional_up||Directional_up_right||Directional_right||
Directional_down_right||Directional_down||Directional_down_left||
Directional_left||Directional_up_left))
{
Directional_delay=-1;
Directional_last_move=SDL_GetTicks();
}
else
{
long time_now;
time_now=SDL_GetTicks();
if (time_now>Directional_last_move+Directional_delay)
{
// Speed parameters, acceleration etc. are here
if (Directional_delay==-1)
{
Directional_delay=150;
Directional_step=16;
}
else if (Directional_delay==150)
Directional_delay=40;
else if (Directional_delay!=0)
Directional_delay=Directional_delay*8/10;
else if (Directional_step<16*4)
Directional_step++;
Directional_last_move = time_now;
// Directional controller UP
if ((Directional_up||Directional_up_left||Directional_up_right) &&
!(Directional_down_right||Directional_down||Directional_down_left))
{
Cursor_displace(0, -Directional_step/16);
}
// Directional controller RIGHT
if ((Directional_up_right||Directional_right||Directional_down_right) &&
!(Directional_down_left||Directional_left||Directional_up_left))
{
Cursor_displace(Directional_step/16,0);
}
// Directional controller DOWN
if ((Directional_down_right||Directional_down||Directional_down_left) &&
!(Directional_up_left||Directional_up||Directional_up_right))
{
Cursor_displace(0, Directional_step/16);
}
// Directional controller LEFT
if ((Directional_down_left||Directional_left||Directional_up_left) &&
!(Directional_up_right||Directional_right||Directional_down_right))
{
Cursor_displace(-Directional_step/16,0);
}
}
}
// Vidage de toute mise <20> jour de l'affichage <20> l'<27>cran qui serait encore en attente.
// (c'est fait ici car on est sur que cette function est apell<6C>e partout ou on a besoin d'interragir avec l'utilisateur)
Flush_update();
return user_feedback_required;
}
void Adjust_mouse_sensitivity(word fullscreen)
{
if (fullscreen == 0)
{
Mouse_mode = 0;
return;
}
Mouse_mode = 1;
Mouse_virtual_x_position = 12*Mouse_X*Pixel_width;
Mouse_virtual_y_position = 12*Mouse_Y*Pixel_height;
Mouse_virtual_width = 12*(Screen_width-1)*Pixel_width;
Mouse_virtual_height = 12*(Screen_height-1)*Pixel_height;
}
void Set_mouse_position(void)
{
if (Mouse_mode == 0)
{
SDL_WarpMouse(
Mouse_X*Pixel_width,
Mouse_Y*Pixel_height
);
}
else
{
Mouse_virtual_x_position = 12*Mouse_X*Pixel_width;
Mouse_virtual_y_position = 12*Mouse_Y*Pixel_height;
}
}