[vlc-devel] [PATCH] Code changes in Globalhokey module to support special keys when application in system tray/minimized for Windows

elangovan elango elangovv at yahoo.co.in
Fri Oct 29 18:31:15 CEST 2010


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


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.videolan.org/pipermail/vlc-devel/attachments/20101029/f5193803/attachment.html>


More information about the vlc-devel mailing list