Page 1 of 1

Input handler program

Posted: Mon May 07, 2007 2:04 pm
by Seldon
I'd like to make a program that performs a certain task when I press a key (for example F12). Which is the best way to achieve this ? To open an invisible window with a normal event handling loop ? Does Windows offer a better method ? I'm thinking of something like an input-handler in AmigaOS. Thank you in advance

Posted: Mon May 07, 2007 2:27 pm
by milan1612
Hi,

Code: Select all

Repeat 
  Delay(1)
  ;your code...
  If GetAsyncKeyState_(#VK_F12) : Break : EndIf
ForEver
End
Regards, milan1612

Posted: Mon May 07, 2007 8:26 pm
by Derek
To perform the code when a key is pressed you need...

Code: Select all

Repeat
Repeat 
  Delay(1)
  If GetAsyncKeyState_(#VK_F12) : Break : EndIf
ForEver
;your code...
ForEver
Although I expect there are better ways. :)

Posted: Mon May 07, 2007 8:59 pm
by milan1612

Code: Select all

Repeat
  Delay(1)
  If GetAsyncKeyState_(#VK_F12)
    ;your code
  EndIf
ForEver
That's the better way :)

Posted: Mon May 14, 2007 7:07 pm
by Trond
This is the correct way:

Code: Select all

Procedure HotKey(Key, Modifiers)
  Static ID
  If RegisterHotKey_(0, ID, Modifiers, Key) = 0
    ProcedureReturn -1
  EndIf
  ID + 1
  ProcedureReturn ID
EndProcedure

Msg.MSG

hk = HotKey(#VK_F1, 0)
Repeat
  GetMessage_(@Msg, 0, 0, 0)
  If MSG\message = #WM_HOTKEY
    Debug "press"
    Break
  EndIf
ForEver

Posted: Tue May 15, 2007 4:11 am
by Rook Zimbabwe
Damn... trond beat me to it! :D

Posted: Tue May 15, 2007 5:26 am
by netmaestro
This is how I'd do it:

Compile this code to a shared dll called F12_Hook.dll :

Code: Select all

#PerformActionMessage = #WM_APP + 1
#UnhookandEndMessage  = #WM_APP + 2

Global KeyboardHook, CallingWindow

ProcedureDLL Attachprocess(instance)
  CompilerIf Defined(KBDLLHOOKSTRUCT, #PB_Structure) = 0
    Structure KBDLLHOOKSTRUCT
      vkCode.l
      scanCode.l
      flags.l
      time.l
      dwExtraInfo.l
    EndStructure
  CompilerEndIf
EndProcedure

ProcedureDLL KeyboardProc(ncode,wparam,lparam)
   *keycode.KBDLLHOOKSTRUCT=lparam
    If wParam = #WM_KEYDOWN
      Select *keycode\vkCode
      Case #VK_F12
        PostMessage_(CallingWindow, #PerformActionMessage, 0, 0)
        ProcedureReturn 1
      Case #VK_F11
        PostMessage_(CallingWindow, #UnhookandEndMessage, 0, 0)
        ProcedureReturn 1
      EndSelect       
    EndIf
  ProcedureReturn CallNextHookEx_( KeyboardHook, nCode, wParam, lParam )
EndProcedure

ProcedureDLL InitHook(hwnd, hook)
  CallingWindow = hwnd
  KeyboardHook = hook
EndProcedure
Compile this code to a Windows exe called Testhook.exe, place it in same folder as F12_Hook.dll:

Code: Select all

;=====================================================================================================
;     Offtopic: Sets up the timed messagebox for status display
;=====================================================================================================

OpenLibrary (0, "user32.dll") 
Prototype MessageBoxTimed(hWnd.l, lpText.s,lpCaption.s, uType.l, wLanguageID.w, dwMilliseconds.l) 
Global MessageBoxTimed.MessageBoxTimed = GetFunction(0,"MessageBoxTimeoutA") 

;=====================================================================================================
;     End of Offtopic section
;=====================================================================================================

#PerformActionMessage = #WM_APP + 1
#UnhookandEndMessage  = #WM_APP + 2

OpenWindow(0,0,0,0,0,"Testhook",#PB_Window_BorderLess|#PB_Window_Invisible)

hooklib = OpenLibrary(0, "F12_Hook.dll")
If hooklib
  keyproc=GetFunction(0, "KeyboardProc")
  KeyboardHook=SetWindowsHookEx_(#WH_KEYBOARD_LL, keyproc, hooklib, 0)
  CallFunction(0, "InitHook", WindowID(0), KeyboardHook)
  MessageRequester("Notice:","Press F12 to perform action, F11 to unhook and unload this program",#MB_OK|#MB_ICONINFORMATION) 
EndIf

Repeat
  ev = WaitWindowEvent()
  Select ev
    Case #WM_CLOSE, #UnhookandEndMessage
      MessageBoxTimed(0,"Unhooking and ending, thanks for testing!","Action:",#MB_OK|#MB_SYSTEMMODAL|#MB_ICONINFORMATION, 0, 1000) 
      Break
    Case #PerformActionMessage
      MessageBoxTimed(0,"Performing the keyboard hook action","Action:",#MB_OK|#MB_SYSTEMMODAL|#MB_ICONINFORMATION, 0, 1000) 
  EndSelect
ForEver
UnhookWindowsHookEx_(KeyboardHook)
Run the Testhook.exe program and press F12 from anywhere in the system, then press F11 to end the test session and unload the hook and test program.

Note that my dll is returning 1 when the key is trapped, which prevents the application having the keyboard focus from getting it at all. If you want the keypress not to lose its effect in other apps, return 0 instead and it will send your window the message while still allowing the other app to process the key normally.

Posted: Sat Nov 24, 2007 7:18 am
by Mistrel
Here is a little fix for your example, Trond. Your procedure was returning the incorrect ID.

Code: Select all

Procedure HotKey(Key, Modifiers)
  Static ID

  If RegisterHotKey_(0, ID, Modifiers, Key) = 0
    ProcedureReturn -1
  EndIf
  ID+1
  ProcedureReturn ID-1
EndProcedure

Re: Input handler program

Posted: Sat Nov 24, 2007 7:26 am
by PB
From MSDN regarding the F12 key:
Windows NT4 and Windows 2000/XP: The F12 key is reserved for use
by the debugger at all times, so it should not be registered as a hot key.
Even when you are not debugging an application, F12 is reserved in case
a kernel-mode debugger or a just-in-time debugger is resident.
So always make sure you set the F12 key with Shift, Control or Alt to avoid
this potential problem. In fact, the RegisterHotKey API won't allow you to set
the F12 hotkey alone on those systems:

Code: Select all

If OpenWindow(0,0,0,0,0,"test")
  Debug RegisterHotKey_(WindowID(0),1,0,#VK_F12) ; Fails.
  Debug RegisterHotKey_(WindowID(0),2,#MOD_SHIFT|#MOD_CONTROL,#VK_F12) ; Works.
  Repeat : Until WaitWindowEvent()=#PB_Event_CloseWindow
EndIf

Posted: Sat Nov 24, 2007 7:37 am
by Mistrel
What does F12 have to do with a debugger?