]> git.sesse.net Git - vlc/blob - modules/control/hotkeys.c
a41ca1401d25753feb93df13c441b4094dfe52cc
[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.2 2003/10/29 01:33:27 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_NEXT )
274             {
275                 p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
276                                               FIND_ANYWHERE );
277                 if( p_playlist )
278                 {
279                     playlist_Next( p_playlist );
280                     vlc_object_release( p_playlist );
281                 }
282             }
283             else if( i_action == ACTIONID_PREV )
284             {
285                 p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
286                                               FIND_ANYWHERE );
287                 if( p_playlist )
288                 {
289                     playlist_Prev( p_playlist );
290                     vlc_object_release( p_playlist );
291                 }
292             }
293             else if( i_action == ACTIONID_STOP )
294             {
295                 p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
296                                               FIND_ANYWHERE );
297                 if( p_playlist )
298                 {
299                     playlist_Stop( p_playlist );
300                     vlc_object_release( p_playlist );
301                 }
302             }
303             else if( i_action == ACTIONID_FASTER )
304             {
305                 input_SetStatus( p_input, INPUT_STATUS_FASTER );
306             }
307             else if( i_action == ACTIONID_FASTER )
308             {
309                 input_SetStatus( p_input, INPUT_STATUS_SLOWER );
310             }
311         }
312
313     }
314 }
315
316 static void Feedback( intf_thread_t *p_intf, char *psz_string )
317 {
318     if ( p_intf->p_sys->p_vout )
319     {
320         vout_ShowTextRelative( p_intf->p_sys->p_vout, psz_string, NULL, 
321                                  OSD_ALIGN_TOP|OSD_ALIGN_RIGHT, 30,20,400000 );
322     }
323 }
324
325 static int GetKey( intf_thread_t *p_intf)
326 {
327     vlc_mutex_lock( &p_intf->p_sys->change_lock );
328     if ( p_intf->p_sys->i_size == 0 )
329     {
330         vlc_mutex_unlock( &p_intf->p_sys->change_lock );
331         return -1;
332     }
333     else
334     {
335         int i_return = p_intf->p_sys->p_keys[ 0 ];
336         int i;
337         p_intf->p_sys->i_size--;
338         for ( i = 0; i < BUFFER_SIZE - 1; i++)
339         {
340             p_intf->p_sys->p_keys[ i ] = p_intf->p_sys->p_keys[ i + 1 ];
341         }
342         vlc_mutex_unlock( &p_intf->p_sys->change_lock );
343         return i_return;
344     }
345 }
346
347 /*****************************************************************************
348  * KeyEvent: callback for keyboard events
349  *****************************************************************************/
350 static int KeyEvent( vlc_object_t *p_this, char const *psz_var,
351                      vlc_value_t oldval, vlc_value_t newval, void *p_data )
352 {
353     intf_thread_t *p_intf = (intf_thread_t *)p_data;
354     vlc_mutex_lock( &p_intf->p_sys->change_lock );
355     if ( p_intf->p_sys->i_size == BUFFER_SIZE )
356     {
357         msg_Warn( p_intf, "Event buffer full, dropping keypress" );
358         vlc_mutex_unlock( &p_intf->p_sys->change_lock );
359         return VLC_EGENERIC;
360     }
361     else
362     {
363         p_intf->p_sys->p_keys[ p_intf->p_sys->i_size ] = newval.i_int;
364         p_intf->p_sys->i_size++;
365     }
366     vlc_mutex_unlock( &p_intf->p_sys->change_lock );
367
368     return VLC_SUCCESS;
369 }
370
371 static int ActionKeyCB( vlc_object_t *p_this, char const *psz_var,
372                         vlc_value_t oldval, vlc_value_t newval, void *p_data )
373 {
374     vlc_t *p_vlc = (vlc_t *)p_this;
375     struct hotkey *p_hotkeys = p_vlc->p_hotkeys;
376     int i;
377
378     for( i = 0; p_hotkeys[i].psz_action != NULL; i++ )
379     {
380         if( !strcmp( p_hotkeys[i].psz_action, psz_var ) )
381         {
382             p_hotkeys[i].i_key = newval.i_int;
383         }
384     }
385
386     return VLC_SUCCESS;
387 }