From 3dcb1349a93e8dc6f62d59ba457161483e955c7e Mon Sep 17 00:00:00 2001 From: Sigmund Augdal Helberg Date: Sun, 9 Feb 2003 23:42:06 +0000 Subject: [PATCH] *: a new mouse gestures interface, currently supporting back, forward, quit fullscreen and a nice debug message when you draw a clockwise square. Video output modules needs to be modified for this to work, but it should be minor in modules supporting dvd navigation. btw: it should be easy to add new gestures, ideas appreciated --- modules/Makefile.am | 1 + modules/control/Modules.am | 1 + modules/control/gestures.c | 376 +++++++++++++++++++++++++++++ modules/video_output/x11/xcommon.c | 54 ++++- src/video_output/video_output.c | 3 +- 5 files changed, 430 insertions(+), 5 deletions(-) create mode 100644 modules/control/Modules.am create mode 100644 modules/control/gestures.c diff --git a/modules/Makefile.am b/modules/Makefile.am index 2c668ba739..5d43d62359 100644 --- a/modules/Makefile.am +++ b/modules/Makefile.am @@ -28,6 +28,7 @@ EXTRA_DIST = \ codec/spudec/Modules.am \ control/lirc/Modules.am \ control/rc/Modules.am \ + control/Modules.am \ demux/Modules.am \ demux/aac/Modules.am \ demux/avi/Modules.am \ diff --git a/modules/control/Modules.am b/modules/control/Modules.am new file mode 100644 index 0000000000..0aca56dea5 --- /dev/null +++ b/modules/control/Modules.am @@ -0,0 +1 @@ +SOURCES_gestures = modules/control/gestures.c diff --git a/modules/control/gestures.c b/modules/control/gestures.c new file mode 100644 index 0000000000..11471b0c4a --- /dev/null +++ b/modules/control/gestures.c @@ -0,0 +1,376 @@ +/***************************************************************************** + * geatures.c: control vlc with mouse gestures + ***************************************************************************** + * Copyright (C) 2002 VideoLAN + * $Id: gestures.c,v 1.1 2003/02/09 23:42:06 sigmunau Exp $ + * + * Authors: Sigmund Augdal + * + * This program 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 of the License, or + * (at your option) any later version. + * + * This program 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; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + *****************************************************************************/ + +/***************************************************************************** + * Preamble + *****************************************************************************/ +#include /* malloc(), free() */ +#include +#include + +#include +#include +#include + +#include "stream_control.h" +#include "input_ext-intf.h" + +/***************************************************************************** + * intf_sys_t: description and status of interface + *****************************************************************************/ +struct intf_sys_t +{ + vlc_object_t * p_vout; + input_thread_t * p_input; + vlc_bool_t b_got_gesture; + vlc_bool_t b_button_pressed; + int i_mouse_x, i_mouse_y; + int i_last_x, i_last_y; + unsigned int i_pattern; + int i_num_gestures; + int i_threshold; + int i_button_mask; +}; + +/***************************************************************************** + * Local prototypes. + *****************************************************************************/ +#define UP 1 +#define DOWN 2 +#define LEFT 3 +#define RIGHT 4 +#define NONE 0 +#define GESTURE( a, b, c, d ) (a | ( b << 4 ) | ( c << 8 ) | ( d << 12 )) + +int E_(Open) ( vlc_object_t * ); +void E_(Close) ( vlc_object_t * ); +static int InitThread ( intf_thread_t *p_intf ); +static int MouseEvent ( vlc_object_t *, char const *, + vlc_value_t, vlc_value_t, void * ); + +/* Exported functions */ +static void RunIntf ( intf_thread_t *p_intf ); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +#define THRESHOLD_TEXT N_( "Motion threshold" ) +#define THRESHOLD_LONGTEXT N_( \ + "the amount of movement required for a mouse" \ + " gesture to be recorded" ) + +#define BUTTON_TEXT N_( "Mouse button" ) +#define BUTTON_LONGTEXT N_( \ + "the mouse button to be held down during mouse gestures" ) + +static char *button_list[] = { "left", "middle", "right", NULL }; + +vlc_module_begin(); + add_category_hint( N_( "Gestures" ), NULL ); + add_integer( "gestures-threshold", 30, NULL, THRESHOLD_TEXT, THRESHOLD_LONGTEXT ); + add_string_from_list( "gestures-button", "right", button_list, NULL, + BUTTON_TEXT, BUTTON_LONGTEXT ); + set_description( _("mouse gestures control module") ); + + set_capability( "interface", 0 ); + set_callbacks( E_(Open), E_(Close) ); +vlc_module_end(); + +/***************************************************************************** + * OpenIntf: initialize interface + *****************************************************************************/ +int E_(Open) ( vlc_object_t *p_this ) +{ + intf_thread_t *p_intf = (intf_thread_t *)p_this; + + /* Allocate instance and initialize some members */ + p_intf->p_sys = malloc( sizeof( intf_sys_t ) ); + if( p_intf->p_sys == NULL ) + { + return( 1 ); + }; + + p_intf->pf_run = RunIntf; + + return( 0 ); +} + +/***************************************************************************** + * gesture: return a subpattern within a pattern + *****************************************************************************/ +static int gesture( int i_pattern, int i_num ) +{ + return ( i_pattern >> ( i_num * 4 ) ) & 0xF; +} + +/***************************************************************************** + * CloseIntf: destroy dummy interface + *****************************************************************************/ +void E_(Close) ( vlc_object_t *p_this ) +{ + intf_thread_t *p_intf = (intf_thread_t *)p_this; + + /* Destroy structure */ + free( p_intf->p_sys ); +} + + +/***************************************************************************** + * RunIntf: main loop + *****************************************************************************/ +static void RunIntf( intf_thread_t *p_intf ) +{ + playlist_t * p_playlist = NULL; + p_intf->p_sys->p_vout = NULL; + + if( InitThread( p_intf ) < 0 ) + { + msg_Err( p_intf, "can't initialize intf" ); + return; + } + msg_Dbg( p_intf, "intf initialized" ); + + /* Main loop */ + while( !p_intf->b_die ) + { + vlc_mutex_lock( &p_intf->change_lock ); + + /* + * mouse cursor + */ + if( p_intf->p_sys->b_got_gesture ) + { + /* Do something */ + switch( p_intf->p_sys->i_pattern ) + { + case LEFT: + p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, + FIND_ANYWHERE ); + if( p_playlist == NULL ) + { + break; + } + + playlist_Prev( p_playlist ); + vlc_object_release( p_playlist ); + break; + case RIGHT: + p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, + FIND_ANYWHERE ); + if( p_playlist == NULL ) + { + break; + } + + playlist_Next( p_playlist ); + vlc_object_release( p_playlist ); + break; + + case DOWN: + if (p_intf->p_sys->p_vout + && ((vout_thread_t *)p_intf->p_sys->p_vout)->b_fullscreen ) + { + ((vout_thread_t *)p_intf->p_sys->p_vout)->i_changes |= VOUT_FULLSCREEN_CHANGE; + } + break; + case GESTURE(DOWN,LEFT,UP,RIGHT): + msg_Dbg(p_intf, "A square!" ); + break; + default: + break; + } + p_intf->p_sys->i_num_gestures = 0; + p_intf->p_sys->i_pattern = 0; + p_intf->p_sys->b_got_gesture = VLC_FALSE; + } + + + vlc_mutex_unlock( &p_intf->change_lock ); + + /* + * video output + */ + if( p_intf->p_sys->p_vout && p_intf->p_sys->p_vout->b_die ) + { + var_DelCallback( p_intf->p_sys->p_vout, "mouse-moved", + MouseEvent, p_intf ); + var_DelCallback( p_intf->p_sys->p_vout, "mouse-button-down", + MouseEvent, p_intf ); + vlc_object_release( p_intf->p_sys->p_vout ); + p_intf->p_sys->p_vout = NULL; + } + + if( p_intf->p_sys->p_vout == NULL ) + { + p_intf->p_sys->p_vout = vlc_object_find( p_intf, + VLC_OBJECT_VOUT, FIND_ANYWHERE ); + if( p_intf->p_sys->p_vout ) + { + var_AddCallback( p_intf->p_sys->p_vout, "mouse-moved", + MouseEvent, p_intf ); + var_AddCallback( p_intf->p_sys->p_vout, "mouse-button-down", + MouseEvent, p_intf ); + } + } + + /* Wait a bit */ + msleep( INTF_IDLE_SLEEP ); + } + + if( p_intf->p_sys->p_vout ) + { + var_DelCallback( p_intf->p_sys->p_vout, "mouse-moved", + MouseEvent, p_intf ); + var_DelCallback( p_intf->p_sys->p_vout, "mouse-button-down", + MouseEvent, p_intf ); + vlc_object_release( p_intf->p_sys->p_vout ); + } +} + +/***************************************************************************** + * InitThread: + *****************************************************************************/ +static int InitThread( intf_thread_t * p_intf ) +{ + char *psz_button; + /* we might need some locking here */ + if( !p_intf->b_die ) + { + input_thread_t * p_input; + + p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT, FIND_PARENT ); + + vlc_mutex_lock( &p_intf->change_lock ); + + p_intf->p_sys->p_input = p_input; + p_intf->p_sys->b_got_gesture = VLC_FALSE; + p_intf->p_sys->b_button_pressed = VLC_FALSE; + p_intf->p_sys->i_threshold = config_GetInt( p_intf, "gestures-threshold" ); + psz_button = config_GetPsz( p_intf, "gestures-button" ); + if ( !strcmp( psz_button, "left" ) ) + { + p_intf->p_sys->i_button_mask = 1; + } + else if ( !strcmp( psz_button, "middle" ) ) + { + p_intf->p_sys->i_button_mask = 2; + } + else if ( !strcmp( psz_button, "right" ) ) + { + p_intf->p_sys->i_button_mask = 4; + } + + p_intf->p_sys->i_pattern = 0; + p_intf->p_sys->i_num_gestures = 0; + vlc_mutex_unlock( &p_intf->change_lock ); + + return 0; + } + else + { + return -1; + } +} + +/***************************************************************************** + * MouseEvent: callback for mouse events + *****************************************************************************/ +static int MouseEvent( vlc_object_t *p_this, char const *psz_var, + vlc_value_t oldval, vlc_value_t newval, void *p_data ) +{ + vlc_value_t val; + int pattern = 0; + + signed int i_horizontal, i_vertical; + intf_thread_t *p_intf = (intf_thread_t *)p_data; + + /* don't process new gestures before the last events are processed */ + if( p_intf->p_sys->b_got_gesture ) { + return VLC_SUCCESS; + } + + vlc_mutex_lock( &p_intf->change_lock ); + if( !strcmp(psz_var, "mouse-moved" ) && p_intf->p_sys->b_button_pressed ) { + var_Get( p_intf->p_sys->p_vout, "mouse-x", &val ); + p_intf->p_sys->i_mouse_x = val.i_int; + var_Get( p_intf->p_sys->p_vout, "mouse-y", &val ); + p_intf->p_sys->i_mouse_y = val.i_int; + i_horizontal = p_intf->p_sys->i_mouse_x - + p_intf->p_sys->i_last_x; + i_horizontal = i_horizontal / p_intf->p_sys->i_threshold; + i_vertical = p_intf->p_sys->i_mouse_y + - p_intf->p_sys->i_last_y; + i_vertical = i_vertical / p_intf->p_sys->i_threshold; + + if ( i_horizontal < 0 ) + { + msg_Dbg( p_intf, "left gesture(%d)", i_horizontal ); + pattern = LEFT; + } + else if ( i_horizontal > 0 ) + { + msg_Dbg( p_intf, "right gesture(%d)", i_horizontal ); + pattern = RIGHT; + } + if ( i_vertical < 0 ) + { + msg_Dbg( p_intf, "up gesture(%d)", i_vertical ); + pattern = UP; + } + else if ( i_vertical > 0 ) + { + msg_Dbg( p_intf, "down gesture(%d)", i_vertical ); + pattern = DOWN; + } + if (pattern ) + { + p_intf->p_sys->i_last_y = p_intf->p_sys->i_mouse_y; + p_intf->p_sys->i_last_x = p_intf->p_sys->i_mouse_x; + if( gesture(p_intf->p_sys->i_pattern, p_intf->p_sys->i_num_gestures - 1 ) != pattern ) + { + p_intf->p_sys->i_pattern |= pattern << ( p_intf->p_sys->i_num_gestures * 4 ); + p_intf->p_sys->i_num_gestures++; + } + } + + } + if( !strcmp( psz_var, "mouse-button-down" ) && newval.i_int & p_intf->p_sys->i_button_mask + && !p_intf->p_sys->b_button_pressed ) + { + p_intf->p_sys->b_button_pressed = VLC_TRUE; + var_Get( p_intf->p_sys->p_vout, "mouse-x", &val ); + p_intf->p_sys->i_last_x = val.i_int; + var_Get( p_intf->p_sys->p_vout, "mouse-y", &val ); + p_intf->p_sys->i_last_y = val.i_int; + } + if( !strcmp( psz_var, "mouse-button-down" ) && !( newval.i_int & p_intf->p_sys->i_button_mask ) + && p_intf->p_sys->b_button_pressed ) + { + p_intf->p_sys->b_button_pressed = VLC_FALSE; + p_intf->p_sys->b_got_gesture = VLC_TRUE; + } + + vlc_mutex_unlock( &p_intf->change_lock ); + + return VLC_SUCCESS; +} diff --git a/modules/video_output/x11/xcommon.c b/modules/video_output/x11/xcommon.c index 3055808030..e8f51092f6 100644 --- a/modules/video_output/x11/xcommon.c +++ b/modules/video_output/x11/xcommon.c @@ -2,7 +2,7 @@ * xcommon.c: Functions common to the X11 and XVideo plugins ***************************************************************************** * Copyright (C) 1998-2001 VideoLAN - * $Id: xcommon.c,v 1.13 2003/02/01 18:54:10 sam Exp $ + * $Id: xcommon.c,v 1.14 2003/02/09 23:42:06 sigmunau Exp $ * * Authors: Vincent Seguin * Samuel Hocevar @@ -613,7 +613,10 @@ static int ManageVideo( vout_thread_t *p_vout ) switch( ((XButtonEvent *)&xevent)->button ) { case Button1: - + var_Get( p_vout, "mouse-button-down", &val ); + val.i_int |= 1; + var_Set( p_vout, "mouse-button-down", val ); + /* detect double-clicks */ if( ( ((XButtonEvent *)&xevent)->time - p_vout->p_sys->i_time_button_last_pressed ) < 300 ) @@ -624,12 +627,29 @@ static int ManageVideo( vout_thread_t *p_vout ) p_vout->p_sys->i_time_button_last_pressed = ((XButtonEvent *)&xevent)->time; break; - + case Button2: + var_Get( p_vout, "mouse-button-down", &val ); + val.i_int |= 2; + var_Set( p_vout, "mouse-button-down", val ); + break; + + case Button3: + var_Get( p_vout, "mouse-button-down", &val ); + val.i_int |= 4; + var_Set( p_vout, "mouse-button-down", val ); + break; + case Button4: + var_Get( p_vout, "mouse-button-down", &val ); + val.i_int |= 8; + var_Set( p_vout, "mouse-button-down", val ); input_Seek( p_vout, 15, INPUT_SEEK_SECONDS | INPUT_SEEK_CUR ); break; case Button5: + var_Get( p_vout, "mouse-button-down", &val ); + val.i_int |= 16; + var_Set( p_vout, "mouse-button-down", val ); input_Seek( p_vout, -15, INPUT_SEEK_SECONDS | INPUT_SEEK_CUR ); break; } @@ -640,13 +660,26 @@ static int ManageVideo( vout_thread_t *p_vout ) switch( ((XButtonEvent *)&xevent)->button ) { case Button1: + var_Get( p_vout, "mouse-button-down", &val ); + val.i_int &= ~1; + var_Set( p_vout, "mouse-button-down", val ); + val.b_bool = VLC_TRUE; var_Set( p_vout, "mouse-clicked", val ); break; - + + case Button2: + var_Get( p_vout, "mouse-button-down", &val ); + val.i_int &= ~2; + var_Set( p_vout, "mouse-button-down", val ); + break; + case Button3: { intf_thread_t *p_intf; + var_Get( p_vout, "mouse-button-down", &val ); + val.i_int &= ~4; + var_Set( p_vout, "mouse-button-down", val ); p_intf = vlc_object_find( p_vout, VLC_OBJECT_INTF, FIND_ANYWHERE ); if( p_intf ) @@ -656,6 +689,19 @@ static int ManageVideo( vout_thread_t *p_vout ) } } break; + + case Button4: + var_Get( p_vout, "mouse-button-down", &val ); + val.i_int &= ~8; + var_Set( p_vout, "mouse-button-down", val ); + break; + + case Button5: + var_Get( p_vout, "mouse-button-down", &val ); + val.i_int &= ~16; + var_Set( p_vout, "mouse-button-down", val ); + break; + } } /* Mouse move */ diff --git a/src/video_output/video_output.c b/src/video_output/video_output.c index 1048e3f137..0f72dffc3c 100644 --- a/src/video_output/video_output.c +++ b/src/video_output/video_output.c @@ -5,7 +5,7 @@ * thread, and destroy a previously oppened video output thread. ***************************************************************************** * Copyright (C) 2000-2001 VideoLAN - * $Id: video_output.c,v 1.211 2003/01/30 19:14:17 gbazin Exp $ + * $Id: video_output.c,v 1.212 2003/02/09 23:42:06 sigmunau Exp $ * * Authors: Vincent Seguin * @@ -327,6 +327,7 @@ vout_thread_t * __vout_Create( vlc_object_t *p_parent, /* Mouse coordinates */ var_Create( p_vout, "mouse-x", VLC_VAR_INTEGER ); var_Create( p_vout, "mouse-y", VLC_VAR_INTEGER ); + var_Create( p_vout, "mouse-button-down", VLC_VAR_INTEGER ); var_Create( p_vout, "mouse-moved", VLC_VAR_BOOL ); var_Create( p_vout, "mouse-clicked", VLC_VAR_INTEGER ); var_Create( p_vout, "key-pressed", VLC_VAR_STRING ); -- 2.39.5