1 /*****************************************************************************
2 * hotkeys.c: Hotkey handling for vlc
3 *****************************************************************************
4 * Copyright (C) 2003 VideoLAN
5 * $Id: hotkeys.c,v 1.13 2003/12/12 23:03:35 yoann Exp $
7 * Authors: Sigmund Augdal <sigmunau@idi.ntnu.no>
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.
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.
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., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
27 #include <stdlib.h> /* malloc(), free() */
31 #include <vlc/input.h>
38 #define BUFFER_SIZE 10
39 /*****************************************************************************
40 * intf_sys_t: description and status of FB interface
41 *****************************************************************************/
44 vlc_mutex_t change_lock; /* mutex to keep the callback
45 * and the main loop from
46 * stepping on each others
48 int p_keys[ BUFFER_SIZE ]; /* buffer that contains
50 int i_size; /* number of events in buffer */
51 input_thread_t * p_input; /* pointer to input */
52 vout_thread_t * p_vout; /* pointer to vout object */
55 /*****************************************************************************
57 *****************************************************************************/
58 static int Open ( vlc_object_t * );
59 static void Close ( vlc_object_t * );
60 static void Run ( intf_thread_t * );
61 static int GetKey ( intf_thread_t *);
62 static int KeyEvent( vlc_object_t *, char const *,
63 vlc_value_t, vlc_value_t, void * );
64 static int ActionKeyCB( vlc_object_t *, char const *,
65 vlc_value_t, vlc_value_t, void * );
66 static void PlayBookmark( intf_thread_t *, int );
67 static void SetBookmark ( intf_thread_t *, int );
69 /*****************************************************************************
71 *****************************************************************************/
72 #define BOOKMARK1_TEXT N_("Playlist bookmark 1")
73 #define BOOKMARK2_TEXT N_("Playlist bookmark 2")
74 #define BOOKMARK3_TEXT N_("Playlist bookmark 3")
75 #define BOOKMARK4_TEXT N_("Playlist bookmark 4")
76 #define BOOKMARK5_TEXT N_("Playlist bookmark 5")
77 #define BOOKMARK6_TEXT N_("Playlist bookmark 6")
78 #define BOOKMARK7_TEXT N_("Playlist bookmark 7")
79 #define BOOKMARK8_TEXT N_("Playlist bookmark 8")
80 #define BOOKMARK9_TEXT N_("Playlist bookmark 9")
81 #define BOOKMARK10_TEXT N_("Playlist bookmark 10")
82 #define BOOKMARK_LONGTEXT N_( \
83 "This option allows you to define playlist bookmarks")
86 set_description( _("hotkey interface") );
87 add_string( "bookmark1", NULL, NULL,
88 BOOKMARK1_TEXT, BOOKMARK_LONGTEXT, VLC_FALSE );
89 add_string( "bookmark2", NULL, NULL,
90 BOOKMARK2_TEXT, BOOKMARK_LONGTEXT, VLC_FALSE );
91 add_string( "bookmark3", NULL, NULL,
92 BOOKMARK3_TEXT, BOOKMARK_LONGTEXT, VLC_FALSE );
93 add_string( "bookmark4", NULL, NULL,
94 BOOKMARK4_TEXT, BOOKMARK_LONGTEXT, VLC_FALSE );
95 add_string( "bookmark5", NULL, NULL,
96 BOOKMARK5_TEXT, BOOKMARK_LONGTEXT, VLC_FALSE );
97 add_string( "bookmark6", NULL, NULL,
98 BOOKMARK6_TEXT, BOOKMARK_LONGTEXT, VLC_FALSE );
99 add_string( "bookmark7", NULL, NULL,
100 BOOKMARK7_TEXT, BOOKMARK_LONGTEXT, VLC_FALSE );
101 add_string( "bookmark8", NULL, NULL,
102 BOOKMARK8_TEXT, BOOKMARK_LONGTEXT, VLC_FALSE );
103 add_string( "bookmark9", NULL, NULL,
104 BOOKMARK9_TEXT, BOOKMARK_LONGTEXT, VLC_FALSE );
105 add_string( "bookmark10", NULL, NULL,
106 BOOKMARK10_TEXT, BOOKMARK_LONGTEXT, VLC_FALSE );
107 set_capability( "interface", 0 );
108 set_callbacks( Open, Close );
111 /*****************************************************************************
112 * Open: initialize interface
113 *****************************************************************************/
114 static int Open( vlc_object_t *p_this )
116 intf_thread_t *p_intf = (intf_thread_t *)p_this;
118 /* Allocate instance and initialize some members */
119 p_intf->p_sys = malloc( sizeof( intf_sys_t ) );
120 if( p_intf->p_sys == NULL )
122 msg_Err( p_intf, "out of memory" );
125 vlc_mutex_init( p_intf, &p_intf->p_sys->change_lock );
126 p_intf->p_sys->i_size = 0;
127 p_intf->pf_run = Run;
129 p_intf->p_sys->p_input = NULL;
130 p_intf->p_sys->p_vout = NULL;
132 var_AddCallback( p_intf->p_vlc, "key-pressed", KeyEvent, p_intf );
136 /*****************************************************************************
137 * Close: destroy interface
138 *****************************************************************************/
139 static void Close( vlc_object_t *p_this )
141 intf_thread_t *p_intf = (intf_thread_t *)p_this;
143 if( p_intf->p_sys->p_input )
145 vlc_object_release( p_intf->p_sys->p_input );
147 if( p_intf->p_sys->p_vout )
149 vlc_object_release( p_intf->p_sys->p_vout );
151 /* Destroy structure */
152 free( p_intf->p_sys );
155 /*****************************************************************************
157 *****************************************************************************/
158 static void Run( intf_thread_t *p_intf )
160 playlist_t *p_playlist;
161 input_thread_t *p_input;
162 vout_thread_t *p_vout = NULL;
163 struct hotkey *p_hotkeys = p_intf->p_vlc->p_hotkeys;
167 /* Initialize hotkey structure */
168 for( i = 0; p_hotkeys[i].psz_action != NULL; i++ )
170 var_Create( p_intf->p_vlc, p_hotkeys[i].psz_action,
171 VLC_VAR_HOTKEY | VLC_VAR_DOINHERIT );
173 var_AddCallback( p_intf->p_vlc, p_hotkeys[i].psz_action,
175 var_Get( p_intf->p_vlc, p_hotkeys[i].psz_action, &val );
176 var_Set( p_intf->p_vlc, p_hotkeys[i].psz_action, val );
179 while( !p_intf->b_die )
184 msleep( INTF_IDLE_SLEEP );
186 /* Update the input */
187 if( p_intf->p_sys->p_input == NULL )
189 p_intf->p_sys->p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT,
192 else if( p_intf->p_sys->p_input->b_dead )
194 vlc_object_release( p_intf->p_sys->p_input );
195 p_intf->p_sys->p_input = NULL;
197 p_input = p_intf->p_sys->p_input;
199 /* Update the vout */
202 p_vout = vlc_object_find( p_intf, VLC_OBJECT_VOUT,
204 p_intf->p_sys->p_vout = p_vout;
206 else if( p_vout->b_die )
208 vlc_object_release( p_vout );
210 p_intf->p_sys->p_vout = NULL;
213 /* Find action triggered by hotkey */
215 i_key = GetKey( p_intf );
216 for( i = 0; p_hotkeys[i].psz_action != NULL; i++ )
218 if( p_hotkeys[i].i_key == i_key )
220 i_action = p_hotkeys[i].i_action;
226 /* No key pressed, sleep a bit more */
227 msleep( INTF_IDLE_SLEEP );
231 if( i_action == ACTIONID_QUIT )
233 p_intf->p_vlc->b_die = VLC_TRUE;
234 vout_OSDMessage( VLC_OBJECT(p_intf), _("Quit" ) );
237 else if( i_action == ACTIONID_VOL_UP )
239 audio_volume_t i_newvol;
241 aout_VolumeUp( p_intf, 1, &i_newvol );
242 sprintf( string, "Vol %d%%", i_newvol*100/AOUT_VOLUME_MAX );
243 vout_OSDMessage( VLC_OBJECT(p_intf), string );
245 else if( i_action == ACTIONID_VOL_DOWN )
247 audio_volume_t i_newvol;
249 aout_VolumeDown( p_intf, 1, &i_newvol );
250 sprintf( string, "Vol %d%%", i_newvol*100/AOUT_VOLUME_MAX );
251 vout_OSDMessage( VLC_OBJECT(p_intf), string );
253 else if( i_action == ACTIONID_VOL_MUTE )
255 audio_volume_t i_newvol = -1;
256 aout_VolumeMute( p_intf, &i_newvol );
259 vout_OSDMessage( VLC_OBJECT(p_intf), "Mute" );
264 sprintf( string, "Vol %d%%", i_newvol*100/AOUT_VOLUME_MAX );
265 vout_OSDMessage( VLC_OBJECT(p_intf), string );
268 else if( i_action == ACTIONID_FULLSCREEN )
272 p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
275 else if( i_action == ACTIONID_PLAY )
277 p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
281 vlc_mutex_lock( &p_playlist->object_lock );
282 if( p_playlist->i_size )
284 vlc_mutex_unlock( &p_playlist->object_lock );
285 playlist_Play( p_playlist );
286 vlc_object_release( p_playlist );
290 else if( i_action == ACTIONID_PLAY_PAUSE )
292 val.i_int = PLAYING_S;
295 var_Get( p_input, "state", &val );
297 if( p_input && val.i_int != PAUSE_S )
299 vout_OSDMessage( VLC_OBJECT(p_intf), _( "Pause" ) );
301 var_Set( p_input, "state", val );
305 p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
309 vlc_mutex_lock( &p_playlist->object_lock );
310 if( p_playlist->i_size )
312 vlc_mutex_unlock( &p_playlist->object_lock );
313 vout_OSDMessage( VLC_OBJECT(p_intf), _( "Play" ) );
314 playlist_Play( p_playlist );
315 vlc_object_release( p_playlist );
322 if( i_action == ACTIONID_PAUSE )
324 vout_OSDMessage( VLC_OBJECT(p_intf), _( "Pause" ) );
326 var_Set( p_input, "state", val );
328 else if( i_action == ACTIONID_JUMP_BACKWARD_10SEC )
330 vout_OSDMessage( VLC_OBJECT(p_intf), _( "Jump -10 seconds" ) );
331 val.i_time = -10000000;
332 var_Set( p_input, "time-offset", val );
334 else if( i_action == ACTIONID_JUMP_FORWARD_10SEC )
336 vout_OSDMessage( VLC_OBJECT(p_intf), _( "Jump +10 seconds" ) );
337 val.i_time = 10000000;
338 var_Set( p_input, "time-offset", val );
340 else if( i_action == ACTIONID_JUMP_BACKWARD_1MIN )
342 vout_OSDMessage( VLC_OBJECT(p_intf), _( "Jump -1 minute" ) );
343 val.i_time = -60000000;
344 var_Set( p_input, "time-offset", val );
346 else if( i_action == ACTIONID_JUMP_FORWARD_1MIN )
348 vout_OSDMessage( VLC_OBJECT(p_intf), _( "Jump +1 minute" ) );
349 val.i_time = 60000000;
350 var_Set( p_input, "time-offset", val );
352 else if( i_action == ACTIONID_JUMP_BACKWARD_5MIN )
354 vout_OSDMessage( VLC_OBJECT(p_intf), _( "Jump -5 minutes" ) );
355 val.i_time = -300000000;
356 var_Set( p_input, "time-offset", val );
358 else if( i_action == ACTIONID_JUMP_FORWARD_5MIN )
360 vout_OSDMessage( VLC_OBJECT(p_intf), _( "Jump +5 minutes" ) );
361 val.i_time = 300000000;
362 var_Set( p_input, "time-offset", val );
364 else if( i_action == ACTIONID_NEXT )
366 p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
370 playlist_Next( p_playlist );
371 vlc_object_release( p_playlist );
374 else if( i_action == ACTIONID_PREV )
376 p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
380 playlist_Prev( p_playlist );
381 vlc_object_release( p_playlist );
384 else if( i_action == ACTIONID_STOP )
386 p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
390 playlist_Stop( p_playlist );
391 vlc_object_release( p_playlist );
394 else if( i_action == ACTIONID_FASTER )
396 vlc_value_t val; val.b_bool = VLC_TRUE;
397 var_Set( p_input, "rate-faster", val );
399 else if( i_action == ACTIONID_FASTER )
401 vlc_value_t val; val.b_bool = VLC_TRUE;
402 var_Set( p_input, "rate-slower", val );
404 else if( i_action == ACTIONID_POSITION )
406 playlist_t *p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
408 char psz_duration[MSTRTIME_MAX_SIZE];
409 char psz_time[MSTRTIME_MAX_SIZE];
413 var_Get( p_input, "time", &time );
418 p_playlist->pp_items[p_playlist->i_index]->i_duration;
420 i_seconds = time.i_time / 1000000;
421 secstotimestr ( psz_time, i_seconds );
425 char psz_position[2*MSTRTIME_MAX_SIZE + 3];
426 secstotimestr( psz_duration, dur/1000000 );
427 strcpy( psz_position, psz_time );
428 strcat( psz_position, " / " );
429 strcat( psz_position, psz_duration );
430 vout_OSDMessage( VLC_OBJECT(p_playlist), psz_position );
432 else if( i_seconds > 0 )
434 vout_OSDMessage( VLC_OBJECT(p_playlist), psz_time );
436 vlc_object_release( p_playlist );
439 else if( i_action >= ACTIONID_PLAY_BOOKMARK1 &&
440 i_action <= ACTIONID_PLAY_BOOKMARK10 )
442 PlayBookmark( p_intf, i_action - ACTIONID_PLAY_BOOKMARK1 + 1 );
444 else if( i_action >= ACTIONID_SET_BOOKMARK1 &&
445 i_action <= ACTIONID_SET_BOOKMARK10 )
447 SetBookmark( p_intf, i_action - ACTIONID_SET_BOOKMARK1 + 1 );
453 static int GetKey( intf_thread_t *p_intf)
455 vlc_mutex_lock( &p_intf->p_sys->change_lock );
456 if ( p_intf->p_sys->i_size == 0 )
458 vlc_mutex_unlock( &p_intf->p_sys->change_lock );
463 int i_return = p_intf->p_sys->p_keys[ 0 ];
465 p_intf->p_sys->i_size--;
466 for ( i = 0; i < BUFFER_SIZE - 1; i++)
468 p_intf->p_sys->p_keys[ i ] = p_intf->p_sys->p_keys[ i + 1 ];
470 vlc_mutex_unlock( &p_intf->p_sys->change_lock );
475 /*****************************************************************************
476 * KeyEvent: callback for keyboard events
477 *****************************************************************************/
478 static int KeyEvent( vlc_object_t *p_this, char const *psz_var,
479 vlc_value_t oldval, vlc_value_t newval, void *p_data )
481 intf_thread_t *p_intf = (intf_thread_t *)p_data;
482 vlc_mutex_lock( &p_intf->p_sys->change_lock );
483 if ( p_intf->p_sys->i_size == BUFFER_SIZE )
485 msg_Warn( p_intf, "Event buffer full, dropping keypress" );
486 vlc_mutex_unlock( &p_intf->p_sys->change_lock );
491 p_intf->p_sys->p_keys[ p_intf->p_sys->i_size ] = newval.i_int;
492 p_intf->p_sys->i_size++;
494 vlc_mutex_unlock( &p_intf->p_sys->change_lock );
499 static int ActionKeyCB( vlc_object_t *p_this, char const *psz_var,
500 vlc_value_t oldval, vlc_value_t newval, void *p_data )
502 vlc_t *p_vlc = (vlc_t *)p_this;
503 struct hotkey *p_hotkeys = p_vlc->p_hotkeys;
506 for( i = 0; p_hotkeys[i].psz_action != NULL; i++ )
508 if( !strcmp( p_hotkeys[i].psz_action, psz_var ) )
510 p_hotkeys[i].i_key = newval.i_int;
517 static void PlayBookmark( intf_thread_t *p_intf, int i_num )
521 char psz_bookmark_name[11];
522 playlist_t *p_playlist = vlc_object_find( p_intf,
523 VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
525 sprintf( psz_bookmark_name, "bookmark%i", i_num );
526 var_Create( p_intf, psz_bookmark_name, VLC_VAR_STRING|VLC_VAR_DOINHERIT );
527 var_Get( p_intf, psz_bookmark_name, &val );
531 char *psz_bookmark = strdup( val.psz_string );
532 for( i_position = 0 ; i_position < p_playlist->i_size ; i_position++)
534 if( !strcmp( psz_bookmark, p_playlist->pp_items[i_position]->psz_uri ) )
536 playlist_Goto( p_playlist, i_position );
540 vlc_object_release( p_playlist );
544 static void SetBookmark( intf_thread_t *p_intf, int i_num )
547 playlist_t *p_playlist = vlc_object_find( p_intf,
548 VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
551 char psz_bookmark_name[11];
552 sprintf( psz_bookmark_name, "bookmark%i", i_num );
553 var_Create( p_intf, psz_bookmark_name, VLC_VAR_STRING|VLC_VAR_DOINHERIT );
554 val.psz_string = strdup( p_playlist->pp_items[p_playlist->i_index]->psz_uri );
555 var_Set( p_intf, psz_bookmark_name, val );
556 msg_Info( p_intf, "Setting playlist bookmark %i to %s", i_num, val.psz_string );
557 vlc_object_release( p_playlist );