1 /*****************************************************************************
2 * win32.c: Global-Hotkey _WIN32 handling for vlc
3 *****************************************************************************
4 * Copyright (C) 2008-2009 the VideoLAN team
6 * Authors: Domani Hannes <ssbssa at yahoo dot de>
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.
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.
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 *****************************************************************************/
29 #include <vlc_common.h>
30 #include <vlc_plugin.h>
31 #include <vlc_interface.h>
34 /*****************************************************************************
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 );
42 /*****************************************************************************
44 *****************************************************************************/
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 add_shortcut( "globalhotkeys" )
63 /*****************************************************************************
64 * Open: initialize interface
65 *****************************************************************************/
66 static int Open( vlc_object_t *p_this )
68 intf_thread_t *p_intf = (intf_thread_t *)p_this;
69 intf_sys_t *p_sys = malloc( sizeof (intf_sys_t) );
74 p_intf->p_sys = p_sys;
75 p_sys->hotkeyWindow = NULL;
76 vlc_mutex_init( &p_sys->lock );
77 vlc_cond_init( &p_sys->wait );
79 if( vlc_clone( &p_sys->thread, Thread, p_intf, VLC_THREAD_PRIORITY_LOW ) )
81 vlc_mutex_destroy( &p_sys->lock );
82 vlc_cond_destroy( &p_sys->wait );
89 vlc_mutex_lock( &p_sys->lock );
90 while( p_sys->hotkeyWindow == NULL )
91 vlc_cond_wait( &p_sys->wait, &p_sys->lock );
92 if( p_sys->hotkeyWindow == INVALID_HANDLE_VALUE )
94 vlc_mutex_unlock( &p_sys->lock );
95 vlc_join( p_sys->thread, NULL );
96 vlc_mutex_destroy( &p_sys->lock );
97 vlc_cond_destroy( &p_sys->wait );
103 vlc_mutex_unlock( &p_sys->lock );
108 /*****************************************************************************
109 * Close: destroy interface
110 *****************************************************************************/
111 static void Close( vlc_object_t *p_this )
113 intf_thread_t *p_intf = (intf_thread_t *)p_this;
114 intf_sys_t *p_sys = p_intf->p_sys;
116 /* stop hotkey window */
117 vlc_mutex_lock( &p_sys->lock );
118 if( p_sys->hotkeyWindow != NULL )
119 PostMessage( p_sys->hotkeyWindow, WM_CLOSE, 0, 0 );
120 vlc_mutex_unlock( &p_sys->lock );
122 vlc_join( p_sys->thread, NULL );
123 vlc_mutex_destroy( &p_sys->lock );
124 vlc_cond_destroy( &p_sys->wait );
128 /*****************************************************************************
130 *****************************************************************************/
131 static void *Thread( void *p_data )
135 intf_thread_t *p_intf = p_data;
136 intf_sys_t *p_sys = p_intf->p_sys;
138 /* Window which receives Hotkeys */
139 vlc_mutex_lock( &p_sys->lock );
140 p_sys->hotkeyWindow =
141 (void*)CreateWindow( _T("STATIC"), /* name of window class */
142 _T("VLC ghk ") _T(VERSION), /* window title bar text */
143 0, /* window style */
144 0, /* default X coordinate */
145 0, /* default Y coordinate */
146 0, /* window width */
147 0, /* window height */
148 NULL, /* no parent window */
149 NULL, /* no menu in this window */
150 GetModuleHandle(NULL), /* handle of this program instance */
151 NULL ); /* sent to WM_CREATE */
153 if( p_sys->hotkeyWindow == NULL )
155 p_sys->hotkeyWindow = INVALID_HANDLE_VALUE;
156 vlc_cond_signal( &p_sys->wait );
157 vlc_mutex_unlock( &p_sys->lock );
160 vlc_cond_signal( &p_sys->wait );
161 vlc_mutex_unlock( &p_sys->lock );
163 SetWindowLongPtr( p_sys->hotkeyWindow, GWLP_WNDPROC,
164 (LONG_PTR)WMHOTKEYPROC );
165 SetWindowLongPtr( p_sys->hotkeyWindow, GWLP_USERDATA,
168 /* Registering of Hotkeys */
169 for( const struct hotkey *p_hotkey = p_intf->p_libvlc->p_hotkeys;
170 p_hotkey->psz_action != NULL;
173 char varname[12 + strlen( p_hotkey->psz_action )];
174 sprintf( varname, "global-key-%s", p_hotkey->psz_action );
176 char *key = var_InheritString( p_intf, varname );
180 UINT i_key = vlc_str2keycode( key );
182 if( i_key == KEY_UNSET )
186 if( i_key & KEY_MODIFIER_SHIFT ) i_keyMod |= MOD_SHIFT;
187 if( i_key & KEY_MODIFIER_ALT ) i_keyMod |= MOD_ALT;
188 if( i_key & KEY_MODIFIER_CTRL ) i_keyMod |= MOD_CONTROL;
190 #define HANDLE( key ) case KEY_##key: i_vk = VK_##key; break
191 #define HANDLE2( key, key2 ) case KEY_##key: i_vk = VK_##key2; break
193 #define KEY_SPACE ' '
195 #ifndef VK_VOLUME_DOWN
196 #define VK_VOLUME_DOWN 0xAE
197 #define VK_VOLUME_UP 0xAF
200 #ifndef VK_MEDIA_NEXT_TRACK
201 #define VK_MEDIA_NEXT_TRACK 0xB0
202 #define VK_MEDIA_PREV_TRACK 0xB1
203 #define VK_MEDIA_STOP 0xB2
204 #define VK_MEDIA_PLAY_PAUSE 0xB3
208 #define VK_PAGEUP 0x21
209 #define VK_PAGEDOWN 0x22
213 switch( i_key & ~KEY_MODIFIER )
220 HANDLE2( ESC, ESCAPE );
221 HANDLE2( ENTER, RETURN );
240 HANDLE( VOLUME_DOWN );
242 HANDLE( MEDIA_PLAY_PAUSE );
243 HANDLE( MEDIA_STOP );
244 HANDLE( MEDIA_PREV_TRACK );
245 HANDLE( MEDIA_NEXT_TRACK );
248 i_vk = toupper( (uint8_t)(i_key & ~KEY_MODIFIER) );
251 if( !i_vk ) continue;
256 ATOM atom = GlobalAddAtomA( p_hotkey->psz_action );
257 if( !atom ) continue;
259 if( !RegisterHotKey( p_sys->hotkeyWindow, atom, i_keyMod, i_vk ) )
260 GlobalDeleteAtom( atom );
263 /* Main message loop */
264 while( GetMessage( &message, NULL, 0, 0 ) )
265 DispatchMessage( &message );
267 /* Unregistering of Hotkeys */
268 for( const struct hotkey *p_hotkey = p_intf->p_libvlc->p_hotkeys;
269 p_hotkey->psz_action != NULL;
272 ATOM atom = GlobalFindAtomA( p_hotkey->psz_action );
273 if( !atom ) continue;
275 if( UnregisterHotKey( p_sys->hotkeyWindow, atom ) )
276 GlobalDeleteAtom( atom );
280 vlc_mutex_lock( &p_sys->lock );
281 DestroyWindow( p_sys->hotkeyWindow );
282 p_sys->hotkeyWindow = NULL;
283 vlc_mutex_unlock( &p_sys->lock );
288 /*****************************************************************************
289 * WMHOTKEYPROC: event callback
290 *****************************************************************************/
291 LRESULT CALLBACK WMHOTKEYPROC( HWND hwnd, UINT uMsg, WPARAM wParam,
298 char psz_atomName[44];
300 LONG_PTR ret = GetWindowLongPtr( hwnd, GWLP_USERDATA );
301 intf_thread_t *p_intf = (intf_thread_t*)ret;
302 strcpy( psz_atomName, "key-" );
304 if( !GlobalGetAtomNameA(
305 wParam, psz_atomName + 4,
306 sizeof( psz_atomName ) - 4 ) )
309 /* search for key associated with VLC */
310 vlc_action_t action = vlc_GetActionId( psz_atomName );
311 if( action != ACTIONID_NONE )
313 var_SetInteger( p_intf->p_libvlc,
314 "key-action", action );
321 PostQuitMessage( 0 );
325 return DefWindowProc( hwnd, uMsg, wParam, lParam );