macosx: Fix display of copyright message
[vlc.git] / 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 #define VLC_MODULE_LICENSE VLC_LICENSE_GPL_2_PLUS
30 #include <vlc_common.h>
31 #include <vlc_plugin.h>
32 #include <vlc_interface.h>
33 #include <vlc_actions.h>
34
35 /*****************************************************************************
36  * Local prototypes
37  *****************************************************************************/
38 static int Open( vlc_object_t *p_this );
39 static void Close( vlc_object_t *p_this );
40 static void *Thread( void *p_data );
41 LRESULT CALLBACK WMHOTKEYPROC( HWND, UINT, WPARAM, LPARAM );
42
43 /*****************************************************************************
44  * Module descriptor
45  *****************************************************************************/
46 vlc_module_begin()
47     set_shortname( N_("Global Hotkeys") )
48     set_category( CAT_INTERFACE )
49     set_subcategory( SUBCAT_INTERFACE_HOTKEYS )
50     set_description( N_("Global Hotkeys interface") )
51     set_capability( "interface", 0 )
52     set_callbacks( Open, Close )
53     add_shortcut( "globalhotkeys" )
54 vlc_module_end()
55
56 struct intf_sys_t
57 {
58     vlc_thread_t thread;
59     HWND hotkeyWindow;
60     vlc_mutex_t lock;
61     vlc_cond_t wait;
62 };
63
64 /*****************************************************************************
65  * Open: initialize interface
66  *****************************************************************************/
67 static int Open( vlc_object_t *p_this )
68 {
69     intf_thread_t *p_intf = (intf_thread_t *)p_this;
70     intf_sys_t *p_sys = malloc( sizeof (intf_sys_t) );
71
72     if( p_sys == NULL )
73         return VLC_ENOMEM;
74
75     p_intf->p_sys = p_sys;
76     p_sys->hotkeyWindow = NULL;
77     vlc_mutex_init( &p_sys->lock );
78     vlc_cond_init( &p_sys->wait );
79
80     if( vlc_clone( &p_sys->thread, Thread, p_intf, VLC_THREAD_PRIORITY_LOW ) )
81     {
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         free( p_sys );
96         p_intf->p_sys = NULL;
97
98         return VLC_ENOMEM;
99     }
100     vlc_mutex_unlock( &p_sys->lock );
101
102     return VLC_SUCCESS;
103 }
104
105 /*****************************************************************************
106  * Close: destroy interface
107  *****************************************************************************/
108 static void Close( vlc_object_t *p_this )
109 {
110     intf_thread_t *p_intf = (intf_thread_t *)p_this;
111     intf_sys_t *p_sys = p_intf->p_sys;
112
113     /* stop hotkey window */
114     vlc_mutex_lock( &p_sys->lock );
115     if( p_sys->hotkeyWindow != NULL )
116         PostMessage( p_sys->hotkeyWindow, WM_CLOSE, 0, 0 );
117     vlc_mutex_unlock( &p_sys->lock );
118
119     vlc_join( p_sys->thread, NULL );
120     free( p_sys );
121 }
122
123 /*****************************************************************************
124  * Thread: main loop
125  *****************************************************************************/
126 static void *Thread( void *p_data )
127 {
128     MSG message;
129
130     intf_thread_t *p_intf = p_data;
131     intf_sys_t *p_sys = p_intf->p_sys;
132
133     /* Window which receives Hotkeys */
134     vlc_mutex_lock( &p_sys->lock );
135     p_sys->hotkeyWindow =
136         (void*)CreateWindow( TEXT("STATIC"),         /* name of window class */
137                 TEXT("VLC ghk ") TEXT(VERSION),     /* window title bar text */
138                 0,                                           /* window style */
139                 0,                                   /* default X coordinate */
140                 0,                                   /* default Y coordinate */
141                 0,                                           /* window width */
142                 0,                                          /* window height */
143                 NULL,                                    /* no parent window */
144                 NULL,                              /* no menu in this window */
145                 GetModuleHandle(NULL),    /* handle of this program instance */
146                 NULL );                                 /* sent to WM_CREATE */
147
148     if( p_sys->hotkeyWindow == NULL )
149     {
150         p_sys->hotkeyWindow = INVALID_HANDLE_VALUE;
151         vlc_cond_signal( &p_sys->wait );
152         vlc_mutex_unlock( &p_sys->lock );
153         return NULL;
154     }
155     vlc_cond_signal( &p_sys->wait );
156     vlc_mutex_unlock( &p_sys->lock );
157
158     SetWindowLongPtr( p_sys->hotkeyWindow, GWLP_WNDPROC,
159             (LONG_PTR)WMHOTKEYPROC );
160     SetWindowLongPtr( p_sys->hotkeyWindow, GWLP_USERDATA,
161             (LONG_PTR)p_intf );
162
163     /* Registering of Hotkeys */
164     for( const char* const* ppsz_keys = vlc_actions_get_key_names( p_intf );
165          *ppsz_keys != NULL; ppsz_keys++ )
166     {
167         uint_fast32_t *p_keys;
168         size_t i_nb_keys = vlc_actions_get_keycodes( p_intf, *ppsz_keys, true,
169                                                      &p_keys );
170         for( size_t i = 0; i < i_nb_keys; ++i )
171         {
172             uint_fast32_t i_key = p_keys[i];
173             UINT i_keyMod = 0;
174             if( i_key & KEY_MODIFIER_SHIFT ) i_keyMod |= MOD_SHIFT;
175             if( i_key & KEY_MODIFIER_ALT ) i_keyMod |= MOD_ALT;
176             if( i_key & KEY_MODIFIER_CTRL ) i_keyMod |= MOD_CONTROL;
177
178 #define HANDLE( key ) case KEY_##key: i_vk = VK_##key; break
179 #define HANDLE2( key, key2 ) case KEY_##key: i_vk = VK_##key2; break
180
181 #define KEY_SPACE ' '
182
183 #ifndef VK_VOLUME_DOWN
184 #define VK_VOLUME_DOWN          0xAE
185 #define VK_VOLUME_UP            0xAF
186 #endif
187
188 #ifndef VK_MEDIA_NEXT_TRACK
189 #define VK_MEDIA_NEXT_TRACK     0xB0
190 #define VK_MEDIA_PREV_TRACK     0xB1
191 #define VK_MEDIA_STOP           0xB2
192 #define VK_MEDIA_PLAY_PAUSE     0xB3
193 #endif
194
195 #ifndef VK_PAGEUP
196 #define VK_PAGEUP               0x21
197 #define VK_PAGEDOWN             0x22
198 #endif
199
200             UINT i_vk = 0;
201             switch( i_key & ~KEY_MODIFIER )
202             {
203                 HANDLE( LEFT );
204                 HANDLE( RIGHT );
205                 HANDLE( UP );
206                 HANDLE( DOWN );
207                 HANDLE( SPACE );
208                 HANDLE2( ESC, ESCAPE );
209                 HANDLE2( ENTER, RETURN );
210                 HANDLE( F1 );
211                 HANDLE( F2 );
212                 HANDLE( F3 );
213                 HANDLE( F4 );
214                 HANDLE( F5 );
215                 HANDLE( F6 );
216                 HANDLE( F7 );
217                 HANDLE( F8 );
218                 HANDLE( F9 );
219                 HANDLE( F10 );
220                 HANDLE( F11 );
221                 HANDLE( F12 );
222                 HANDLE( PAGEUP );
223                 HANDLE( PAGEDOWN );
224                 HANDLE( HOME );
225                 HANDLE( END );
226                 HANDLE( INSERT );
227                 HANDLE( DELETE );
228                 HANDLE( VOLUME_DOWN );
229                 HANDLE( VOLUME_UP );
230                 HANDLE( MEDIA_PLAY_PAUSE );
231                 HANDLE( MEDIA_STOP );
232                 HANDLE( MEDIA_PREV_TRACK );
233                 HANDLE( MEDIA_NEXT_TRACK );
234
235                 default:
236                     i_vk = toupper( (uint8_t)(i_key & ~KEY_MODIFIER) );
237                     break;
238             }
239             if( !i_vk ) continue;
240
241 #undef HANDLE
242 #undef HANDLE2
243
244             ATOM atom = GlobalAddAtomA( *ppsz_keys );
245             if( !atom ) continue;
246
247             if( !RegisterHotKey( p_sys->hotkeyWindow, atom, i_keyMod, i_vk ) )
248                 GlobalDeleteAtom( atom );
249         }
250         free( p_keys );
251     }
252
253     /* Main message loop */
254     while( GetMessage( &message, NULL, 0, 0 ) )
255         DispatchMessage( &message );
256
257     /* Unregistering of Hotkeys */
258     for( const char* const* ppsz_keys = vlc_actions_get_key_names( p_intf );
259          *ppsz_keys != NULL; ppsz_keys++ )
260     {
261         ATOM atom = GlobalFindAtomA( *ppsz_keys );
262         if( !atom ) continue;
263
264         if( UnregisterHotKey( p_sys->hotkeyWindow, atom ) )
265             GlobalDeleteAtom( atom );
266     }
267
268     /* close window */
269     vlc_mutex_lock( &p_sys->lock );
270     DestroyWindow( p_sys->hotkeyWindow );
271     p_sys->hotkeyWindow = NULL;
272     vlc_mutex_unlock( &p_sys->lock );
273
274     return NULL;
275 }
276
277 /*****************************************************************************
278  * WMHOTKEYPROC: event callback
279  *****************************************************************************/
280 LRESULT CALLBACK WMHOTKEYPROC( HWND hwnd, UINT uMsg, WPARAM wParam,
281         LPARAM lParam )
282 {
283     switch( uMsg )
284     {
285         case WM_HOTKEY:
286             {
287                 char psz_atomName[44];
288
289                 LONG_PTR ret = GetWindowLongPtr( hwnd, GWLP_USERDATA );
290                 intf_thread_t *p_intf = (intf_thread_t*)ret;
291                 strcpy( psz_atomName, "key-" );
292
293                 if( !GlobalGetAtomNameA(
294                         wParam, psz_atomName + 4,
295                         sizeof( psz_atomName ) - 4 ) )
296                     return 0;
297
298                 /* search for key associated with VLC */
299                 vlc_action_id_t action = vlc_actions_get_id( psz_atomName );
300                 if( action != ACTIONID_NONE )
301                 {
302                     var_SetInteger( vlc_object_instance(p_intf),
303                             "key-action", action );
304                     return 1;
305                 }
306             }
307             break;
308
309         case WM_DESTROY:
310             PostQuitMessage( 0 );
311             break;
312
313         default:
314             return DefWindowProc( hwnd, uMsg, wParam, lParam );
315     }
316
317     return 0;
318 }