[vlc-devel] [PATCH] Code changes in Globalhokey module to support special keys when application in system tray/minimized for Windows
Geoffroy Couprie
geo.couprie at gmail.com
Fri Oct 29 19:26:31 CEST 2010
Hello,
Using global hooks is not being a good Windows citizen. You might
break other applications doing so. This feature should be enabled by a
config option, and disabled by default.
On 10/29/10, elangovan elango <elangovv at yahoo.co.in> wrote:
> Hello All,
>
> This patch is created to support windows special key functionality even when
> the
> application is in system tray/minimized/not interacted by the user. This is
> added in windows globalhotkey module. This will enable the user to interact
> with
> VLC even when it is system tray. This is implemented using windows hook
> concept
> to detect the user key press of PLAY,PAUSE, NEXT and PREVIOUS keys. Here am
> used
> WH_KEYBOARD_LL instead of WH_KEYBOARD which eliminates the need of DLL and
> makes
> it as Window Global hook which does not require any dependencies and can be
> part
> of any exe. This Current implementation only handles the This can be
> extended to
> other keys when needed.
>
>
> /*****************************************************************************
> * win32.c: Global-Hotkey WIN32 handling for vlc
> *****************************************************************************
> * Copyright (C) 2008-2009 the VideoLAN team
> *
> * Authors: Domani Hannes <ssbssa at yahoo dot de>
> + * Elangovan <elangovv at gmail dot com>
> *
> * 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
>
>
> #ifdef HAVE_CONFIG_H
> # include "config.h"
> #endif
>
> #include <ctype.h>
>
> #include <vlc_common.h>
> #include <vlc_plugin.h>
> #include <vlc_interface.h>
> #include <vlc_keys.h>
>
> /*****************************************************************************
> * 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 );
> + LRESULT CALLBACK WINTRAYSUPPORTPROC( int nCode, WPARAM wParam, LPARAM
> lParam);
>
>
> /*****************************************************************************
> * Module descriptor
>
> *****************************************************************************/
> vlc_module_begin()
> set_shortname( N_("Global Hotkeys") )
> set_category( CAT_INTERFACE )
> set_subcategory( SUBCAT_INTERFACE_HOTKEYS )
> set_description( N_("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;
> HHOOK hHook;
> };
>
>
> /*****************************************************************************
> * 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;
> + /* Unregister the HOOK Procedure */
> + if( p_sys->hHook !=NULL )
> + UnhookWindowsHookEx(p_sys->hHook);
>
> /* 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
> */
>
> + //Get Module handle and register the HOOK
> + HINSTANCE hExe = GetModuleHandle(NULL);
> + if (hExe !=NULL)
> + {
> + p_sys->hHook = SetWindowsHookEx( WH_KEYBOARD_LL,
> (HOOKPROC)WINTRAYSUPPORTPROC, hExe, NULL);
> + }
> 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, GWLP_WNDPROC,
> (LONG_PTR)WMHOTKEYPROC );
> SetWindowLongPtr( p_sys->hotkeyWindow, GWLP_USERDATA,
> (LONG_PTR)p_intf );
>
> /* Registering of Hotkeys */
> for( const 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 = var_InheritInteger( 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
>
> #define KEY_SPACE ' '
>
> #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( const 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:
> {
> char psz_atomName[40];
>
> LONG_PTR ret = GetWindowLongPtr( hwnd, GWLP_USERDATA );
> intf_thread_t *p_intf = (intf_thread_t*)ret;
> const struct hotkey *p_hotkeys =
> p_intf->p_libvlc->p_hotkeys;
>
> if( !GlobalGetAtomNameA(
> wParam, psz_atomName, sizeof( psz_atomName ) ) )
> return 0;
>
> /* search for key associated with VLC */
> for( int 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;
> }
>
> +
> /*****************************************************************************
> + * WINTRAYSUPPORTPROC: event callback method
> +
> *****************************************************************************/
> + LRESULT CALLBACK WINTRAYSUPPORTPROC( int nCode, WPARAM wParam, LPARAM
> lParam)
> + {
> + #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
> + static HHOOK hkb=NULL;
> + if ((nCode == HC_ACTION) && (wParam == WM_KEYDOWN))
> + {
> + KBDLLHOOKSTRUCT hookstruct = *((KBDLLHOOKSTRUCT*)lParam);
> + if( VK_MEDIA_PLAY_PAUSE == hookstruct.vkCode ||
> VK_MEDIA_NEXT_TRACK
> == hookstruct.vkCode || VK_MEDIA_STOP == hookstruct.vkCode ||
> VK_MEDIA_PREV_TRACK == hookstruct.vkCode)
> + {
> + HANDLE hotkeyWindow = FindWindow(_T("STATIC"), _T("VLC ghk ")
> _T(VERSION));
> + if(hotkeyWindow !=NULL)
> + {
> + LONG_PTR ret = GetWindowLongPtr( hotkeyWindow,
> GWLP_USERDATA );
> + intf_thread_t *p_intf = (intf_thread_t*)ret;
> + switch(hookstruct.vkCode)
> + {
> + case VK_MEDIA_PLAY_PAUSE:
> + var_SetInteger( p_intf->p_libvlc,"key-action",
> ACTIONID_PLAY_PAUSE );
> + break;
> + case VK_MEDIA_STOP:
> + var_SetInteger( p_intf->p_libvlc,"key-action",
> ACTIONID_STOP );
> + break;
> + case VK_MEDIA_PREV_TRACK:
> + var_SetInteger( p_intf->p_libvlc,"key-action",
> ACTIONID_PREV );
> + break;
> + case VK_MEDIA_NEXT_TRACK:
> + var_SetInteger( p_intf->p_libvlc,"key-action",
> ACTIONID_NEXT );
> + }
> + }
> + }
> + }
> + return CallNextHookEx( hkb, nCode, wParam, lParam );
> + }
>
>
> Regards
> Elangovan
>
>
>
More information about the vlc-devel
mailing list