]> git.sesse.net Git - vlc/blob - modules/control/globalhotkeys/win32.c
Use _WIN32 rather than WIN32 (same for WIN64)
[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
134     intf_thread_t *p_intf = p_data;
135     intf_sys_t *p_sys = p_intf->p_sys;
136
137     /* Window which receives Hotkeys */
138     vlc_mutex_lock( &p_sys->lock );
139     p_sys->hotkeyWindow =
140         (void*)CreateWindow( _T("STATIC"),           /* name of window class */
141                 _T("VLC ghk ") _T(VERSION),         /* window title bar text */
142                 0,                                           /* window style */
143                 0,                                   /* default X coordinate */
144                 0,                                   /* default Y coordinate */
145                 0,                                           /* window width */
146                 0,                                          /* window height */
147                 NULL,                                    /* no parent window */
148                 NULL,                              /* no menu in this window */
149                 GetModuleHandle(NULL),    /* handle of this program instance */
150                 NULL );                                 /* sent to WM_CREATE */
151
152     if( p_sys->hotkeyWindow == NULL )
153     {
154         p_sys->hotkeyWindow = INVALID_HANDLE_VALUE;
155         vlc_cond_signal( &p_sys->wait );
156         vlc_mutex_unlock( &p_sys->lock );
157         return NULL;
158     }
159     vlc_cond_signal( &p_sys->wait );
160     vlc_mutex_unlock( &p_sys->lock );
161
162     SetWindowLongPtr( p_sys->hotkeyWindow, GWLP_WNDPROC,
163             (LONG_PTR)WMHOTKEYPROC );
164     SetWindowLongPtr( p_sys->hotkeyWindow, GWLP_USERDATA,
165             (LONG_PTR)p_intf );
166
167     /* Registering of Hotkeys */
168     for( const struct hotkey *p_hotkey = p_intf->p_libvlc->p_hotkeys;
169             p_hotkey->psz_action != NULL;
170             p_hotkey++ )
171     {
172         char varname[12 + strlen( p_hotkey->psz_action )];
173         sprintf( varname, "global-key-%s", p_hotkey->psz_action );
174
175         char *key = var_InheritString( p_intf, varname );
176         if( key == NULL )
177             continue;
178
179         UINT i_key = vlc_str2keycode( key );
180         free( key );
181         if( i_key == KEY_UNSET )
182             continue;
183
184         UINT i_keyMod = 0;
185         if( i_key & KEY_MODIFIER_SHIFT ) i_keyMod |= MOD_SHIFT;
186         if( i_key & KEY_MODIFIER_ALT ) i_keyMod |= MOD_ALT;
187         if( i_key & KEY_MODIFIER_CTRL ) i_keyMod |= MOD_CONTROL;
188
189 #define HANDLE( key ) case KEY_##key: i_vk = VK_##key; break
190 #define HANDLE2( key, key2 ) case KEY_##key: i_vk = VK_##key2; break
191
192 #define KEY_SPACE ' '
193
194 #ifndef VK_VOLUME_DOWN
195 #define VK_VOLUME_DOWN          0xAE
196 #define VK_VOLUME_UP            0xAF
197 #endif
198
199 #ifndef VK_MEDIA_NEXT_TRACK
200 #define VK_MEDIA_NEXT_TRACK     0xB0
201 #define VK_MEDIA_PREV_TRACK     0xB1
202 #define VK_MEDIA_STOP           0xB2
203 #define VK_MEDIA_PLAY_PAUSE     0xB3
204 #endif
205
206 #ifndef VK_PAGEUP
207 #define VK_PAGEUP               0x21
208 #define VK_PAGEDOWN             0x22
209 #endif
210
211         UINT i_vk = 0;
212         switch( i_key & ~KEY_MODIFIER )
213         {
214             HANDLE( LEFT );
215             HANDLE( RIGHT );
216             HANDLE( UP );
217             HANDLE( DOWN );
218             HANDLE( SPACE );
219             HANDLE2( ESC, ESCAPE );
220             HANDLE2( ENTER, RETURN );
221             HANDLE( F1 );
222             HANDLE( F2 );
223             HANDLE( F3 );
224             HANDLE( F4 );
225             HANDLE( F5 );
226             HANDLE( F6 );
227             HANDLE( F7 );
228             HANDLE( F8 );
229             HANDLE( F9 );
230             HANDLE( F10 );
231             HANDLE( F11 );
232             HANDLE( F12 );
233             HANDLE( PAGEUP );
234             HANDLE( PAGEDOWN );
235             HANDLE( HOME );
236             HANDLE( END );
237             HANDLE( INSERT );
238             HANDLE( DELETE );
239             HANDLE( VOLUME_DOWN );
240             HANDLE( VOLUME_UP );
241             HANDLE( MEDIA_PLAY_PAUSE );
242             HANDLE( MEDIA_STOP );
243             HANDLE( MEDIA_PREV_TRACK );
244             HANDLE( MEDIA_NEXT_TRACK );
245
246             default:
247                 i_vk = toupper( (uint8_t)(i_key & ~KEY_MODIFIER) );
248                 break;
249         }
250         if( !i_vk ) continue;
251
252 #undef HANDLE
253 #undef HANDLE2
254
255         ATOM atom = GlobalAddAtomA( p_hotkey->psz_action );
256         if( !atom ) continue;
257
258         if( !RegisterHotKey( p_sys->hotkeyWindow, atom, i_keyMod, i_vk ) )
259             GlobalDeleteAtom( atom );
260     }
261
262     /* Main message loop */
263     while( GetMessage( &message, NULL, 0, 0 ) )
264         DispatchMessage( &message );
265
266     /* Unregistering of Hotkeys */
267     for( const struct hotkey *p_hotkey = p_intf->p_libvlc->p_hotkeys;
268             p_hotkey->psz_action != NULL;
269             p_hotkey++ )
270     {
271         ATOM atom = GlobalFindAtomA( p_hotkey->psz_action );
272         if( !atom ) continue;
273
274         if( UnregisterHotKey( p_sys->hotkeyWindow, atom ) )
275             GlobalDeleteAtom( atom );
276     }
277
278     /* close window */
279     vlc_mutex_lock( &p_sys->lock );
280     DestroyWindow( p_sys->hotkeyWindow );
281     p_sys->hotkeyWindow = NULL;
282     vlc_mutex_unlock( &p_sys->lock );
283
284     return NULL;
285 }
286
287 /*****************************************************************************
288  * WMHOTKEYPROC: event callback
289  *****************************************************************************/
290 LRESULT CALLBACK WMHOTKEYPROC( HWND hwnd, UINT uMsg, WPARAM wParam,
291         LPARAM lParam )
292 {
293     switch( uMsg )
294     {
295         case WM_HOTKEY:
296             {
297                 char psz_atomName[44];
298
299                 LONG_PTR ret = GetWindowLongPtr( hwnd, GWLP_USERDATA );
300                 intf_thread_t *p_intf = (intf_thread_t*)ret;
301                 strcpy( psz_atomName, "key-" );
302
303                 if( !GlobalGetAtomNameA(
304                         wParam, psz_atomName + 4,
305                         sizeof( psz_atomName ) - 4 ) )
306                     return 0;
307
308                 /* search for key associated with VLC */
309                 vlc_action_t action = vlc_GetActionId( psz_atomName );
310                 if( action != ACTIONID_NONE )
311                 {
312                     var_SetInteger( p_intf->p_libvlc,
313                             "key-action", action );
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 }