]> git.sesse.net Git - vlc/blob - modules/control/hotkeys.c
* modules/control/hotkeys.c, src/libvlc.h, include/vlc_keys.h: added hotkeys for...
[vlc] / modules / control / hotkeys.c
1 /*****************************************************************************
2  * hotkeys.c: Hotkey handling for vlc
3  *****************************************************************************
4  * Copyright (C) 2003 VideoLAN
5  * $Id: hotkeys.c,v 1.4 2003/10/30 17:58:07 gbazin Exp $
6  *
7  * Authors: Sigmund Augdal <sigmunau@idi.ntnu.no>
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., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdlib.h>                                      /* malloc(), free() */
28 #include <string.h>
29
30 #include <vlc/vlc.h>
31 #include <vlc/intf.h>
32 #include <vlc/vout.h>
33 #include <vlc/aout.h>
34 #include <osd.h>
35
36 #include "vlc_keys.h"
37
38 #define BUFFER_SIZE 10
39 /*****************************************************************************
40  * intf_sys_t: description and status of FB interface
41  *****************************************************************************/
42 struct intf_sys_t
43 {
44     vlc_mutex_t         change_lock;  /* mutex to keep the callback
45                                        * and the main loop from
46                                        * stepping on each others
47                                        * toes */
48     int                 p_keys[ BUFFER_SIZE ]; /* buffer that contains
49                                                 * keyevents */
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 */
53 };
54
55 /*****************************************************************************
56  * Local prototypes
57  *****************************************************************************/
58 static int  Open    ( vlc_object_t * );
59 static void Close   ( vlc_object_t * );
60 static void Run     ( intf_thread_t * );
61 static void Feedback( intf_thread_t *, char * );
62 static int  GetKey  ( intf_thread_t *);
63 static int  KeyEvent( vlc_object_t *, char const *,
64                       vlc_value_t, vlc_value_t, void * );
65 static int  ActionKeyCB( vlc_object_t *, char const *,
66                          vlc_value_t, vlc_value_t, void * );
67
68 /*****************************************************************************
69  * Module descriptor
70  *****************************************************************************/
71 vlc_module_begin();
72     set_description( _("hotkey interface") );
73     set_capability( "interface", 0 );
74     set_callbacks( Open, Close );
75 vlc_module_end();
76
77 /*****************************************************************************
78  * Open: initialize interface
79  *****************************************************************************/
80 static int Open( vlc_object_t *p_this )
81 {
82     intf_thread_t *p_intf = (intf_thread_t *)p_this;
83
84     /* Allocate instance and initialize some members */
85     p_intf->p_sys = malloc( sizeof( intf_sys_t ) );
86     if( p_intf->p_sys == NULL )
87     {
88         msg_Err( p_intf, "out of memory" );
89         return 1;
90     }
91     vlc_mutex_init( p_intf, &p_intf->p_sys->change_lock );
92     p_intf->p_sys->i_size = 0;
93     p_intf->pf_run = Run;
94
95     p_intf->p_sys->p_input = NULL;
96     p_intf->p_sys->p_vout = NULL;
97
98     var_AddCallback( p_intf->p_vlc, "key-pressed", KeyEvent, p_intf );
99     return 0;
100 }
101
102 /*****************************************************************************
103  * Close: destroy interface
104  *****************************************************************************/
105 static void Close( vlc_object_t *p_this )
106 {
107     intf_thread_t *p_intf = (intf_thread_t *)p_this;
108
109     if( p_intf->p_sys->p_input )
110     {
111         vlc_object_release( p_intf->p_sys->p_input );
112     }
113     if( p_intf->p_sys->p_vout )
114     {
115         vlc_object_release( p_intf->p_sys->p_vout );
116     }
117     /* Destroy structure */
118     free( p_intf->p_sys );
119 }
120
121 /*****************************************************************************
122  * Run: main loop
123  *****************************************************************************/
124 static void Run( intf_thread_t *p_intf )
125 {
126     playlist_t *p_playlist;
127     input_thread_t *p_input;
128     vout_thread_t *p_vout = NULL;
129     struct hotkey *p_hotkeys = p_intf->p_vlc->p_hotkeys;
130     vlc_value_t val;
131     int i;
132
133     /* Initialize hotkey structure */
134     for( i = 0; p_hotkeys[i].psz_action != NULL; i++ )
135     {
136         var_Create( p_intf->p_vlc, p_hotkeys[i].psz_action,
137                     VLC_VAR_HOTKEY | VLC_VAR_DOINHERIT );
138
139         var_AddCallback( p_intf->p_vlc, p_hotkeys[i].psz_action,
140                          ActionKeyCB, NULL );
141         var_Get( p_intf->p_vlc, p_hotkeys[i].psz_action, &val );
142         var_Set( p_intf->p_vlc, p_hotkeys[i].psz_action, val );
143     }
144
145     while( !p_intf->b_die )
146     {
147         int i_key, i_action;
148
149         /* Sleep a bit */
150         msleep( INTF_IDLE_SLEEP );
151
152         /* Update the input */
153         if( p_intf->p_sys->p_input == NULL )
154         {
155             p_intf->p_sys->p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT,
156                                                       FIND_ANYWHERE );
157         }
158         else if( p_intf->p_sys->p_input->b_dead )
159         {
160             vlc_object_release( p_intf->p_sys->p_input );
161             p_intf->p_sys->p_input = NULL;
162         }
163         p_input = p_intf->p_sys->p_input;
164
165         /* Update the vout */
166         if( p_vout == NULL )
167         {
168             p_vout = vlc_object_find( p_intf, VLC_OBJECT_VOUT,
169                                       FIND_ANYWHERE );
170             p_intf->p_sys->p_vout = p_vout;
171         }
172         else if( p_vout->b_die )
173         {
174             vlc_object_release( p_vout );
175             p_vout = NULL;
176             p_intf->p_sys->p_vout = NULL;
177         }
178
179         /* Find action triggered by hotkey */
180         i_action = 0;
181         i_key = GetKey( p_intf );
182         for( i = 0; p_hotkeys[i].psz_action != NULL; i++ )
183         {
184             if( p_hotkeys[i].i_key == i_key )
185             {
186                  i_action = p_hotkeys[i].i_action;
187             }
188         }
189
190         if( !i_action )
191         {
192             /* No key pressed, sleep a bit more */
193             msleep( INTF_IDLE_SLEEP );
194             continue;
195         }
196
197         if( i_action == ACTIONID_QUIT )
198         {
199             p_intf->p_vlc->b_die = VLC_TRUE;
200             Feedback( p_intf, _("Quit" ) );
201             continue;
202         }
203         else if( i_action == ACTIONID_VOL_UP )
204         {
205             audio_volume_t i_newvol;
206             char string[9];
207             aout_VolumeUp( p_intf, 1, &i_newvol );
208             sprintf( string, "Vol %d%%", i_newvol*100/AOUT_VOLUME_MAX );
209             Feedback( p_intf, string );
210         }
211         else if( i_action == ACTIONID_VOL_DOWN )
212         {
213             audio_volume_t i_newvol;
214             char string[9];
215             aout_VolumeDown( p_intf, 1, &i_newvol );
216             sprintf( string, "Vol %d%%", i_newvol*100/AOUT_VOLUME_MAX );
217             Feedback( p_intf, string );
218         }
219         else if( i_action == ACTIONID_FULLSCREEN )
220         {
221             if( p_vout )
222             {
223                 p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
224             }
225         }
226         else if( i_action == ACTIONID_PLAY )
227         {
228             p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
229                                           FIND_ANYWHERE );
230             if( p_playlist )
231             {
232                 vlc_mutex_lock( &p_playlist->object_lock );
233                 if( p_playlist->i_size )
234                 {
235                     vlc_mutex_unlock( &p_playlist->object_lock );
236                     playlist_Play( p_playlist );
237                     vlc_object_release( p_playlist );
238                 }
239             }
240         }
241         else if( i_action == ACTIONID_PLAY_PAUSE )
242         {
243             if( p_input &&
244                 p_input->stream.control.i_status != PAUSE_S )
245             {
246                 Feedback( p_intf, _( "Pause" ) );
247                 input_SetStatus( p_input, INPUT_STATUS_PAUSE );
248             }
249             else
250             {
251                 p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
252                                               FIND_ANYWHERE );
253                 if( p_playlist )
254                 {
255                     vlc_mutex_lock( &p_playlist->object_lock );
256                     if( p_playlist->i_size )
257                     {
258                         vlc_mutex_unlock( &p_playlist->object_lock );
259                         Feedback( p_intf, _( "Play" ) );
260                         playlist_Play( p_playlist );
261                         vlc_object_release( p_playlist );
262                     }
263                 }
264             }
265         }
266         else if( p_input )
267         {
268             if( i_action == ACTIONID_PAUSE )
269             {
270                 Feedback( p_intf, _( "Pause" ) );
271                 input_SetStatus( p_input, INPUT_STATUS_PAUSE );
272             }
273             else if( i_action == ACTIONID_JUMP_BACKWARD_10SEC )
274             {
275                 Feedback( p_intf, _( "Jump -10 seconds" ) );
276                 input_Seek( p_input, -10, INPUT_SEEK_SECONDS|INPUT_SEEK_CUR );
277             }
278             else if( i_action == ACTIONID_JUMP_FORWARD_10SEC )
279             {
280                 Feedback( p_intf, _( "Jump +10 seconds" ) );
281                 input_Seek( p_input, 10, INPUT_SEEK_SECONDS|INPUT_SEEK_CUR );
282             }
283             else if( i_action == ACTIONID_JUMP_BACKWARD_1MIN )
284             {
285                 Feedback( p_intf, _( "Jump -1 minute" ) );
286                 input_Seek( p_input, -60, INPUT_SEEK_SECONDS|INPUT_SEEK_CUR );
287             }
288             else if( i_action == ACTIONID_JUMP_FORWARD_1MIN )
289             {
290                 Feedback( p_intf, _( "Jump +1 minute" ) );
291                 input_Seek( p_input, 60, INPUT_SEEK_SECONDS|INPUT_SEEK_CUR );
292             }
293             else if( i_action == ACTIONID_JUMP_BACKWARD_5MIN )
294             {
295                 Feedback( p_intf, _( "Jump -5 minutes" ) );
296                 input_Seek( p_input, -300, INPUT_SEEK_SECONDS|INPUT_SEEK_CUR );
297             }
298             else if( i_action == ACTIONID_JUMP_FORWARD_5MIN )
299             {
300                 Feedback( p_intf, _( "Jump +5 minutes" ) );
301                 input_Seek( p_input, 300, INPUT_SEEK_SECONDS|INPUT_SEEK_CUR );
302             }
303             else if( i_action == ACTIONID_NEXT )
304             {
305                 p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
306                                               FIND_ANYWHERE );
307                 if( p_playlist )
308                 {
309                     playlist_Next( p_playlist );
310                     vlc_object_release( p_playlist );
311                 }
312             }
313             else if( i_action == ACTIONID_PREV )
314             {
315                 p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
316                                               FIND_ANYWHERE );
317                 if( p_playlist )
318                 {
319                     playlist_Prev( p_playlist );
320                     vlc_object_release( p_playlist );
321                 }
322             }
323             else if( i_action == ACTIONID_STOP )
324             {
325                 p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
326                                               FIND_ANYWHERE );
327                 if( p_playlist )
328                 {
329                     playlist_Stop( p_playlist );
330                     vlc_object_release( p_playlist );
331                 }
332             }
333             else if( i_action == ACTIONID_FASTER )
334             {
335                 vlc_value_t val; val.b_bool = VLC_TRUE;
336                 var_Set( p_input, "rate-faster", val );
337             }
338             else if( i_action == ACTIONID_FASTER )
339             {
340                 vlc_value_t val; val.b_bool = VLC_TRUE;
341                 var_Set( p_input, "rate-slower", val );
342             }
343         }
344
345     }
346 }
347
348 static void Feedback( intf_thread_t *p_intf, char *psz_string )
349 {
350     if ( p_intf->p_sys->p_vout )
351     {
352         vout_ShowTextRelative( p_intf->p_sys->p_vout, psz_string, NULL, 
353                                OSD_ALIGN_TOP | OSD_ALIGN_RIGHT,
354                                30, 20, 1500000 );
355     }
356 }
357
358 static int GetKey( intf_thread_t *p_intf)
359 {
360     vlc_mutex_lock( &p_intf->p_sys->change_lock );
361     if ( p_intf->p_sys->i_size == 0 )
362     {
363         vlc_mutex_unlock( &p_intf->p_sys->change_lock );
364         return -1;
365     }
366     else
367     {
368         int i_return = p_intf->p_sys->p_keys[ 0 ];
369         int i;
370         p_intf->p_sys->i_size--;
371         for ( i = 0; i < BUFFER_SIZE - 1; i++)
372         {
373             p_intf->p_sys->p_keys[ i ] = p_intf->p_sys->p_keys[ i + 1 ];
374         }
375         vlc_mutex_unlock( &p_intf->p_sys->change_lock );
376         return i_return;
377     }
378 }
379
380 /*****************************************************************************
381  * KeyEvent: callback for keyboard events
382  *****************************************************************************/
383 static int KeyEvent( vlc_object_t *p_this, char const *psz_var,
384                      vlc_value_t oldval, vlc_value_t newval, void *p_data )
385 {
386     intf_thread_t *p_intf = (intf_thread_t *)p_data;
387     vlc_mutex_lock( &p_intf->p_sys->change_lock );
388     if ( p_intf->p_sys->i_size == BUFFER_SIZE )
389     {
390         msg_Warn( p_intf, "Event buffer full, dropping keypress" );
391         vlc_mutex_unlock( &p_intf->p_sys->change_lock );
392         return VLC_EGENERIC;
393     }
394     else
395     {
396         p_intf->p_sys->p_keys[ p_intf->p_sys->i_size ] = newval.i_int;
397         p_intf->p_sys->i_size++;
398     }
399     vlc_mutex_unlock( &p_intf->p_sys->change_lock );
400
401     return VLC_SUCCESS;
402 }
403
404 static int ActionKeyCB( vlc_object_t *p_this, char const *psz_var,
405                         vlc_value_t oldval, vlc_value_t newval, void *p_data )
406 {
407     vlc_t *p_vlc = (vlc_t *)p_this;
408     struct hotkey *p_hotkeys = p_vlc->p_hotkeys;
409     int i;
410
411     for( i = 0; p_hotkeys[i].psz_action != NULL; i++ )
412     {
413         if( !strcmp( p_hotkeys[i].psz_action, psz_var ) )
414         {
415             p_hotkeys[i].i_key = newval.i_int;
416         }
417     }
418
419     return VLC_SUCCESS;
420 }