[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