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 #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>
35 /*****************************************************************************
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
);
43 /*****************************************************************************
45 *****************************************************************************/
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" )
64 /*****************************************************************************
65 * Open: initialize interface
66 *****************************************************************************/
67 static int Open( vlc_object_t
*p_this
)
69 intf_thread_t
*p_intf
= (intf_thread_t
*)p_this
;
70 intf_sys_t
*p_sys
= malloc( sizeof (intf_sys_t
) );
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
);
80 if( vlc_clone( &p_sys
->thread
, Thread
, p_intf
, VLC_THREAD_PRIORITY_LOW
) )
82 vlc_mutex_destroy( &p_sys
->lock
);
83 vlc_cond_destroy( &p_sys
->wait
);
90 vlc_mutex_lock( &p_sys
->lock
);
91 while( p_sys
->hotkeyWindow
== NULL
)
92 vlc_cond_wait( &p_sys
->wait
, &p_sys
->lock
);
93 if( p_sys
->hotkeyWindow
== INVALID_HANDLE_VALUE
)
95 vlc_mutex_unlock( &p_sys
->lock
);
96 vlc_join( p_sys
->thread
, NULL
);
97 vlc_mutex_destroy( &p_sys
->lock
);
98 vlc_cond_destroy( &p_sys
->wait
);
100 p_intf
->p_sys
= NULL
;
104 vlc_mutex_unlock( &p_sys
->lock
);
109 /*****************************************************************************
110 * Close: destroy interface
111 *****************************************************************************/
112 static void Close( vlc_object_t
*p_this
)
114 intf_thread_t
*p_intf
= (intf_thread_t
*)p_this
;
115 intf_sys_t
*p_sys
= p_intf
->p_sys
;
117 /* stop hotkey window */
118 vlc_mutex_lock( &p_sys
->lock
);
119 if( p_sys
->hotkeyWindow
!= NULL
)
120 PostMessage( p_sys
->hotkeyWindow
, WM_CLOSE
, 0, 0 );
121 vlc_mutex_unlock( &p_sys
->lock
);
123 vlc_join( p_sys
->thread
, NULL
);
124 vlc_mutex_destroy( &p_sys
->lock
);
125 vlc_cond_destroy( &p_sys
->wait
);
129 /*****************************************************************************
131 *****************************************************************************/
132 static void *Thread( void *p_data
)
136 intf_thread_t
*p_intf
= p_data
;
137 intf_sys_t
*p_sys
= p_intf
->p_sys
;
139 /* Window which receives Hotkeys */
140 vlc_mutex_lock( &p_sys
->lock
);
141 p_sys
->hotkeyWindow
=
142 (void*)CreateWindow( _T("STATIC"), /* name of window class */
143 _T("VLC ghk ") _T(VERSION
), /* window title bar text */
144 0, /* window style */
145 0, /* default X coordinate */
146 0, /* default Y coordinate */
147 0, /* window width */
148 0, /* window height */
149 NULL
, /* no parent window */
150 NULL
, /* no menu in this window */
151 GetModuleHandle(NULL
), /* handle of this program instance */
152 NULL
); /* sent to WM_CREATE */
154 if( p_sys
->hotkeyWindow
== NULL
)
156 p_sys
->hotkeyWindow
= INVALID_HANDLE_VALUE
;
157 vlc_cond_signal( &p_sys
->wait
);
158 vlc_mutex_unlock( &p_sys
->lock
);
161 vlc_cond_signal( &p_sys
->wait
);
162 vlc_mutex_unlock( &p_sys
->lock
);
164 SetWindowLongPtr( p_sys
->hotkeyWindow
, GWLP_WNDPROC
,
165 (LONG_PTR
)WMHOTKEYPROC
);
166 SetWindowLongPtr( p_sys
->hotkeyWindow
, GWLP_USERDATA
,
169 /* Registering of Hotkeys */
170 for( const char* const* ppsz_keys
= vlc_actions_get_key_names( p_intf
);
171 *ppsz_keys
!= NULL
; ppsz_keys
++ )
173 uint_fast32_t *p_keys
;
174 size_t i_nb_keys
= vlc_actions_get_keycodes( p_intf
, *ppsz_keys
, true,
176 for( size_t i
= 0; i
< i_nb_keys
; ++i
)
178 uint_fast32_t i_key
= p_keys
[i
];
180 if( i_key
& KEY_MODIFIER_SHIFT
) i_keyMod
|= MOD_SHIFT
;
181 if( i_key
& KEY_MODIFIER_ALT
) i_keyMod
|= MOD_ALT
;
182 if( i_key
& KEY_MODIFIER_CTRL
) i_keyMod
|= MOD_CONTROL
;
184 #define HANDLE( key ) case KEY_##key: i_vk = VK_##key; break
185 #define HANDLE2( key, key2 ) case KEY_##key: i_vk = VK_##key2; break
187 #define KEY_SPACE ' '
189 #ifndef VK_VOLUME_DOWN
190 #define VK_VOLUME_DOWN 0xAE
191 #define VK_VOLUME_UP 0xAF
194 #ifndef VK_MEDIA_NEXT_TRACK
195 #define VK_MEDIA_NEXT_TRACK 0xB0
196 #define VK_MEDIA_PREV_TRACK 0xB1
197 #define VK_MEDIA_STOP 0xB2
198 #define VK_MEDIA_PLAY_PAUSE 0xB3
202 #define VK_PAGEUP 0x21
203 #define VK_PAGEDOWN 0x22
207 switch( i_key
& ~KEY_MODIFIER
)
214 HANDLE2( ESC
, ESCAPE
);
215 HANDLE2( ENTER
, RETURN
);
234 HANDLE( VOLUME_DOWN
);
236 HANDLE( MEDIA_PLAY_PAUSE
);
237 HANDLE( MEDIA_STOP
);
238 HANDLE( MEDIA_PREV_TRACK
);
239 HANDLE( MEDIA_NEXT_TRACK
);
242 i_vk
= toupper( (uint8_t)(i_key
& ~KEY_MODIFIER
) );
245 if( !i_vk
) continue;
250 ATOM atom
= GlobalAddAtomA( *ppsz_keys
);
251 if( !atom
) continue;
253 if( !RegisterHotKey( p_sys
->hotkeyWindow
, atom
, i_keyMod
, i_vk
) )
254 GlobalDeleteAtom( atom
);
259 /* Main message loop */
260 while( GetMessage( &message
, NULL
, 0, 0 ) )
261 DispatchMessage( &message
);
263 /* Unregistering of Hotkeys */
264 for( const char* const* ppsz_keys
= vlc_actions_get_key_names( p_intf
);
265 *ppsz_keys
!= NULL
; ppsz_keys
++ )
267 ATOM atom
= GlobalFindAtomA( *ppsz_keys
);
268 if( !atom
) continue;
270 if( UnregisterHotKey( p_sys
->hotkeyWindow
, atom
) )
271 GlobalDeleteAtom( atom
);
275 vlc_mutex_lock( &p_sys
->lock
);
276 DestroyWindow( p_sys
->hotkeyWindow
);
277 p_sys
->hotkeyWindow
= NULL
;
278 vlc_mutex_unlock( &p_sys
->lock
);
283 /*****************************************************************************
284 * WMHOTKEYPROC: event callback
285 *****************************************************************************/
286 LRESULT CALLBACK
WMHOTKEYPROC( HWND hwnd
, UINT uMsg
, WPARAM wParam
,
293 char psz_atomName
[44];
295 LONG_PTR ret
= GetWindowLongPtr( hwnd
, GWLP_USERDATA
);
296 intf_thread_t
*p_intf
= (intf_thread_t
*)ret
;
297 strcpy( psz_atomName
, "key-" );
299 if( !GlobalGetAtomNameA(
300 wParam
, psz_atomName
+ 4,
301 sizeof( psz_atomName
) - 4 ) )
304 /* search for key associated with VLC */
305 vlc_action_id_t action
= vlc_actions_get_id( psz_atomName
);
306 if( action
!= ACTIONID_NONE
)
308 var_SetInteger( p_intf
->obj
.libvlc
,
309 "key-action", action
);
316 PostQuitMessage( 0 );
320 return DefWindowProc( hwnd
, uMsg
, wParam
, lParam
);