Main Page | Modules | Class Hierarchy | Class List | Directories | File List | Class Members | File Members | Related Pages

gestures.c

00001 /*****************************************************************************
00002  * gestures.c: control vlc with mouse gestures
00003  *****************************************************************************
00004  * Copyright (C) 2004 the VideoLAN team
00005  * $Id: gestures.c 12836 2005-10-15 13:23:08Z sigmunau $
00006  *
00007  * Authors: Sigmund Augdal Helberg <[email protected]>
00008  *
00009  * This program is free software; you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation; either version 2 of the License, or
00012  * (at your option) any later version.
00013  *
00014  * This program is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  * GNU General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU General Public License
00020  * along with this program; if not, write to the Free Software
00021  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
00022  *****************************************************************************/
00023 
00024 /*****************************************************************************
00025  * Preamble
00026  *****************************************************************************/
00027 #include <stdlib.h>                                      /* malloc(), free() */
00028 #include <string.h>
00029 
00030 #include <vlc/vlc.h>
00031 #include <vlc/intf.h>
00032 #include <vlc/vout.h>
00033 
00034 #ifdef HAVE_UNISTD_H
00035 #    include <unistd.h>
00036 #endif
00037 
00038 /*****************************************************************************
00039  * intf_sys_t: description and status of interface
00040  *****************************************************************************/
00041 struct intf_sys_t
00042 {
00043     vlc_object_t *      p_vout;
00044     input_thread_t *    p_input;
00045     vlc_bool_t          b_got_gesture;
00046     vlc_bool_t          b_button_pressed;
00047     int                 i_mouse_x, i_mouse_y;
00048     int                 i_last_x, i_last_y;
00049     unsigned int        i_pattern;
00050     int                 i_num_gestures;
00051     int                 i_threshold;
00052     int                 i_button_mask;
00053 };
00054 
00055 /*****************************************************************************
00056  * Local prototypes.
00057  *****************************************************************************/
00058 #define UP 1
00059 #define DOWN 2
00060 #define LEFT 3
00061 #define RIGHT 4
00062 #define NONE 0
00063 #define GESTURE( a, b, c, d ) (a | ( b << 4 ) | ( c << 8 ) | ( d << 12 ))
00064 
00065 int  E_(Open)   ( vlc_object_t * );
00066 void E_(Close)  ( vlc_object_t * );
00067 static int  InitThread     ( intf_thread_t *p_intf );
00068 static int  MouseEvent     ( vlc_object_t *, char const *,
00069                              vlc_value_t, vlc_value_t, void * );
00070 
00071 /* Exported functions */
00072 static void RunIntf        ( intf_thread_t *p_intf );
00073 
00074 /*****************************************************************************
00075  * Module descriptor
00076  *****************************************************************************/
00077 #define THRESHOLD_TEXT N_( "Motion threshold (10-100)" )
00078 #define THRESHOLD_LONGTEXT N_( \
00079     "Amount of movement required for a mouse" \
00080     " gesture to be recorded." )
00081 
00082 #define BUTTON_TEXT N_( "Trigger button" )
00083 #define BUTTON_LONGTEXT N_( \
00084     "You can set the trigger button for mouse gestures here." )
00085 
00086 static char *button_list[] = { "left", "middle", "right" };
00087 static char *button_list_text[] = { N_("Left"), N_("Middle"), N_("Right") };
00088 
00089 vlc_module_begin();
00090     set_shortname( _("Gestures"));
00091     set_category( CAT_INTERFACE );
00092     set_subcategory( SUBCAT_INTERFACE_CONTROL );
00093     add_integer( "gestures-threshold", 30, NULL, THRESHOLD_TEXT, THRESHOLD_LONGTEXT, VLC_TRUE );
00094     add_string( "gestures-button", "right", NULL,
00095                 BUTTON_TEXT, BUTTON_LONGTEXT, VLC_FALSE );
00096         change_string_list( button_list, button_list_text, 0 );
00097     set_description( _("Mouse gestures control interface") );
00098 
00099     set_capability( "interface", 0 );
00100     set_callbacks( E_(Open), E_(Close) );
00101 vlc_module_end();
00102 
00103 /*****************************************************************************
00104  * OpenIntf: initialize interface
00105  *****************************************************************************/
00106 int E_(Open) ( vlc_object_t *p_this )
00107 {
00108     intf_thread_t *p_intf = (intf_thread_t *)p_this;
00109 
00110     /* Allocate instance and initialize some members */
00111     p_intf->p_sys = malloc( sizeof( intf_sys_t ) );
00112     if( p_intf->p_sys == NULL )
00113     {
00114         return( 1 );
00115     };
00116 
00117     p_intf->pf_run = RunIntf;
00118 
00119     return( 0 );
00120 }
00121 
00122 /*****************************************************************************
00123  * gesture: return a subpattern within a pattern
00124  *****************************************************************************/
00125 static int gesture( int i_pattern, int i_num )
00126 {
00127     return ( i_pattern >> ( i_num * 4 ) ) & 0xF;
00128 }
00129         
00130 /*****************************************************************************
00131  * CloseIntf: destroy dummy interface
00132  *****************************************************************************/
00133 void E_(Close) ( vlc_object_t *p_this )
00134 {
00135     intf_thread_t *p_intf = (intf_thread_t *)p_this;
00136 
00137     /* Destroy structure */
00138     free( p_intf->p_sys );
00139 }
00140 
00141 
00142 /*****************************************************************************
00143  * RunIntf: main loop
00144  *****************************************************************************/
00145 static void RunIntf( intf_thread_t *p_intf )
00146 {
00147     playlist_t * p_playlist = NULL;
00148     p_intf->p_sys->p_vout = NULL;
00149 
00150     if( InitThread( p_intf ) < 0 )
00151     {
00152         msg_Err( p_intf, "can't initialize intf" );
00153         return;
00154     }
00155     msg_Dbg( p_intf, "intf initialized" );
00156 
00157     /* Main loop */
00158     while( !p_intf->b_die )
00159     {
00160         vlc_mutex_lock( &p_intf->change_lock );
00161 
00162         /* 
00163          * mouse cursor
00164          */
00165         if( p_intf->p_sys->b_got_gesture )
00166         {
00167             /* Do something */
00168             switch( p_intf->p_sys->i_pattern )
00169             {
00170             case LEFT:
00171                 p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
00172                                               FIND_ANYWHERE );
00173                 if( p_playlist == NULL )
00174                 {
00175                     break;
00176                 }
00177                 
00178                 playlist_Prev( p_playlist );
00179                 vlc_object_release( p_playlist );
00180                 break;
00181             case RIGHT:
00182                 p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
00183                                               FIND_ANYWHERE );
00184                 if( p_playlist == NULL )
00185                 {
00186                     break;
00187                 }
00188                 
00189                 playlist_Next( p_playlist );
00190                 vlc_object_release( p_playlist );
00191                 break;
00192             case GESTURE(UP,RIGHT,NONE,NONE):
00193                 if (p_intf->p_sys->p_vout )
00194                 {
00195                     ((vout_thread_t *)p_intf->p_sys->p_vout)->i_changes |=
00196                         VOUT_FULLSCREEN_CHANGE;
00197                 }
00198                 break;
00199             case GESTURE(DOWN,RIGHT,NONE,NONE):
00200                 /* FIXME: Should close the vout!"*/
00201                 p_intf->p_vlc->b_die = VLC_TRUE;
00202                 break;
00203             case GESTURE(DOWN,LEFT,UP,RIGHT):
00204                 msg_Dbg(p_intf, "a square!" );
00205                 break;
00206             default:
00207                 break;
00208             }
00209             p_intf->p_sys->i_num_gestures = 0;
00210             p_intf->p_sys->i_pattern = 0;
00211             p_intf->p_sys->b_got_gesture = VLC_FALSE;
00212         }
00213                 
00214 
00215         vlc_mutex_unlock( &p_intf->change_lock );
00216 
00217         /* 
00218          * video output
00219          */
00220         if( p_intf->p_sys->p_vout && p_intf->p_sys->p_vout->b_die )
00221         {
00222             var_DelCallback( p_intf->p_sys->p_vout, "mouse-moved",
00223                              MouseEvent, p_intf );
00224             var_DelCallback( p_intf->p_sys->p_vout, "mouse-button-down",
00225                              MouseEvent, p_intf );
00226             vlc_object_release( p_intf->p_sys->p_vout );
00227             p_intf->p_sys->p_vout = NULL;
00228         }
00229 
00230         if( p_intf->p_sys->p_vout == NULL )
00231         {
00232             p_intf->p_sys->p_vout = vlc_object_find( p_intf,
00233                                       VLC_OBJECT_VOUT, FIND_ANYWHERE );
00234             if( p_intf->p_sys->p_vout )
00235             {
00236                 var_AddCallback( p_intf->p_sys->p_vout, "mouse-moved",
00237                                  MouseEvent, p_intf );
00238                 var_AddCallback( p_intf->p_sys->p_vout, "mouse-button-down",
00239                                  MouseEvent, p_intf );
00240             }
00241         }
00242 
00243         /* Wait a bit */
00244         msleep( INTF_IDLE_SLEEP );
00245     }
00246 
00247     if( p_intf->p_sys->p_vout )
00248     {
00249         var_DelCallback( p_intf->p_sys->p_vout, "mouse-moved",
00250                          MouseEvent, p_intf );
00251         var_DelCallback( p_intf->p_sys->p_vout, "mouse-button-down",
00252                          MouseEvent, p_intf );
00253         vlc_object_release( p_intf->p_sys->p_vout );
00254     }
00255 }
00256 
00257 /*****************************************************************************
00258  * InitThread:
00259  *****************************************************************************/
00260 static int InitThread( intf_thread_t * p_intf )
00261 {
00262     char *psz_button;
00263     /* we might need some locking here */
00264     if( !p_intf->b_die )
00265     {
00266         input_thread_t * p_input;
00267 
00268         p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT, FIND_PARENT );
00269 
00270         vlc_mutex_lock( &p_intf->change_lock );
00271 
00272         p_intf->p_sys->p_input = p_input;
00273         p_intf->p_sys->b_got_gesture = VLC_FALSE;
00274         p_intf->p_sys->b_button_pressed = VLC_FALSE;
00275         p_intf->p_sys->i_threshold = config_GetInt( p_intf, "gestures-threshold" );
00276         psz_button = config_GetPsz( p_intf, "gestures-button" );
00277         if ( !strcmp( psz_button, "left" ) )
00278         {
00279             p_intf->p_sys->i_button_mask = 1;
00280         }
00281         else if ( !strcmp( psz_button, "middle" ) )
00282         {
00283             p_intf->p_sys->i_button_mask = 2;
00284         }
00285         else if ( !strcmp( psz_button, "right" ) )
00286         {
00287             p_intf->p_sys->i_button_mask = 4;
00288         }
00289 
00290         p_intf->p_sys->i_pattern = 0;
00291         p_intf->p_sys->i_num_gestures = 0;
00292         vlc_mutex_unlock( &p_intf->change_lock );
00293 
00294         return 0;
00295     }
00296     else
00297     {
00298         return -1;
00299     }
00300 }
00301 
00302 /*****************************************************************************
00303  * MouseEvent: callback for mouse events
00304  *****************************************************************************/
00305 static int MouseEvent( vlc_object_t *p_this, char const *psz_var,
00306                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
00307 {
00308     vlc_value_t val;
00309     int pattern = 0;
00310     
00311     signed int i_horizontal, i_vertical;
00312     intf_thread_t *p_intf = (intf_thread_t *)p_data;
00313 
00314     /* don't process new gestures before the last events are processed */
00315     if( p_intf->p_sys->b_got_gesture ) {
00316         return VLC_SUCCESS;
00317     }
00318 
00319     vlc_mutex_lock( &p_intf->change_lock );
00320     if( !strcmp(psz_var, "mouse-moved" ) && p_intf->p_sys->b_button_pressed ) {
00321         var_Get( p_intf->p_sys->p_vout, "mouse-x", &val );
00322         p_intf->p_sys->i_mouse_x = val.i_int;
00323         var_Get( p_intf->p_sys->p_vout, "mouse-y", &val );
00324         p_intf->p_sys->i_mouse_y = val.i_int;
00325         i_horizontal = p_intf->p_sys->i_mouse_x -
00326             p_intf->p_sys->i_last_x;
00327         i_horizontal = i_horizontal / p_intf->p_sys->i_threshold;
00328         i_vertical = p_intf->p_sys->i_mouse_y
00329             - p_intf->p_sys->i_last_y;
00330         i_vertical = i_vertical / p_intf->p_sys->i_threshold;
00331         
00332         if ( i_horizontal < 0 )
00333         {
00334             msg_Dbg( p_intf, "left gesture(%d)", i_horizontal );
00335             pattern = LEFT;
00336         }
00337         else if ( i_horizontal > 0 )
00338         {
00339             msg_Dbg( p_intf, "right gesture(%d)", i_horizontal );
00340             pattern = RIGHT;
00341         }
00342         if ( i_vertical < 0 )
00343         {
00344             msg_Dbg( p_intf, "up gesture(%d)", i_vertical );
00345             pattern = UP;
00346         }
00347         else if ( i_vertical > 0 )
00348         {
00349             msg_Dbg( p_intf, "down gesture(%d)", i_vertical );
00350             pattern = DOWN;
00351         }
00352         if (pattern )
00353         {
00354             p_intf->p_sys->i_last_y = p_intf->p_sys->i_mouse_y;
00355             p_intf->p_sys->i_last_x = p_intf->p_sys->i_mouse_x;
00356             if( gesture(p_intf->p_sys->i_pattern, p_intf->p_sys->i_num_gestures - 1 ) != pattern )
00357             {
00358                 p_intf->p_sys->i_pattern |= pattern << ( p_intf->p_sys->i_num_gestures * 4 );
00359                 p_intf->p_sys->i_num_gestures++;
00360             }
00361         }
00362 
00363     }
00364     if( !strcmp( psz_var, "mouse-button-down" ) && newval.i_int & p_intf->p_sys->i_button_mask
00365         && !p_intf->p_sys->b_button_pressed )
00366     {
00367         p_intf->p_sys->b_button_pressed = VLC_TRUE;
00368         var_Get( p_intf->p_sys->p_vout, "mouse-x", &val );
00369         p_intf->p_sys->i_last_x = val.i_int;
00370         var_Get( p_intf->p_sys->p_vout, "mouse-y", &val );
00371         p_intf->p_sys->i_last_y = val.i_int;
00372     }
00373     if( !strcmp( psz_var, "mouse-button-down" ) && !( newval.i_int & p_intf->p_sys->i_button_mask )
00374         && p_intf->p_sys->b_button_pressed )
00375     {
00376         p_intf->p_sys->b_button_pressed = VLC_FALSE;
00377         p_intf->p_sys->b_got_gesture = VLC_TRUE;
00378     }
00379 
00380     vlc_mutex_unlock( &p_intf->change_lock );
00381 
00382     return VLC_SUCCESS;
00383 }

Generated on Tue Dec 20 10:14:30 2005 for vlc-0.8.4a by  doxygen 1.4.2