I want to perform very nontrivial input handling:
1) Monitor input from several keyboards at once and differentiate it
2) Block all keyboard input by default (not allowing it pass into a system, reaching any application window)
3) Process the collected input (storing it in separated buffers, one per device) and in some conditions, pass it after a small delay to a system (to a foreground window)
The first and third steps I've made successfully (using Raw Input to collect inputs and SendInput to emulate).
The second is more serious ^^ I've made some working stuff, but it is full of unstable workarounds, also several more such problems exposed recently.
I also tried SetWindowsHookEx() API, which makes possible to block any KB input. But it can't be used because it is incompatible with Raw Input processing (if set up keyboard_LL hook, Raw Input callback will never receive any messages).
Any other ideas how it is possible to block keyboard input for whole system, using user-mode code? :)
Or well, if there is some full of hacks driver for this it will be fine too.
PS. Following code used to capture inputs
Code: Select all
EnableExplicit
;{ Raw Input }
; GetRawInputData() command flags
#RID_HEADER = $10000005 ; get header structure
#RID_INPUT = $10000003 ; get whole RAWINPUT structure
; Types of raw input data
#RIM_TYPEMOUSE = 0
#RIM_TYPEKEYBOARD = 1
#RIM_TYPEHID = 2
; RAWINPUTDEVICE flags
#RIDEV_REMOVE = $00000001
#RIDEV_EXCLUDE = $00000010
#RIDEV_PAGEONLY = $00000020
#RIDEV_NOLEGACY = $00000030
#RIDEV_INPUTSINK = $00000100
#RIDEV_CAPTUREMOUSE = $00000200
#RIDEV_NOHOTKEYS = $00000200
#RIDEV_APPKEYS = $00000400
#RIDEV_EXINPUTSINK = $00001000
#RIDEV_DEVNOTIFY = $00002000
; GetRawInputDeviceInfo() flags
#RIDI_PREPARSEDDATA = $20000005 ; returns previously parsed data
#RIDI_DEVICENAME = $20000007 ;- a string containing the device name
#RIDI_DEVICEINFO = $2000000b ;- an RIDI_DEVICE_INFO Structure
Structure RAWINPUTDEVICE
usUsagePage.w
usUsage.w
dwFlags.l
hwndTarget.l
EndStructure
Structure RAWINPUTDEVICELIST
hDevice.l
dwType.l ; The type of device. RIM_TYPEKEYBOARD, RIM_TYPEMOUSE, RIM_TYPEHID
EndStructure
Structure RAWINPUTHEADER
dwType.l ; The type of raw input. RIM_TYPEKEYBOARD, RIM_TYPEMOUSE, RIM_TYPEHID
dwSize.l
hDevice.l ; A handle to the device generating the raw input data.
wParam.l ; Same value as wParam of WM_INPUT message
EndStructure
Structure RAWMOUSE
usFlags.l
usButtonFlags.w
usButtonData.w
ulRawButtons.l
lLastX.l
lLastY.l
ulExtraInformation.l
EndStructure
Structure RAWKEYBOARD
MakeCode.w ; The scan code from the key depression. The scan code for keyboard overrun is KEYBOARD_OVERRUN_MAKE_CODE
Flags.w ; Flags for scan code information. RI_KEY_BREAK, RI_KEY_MAKE and some others
Reserved.w
VKey.w ; Windows message compatible virtual-key code.
Message.l ; WM_KEYDOWN, WM_SYSKEYDOWN and so on
ExtraInformation.l ; Device-specific value
EndStructure
Structure RAWHID
dwSizeHid.l
dwCount.l
bRawData.b [1] ; this array has variable size, thus structure too
EndStructure
Structure RAWINPUT
header.RAWINPUTHEADER
StructureUnion
mouse.RAWMOUSE
keyboard.RAWKEYBOARD
hid.RAWHID
EndStructureUnion
EndStructure
Prototype GetRawInputData(hRawInput, uiCommand, *pData.RAWINPUT, *pcbSize, cbSizeHeader)
Prototype RegisterRawInputDevices(*pRawInputDevices.RAWINPUTDEVICE, *uiNumDevices, cbSize)
Prototype GetRawInputDeviceList(*pRawInputDeviceList.RAWINPUTDEVICELIST, *uiNumDevices, cbSize)
Prototype GetRawInputDeviceInfo(hDevice, uiCommand, *pData, *pcbSize)
; import functions
Global User32_dll = OpenLibrary(#PB_Any, "user32.dll")
If IsLibrary(User32_dll)
Global RegisterRawInputDevices.RegisterRawInputDevices = GetFunction(User32_dll, "RegisterRawInputDevices")
Global GetRawInputData.GetRawInputData = GetFunction(User32_dll, "GetRawInputData")
Global GetRawInputDeviceList.GetRawInputDeviceList = GetFunction(User32_dll, "GetRawInputDeviceList")
Global GetRawInputDeviceInfo.GetRawInputDeviceInfo = GetFunction(User32_dll, "GetRawInputDeviceInfoW")
EndIf
;}
; windows message processing
Procedure WinCallback (hWnd, Message, WParam, LParam)
Select Message
Case #WM_INPUT: ; Raw Input
Protected pcbSize.l
Protected *pRawData.RAWINPUT
If GetRawInputData(lParam, #RID_INPUT, #Null, @pcbSize, SizeOf(RAWINPUTHEADER)) = 0
*pRawData = AllocateMemory(pcbSize) ; If input is from HID-device, data size can vary
If *pRawData
GetRawInputData(lParam, #RID_INPUT, *pRawData, @pcbSize, SizeOf(RAWINPUTHEADER))
Select *pRawData\header\dwType
Case #RIM_TYPEKEYBOARD:
; here input is collected
Debug "Vk " + Str(*pRawData\keyboard\VKey) + " from device " + Str(*pRawData\header\hDevice)
EndSelect
FreeMemory(*pRawData)
EndIf
EndIf
EndSelect
ProcedureReturn #PB_ProcessPureBasicEvents
EndProcedure
Procedure Main ()
Protected WndMain = 123
Protected hWnd = OpenWindow(WndMain, #PB_Ignore, #PB_Ignore, 300, 200, "SOME RAW INPUT HOOK", #PB_Window_Invisible)
; capture window messages
SetWindowCallback(@WinCallback())
; set raw input capture for all mouses and keyboards
Dim Rid.RAWINPUTDEVICE(0)
Rid(0)\usUsagePage = 1
Rid(0)\usUsage = 0
Rid(0)\hwndTarget = hWnd
Rid(0)\dwFlags = #RIDEV_INPUTSINK | #RIDEV_PAGEONLY
If RegisterRawInputDevices (@Rid(), ArraySize(Rid()) + 1, SizeOf(RAWINPUTDEVICE)) = #True
Debug "Press any key on any keyboard ..."
Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow
Else
; Msg("Failed to register devices: " + NameLastError())
EndIf
If IsLibrary(User32_dll)
CloseLibrary(User32_dll)
EndIf
EndProcedure
;;;;;;;;;
Main()
End