gestures.c
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:19k
源码类别:

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * gestures.c: control vlc with mouse gestures
  3.  *****************************************************************************
  4.  * Copyright (C) 2004-2009 the VideoLAN team
  5.  * $Id: 5c117905c54891aaebadda02d98432b0b7584a4b $
  6.  *
  7.  * Authors: Sigmund Augdal Helberg <dnumgis@videolan.org>
  8.  *
  9.  * This program is free software; you can redistribute it and/or modify
  10.  * it under the terms of the GNU General Public License as published by
  11.  * the Free Software Foundation; either version 2 of the License, or
  12.  * (at your option) any later version.
  13.  *
  14.  * This program is distributed in the hope that it will be useful,
  15.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  * GNU General Public License for more details.
  18.  *
  19.  * You should have received a copy of the GNU General Public License
  20.  * along with this program; if not, write to the Free Software
  21.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  22.  *****************************************************************************/
  23. /*****************************************************************************
  24.  * Preamble
  25.  *****************************************************************************/
  26. #ifdef HAVE_CONFIG_H
  27. # include "config.h"
  28. #endif
  29. #include <vlc_common.h>
  30. #include <vlc_plugin.h>
  31. #include <vlc_interface.h>
  32. #include <vlc_vout.h>
  33. #include <vlc_aout.h>
  34. #include <vlc_playlist.h>
  35. #ifdef HAVE_UNISTD_H
  36. #    include <unistd.h>
  37. #endif
  38. /*****************************************************************************
  39.  * intf_sys_t: description and status of interface
  40.  *****************************************************************************/
  41. struct intf_sys_t
  42. {
  43.     vlc_mutex_t         lock;
  44.     vout_thread_t      *p_vout;
  45.     bool                b_got_gesture;
  46.     bool                b_button_pressed;
  47.     int                 i_mouse_x, i_mouse_y;
  48.     int                 i_last_x, i_last_y;
  49.     unsigned int        i_pattern;
  50.     int                 i_num_gestures;
  51.     int                 i_threshold;
  52.     int                 i_button_mask;
  53. };
  54. /*****************************************************************************
  55.  * Local prototypes.
  56.  *****************************************************************************/
  57. #define UP 1
  58. #define DOWN 2
  59. #define LEFT 3
  60. #define RIGHT 4
  61. #define NONE 0
  62. #define GESTURE( a, b, c, d ) (a | ( b << 4 ) | ( c << 8 ) | ( d << 12 ))
  63. int  Open   ( vlc_object_t * );
  64. void Close  ( vlc_object_t * );
  65. static int  MouseEvent     ( vlc_object_t *, char const *,
  66.                              vlc_value_t, vlc_value_t, void * );
  67. /* Exported functions */
  68. static void RunIntf        ( intf_thread_t *p_intf );
  69. /*****************************************************************************
  70.  * Module descriptor
  71.  *****************************************************************************/
  72. #define THRESHOLD_TEXT N_( "Motion threshold (10-100)" )
  73. #define THRESHOLD_LONGTEXT N_( 
  74.     "Amount of movement required for a mouse gesture to be recorded." )
  75. #define BUTTON_TEXT N_( "Trigger button" )
  76. #define BUTTON_LONGTEXT N_( 
  77.     "Trigger button for mouse gestures." )
  78. static const char *const button_list[] = { "left", "middle", "right" };
  79. static const char *const button_list_text[] =
  80.                                    { N_("Left"), N_("Middle"), N_("Right") };
  81. vlc_module_begin ()
  82.     set_shortname( N_("Gestures"))
  83.     set_category( CAT_INTERFACE )
  84.     set_subcategory( SUBCAT_INTERFACE_CONTROL )
  85.     add_integer( "gestures-threshold", 30, NULL,
  86.                  THRESHOLD_TEXT, THRESHOLD_LONGTEXT, true )
  87.     add_string( "gestures-button", "right", NULL,
  88.                 BUTTON_TEXT, BUTTON_LONGTEXT, false )
  89.         change_string_list( button_list, button_list_text, 0 )
  90.     set_description( N_("Mouse gestures control interface") )
  91.     set_capability( "interface", 0 )
  92.     set_callbacks( Open, Close )
  93. vlc_module_end ()
  94. /*****************************************************************************
  95.  * OpenIntf: initialize interface
  96.  *****************************************************************************/
  97. int Open ( vlc_object_t *p_this )
  98. {
  99.     intf_thread_t *p_intf = (intf_thread_t *)p_this;
  100.     /* Allocate instance and initialize some members */
  101.     intf_sys_t *p_sys = p_intf->p_sys = malloc( sizeof( intf_sys_t ) );
  102.     if( p_intf->p_sys == NULL )
  103.         return VLC_ENOMEM;
  104.     // Configure the module
  105.     p_intf->pf_run = RunIntf;
  106.     vlc_mutex_init( &p_sys->lock );
  107.     p_sys->p_vout = NULL;
  108.     p_sys->b_got_gesture = false;
  109.     p_sys->b_button_pressed = false;
  110.     p_sys->i_threshold = config_GetInt( p_intf, "gestures-threshold" );
  111.     // Choose the tight button to use
  112.     char *psz_button = config_GetPsz( p_intf, "gestures-button" );
  113.     if( !strcmp( psz_button, "left" ) )
  114.         p_sys->i_button_mask = 1;
  115.     else if( !strcmp( psz_button, "middle" ) )
  116.         p_sys->i_button_mask = 2;
  117.     else // psz_button == "right"
  118.         p_sys->i_button_mask = 4;
  119.     free( psz_button );
  120.     p_sys->i_pattern = 0;
  121.     p_sys->i_num_gestures = 0;
  122.     return VLC_SUCCESS;
  123. }
  124. /*****************************************************************************
  125.  * gesture: return a subpattern within a pattern
  126.  *****************************************************************************/
  127. static int gesture( int i_pattern, int i_num )
  128. {
  129.     return ( i_pattern >> ( i_num * 4 ) ) & 0xF;
  130. }
  131. /*****************************************************************************
  132.  * CloseIntf: destroy dummy interface
  133.  *****************************************************************************/
  134. void Close ( vlc_object_t *p_this )
  135. {
  136.     intf_thread_t *p_intf = (intf_thread_t *)p_this;
  137.     // Destroy the callbacks
  138.     if( p_intf->p_sys->p_vout )
  139.     {
  140.         var_DelCallback( p_intf->p_sys->p_vout, "mouse-moved",
  141.                          MouseEvent, p_intf );
  142.         var_DelCallback( p_intf->p_sys->p_vout, "mouse-button-down",
  143.                          MouseEvent, p_intf );
  144.         vlc_object_release( p_intf->p_sys->p_vout );
  145.     }
  146.     /* Destroy structure */
  147.     vlc_mutex_destroy( &p_intf->p_sys->lock );
  148.     free( p_intf->p_sys );
  149. }
  150. /*****************************************************************************
  151.  * RunIntf: main loop
  152.  *****************************************************************************/
  153. static void RunIntf( intf_thread_t *p_intf )
  154. {
  155.     intf_sys_t *p_sys = p_intf->p_sys;
  156.     playlist_t * p_playlist = NULL;
  157.     int canc = vlc_savecancel();
  158.     input_thread_t *p_input;
  159.     /* Main loop */
  160.     while( vlc_object_alive( p_intf ) )
  161.     {
  162.         vlc_mutex_lock( &p_sys->lock );
  163.         /*
  164.          * mouse cursor
  165.          */
  166.         if( p_sys->b_got_gesture )
  167.         {
  168.             vlc_value_t val;
  169.             int i_interval = 0;
  170.             /* Do something */
  171.             /* If you modify this, please try to follow this convention:
  172.                Start with LEFT, RIGHT for playback related commands
  173.                and UP, DOWN, for other commands */
  174.             switch( p_sys->i_pattern )
  175.             {
  176.             case LEFT:
  177.                 msg_Dbg( p_intf, "Go backward in the movie!" );
  178.                 p_playlist = pl_Hold( p_intf );
  179.                 p_input = playlist_CurrentInput( p_playlist );
  180.                 pl_Release( p_intf );
  181.                 if( p_input )
  182.                 {
  183.                     i_interval = config_GetInt( p_intf , "short-jump-size" );
  184.                     if ( i_interval > 0 )
  185.                     {
  186.                         val.i_time = ( (mtime_t)( -i_interval ) * 1000000L);
  187.                         var_Set( p_input, "time-offset", val );
  188.                     }
  189.                     vlc_object_release( p_input );
  190.                 }
  191.                 break;
  192.             case RIGHT:
  193.                 msg_Dbg( p_intf, "Go forward in the movie!" );
  194.                 p_playlist = pl_Hold( p_intf );
  195.                 p_input = playlist_CurrentInput( p_playlist );
  196.                 pl_Release( p_intf );
  197.                 if( p_input )
  198.                 {
  199.                     i_interval = config_GetInt( p_intf , "short-jump-size" );
  200.                     if ( i_interval > 0 )
  201.                     {
  202.                         val.i_time = ( (mtime_t)( i_interval ) * 1000000L);
  203.                         var_Set( p_input, "time-offset", val );
  204.                     }
  205.                     vlc_object_release( p_input );
  206.                 }
  207.                 break;
  208.             case GESTURE(LEFT,UP,NONE,NONE):
  209.                 msg_Dbg( p_intf, "Going slower." );
  210.                 p_playlist = pl_Hold( p_intf );
  211.                 p_input = playlist_CurrentInput( p_playlist );
  212.                 pl_Release( p_intf );
  213.                 if( p_input )
  214.                 {
  215.                     var_SetVoid( p_input, "rate-slower" );
  216.                     vlc_object_release( p_input );
  217.                 }
  218.                 break;
  219.             case GESTURE(RIGHT,UP,NONE,NONE):
  220.                 msg_Dbg( p_intf, "Going faster." );
  221.                 p_playlist = pl_Hold( p_intf );
  222.                 p_input = playlist_CurrentInput( p_playlist );
  223.                 pl_Release( p_intf );
  224.                 if( p_input )
  225.                 {
  226.                     var_SetVoid( p_input, "rate-faster" );
  227.                     vlc_object_release( p_input );
  228.                 }
  229.                 break;
  230.             case GESTURE(LEFT,RIGHT,NONE,NONE):
  231.             case GESTURE(RIGHT,LEFT,NONE,NONE):
  232.                 msg_Dbg( p_intf, "Play/Pause" );
  233.                 p_playlist = pl_Hold( p_intf );
  234.                 p_input = playlist_CurrentInput( p_playlist );
  235.                 pl_Release( p_intf );
  236.  
  237.                 if( p_input )
  238.                 {
  239.                     var_Get( p_input, "state", &val);
  240.                     val.i_int = ( val.i_int != PLAYING_S ) ? PLAYING_S : PAUSE_S;
  241.                     var_Set( p_input, "state", val);
  242.                     vlc_object_release( p_input );
  243.                 }
  244.                 break;
  245.             case GESTURE(LEFT,DOWN,NONE,NONE):
  246.                 p_playlist = pl_Hold( p_intf );
  247.                 playlist_Prev( p_playlist );
  248.                 pl_Release( p_intf );
  249.                 break;
  250.             case GESTURE(RIGHT,DOWN,NONE,NONE):
  251.                 p_playlist = pl_Hold( p_intf );
  252.                 playlist_Next( p_playlist );
  253.                 pl_Release( p_intf );
  254.                 break;
  255.             case UP:
  256.                 msg_Dbg(p_intf, "Louder");
  257.                 aout_VolumeUp( p_intf, 1, NULL );
  258.                 break;
  259.             case DOWN:
  260.                 msg_Dbg(p_intf, "Quieter");
  261.                 aout_VolumeDown( p_intf, 1, NULL );
  262.                 break;
  263.             case GESTURE(UP,DOWN,NONE,NONE):
  264.             case GESTURE(DOWN,UP,NONE,NONE):
  265.                 msg_Dbg( p_intf, "Mute sound" );
  266.                 aout_VolumeMute( p_intf, NULL );
  267.                 break;
  268.             case GESTURE(UP,RIGHT,NONE,NONE):
  269.                 {
  270.                     vlc_value_t val, list, list2;
  271.                     int i_count, i;
  272.                     p_playlist = pl_Hold( p_intf );
  273.                     p_input = playlist_CurrentInput( p_playlist );
  274.                     pl_Release( p_intf );
  275.                     if( !p_input )
  276.                         break;
  277.                     var_Get( p_input, "audio-es", &val );
  278.                     var_Change( p_input, "audio-es", VLC_VAR_GETCHOICES,
  279.                                 &list, &list2 );
  280.                     i_count = list.p_list->i_count;
  281.                     if( i_count <= 1 )
  282.                     {
  283.                         var_Change( p_input, "audio-es", VLC_VAR_FREELIST, &list,
  284.                                     &list2 );
  285.                         vlc_object_release( p_input );
  286.                         break;
  287.                     }
  288.                     for( i = 0; i < i_count; i++ )
  289.                     {
  290.                         if( val.i_int == list.p_list->p_values[i].i_int )
  291.                             break;
  292.                     }
  293.                     /* value of audio-es was not in choices list */
  294.                     if( i == i_count )
  295.                     {
  296.                         msg_Warn( p_input,
  297.                                   "invalid current audio track, selecting 0" );
  298.                         i = 0;
  299.                     }
  300.                     else if( i == i_count - 1 )
  301.                         i = 1;
  302.                     else
  303.                         i++;
  304.                     var_Set( p_input, "audio-es", list.p_list->p_values[i] );
  305.                     var_Change( p_input, "audio-es", VLC_VAR_FREELIST, &list,
  306.                                 &list2 );
  307.                     vlc_object_release( p_input );
  308.                 }
  309.                 break;
  310.             case GESTURE(DOWN,RIGHT,NONE,NONE):
  311.                 {
  312.                     vlc_value_t val, list, list2;
  313.                     int i_count, i;
  314.                     p_playlist = pl_Hold( p_intf );
  315.                     p_input = playlist_CurrentInput( p_playlist );
  316.                     pl_Release( p_intf );
  317.                     if( !p_input )
  318.                         break;
  319.                     var_Get( p_input, "spu-es", &val );
  320.                     var_Change( p_input, "spu-es", VLC_VAR_GETCHOICES,
  321.                             &list, &list2 );
  322.                     i_count = list.p_list->i_count;
  323.                     if( i_count <= 1 )
  324.                     {
  325.                         vlc_object_release( p_input );
  326.                         var_Change( p_input, "spu-es", VLC_VAR_FREELIST,
  327.                                     &list, &list2 );
  328.                         break;
  329.                     }
  330.                     for( i = 0; i < i_count; i++ )
  331.                     {
  332.                         if( val.i_int == list.p_list->p_values[i].i_int )
  333.                         {
  334.                             break;
  335.                         }
  336.                     }
  337.                     /* value of spu-es was not in choices list */
  338.                     if( i == i_count )
  339.                     {
  340.                         msg_Warn( p_input,
  341.                                 "invalid current subtitle track, selecting 0" );
  342.                         i = 0;
  343.                     }
  344.                     else if( i == i_count - 1 )
  345.                         i = 0;
  346.                     else
  347.                         i++;
  348.                     var_Set( p_input, "spu-es", list.p_list->p_values[i] );
  349.                     var_Change( p_input, "spu-es", VLC_VAR_FREELIST,
  350.                                 &list, &list2 );
  351.                     vlc_object_release( p_input );
  352.                 }
  353.                 break;
  354.             case GESTURE(UP,LEFT,NONE,NONE):
  355.                 if( p_sys->p_vout )
  356.                 {
  357.                     var_Get( p_sys->p_vout, "fullscreen", &val );
  358.                     val.b_bool = !val.b_bool;
  359.                     var_Set( p_sys->p_vout, "fullscreen", val );
  360.                 }
  361.                 break;
  362.             case GESTURE(DOWN,LEFT,NONE,NONE):
  363.                 /* FIXME: Should close the vout!"*/
  364.                 libvlc_Quit( p_intf->p_libvlc );
  365.                 break;
  366.             case GESTURE(DOWN,LEFT,UP,RIGHT):
  367.             case GESTURE(UP,RIGHT,DOWN,LEFT):
  368.                 msg_Dbg( p_intf, "a square was drawn!" );
  369.                 break;
  370.             default:
  371.                 break;
  372.             }
  373.             p_sys->i_num_gestures = 0;
  374.             p_sys->i_pattern = 0;
  375.             p_sys->b_got_gesture = false;
  376.         }
  377.         /*
  378.          * video output
  379.          */
  380.         if( p_sys->p_vout && !vlc_object_alive( p_sys->p_vout ) )
  381.         {
  382.             var_DelCallback( p_sys->p_vout, "mouse-moved",
  383.                              MouseEvent, p_intf );
  384.             var_DelCallback( p_sys->p_vout, "mouse-button-down",
  385.                              MouseEvent, p_intf );
  386.             vlc_object_release( p_sys->p_vout );
  387.             p_sys->p_vout = NULL;
  388.         }
  389.         if( p_sys->p_vout == NULL )
  390.         {
  391.             p_playlist = pl_Hold( p_intf );
  392.             p_input = playlist_CurrentInput( p_playlist );
  393.             pl_Release( p_intf );
  394.             if( p_input )
  395.             {
  396.                 p_sys->p_vout = input_GetVout( p_input );
  397.                 vlc_object_release( p_input );
  398.             }
  399.             if( p_sys->p_vout )
  400.             {
  401.                 var_AddCallback( p_sys->p_vout, "mouse-moved",
  402.                                  MouseEvent, p_intf );
  403.                 var_AddCallback( p_sys->p_vout, "mouse-button-down",
  404.                                  MouseEvent, p_intf );
  405.             }
  406.         }
  407.         vlc_mutex_unlock( &p_sys->lock );
  408.         /* Wait a bit */
  409.         msleep( INTF_IDLE_SLEEP );
  410.     }
  411.     vlc_restorecancel( canc );
  412. }
  413. /*****************************************************************************
  414.  * MouseEvent: callback for mouse events
  415.  *****************************************************************************/
  416. static int MouseEvent( vlc_object_t *p_this, char const *psz_var,
  417.                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
  418. {
  419.     VLC_UNUSED(p_this); VLC_UNUSED(oldval);
  420.     int pattern = 0;
  421.     signed int i_horizontal, i_vertical;
  422.     intf_thread_t *p_intf = (intf_thread_t *)p_data;
  423.     intf_sys_t    *p_sys = p_intf->p_sys;
  424.     vlc_mutex_lock( &p_sys->lock );
  425.     /* don't process new gestures before the last events are processed */
  426.     if( p_sys->b_got_gesture )
  427.     {
  428.         vlc_mutex_unlock( &p_sys->lock );
  429.         return VLC_SUCCESS;
  430.     }
  431.     if( !strcmp( psz_var, "mouse-moved" ) && p_sys->b_button_pressed )
  432.     {
  433.         p_sys->i_mouse_x = var_GetInteger( p_sys->p_vout, "mouse-x" );
  434.         p_sys->i_mouse_y = var_GetInteger( p_sys->p_vout, "mouse-y" );
  435.         i_horizontal = p_sys->i_mouse_x - p_sys->i_last_x;
  436.         i_horizontal = i_horizontal / p_sys->i_threshold;
  437.         i_vertical = p_sys->i_mouse_y - p_sys->i_last_y;
  438.         i_vertical = i_vertical / p_sys->i_threshold;
  439.         if( i_horizontal < 0 )
  440.         {
  441.             msg_Dbg( p_intf, "left gesture (%d)", i_horizontal );
  442.             pattern = LEFT;
  443.         }
  444.         else if( i_horizontal > 0 )
  445.         {
  446.             msg_Dbg( p_intf, "right gesture (%d)", i_horizontal );
  447.             pattern = RIGHT;
  448.         }
  449.         if( i_vertical < 0 )
  450.         {
  451.             msg_Dbg( p_intf, "up gesture (%d)", i_vertical );
  452.             pattern = UP;
  453.         }
  454.         else if( i_vertical > 0 )
  455.         {
  456.             msg_Dbg( p_intf, "down gesture (%d)", i_vertical );
  457.             pattern = DOWN;
  458.         }
  459.         if( pattern )
  460.         {
  461.             p_sys->i_last_y = p_sys->i_mouse_y;
  462.             p_sys->i_last_x = p_sys->i_mouse_x;
  463.             if( gesture( p_sys->i_pattern, p_sys->i_num_gestures - 1 )
  464.                     != pattern )
  465.             {
  466.                 p_sys->i_pattern |= pattern << ( p_sys->i_num_gestures * 4 );
  467.                 p_sys->i_num_gestures++;
  468.             }
  469.         }
  470.     }
  471.     else if( !strcmp( psz_var, "mouse-button-down" ) )
  472.     {
  473.         if( (newval.i_int & p_sys->i_button_mask) && !p_sys->b_button_pressed )
  474.         {
  475.             p_sys->b_button_pressed = true;
  476.             p_sys->i_last_x = var_GetInteger( p_sys->p_vout, "mouse-x" );
  477.             p_sys->i_last_y = var_GetInteger( p_sys->p_vout, "mouse-y" );
  478.         }
  479.         else if( !( newval.i_int & p_sys->i_button_mask ) && p_sys->b_button_pressed )
  480.         {
  481.             p_sys->b_button_pressed = false;
  482.             p_sys->b_got_gesture = true;
  483.         }
  484.     }
  485.     vlc_mutex_unlock( &p_sys->lock );
  486.     return VLC_SUCCESS;
  487. }