use strict; use warnings; use Data::Dumper; use Win32::API; use Win32::API::Callback; use Convert::Binary::C; #use experimental 'bitwise'; =for comment https://www.reddit.com/r/perl/comments/1i13h7/win32api_and_user32setwineventhook_help/ https://msdn.microsoft.com/en-us/library/windows/desktop/ms681382(v=vs.85).aspx https://msdn.microsoft.com/en-us/library/windows/desktop/ms644990(v=vs.85).aspx https://msdn.microsoft.com/en-us/library/windows/desktop/aa383751(v=vs.85).aspx http://code.activestate.com/lists/perl-win32-users/22434/ =cut BEGIN { $Win32::API::DEBUG = 1; } my $WH_KEYBOARD_LL = 13; Win32::API::Struct->typedef( POINT => qw( LONG x; LONG y; ) ); use constant { KEYEVENTF_EXTENDEDKEY => 0x0001, KEYEVENTF_KEYUP => 0x0002, KEYEVENTF_SCANCODE => 0x0008, KEYEVENTF_UNICODE => 0x0004, INPUT_KEYBOARD => 1 }; Win32::API::Struct->typedef( MSG => qw( HWND hwnd; UINT message; WPARAM wParam; LPARAM lParam; DWORD time; POINT pt; ) ); Win32::API::Struct->typedef( KEYBDINPUT => qw( WORD wVk; WORD wScan; DWORD dwFlags; DWORD time; UINT_PTR dwExtraInfo; DWORD junk1; DWORD junk2; ) ); Win32::API::Struct->typedef( INPUT => qw( DWORD type; KEYBDINPUT ki; ) ); my $code = <new->parse($code); my $GetCurrentThreadId = new Win32::API( 'kernel32', 'GetCurrentThreadId', '', 'N' ); print Win32::GetLastError(), "\n"; #0 # my $SetWindowsHookEx = new Win32::API('user32', 'SetWindowsHookEx', 'NKPP', 'P'); # my $SetWindowsHookEx = Win32::API->Import('user32', 'HHOOK SetWindowsHookEx(int idHook, HOOKPROC lpfn, HINSTANCE hMod, int dwThreadId)'); # #my $CallNextHookEx = Win32::API->Import('user32', 'CallNextHookEx', 'PNNN', 'N'); #my $GetMsg = Win32::API->Import('user32', 'GetMessage', 'NNII', 'i' ); my $SetWindowsHookEx = Win32::API->Import( 'user32', 'SetWindowsHookEx', 'IKNI', 'N' ) ; #, "idHook, HOOKPROC lpfn, HINSTANCE hMod, int dwThreadId"); die( "Failed to import" . $^E ) if !$SetWindowsHookEx; my $CallNextHookEx = Win32::API->Import( 'user32', 'LRESULT WINAPI CallNextHookEx(HHOOK hhk, int nCode, WPARAM wParam, LPARAM lParam)' ); my $GetMsg = Win32::API->Import( 'user32', 'BOOL WINAPI GetMessage(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax)' ); die "Error: $^E" if !$GetMsg; my $TranslateMsg = Win32::API->Import( 'user32', 'TranslateMessage', 'N', 'i' ); die "Error: $^E" if !$TranslateMsg; my $DispatchMsg = Win32::API->Import( 'user32', 'DispatchMessage', 'N', 'N' ); die "Error: $^E" if !$DispatchMsg; my $GetModuleHandle = Win32::API->Import( 'kernel32', 'HMODULE WINAPI GetModuleHandle(LPCTSTR lpModuleName)' ); my $UnhookWindowsHookEx = Win32::API->Import( 'user32', 'BOOL WINAPI UnhookWindowsHookEx(HHOOK hhk)' ); my $SendInput = Win32::API->Import( 'user32', 'UINT WINAPI SendInput(UINT nInputs, LPINPUT pInputs, int cbSize)' ); die "Error: $^E" if !$SendInput; print Win32::GetLastError(), "\n"; #127 sub MsgLoop { my $msg = Win32::API::Struct->new("MSG"); print "msgloop\n"; my $lp = $cparser->pack( "MSG", $msg ); # print "getmsg:" , Dumper ($GetMsg->Call($msg, undef, 0,0)); # die; my $res; while ( $res = $GetMsg->Call( $lp, undef, 0, 0 ) ) { die "Error in GetMsf" if ( $res == -1 ); # while (GetMsg($msg, undef, 0,0)) { die unless $msg; $TranslateMsg->Call($lp); $DispatchMsg->Call($lp); } } sub KeyboardHook { my ( $nCode, $wParam, $lParam ) = @_; print "kbhook\n"; print join( ", ", @_ ) . "\n"; #print "nCode=$nCode, wParam=$wParam, lParam=$lParam\n"; $CallNextHookEx->Call( 0, $nCode, $wParam, $lParam ); } sub registerHook { my $ThreadId = $GetCurrentThreadId->Call(); print "ThreadID : $ThreadId\n"; my $hMod = $GetModuleHandle->Call(undef); my $KeyboardHookCallback = Win32::API::Callback->new( \&KeyboardHook, "NNNN", "V" ); my $Hook = $SetWindowsHookEx->Call( $WH_KEYBOARD_LL, $KeyboardHookCallback, $hMod, $ThreadId ); MsgLoop(); $UnhookWindowsHookEx->Call($Hook); return $Hook; } sub unregisterHook { $UnhookWindowsHookEx->Call(shift); } sub sendString { my $val = shift; my @val = split( //, $val ); my $input_str = Win32::API::Struct->new("INPUT"); my @input = ( $input_str, $input_str ); $input[0]->{type} = INPUT_KEYBOARD; $input[0]->{ki}->{dwFlags} = KEYEVENTF_UNICODE; $input[1] = $input[0]; $input[1]->{ki}->{dwFlags} |= KEYEVENTF_KEYUP; for my $v (@val) { ( $input[0]->{ki}->{wVk}, $input[1]->{ki}->{wVk} ) = ( 0, 0 ); ( $input[0]->{ki}->{wScan}, $input[1]->{ki}->{wScan} ) = ( $v, $v ); for my $i ( 0 .. 1 ) { my $lp = $cparser->pack( "INPUT", $input[$i] ); $SendInput->Call( 1, $lp, $cparser->('INPUT')->sizeof ); #print 'Error: ', Win32::FormatMessage( Win32::GetLastError() ) unless ( $SendInput->Call( 2, \@input, 2 * $input_str->sizeof ) ); } } } my $hook = registerHook(); print "hook:", Dumper($hook), "\n"; sendString("abc"); unregisterHook($hook);