in reply to Continueing the Quest to get RegisterHotKey to work!

In sub WindowProc, you need to unpack $lParam, which is a pointer to a struct of type MSG.
You then need to check the message field in MSG to see if the message is of type WM_HOTKEY.

Here are the minimum changes to make your code work.
Add this to your constant section:

use constant WM_HOTKEY => 0x0312;
Add this to the middle of sub WindowProc:
my ($hwnd, $message, $msg_wParam, $msg_lParam, $time, $pt) = unpack 'L L L l L L ', unpack( 'P24', pack('L', $lParam) ); if ( $message == WM_HOTKEY ) { print "**************************\n"; }

These are some thoughts I had during my research of this problem:

  1. use Tk; is not needed in your example code.
  2. Sub KeyboardHook, and all of the code to hook it to the WH_KEYBOARD message, can be removed.
  3. If you read 'When to use Prototypes?', I think you will want to remove the ($$$) from your subs.
  4. According to this MSDN article, you should unregister your hotkey before exiting your program.
  5. You don't have to cheat and use $mw_win32->{-handle}; you can get the window handle with GetActiveWindow() as long as it is run *after* Show().
  6. The MSG structure could be decoded using Win32::API::Struct, but WindowProc gets called for *all* the window's messages and needs to perform quickly, so manual unpacking seems best.
  7. Your WindowProc() is a callback function of type GetMsgProc. The MSDN page on GetMsgProc seems to say that parameters $nCode and $wParam, along with the return value, should be considered (by comparing with HC_* and PM_* constants) to determine whether to call CallNextHookEx or not. You are not doing so, but your code is working, and the MS docs are very unclear to me, so I can't recommend a more "correct" solution. If the program gets twitchy under a heavy load, this is a good place to start looking for the problem.

Refactored, working, tested code:

use strict; use warnings; use Win32::GUI; use Win32::API; use Win32::API::Callback; # From PlatformSDK/Include/WinUser.h use constant MOD_CONTROL => 2; use constant KEY_A => ord('A'); use constant MY_HOTKEY_ID => 99; use constant { # Codes for SetWindowHook WH_GETMESSAGE => 3, # Window Messages WM_HOTKEY => 0x0312, ### # Hook Codes ### HC_ACTION => 0, ### HC_GETNEXT => 1, ### HC_SKIP => 2, ### HC_NOREMOVE => 3, ### HC_SYSMODALON => 4, ### HC_SYSMODALOFF => 5, ### ### # PeekMessage() Options ### PM_NOREMOVE => 0x0000, ### PM_REMOVE => 0x0001, ### PM_NOYIELD => 0x0002, }; sub WindowProc { my ( $nCode, $wParam, $lParam ) = @_; # See http://msdn.microsoft.com/library/en-us/winui/winui/windowsu +serinterface/windowing/messagesandmessagequeues/messagesandmessageque +uesreference/messageandmessagequeuestructures/msg.asp # typedef struct { # HWND hwnd; # UINT message; # WPARAM wParam; # Unsigned # LPARAM lParam; # Signed # DWORD time; # POINT pt; # } MSG, *PMSG; my ( $msg_hwnd, $msg_message, $msg_wParam, $msg_lParam, $msg_time, + $msg_pt ) = unpack 'L L L l L L ', unpack( 'P24', pack('L', $lParam) ); if ( $msg_message == WM_HOTKEY ) { print "**************************\n"; } CallNextHookEx( 0, $nCode, $wParam, $lParam ); } my $WinProc = Win32::API::Callback->new( \&WindowProc, 'NNN', 'N' ); Win32::API->Import( kernel32 => GetCurrentThreadId => '', 'N' ) or + die; Win32::API->Import( user32 => SetWindowsHookEx => 'NKNN', 'N' ) or + die; Win32::API->Import( user32 => CallNextHookEx => 'PNNN', 'N' ) or + die; Win32::API->Import( user32 => RegisterHotKey => 'NNNN', 'N' ) or + die; Win32::API->Import( user32 => UnregisterHotKey => 'NN', 'N' ) or + die; my $ThreadId = GetCurrentThreadId() or die; SetWindowsHookEx( WH_GETMESSAGE, $WinProc, 0, $ThreadId ) or die $^E; my $mw_win32 = Win32::GUI::Window->new( -name => 'MainWindow', -title => 'This is a test!', -width => 100, -height => 100, ); $mw_win32->Show(); my $mw_handle = $mw_win32->GetActiveWindow(); RegisterHotKey( $mw_handle, MY_HOTKEY_ID, MOD_CONTROL, KEY_A ) or die +$^E; Win32::GUI::Dialog(); UnregisterHotKey( $mw_handle, MY_HOTKEY_ID ) or die $^E;

Replies are listed 'Best First'.
Re^2: Continueing the Quest to get RegisterHotKey to work!
by eric256 (Parson) on Jul 16, 2006 at 21:42 UTC

    OMG Thank you!. For your points. I was using Tk for other stuff before I started pairing down to find this specific issue. That is also why the keyboard hook was still in there, it was kind of my "yes its still running and catching input" test. ;) Prototyps and some of the other gruff was collected from other examples I'd found, all used prototypes so I made the assumption that they were needed. I'm so friggin happy you don't even know! lol. I'm off to play with this, thank you very very much. Now to figure out what you did differently that made it work! BTW I knew i would need to decode, but as far as i could tell it wasn't even getting messages when it didn't have focus so I hadn't even tried decoding them yet.


    ___________
    Eric Hodges