From c85aed3c01df4cc2c41e4ee8e2bb04b645def218 Mon Sep 17 00:00:00 2001 From: Hannes Domani Date: Fri, 16 Jan 2009 15:39:58 +0100 Subject: [PATCH] Global Hotkeys for windows Signed-off-by: Laurent Aimar --- configure.ac | 1 + include/vlc_plugin.h | 8 + modules/control/Modules.am | 1 + modules/control/globalhotkeys.c | 327 ++++++++++++++++++++++++++++++++ src/libvlc.c | 3 + 5 files changed, 340 insertions(+) create mode 100644 modules/control/globalhotkeys.c diff --git a/configure.ac b/configure.ac index d5083759e8..f792a6266b 100644 --- a/configure.ac +++ b/configure.ac @@ -1191,6 +1191,7 @@ elif test "${SYS}" != "mingwce"; then VLC_ADD_PLUGIN([dmo]) VLC_ADD_PLUGIN([msn]) VLC_ADD_LIBS([dmo],[-lole32 -luuid]) + VLC_ADD_PLUGIN([globalhotkeys]) else VLC_ADD_PLUGIN([win32text]) fi diff --git a/include/vlc_plugin.h b/include/vlc_plugin.h index 41e3374a4f..0d2542f4b4 100644 --- a/include/vlc_plugin.h +++ b/include/vlc_plugin.h @@ -353,9 +353,17 @@ enum vlc_config_properties add_int_inner( CONFIG_ITEM_INTEGER, name, text, longtext, advc, \ p_callback, value ) +#ifndef WIN32 #define add_key( name, value, p_callback, text, longtext, advc ) \ add_int_inner( CONFIG_ITEM_KEY, name, text, longtext, advc, p_callback, \ value ) +#else +#define add_key( name, value, p_callback, text, longtext, advc ) \ + add_int_inner( CONFIG_ITEM_KEY, name, text, longtext, advc, \ + p_callback, value ) \ + add_int_inner( CONFIG_ITEM_KEY, "global-" name, text, longtext, advc, \ + p_callback, KEY_UNSET ) +#endif #define add_integer_with_range( name, value, i_min, i_max, p_callback, text, longtext, advc ) \ add_integer( name, value, p_callback, text, longtext, advc ) \ diff --git a/modules/control/Modules.am b/modules/control/Modules.am index 9813627e25..0ac597812a 100644 --- a/modules/control/Modules.am +++ b/modules/control/Modules.am @@ -5,6 +5,7 @@ SOURCES_telnet = telnet.c SOURCES_netsync = netsync.c SOURCES_ntservice = ntservice.c SOURCES_hotkeys = hotkeys.c +SOURCES_globalhotkeys = globalhotkeys.c SOURCES_lirc = lirc.c SOURCES_rc = rc.c SOURCES_dbus = dbus.c dbus.h diff --git a/modules/control/globalhotkeys.c b/modules/control/globalhotkeys.c new file mode 100644 index 0000000000..af88dd2f6e --- /dev/null +++ b/modules/control/globalhotkeys.c @@ -0,0 +1,327 @@ +/***************************************************************************** + * globalhotkeys.c: Global-Hotkey handling for vlc + ***************************************************************************** + * Copyright (C) 2008-2009 the VideoLAN team + * + * Authors: Domani Hannes + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + *****************************************************************************/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include +#include +#include +#include + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ +static int Open( vlc_object_t *p_this ); +static void Close( vlc_object_t *p_this ); +static void *Thread( void *p_data ); +LRESULT CALLBACK WMHOTKEYPROC( HWND, UINT, WPARAM, LPARAM ); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +vlc_module_begin(); + set_shortname( _("Global Hotkeys") ); + set_category( CAT_INTERFACE ); + set_subcategory( SUBCAT_INTERFACE_HOTKEYS ); + set_description( _("Global Hotkeys interface") ); + set_capability( "interface", 0 ); + set_callbacks( Open, Close ); +vlc_module_end(); + +struct intf_sys_t +{ + vlc_thread_t thread; + HWND hotkeyWindow; + vlc_mutex_t lock; + vlc_cond_t wait; +}; + +/***************************************************************************** + * Open: initialize interface + *****************************************************************************/ +static int Open( vlc_object_t *p_this ) +{ + intf_thread_t *p_intf = (intf_thread_t *)p_this; + intf_sys_t *p_sys = malloc( sizeof (intf_sys_t) ); + + if( p_sys == NULL ) + return VLC_ENOMEM; + + p_intf->p_sys = p_sys; + p_sys->hotkeyWindow = NULL; + vlc_mutex_init( &p_sys->lock ); + vlc_cond_init( &p_sys->wait ); + + if( vlc_clone( &p_sys->thread, Thread, p_intf, VLC_THREAD_PRIORITY_LOW ) ) + { + vlc_mutex_destroy( &p_sys->lock ); + vlc_cond_destroy( &p_sys->wait ); + free( p_sys ); + p_intf->p_sys = NULL; + + return VLC_ENOMEM; + } + + vlc_mutex_lock( &p_sys->lock ); + while( p_sys->hotkeyWindow == NULL ) + vlc_cond_wait( &p_sys->wait, &p_sys->lock ); + if( p_sys->hotkeyWindow == INVALID_HANDLE_VALUE ) + { + vlc_mutex_unlock( &p_sys->lock ); + vlc_join( p_sys->thread, NULL ); + vlc_mutex_destroy( &p_sys->lock ); + vlc_cond_destroy( &p_sys->wait ); + free( p_sys ); + p_intf->p_sys = NULL; + + return VLC_ENOMEM; + } + vlc_mutex_unlock( &p_sys->lock ); + + return VLC_SUCCESS; +} + +/***************************************************************************** + * Close: destroy interface + *****************************************************************************/ +static void Close( vlc_object_t *p_this ) +{ + intf_thread_t *p_intf = (intf_thread_t *)p_this; + intf_sys_t *p_sys = p_intf->p_sys; + + /* stop hotkey window */ + vlc_mutex_lock( &p_sys->lock ); + if( p_sys->hotkeyWindow != NULL ) + PostMessage( p_sys->hotkeyWindow, WM_CLOSE, 0, 0 ); + vlc_mutex_unlock( &p_sys->lock ); + + vlc_join( p_sys->thread, NULL ); + vlc_mutex_destroy( &p_sys->lock ); + vlc_cond_destroy( &p_sys->wait ); + free( p_sys ); +} + +/***************************************************************************** + * Thread: main loop + *****************************************************************************/ +static void *Thread( void *p_data ) +{ + MSG message; + UINT i_key, i_keyMod, i_vk; + ATOM atom; + char *psz_hotkey = NULL; + + intf_thread_t *p_intf = p_data; + intf_sys_t *p_sys = p_intf->p_sys; + + /* Window which receives Hotkeys */ + vlc_mutex_lock( &p_sys->lock ); + p_sys->hotkeyWindow = + (void*)CreateWindow( _T("STATIC"), /* name of window class */ + _T("VLC ghk ") _T(VERSION), /* window title bar text */ + 0, /* window style */ + 0, /* default X coordinate */ + 0, /* default Y coordinate */ + 0, /* window width */ + 0, /* window height */ + NULL, /* no parent window */ + NULL, /* no menu in this window */ + GetModuleHandle(NULL), /* handle of this program instance */ + NULL ); /* sent to WM_CREATE */ + + if( p_sys->hotkeyWindow == NULL ) + { + p_sys->hotkeyWindow = INVALID_HANDLE_VALUE; + vlc_cond_signal( &p_sys->wait ); + vlc_mutex_unlock( &p_sys->lock ); + return NULL; + } + vlc_cond_signal( &p_sys->wait ); + vlc_mutex_unlock( &p_sys->lock ); + + SetWindowLongPtr( p_sys->hotkeyWindow, GWL_WNDPROC, + (LONG_PTR)WMHOTKEYPROC ); + SetWindowLongPtr( p_sys->hotkeyWindow, GWL_USERDATA, + (LONG_PTR)p_intf ); + + /* Registering of Hotkeys */ + for( struct hotkey *p_hotkey = p_intf->p_libvlc->p_hotkeys; + p_hotkey->psz_action != NULL; + p_hotkey++ ) + { + if( asprintf( &psz_hotkey, "global-%s", p_hotkey->psz_action ) < 0 ) + break; + + i_key = config_GetInt( p_intf, psz_hotkey ); + + free( psz_hotkey ); + + i_keyMod = 0; + if( i_key & KEY_MODIFIER_SHIFT ) i_keyMod |= MOD_SHIFT; + if( i_key & KEY_MODIFIER_ALT ) i_keyMod |= MOD_ALT; + if( i_key & KEY_MODIFIER_CTRL ) i_keyMod |= MOD_CONTROL; + +#define HANDLE( key ) case KEY_##key: i_vk = VK_##key; break +#define HANDLE2( key, key2 ) case KEY_##key: i_vk = VK_##key2; break + +#ifndef VK_VOLUME_DOWN +#define VK_VOLUME_DOWN 0xAE +#define VK_VOLUME_UP 0xAF +#endif + +#ifndef VK_MEDIA_NEXT_TRACK +#define VK_MEDIA_NEXT_TRACK 0xB0 +#define VK_MEDIA_PREV_TRACK 0xB1 +#define VK_MEDIA_STOP 0xB2 +#define VK_MEDIA_PLAY_PAUSE 0xB3 +#endif + +#ifndef VK_PAGEUP +#define VK_PAGEUP 0x21 +#define VK_PAGEDOWN 0x22 +#endif + + i_vk = 0; + switch( i_key & ~KEY_MODIFIER ) + { + HANDLE( LEFT ); + HANDLE( RIGHT ); + HANDLE( UP ); + HANDLE( DOWN ); + HANDLE( SPACE ); + HANDLE2( ESC, ESCAPE ); + HANDLE2( ENTER, RETURN ); + HANDLE( F1 ); + HANDLE( F2 ); + HANDLE( F3 ); + HANDLE( F4 ); + HANDLE( F5 ); + HANDLE( F6 ); + HANDLE( F7 ); + HANDLE( F8 ); + HANDLE( F9 ); + HANDLE( F10 ); + HANDLE( F11 ); + HANDLE( F12 ); + HANDLE( PAGEUP ); + HANDLE( PAGEDOWN ); + HANDLE( HOME ); + HANDLE( END ); + HANDLE( INSERT ); + HANDLE( DELETE ); + HANDLE( VOLUME_DOWN ); + HANDLE( VOLUME_UP ); + HANDLE( MEDIA_PLAY_PAUSE ); + HANDLE( MEDIA_STOP ); + HANDLE( MEDIA_PREV_TRACK ); + HANDLE( MEDIA_NEXT_TRACK ); + + default: + i_vk = toupper( i_key & ~KEY_MODIFIER ); + break; + } + if( !i_vk ) continue; + +#undef HANDLE +#undef HANDLE2 + + atom = GlobalAddAtomA( p_hotkey->psz_action ); + if( !atom ) continue; + + if( !RegisterHotKey( p_sys->hotkeyWindow, atom, i_keyMod, i_vk ) ) + GlobalDeleteAtom( atom ); + } + + /* Main message loop */ + while( GetMessage( &message, NULL, 0, 0 ) ) + DispatchMessage( &message ); + + /* Unregistering of Hotkeys */ + for( struct hotkey *p_hotkey = p_intf->p_libvlc->p_hotkeys; + p_hotkey->psz_action != NULL; + p_hotkey++ ) + { + atom = GlobalFindAtomA( p_hotkey->psz_action ); + if( !atom ) continue; + + if( UnregisterHotKey( p_sys->hotkeyWindow, atom ) ) + GlobalDeleteAtom( atom ); + } + + /* close window */ + vlc_mutex_lock( &p_sys->lock ); + DestroyWindow( p_sys->hotkeyWindow ); + p_sys->hotkeyWindow = NULL; + vlc_mutex_unlock( &p_sys->lock ); + + return NULL; +} + +/***************************************************************************** + * WMHOTKEYPROC: event callback + *****************************************************************************/ +LRESULT CALLBACK WMHOTKEYPROC( HWND hwnd, UINT uMsg, WPARAM wParam, + LPARAM lParam ) +{ + switch( uMsg ) + { + case WM_HOTKEY: + { + int i; + char psz_atomName[40]; + + intf_thread_t *p_intf = + (intf_thread_t*)GetWindowLongPtr( hwnd, GWL_USERDATA ); + struct hotkey *p_hotkeys = p_intf->p_libvlc->p_hotkeys; + + i = GlobalGetAtomNameA( + wParam, psz_atomName, sizeof( psz_atomName ) ); + if( !i ) return 0; + + /* search for key associated with VLC */ + for( i = 0; p_hotkeys[i].psz_action != NULL; i++ ) + { + if( strcmp( p_hotkeys[i].psz_action, psz_atomName ) ) + continue; + + var_SetInteger( p_intf->p_libvlc, + "key-action", p_hotkeys[i].i_action ); + + return 1; + } + } + break; + + case WM_DESTROY: + PostQuitMessage( 0 ); + break; + + default: + return DefWindowProc( hwnd, uMsg, wParam, lParam ); + } + + return 0; +} diff --git a/src/libvlc.c b/src/libvlc.c index c74a681654..51d555c986 100644 --- a/src/libvlc.c +++ b/src/libvlc.c @@ -896,6 +896,9 @@ int libvlc_InternalInit( libvlc_int_t *p_libvlc, int i_argc, * Always load the hotkeys interface if it exists */ libvlc_InternalAddIntf( p_libvlc, "hotkeys,none" ); +#ifdef WIN32 + libvlc_InternalAddIntf( p_libvlc, "globalhotkeys,none" ); +#endif #ifdef HAVE_DBUS /* loads dbus control interface if in one-instance mode -- 2.39.2