Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris
 
PerlMonks  

Re^3: Win32::API and keyboard hook

by beech (Parson)
on Sep 19, 2017 at 23:25 UTC ( [id://1199699]=note: print w/replies, xml ) Need Help??


in reply to Re^2: Win32::API and keyboard hook
in thread Win32::API and keyboard hook

Hi,

https://metacpan.org/pod/Win32::API#USING-STRUCTURES gives some explanation about "LP" prefix

Here is a modified version of samples/GetCursorPos.pl

#!/usr/bin/perl -- use strict; use warnings; use Data::Dump qw/ dd /; use Win32::API; Win32::API::Struct->typedef( POINT => qw( LONG x; LONG y; ) ); Win32::API->Import('user32' => 'BOOL GetCursorPos(LPPOINT pt)'); #### using OO semantics my $pt = Win32::API::Struct->new('POINT'); @{$pt}{qw/x y/} = (0,0); GetCursorPos($pt) or die "GetCursorPos failed: $^E"; print "Cursor is at: $pt->{x}, $pt->{y}\n"; #### using tie semantics my %pt; tie %pt, 'Win32::API::Struct' => 'POINT'; @pt{qw/x y/}=(0,0); GetCursorPos(\%pt) or die "GetCursorPos failed: $^E"; print "Cursor is at: $pt{x}, $pt{y}\n"; dd( map{ { "is_known $_ ", Win32::API::Type->is_known($_)}; } qw{ POIN +T LPPOINT } ); __END__ Cursor is at: 198, 273 Cursor is at: 198, 273 ({ "is_known POINT " => 1 }, { "is_known LPPOINT " => "" })

so POINT is know, but LPPOINT is not known, and that isn't a problem

Replies are listed 'Best First'.
Re^4: Win32::API and keyboard hook
by frazap (Monk) on Sep 20, 2017 at 07:20 UTC
    Thanks !

    The following code should use the SendInput to send abc to the keyboard. Windows responds that "The operation completed successfully."

    However I don't see any abc in the console.

    am I still wrong with the way I encode the character in the wScan field ?

    Is this because I'm SendingInput in another thread ?

    Here is the code
    use strict; use warnings; use Data::Dumper; use Win32::API; use constant { KEYEVENTF_EXTENDEDKEY => 0x0001, KEYEVENTF_KEYUP => 0x0002, KEYEVENTF_SCANCODE => 0x0008, KEYEVENTF_UNICODE => 0x0004, INPUT_KEYBOARD => 1 }; 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; ) ); #https://msdn.microsoft.com/en-us/library/windows/desktop/ms646310(v=v +s.85).aspx die("Error: $^E") unless ( Win32::API::More->Import( 'user32', 'UINT WINAPI SendInput(UINT nInputs, LPINPUT pInputs, int cbSi +ze)' ) ); sub sendString { my $val = shift; my @val = split( //, $val ); my @input = ( Win32::API::Struct->new("INPUT"), Win32::API::Struct->new("INPUT") ); $input[0]->{type} = INPUT_KEYBOARD; $input[0]->{ki}->{dwFlags} = KEYEVENTF_UNICODE; #$input[0]->{ki}->{dwFlags} = 0; $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}->{junk1}, $input[1]->{ki}->{junk1} ) = ( 0, +0 ); ( $input[0]->{ki}->{junk2}, $input[1]->{ki}->{junk2} ) = ( 0, +0 ); ( $input[0]->{ki}->{time}, $input[1]->{ki}->{time} ) = ( 0, +0 ); ( $input[0]->{ki}->{dwExtraInfo}, $input[1]->{ki}->{dwExtraInf +o} ) = ( 0, 0 ); my $code = ord($v); #A hardware scan code for the key. If dwFlags specifies KEYEVE +NTF_UNICODE, #wScan specifies a Unicode character which is to be sent to th +e foreground application. print "$code\n"; ( $input[0]->{ki}->{wScan}, $input[1]->{ki}->{wScan} ) = ( $co +de, $code ); for my $i ( 0 .. 1 ) { my $c = SendInput( 1, $input[$i], $input[$i]->sizeof ); print "SendInput : $c\n"; print Win32::FormatMessage( Win32::GetLastError() ); } } } sendString("abc");

      However I don't see any abc in the console. am I still wrong with the way I encode the character in the wScan field ? Is this because I'm SendingInput in another thread ?

      Hi

      I don't know, the SendInput docs doesn't have an example(and I'm loathe to interpret those too much), but it does link keybd_event() which appears much simpler and has an example

      Have you heard of Win32::GuiTest? It has a "SendKeys" and WMSetText ...

      update: I gave keybd_event a shot it prints 1 instead of toggling numlock, so SendKeys works to type "abc" :)

        For completness, here is a working example using the C windows API directly.

        module: Win32::Shortkeys::Kbh

        hook.h
        LRESULT CALLBACK HookCallback(int nCode, WPARAM wParam, LPARAM lParam) +; void processKey(); void register_hook(); void unregister_hook(); void MsgLoop();
        send_string.h
        typedef struct delayed { INPUT data; struct delayed * next; } delayed; typedef unsigned char byte; void send_string (const wchar_t * str); void send_cmd(int time, byte vkcode); void sendDelayedKeys(); void paste_from_clpb(int dk)

        hook.c

        #include <windows.h> #include <WinAble.h> #include "stdio.h" #include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include "ppport.h" #include "hook.h" #include "send_string.h" HHOOK hook; int delayedSize = 0; delayed * start = NULL; delayed * last = NULL; LRESULT CALLBACK HookCallback( int nCode, WPARAM wParam, LPARAM lParam + ) { KBDLLHOOKSTRUCT * p = ( KBDLLHOOKSTRUCT * ) lParam; int kup = p->flags & LLKHF_UP; int alt = p->flags & LLKHF_ALTDOWN; int ext = p->flags & LLKHF_EXTENDED; processKey( kup, p->vkCode, alt, ext ); return CallNextHookEx( hook, nCode, wParam, lParam ); } void processKey( int kup, int vkCode, int alt, int ext ) { //printf ("processKey in C\n"); dSP; ENTER; SAVETMPS; PUSHMARK(SP); EXTEND( SP, 4 ); PUSHs( sv_2mortal( newSViv(kup) ) ); PUSHs( sv_2mortal( newSViv(vkCode) ) ); PUSHs( sv_2mortal( newSViv(alt) ) ); PUSHs( sv_2mortal( newSViv(ext) ) ); PUTBACK; //count = call_pv( "Adder", G_SCALAR ); int count = call_pv( "Win32::Shortkeys::Kbh::process_key", G_DISCA +RD ); PUTBACK; FREETMPS; LEAVE; if ( count != 0 ) croak("Big trouble\n"); } void MsgLoop() { MSG message; while ( GetMessage( &message, NULL, 0, 0 ) ) { TranslateMessage(&message); DispatchMessage(&message); } } void register_hook() { HMODULE hMod = (HMODULE) GetModuleHandle(NULL); hook = SetWindowsHookEx( WH_KEYBOARD_LL, HookCallback, hMod, 0 ); } void unregister_hook() { UnhookWindowsHookEx(hook); DWORD hookThreadId = GetCurrentThreadId(); PostThreadMessage( hookThreadId, WM_QUIT, 0, 0L ); } void send_string( const wchar_t * str ) { printf( "send_string : %s L:%i\n", str, wcslen(str) ); INPUT inp [2]; memset( inp, 0, sizeof(INPUT) ); inp [0] . type = INPUT_KEYBOARD; /** * KEYEVENTF_UNICODE flag send the string as Unicode characters. * Unicode makes life easy because you don't have * to synthesize capital letters using the Shift key. Without KEYEV +ENTF_ UNICODE, * you'd have to send capital E as <Shift> * followed by e, with down/up events for each, for a total of fou +r keystrokes. */ // to avoid shift, and so on inp [0] . ki . dwFlags = KEYEVENTF_UNICODE; inp [1] = inp [0]; inp [1] . ki . dwFlags |= KEYEVENTF_KEYUP; int count = 0; const wchar_t * p; for ( p = str; *p; p++ ) { count++; if (delayedSize > 0 && count ==1 ){ inp[0].ki.wVk = inp[1].ki.wVk = LOBYTE(VkKeyScan(*p)); //inp[0].ki.wScan = inp[1].ki.wScan = *p; } else { inp[0].ki.wVk = inp[1].ki.wVk = 0; //inp[0].ki.wScan = inp[1].ki.wScan = *p; } inp[0].ki.wScan = inp[1].ki.wScan = *p; printf("wScan has %i\n", *p); SendInput(2, inp, sizeof(INPUT)); if (count ==1){ sendDelayedKeys(); } }//for } void send_cmd(int time, byte vkcode){ time*=2; //doubler le nombre de touche delete à envoyer int size = time; INPUT i[size]; //printf ("sendCmd : %d \n", cont++); ZeroMemory(&i,sizeof(i)); int sendKey = 0; int j; for (j=0;j<time;j++){ if (vkcode == VK_SHIFT || vkcode == VK_CONTROL || vkcode == VK +_MENU){ if (j%2==0) { i[j].type = INPUT_KEYBOARD; i[j].ki.wVk=vkcode; i[j].ki.dwFlags =0; sendKey++; } else { delayed *tmp; tmp = (delayed*) malloc(sizeof(struct delayed)); tmp->data.type = INPUT_KEYBOARD; tmp->data.ki.wVk = vkcode; tmp->data.ki.dwFlags = KEYEVENTF_KEYUP; tmp->next = NULL; delayedSize++; if (start == NULL){ start = tmp; } else { last->next = tmp; } last = tmp; } } else { i[sendKey].type = INPUT_KEYBOARD; i[sendKey].ki.wVk=vkcode; i[sendKey].ki.dwFlags = (j%2==0?0:KEYEVENTF_KEYUP); sendKey++; } } SendInput(sendKey,i,sizeof(INPUT)); } void sendDelayedKeys(){ delayed *current; current = start; INPUT s[delayedSize]; int pos =0; while (current != NULL) { delayed *temp; s[pos++]= current->data; temp = current; free(current); current = temp->next; } start = NULL; last = NULL; if (delayedSize > 0){ SendInput(delayedSize, s, sizeof(INPUT) ); delayedSize=0; } } void paste_from_clpb(int dk) { dk*=2; //doubler le nombre de touche delete à envoyer int size = 4+dk; INPUT i[size]; ZeroMemory(&i,sizeof(i)); int j; for (j=0;j<dk;j++){ i[j].type = INPUT_KEYBOARD; i[j].ki.wVk=VK_BACK; i[j].ki.dwFlags = (j%2==0?0:KEYEVENTF_KEYUP); } i[0+dk].type = INPUT_KEYBOARD; i[0+dk].ki.wVk =VK_CONTROL; i[1+dk].type = INPUT_KEYBOARD; i[1+dk].ki.wVk = LOBYTE(VkKeyScan('v')); i[2+dk].type = INPUT_KEYBOARD; i[2+dk].ki.dwFlags = KEYEVENTF_KEYUP; i[2+dk].ki.wVk =LOBYTE(VkKeyScan('v')); i[3+dk].type = INPUT_KEYBOARD; i[3+dk].ki.dwFlags = KEYEVENTF_KEYUP; i[3+dk].ki.wVk = VK_CONTROL; SendInput(size,i,sizeof(INPUT)); }
        typemap
        const wchar_t * T_WCHAR byte T_U_CHAR INPUT T_WCHAR // $var = ($type)SvPV_nolen($arg) { Newz(0, $var, SvLEN($arg), wchar_t); U8* src = (U8*) SvPV_nolen($arg); wchar_t* dst = (wchar_t*) $var; if (SvUTF8($arg)) { STRLEN len; while (*src) { *dst++ = utf8_to_uvuni((U8*) src, &len); //*dst++ = uvchr_to_urf8() src += len; } } else { while (*src) { *dst++ = (wchar_t) *src++; } } *dst = 0; SAVEFREEPV($var); } T_U_CHAR $var = (unsigned char)SvUV($arg) OUTPUT T_WCHAR //sv_setpv((SV*)$arg, $var); { wchar_t* src = (wchar_t*) $var; U8* dst; U8* d; Newz(0, dst, 3 * wcslen(src), U8); d = dst; while (*src) { d = uvuni_to_utf8(d, *src++); } *d = 0; sv_setpv((SV*)$arg, (char*) dst); sv_utf8_decode($arg); Safefree(dst); } T_U_CHAR sv_setuv($arg, (UV)$var);
        Kbh.xs
        #include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include "ppport.h" #include "hook.h" #include "send_string.h" MODULE = Win32::Shortkeys::Kbh PACKAGE = Win32::Shortkey +s::Kbh PROTOTYPES: DISABLE void MsgLoop() void register_hook() void unregister_hook() void send_string(s) const wchar_t * s void send_cmd(howmutch, vkcode) int howmutch byte vkcode void paste_from_clpb(dk) int dk
        Makefile.pl
        use ExtUtils::MakeMaker; # See lib/ExtUtils/MakeMaker.pm for details of how to influence # the contents of the Makefile that is written. WriteMakefile( NAME => 'Win32::Shortkeys::Kbh', VERSION_FROM => 'lib/Win32/Shortkeys/Kbh.pm', # finds $VERSIO +N, requires EU::MM from perl >= 5.5 PREREQ_PM => {}, # e.g., Module::Name => 1.1 ABSTRACT_FROM => 'lib/Win32/Shortkeys/Kbh.pm', # retrieve abst +ract from module OBJECT => 'hook.o Kbh.o', AUTHOR => 'frazap', #LICENSE => 'perl', #Value must be from legacy list of licenses here #http://search.cpan.org/perldoc?Module%3A%3ABuild%3A%3AAPI LIBS => [''], # e.g., '-lm' DEFINE => '', # e.g., '-DHAVE_SOMETHING' INC => '-I.', # e.g., '-I. -I/usr/include/other' # Un-comment this if you add C files to link with later: # OBJECT => '$(O_FILES)', # link all the C files too );
        lib/Win32/Shortkeys/Kbh.pm
        package Win32::Shortkeys::Kbh; use strict; use warnings; use Carp; require Exporter; #use AutoLoader qw(AUTOLOAD); our @ISA = qw(Exporter); # Items to export into callers namespace by default. Note: do not expo +rt # names by default without a very good reason. Use EXPORT_OK instead. # Do not simply export all your public functions/methods/constants. # This allows declaration use Win32::Shortkeys::Kbh ':all'; # If you do not need this, moving things directly into @EXPORT or @EXP +ORT_OK # will save memory. our %EXPORT_TAGS = ( input => [ qw(send_string send_cmd paste_from_clpb) ], hook => [qw(register_hook unregister_hook MsgLoop set_key_processor +)], vkcode => [qw ( VK_LBUTTON VK_RBUTTON VK_CANCEL VK_MBUTTON VK_XBUTTON1 VK_XBUTTON2 VK_ +BACK VK_TAB VK_CLEAR VK_RETURN VK_SHIFT VK_CONTROL VK_MENU VK_PAUSE VK_CAPI +TAL VK_KANA VK_HANGEUL VK_HANGUL VK_JUNJA VK_FINAL VK_HANJA VK_KANJI VK_ES +CAPE VK_CONVERT VK_NONCONVERT VK_ACCEPT VK_MODECHANGE VK_SPACE VK_PRIOR VK_ +NEXT VK_END VK_HOME VK_LEFT VK_UP VK_RIGHT VK_DOWN VK_SELECT VK_PRINT VK_EX +ECUTE VK_SNAPSHOT VK_INSERT VK_DELETE VK_HELP VK_LWIN VK_RWIN VK_APPS VK_SLE +EP VK_NUMPAD0 VK_NUMPAD1 VK_NUMPAD2 VK_NUMPAD3 VK_NUMPAD4 VK_NUMPAD5 VK_N +UMPAD6 VK_NUMPAD7 VK_NUMPAD8 VK_NUMPAD9 VK_MULTIPLY VK_ADD VK_SEPARATOR VK_SU +BTRACT VK_DECIMAL VK_DIVIDE VK_F1 VK_F2 VK_F3 VK_F4 VK_F5 VK_F6 VK_F7 VK_F8 V +K_F9 VK_F10 VK_F11 VK_F12 VK_F13 VK_F14 VK_F15 VK_F16 VK_F17 VK_F18 VK_F19 +VK_F20 VK_F21 VK_F22 VK_F23 VK_F24 VK_NUMLOCK VK_SCROLL VK_OEM_NEC_EQUAL VK_OEM_FJ_JISHO VK_OEM_FJ_MASSHOU VK_OEM_FJ_TOUROKU VK_OEM_FJ_LOYA VK_OEM_FJ_ROYA VK_LSHIFT VK_RSHIFT VK_LCONTROL VK_RCONTROL VK_LMENU VK_RMENU VK_BROWSER_BACK VK_BROWSER_FORWARD VK_BROWSER_REFRESH VK_BROWSER_STOP VK_BROWSER_SEARCH VK_BROWSER_FAVORITES VK_BROWSER_HOME + VK_VOLUME_MUTE VK_VOLUME_DOWN VK_VOLUME_UP VK_MEDIA_NEXT_TRACK VK_MEDIA_PREV_TRACK VK_MEDIA_STOP VK_MEDIA_PLAY_PAUSE VK_LAUNCH_MAIL VK_LAUNCH_MEDIA_SELECT VK_LAUNCH_APP1 VK_LAUNCH_APP2 VK_OEM_1 VK_OEM_P +LUS VK_OEM_COMMA VK_OEM_MINUS VK_OEM_PERIOD VK_OEM_2 VK_OEM_3 VK_OEM_4 VK_ +OEM_5 VK_OEM_6 VK_OEM_7 VK_OEM_8 VK_OEM_AX VK_OEM_102 VK_ICO_HELP VK_ICO_00 VK_PROCESSKEY VK_ICO_CLEAR VK_PACKET VK_OEM_RESET VK_OEM_JUMP VK_OEM_P +A1 VK_OEM_PA2 VK_OEM_PA3 VK_OEM_WSCTRL VK_OEM_CUSEL VK_OEM_ATTN VK_OEM_FI +NISH VK_OEM_COPY VK_OEM_AUTO VK_OEM_ENLW VK_OEM_BACKTAB VK_ATTN VK_CRSEL VK_EXSEL VK_EREOF VK_PLAY VK_ZOOM VK_NONAME VK_PA1 VK_OEM_CLEAR )], ); my %seen; push @{$EXPORT_TAGS{all}}, grep {!$seen{$_}++} @{$EXPORT_TAGS{$_}} foreach keys %EXPORT_TAGS; Exporter::export_tags('hook'); Exporter::export_ok_tags(qw(input vkcode)); our $VERSION = '0.01'; require XSLoader; XSLoader::load('Win32::Shortkeys::Kbh', $VERSION); my $key_processor; sub set_key_processor { $key_processor = shift; confess ("set_key_processor must receive a sub ref") unless (ref $ +key_processor eq "CODE"); } sub process_key { # my ($cup, $code, $alt, $ext) = @_; #print "process_key in perl cup: $cup code: $code alt: $alt ext: $ +ext \n"; $key_processor->(@_); } use constant { VK_LBUTTON =>0x01, VK_RBUTTON =>0x02, VK_CANCEL =>0x03, VK_MBUTTON =>0x04, VK_XBUTTON1 =>0x05, VK_XBUTTON2 =>0x06, VK_BACK =>0x08, VK_TAB =>0x09, VK_CLEAR =>0x0C, VK_RETURN =>0x0D, VK_SHIFT =>0x10, VK_CONTROL =>0x11, VK_MENU =>0x12, VK_PAUSE =>0x13, VK_CAPITAL =>0x14, VK_KANA =>0x15, VK_HANGEUL =>0x15, VK_HANGUL =>0x15, VK_JUNJA =>0x17, VK_FINAL =>0x18, VK_HANJA =>0x19, VK_KANJI =>0x19, VK_ESCAPE =>0x1B, VK_CONVERT =>0x1C, VK_NONCONVERT =>0x1D, VK_ACCEPT =>0x1E, VK_MODECHANGE =>0x1F, VK_SPACE =>0x20, VK_PRIOR =>0x21, VK_NEXT =>0x22, VK_END =>0x23, VK_HOME =>0x24, VK_LEFT =>0x25, VK_UP =>0x26, VK_RIGHT =>0x27, VK_DOWN =>0x28, VK_SELECT =>0x29, VK_PRINT =>0x2A, VK_EXECUTE =>0x2B, VK_SNAPSHOT =>0x2C, VK_INSERT =>0x2D, VK_DELETE =>0x2E, VK_HELP =>0x2F, VK_LWIN =>0x5B, VK_RWIN =>0x5C, VK_APPS =>0x5D, VK_SLEEP =>0x5F, VK_NUMPAD0 =>0x60, VK_NUMPAD1 =>0x61, VK_NUMPAD2 =>0x62, VK_NUMPAD3 =>0x63, VK_NUMPAD4 =>0x64, VK_NUMPAD5 =>0x65, VK_NUMPAD6 =>0x66, VK_NUMPAD7 =>0x67, VK_NUMPAD8 =>0x68, VK_NUMPAD9 =>0x69, VK_MULTIPLY =>0x6A, VK_ADD =>0x6B, VK_SEPARATOR =>0x6C, VK_SUBTRACT =>0x6D, VK_DECIMAL =>0x6E, VK_DIVIDE =>0x6F, VK_F1 =>0x70, VK_F2 =>0x71, VK_F3 =>0x72, VK_F4 =>0x73, VK_F5 =>0x74, VK_F6 =>0x75, VK_F7 =>0x76, VK_F8 =>0x77, VK_F9 =>0x78, VK_F10 =>0x79, VK_F11 =>0x7A, VK_F12 =>0x7B, VK_F13 =>0x7C, VK_F14 =>0x7D, VK_F15 =>0x7E, VK_F16 =>0x7F, VK_F17 =>0x80, VK_F18 =>0x81, VK_F19 =>0x82, VK_F20 =>0x83, VK_F21 =>0x84, VK_F22 =>0x85, VK_F23 =>0x86, VK_F24 =>0x87, VK_NUMLOCK =>0x90, VK_SCROLL =>0x91, VK_OEM_NEC_EQUAL =>0x92, VK_OEM_FJ_JISHO =>0x92, VK_OEM_FJ_MASSHOU =>0x93, VK_OEM_FJ_TOUROKU =>0x94, VK_OEM_FJ_LOYA =>0x95, VK_OEM_FJ_ROYA =>0x96, VK_LSHIFT =>0xA0, VK_RSHIFT =>0xA1, VK_LCONTROL =>0xA2, VK_RCONTROL =>0xA3, VK_LMENU =>0xA4, VK_RMENU =>0xA5, VK_BROWSER_BACK =>0xA6, VK_BROWSER_FORWARD =>0xA7, VK_BROWSER_REFRESH =>0xA8, VK_BROWSER_STOP =>0xA9, VK_BROWSER_SEARCH =>0xAA, VK_BROWSER_FAVORITES =>0xAB, VK_BROWSER_HOME =>0xAC, VK_VOLUME_MUTE =>0xAD, VK_VOLUME_DOWN =>0xAE, VK_VOLUME_UP =>0xAF, VK_MEDIA_NEXT_TRACK =>0xB0, VK_MEDIA_PREV_TRACK =>0xB1, VK_MEDIA_STOP =>0xB2, VK_MEDIA_PLAY_PAUSE =>0xB3, VK_LAUNCH_MAIL =>0xB4, VK_LAUNCH_MEDIA_SELECT =>0xB5, VK_LAUNCH_APP1 =>0xB6, VK_LAUNCH_APP2 =>0xB7, VK_OEM_1 =>0xBA, VK_OEM_PLUS =>0xBB, VK_OEM_COMMA =>0xBC, VK_OEM_MINUS =>0xBD, VK_OEM_PERIOD =>0xBE, VK_OEM_2 =>0xBF, VK_OEM_3 =>0xC0, VK_OEM_4 =>0xDB, VK_OEM_5 =>0xDC, VK_OEM_6 =>0xDD, VK_OEM_7 =>0xDE, VK_OEM_8 =>0xDF, VK_OEM_AX =>0xE1, VK_OEM_102 =>0xE2, VK_ICO_HELP =>0xE3, VK_ICO_00 =>0xE4, VK_PROCESSKEY =>0xE5, VK_ICO_CLEAR =>0xE6, VK_PACKET =>0xE7, VK_OEM_RESET =>0xE9, VK_OEM_JUMP =>0xEA, VK_OEM_PA1 =>0xEB, VK_OEM_PA2 =>0xEC, VK_OEM_PA3 =>0xED, VK_OEM_WSCTRL =>0xEE, VK_OEM_CUSEL =>0xEF, VK_OEM_ATTN =>0xF0, VK_OEM_FINISH =>0xF1, VK_OEM_COPY =>0xF2, VK_OEM_AUTO =>0xF3, VK_OEM_ENLW =>0xF4, VK_OEM_BACKTAB =>0xF5, VK_ATTN =>0xF6, VK_CRSEL =>0xF7, VK_EXSEL =>0xF8, VK_EREOF =>0xF9, VK_PLAY =>0xFA, VK_ZOOM =>0xFB, VK_NONAME =>0xFC, VK_PA1 =>0xFD, VK_OEM_CLEAR =>0xF }; 1; __END__ =head1 NAME Win32::Shortkeys::Kbh - Perl extension for blah blah blah =head1 SYNOPSIS use Win32::Shortkeys::Kbh; .... =cut
        example.pl in the module folder
        use lib qw(./lib ./blib/arch/auto/Win32/Shortkeys/Kbh); #use blib; use strict; use warnings; use Time::HiRes qw(usleep); use Win32::Shortkeys::Kbh qw(:hook :input VK_BACK VK_TAB); set_key_processor(sub { my ($cup, $code, $alt, $ext) = @_; return unless $cup == 0; print "process_key in perl cup: $cup code: $code alt: $alt ex +t: $ext \n"; // F12 to leave the script if ($code == 123) { unregister_hook(); } // s: hitting s in notepad replace s with the string below if ($code == 83) { usleep(400_000); send_cmd(1, VK_BACK); send_string("You hit the s key !!!"); } }); register_hook(); MsgLoop();

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://1199699]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others pondering the Monastery: (5)
As of 2024-04-19 23:22 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found