]> git.sesse.net Git - vlc/blob - modules/control/globalhotkeys/win32.c
Win32 globalhotkeys: kill warnings
[vlc] / modules / control / globalhotkeys / win32.c
1 /*****************************************************************************
2  * win32.c: Global-Hotkey WIN32 handling for vlc
3  *****************************************************************************
4  * Copyright (C) 2008-2009 the VideoLAN team
5  *
6  * Authors: Domani Hannes <ssbssa at yahoo dot de>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21  *****************************************************************************/
22
23 #ifdef HAVE_CONFIG_H
24 # include "config.h"
25 #endif
26
27 #include <ctype.h>
28
29 #include <vlc_common.h>
30 #include <vlc_plugin.h>
31 #include <vlc_interface.h>
32 #include <vlc_keys.h>
33
34 /*****************************************************************************
35  * Local prototypes
36  *****************************************************************************/
37 static int Open( vlc_object_t *p_this );
38 static void Close( vlc_object_t *p_this );
39 static void *Thread( void *p_data );
40 LRESULT CALLBACK WMHOTKEYPROC( HWND, UINT, WPARAM, LPARAM );
41
42 /*****************************************************************************
43  * Module descriptor
44  *****************************************************************************/
45 vlc_module_begin()
46     set_shortname( N_("Global Hotkeys") )
47     set_category( CAT_INTERFACE )
48     set_subcategory( SUBCAT_INTERFACE_HOTKEYS )
49     set_description( N_("Global Hotkeys interface") )
50     set_capability( "interface", 0 )
51     set_callbacks( Open, Close )
52 vlc_module_end()
53
54 struct intf_sys_t
55 {
56     vlc_thread_t thread;
57     HWND hotkeyWindow;
58     vlc_mutex_t lock;
59     vlc_cond_t wait;
60 };
61
62 /*****************************************************************************
63  * Open: initialize interface
64  *****************************************************************************/
65 static int Open( vlc_object_t *p_this )
66 {
67     intf_thread_t *p_intf = (intf_thread_t *)p_this;
68     intf_sys_t *p_sys = malloc( sizeof (intf_sys_t) );
69
70     if( p_sys == NULL )
71         return VLC_ENOMEM;
72
73     p_intf->p_sys = p_sys;
74     p_sys->hotkeyWindow = NULL;
75     vlc_mutex_init( &p_sys->lock );
76     vlc_cond_init( &p_sys->wait );
77
78     if( vlc_clone( &p_sys->thread, Thread, p_intf, VLC_THREAD_PRIORITY_LOW ) )
79     {
80         vlc_mutex_destroy( &p_sys->lock );
81         vlc_cond_destroy( &p_sys->wait );
82         free( p_sys );
83         p_intf->p_sys = NULL;
84
85         return VLC_ENOMEM;
86     }
87
88     vlc_mutex_lock( &p_sys->lock );
89     while( p_sys->hotkeyWindow == NULL )
90         vlc_cond_wait( &p_sys->wait, &p_sys->lock );
91     if( p_sys->hotkeyWindow == INVALID_HANDLE_VALUE )
92     {
93         vlc_mutex_unlock( &p_sys->lock );
94         vlc_join( p_sys->thread, NULL );
95         vlc_mutex_destroy( &p_sys->lock );
96         vlc_cond_destroy( &p_sys->wait );
97         free( p_sys );
98         p_intf->p_sys = NULL;
99
100         return VLC_ENOMEM;
101     }
102     vlc_mutex_unlock( &p_sys->lock );
103
104     return VLC_SUCCESS;
105 }
106
107 /*****************************************************************************
108  * Close: destroy interface
109  *****************************************************************************/
110 static void Close( vlc_object_t *p_this )
111 {
112     intf_thread_t *p_intf = (intf_thread_t *)p_this;
113     intf_sys_t *p_sys = p_intf->p_sys;
114
115     /* stop hotkey window */
116     vlc_mutex_lock( &p_sys->lock );
117     if( p_sys->hotkeyWindow != NULL )
118         PostMessage( p_sys->hotkeyWindow, WM_CLOSE, 0, 0 );
119     vlc_mutex_unlock( &p_sys->lock );
120
121     vlc_join( p_sys->thread, NULL );
122     vlc_mutex_destroy( &p_sys->lock );
123     vlc_cond_destroy( &p_sys->wait );
124     free( p_sys );
125 }
126
127 /*****************************************************************************
128  * Thread: main loop
129  *****************************************************************************/
130 static void *Thread( void *p_data )
131 {
132     MSG message;
133     UINT i_key, i_keyMod, i_vk;
134     ATOM atom;
135     char *psz_hotkey = NULL;
136
137     intf_thread_t *p_intf = p_data;
138     intf_sys_t *p_sys = p_intf->p_sys;
139
140     /* Window which receives Hotkeys */
141     vlc_mutex_lock( &p_sys->lock );
142     p_sys->hotkeyWindow =
143         (void*)CreateWindow( _T("STATIC"),           /* name of window class */
144                 _T("VLC ghk ") _T(VERSION),         /* window title bar text */
145                 0,                                           /* window style */
146                 0,                                   /* default X coordinate */
147                 0,                                   /* default Y coordinate */
148                 0,                                           /* window width */
149                 0,                                          /* window height */
150                 NULL,                                    /* no parent window */
151                 NULL,                              /* no menu in this window */
152                 GetModuleHandle(NULL),    /* handle of this program instance */
153                 NULL );                                 /* sent to WM_CREATE */
154
155     if( p_sys->hotkeyWindow == NULL )
156     {
157         p_sys->hotkeyWindow = INVALID_HANDLE_VALUE;
158         vlc_cond_signal( &p_sys->wait );
159         vlc_mutex_unlock( &p_sys->lock );
160         return NULL;
161     }
162     vlc_cond_signal( &p_sys->wait );
163     vlc_mutex_unlock( &p_sys->lock );
164
165     SetWindowLongPtr( p_sys->hotkeyWindow, GWLP_WNDPROC,
166             (LONG_PTR)WMHOTKEYPROC );
167     SetWindowLongPtr( p_sys->hotkeyWindow, GWLP_USERDATA,
168             (LONG_PTR)p_intf );
169
170     /* Registering of Hotkeys */
171     for( const struct hotkey *p_hotkey = p_intf->p_libvlc->p_hotkeys;
172             p_hotkey->psz_action != NULL;
173             p_hotkey++ )
174     {
175         if( asprintf( &psz_hotkey, "global-%s", p_hotkey->psz_action ) < 0 )
176             break;
177
178         i_key = var_InheritInteger( p_intf, psz_hotkey );
179
180         free( psz_hotkey );
181
182         i_keyMod = 0;
183         if( i_key & KEY_MODIFIER_SHIFT ) i_keyMod |= MOD_SHIFT;
184         if( i_key & KEY_MODIFIER_ALT ) i_keyMod |= MOD_ALT;
185         if( i_key & KEY_MODIFIER_CTRL ) i_keyMod |= MOD_CONTROL;
186
187 #define HANDLE( key ) case KEY_##key: i_vk = VK_##key; break
188 #define HANDLE2( key, key2 ) case KEY_##key: i_vk = VK_##key2; break
189
190 #define KEY_SPACE ' '
191
192 #ifndef VK_VOLUME_DOWN
193 #define VK_VOLUME_DOWN          0xAE
194 #define VK_VOLUME_UP            0xAF
195 #endif
196
197 #ifndef VK_MEDIA_NEXT_TRACK
198 #define VK_MEDIA_NEXT_TRACK     0xB0
199 #define VK_MEDIA_PREV_TRACK     0xB1
200 #define VK_MEDIA_STOP           0xB2
201 #define VK_MEDIA_PLAY_PAUSE     0xB3
202 #endif
203
204 #ifndef VK_PAGEUP
205 #define VK_PAGEUP               0x21
206 #define VK_PAGEDOWN             0x22
207 #endif
208
209         i_vk = 0;
210         switch( i_key & ~KEY_MODIFIER )
211         {
212             HANDLE( LEFT );
213             HANDLE( RIGHT );
214             HANDLE( UP );
215             HANDLE( DOWN );
216             HANDLE( SPACE );
217             HANDLE2( ESC, ESCAPE );
218             HANDLE2( ENTER, RETURN );
219             HANDLE( F1 );
220             HANDLE( F2 );
221             HANDLE( F3 );
222             HANDLE( F4 );
223             HANDLE( F5 );
224             HANDLE( F6 );
225             HANDLE( F7 );
226             HANDLE( F8 );
227             HANDLE( F9 );
228             HANDLE( F10 );
229             HANDLE( F11 );
230             HANDLE( F12 );
231             HANDLE( PAGEUP );
232             HANDLE( PAGEDOWN );
233             HANDLE( HOME );
234             HANDLE( END );
235             HANDLE( INSERT );
236             HANDLE( DELETE );
237             HANDLE( VOLUME_DOWN );
238             HANDLE( VOLUME_UP );
239             HANDLE( MEDIA_PLAY_PAUSE );
240             HANDLE( MEDIA_STOP );
241             HANDLE( MEDIA_PREV_TRACK );
242             HANDLE( MEDIA_NEXT_TRACK );
243
244             default:
245                 i_vk = toupper( i_key & ~KEY_MODIFIER );
246                 break;
247         }
248         if( !i_vk ) continue;
249
250 #undef HANDLE
251 #undef HANDLE2
252
253         atom = GlobalAddAtomA( p_hotkey->psz_action );
254         if( !atom ) continue;
255
256         if( !RegisterHotKey( p_sys->hotkeyWindow, atom, i_keyMod, i_vk ) )
257             GlobalDeleteAtom( atom );
258     }
259
260     /* Main message loop */
261     while( GetMessage( &message, NULL, 0, 0 ) )
262         DispatchMessage( &message );
263
264     /* Unregistering of Hotkeys */
265     for( const struct hotkey *p_hotkey = p_intf->p_libvlc->p_hotkeys;
266             p_hotkey->psz_action != NULL;
267             p_hotkey++ )
268     {
269         atom = GlobalFindAtomA( p_hotkey->psz_action );
270         if( !atom ) continue;
271
272         if( UnregisterHotKey( p_sys->hotkeyWindow, atom ) )
273             GlobalDeleteAtom( atom );
274     }
275
276     /* close window */
277     vlc_mutex_lock( &p_sys->lock );
278     DestroyWindow( p_sys->hotkeyWindow );
279     p_sys->hotkeyWindow = NULL;
280     vlc_mutex_unlock( &p_sys->lock );
281
282     return NULL;
283 }
284
285 /*****************************************************************************
286  * WMHOTKEYPROC: event callback
287  *****************************************************************************/
288 LRESULT CALLBACK WMHOTKEYPROC( HWND hwnd, UINT uMsg, WPARAM wParam,
289         LPARAM lParam )
290 {
291     switch( uMsg )
292     {
293         case WM_HOTKEY:
294             {
295                 char psz_atomName[40];
296
297                 LONG_PTR ret = GetWindowLongPtr( hwnd, GWLP_USERDATA );
298                 intf_thread_t *p_intf = (intf_thread_t*)ret;
299                 const struct hotkey *p_hotkeys = p_intf->p_libvlc->p_hotkeys;
300
301                 if( !GlobalGetAtomNameA(
302                         wParam, psz_atomName, sizeof( psz_atomName ) ) )
303                     return 0;
304
305                 /* search for key associated with VLC */
306                 for( int i = 0; p_hotkeys[i].psz_action != NULL; i++ )
307                 {
308                     if( strcmp( p_hotkeys[i].psz_action, psz_atomName ) )
309                         continue;
310
311                     var_SetInteger( p_intf->p_libvlc,
312                             "key-action", p_hotkeys[i].i_action );
313
314                     return 1;
315                 }
316             }
317             break;
318
319         case WM_DESTROY:
320             PostQuitMessage( 0 );
321             break;
322
323         default:
324             return DefWindowProc( hwnd, uMsg, wParam, lParam );
325     }
326
327     return 0;
328 }