[Windows] SendInput_() and the [Alt] key
Posted: Fri Oct 04, 2024 2:35 pm
Hi,
I have a program that useses SendInput_() for sending strings to windows of 3rd party programs. That works fine so far.
However, I want to send different strings, depending on whether or not the user presses [Shift], [Ctrl] or [Alt] while clicking with the mouse at the respective button.
The following code demonstrates the situation. It works as expected, except with [Alt]: When the [Alt] key is pressed while klicking at the button, no text is sent to the editor gadget.
I have a program that useses SendInput_() for sending strings to windows of 3rd party programs. That works fine so far.
However, I want to send different strings, depending on whether or not the user presses [Shift], [Ctrl] or [Alt] while clicking with the mouse at the respective button.
The following code demonstrates the situation. It works as expected, except with [Alt]: When the [Alt] key is pressed while klicking at the button, no text is sent to the editor gadget.
So how to “correct as necessary”? How can I make the code work also when [Alt] is pressed?Microsoft wrote: This function does not reset the keyboard's current state. Any keys that are already pressed when the function is called might interfere with the events that this function generates. To avoid this problem, check the keyboard's state with the GetAsyncKeyState function and correct as necessary.
Code: Select all
; PB 6.12 LTS
EnableExplicit
#KEYEVENTF_UNICODE = 4
Procedure.i SendString (s$)
; -- sends a Unicode string to the foreground window
; in : s$: Unicode-String (may contain characters outside of the BMP)
; out: number of events that were successfully inserted into the input stream
;
; <https://stackoverflow.com/questions/50420514/sendinput-wont-send-basic-unicode-to-some-windows>
Protected.Character *char, *char2
Protected.i i=0, nEvents=2*Len(s$)
If OSVersion() < #PB_OS_Windows_2000 Or nEvents = 0
ProcedureReturn 0
EndIf
Protected Dim send.Input(nEvents-1)
*char = @s$
While *char\c <> 0
If *char\c < $D800 Or *char\c > $DFFF
send(i)\type = #INPUT_KEYBOARD
send(i)\ki\wVk = 0
send(i)\ki\wScan = *char\c
send(i)\ki\dwFlags = #KEYEVENTF_UNICODE ; Mit diesem Flag muss \wVk = 0 sein.
i + 1
send(i)\type = #INPUT_KEYBOARD
send(i)\ki\wVk = 0
send(i)\ki\wScan = *char\c
send(i)\ki\dwFlags = #KEYEVENTF_UNICODE | #KEYEVENTF_KEYUP
i + 1
Else
*char2 = *char + SizeOf(Character)
send(i)\type = #INPUT_KEYBOARD
send(i)\ki\wVk = 0
send(i)\ki\wScan = *char\c
send(i)\ki\dwFlags = #KEYEVENTF_UNICODE
i + 1
send(i)\type = #INPUT_KEYBOARD
send(i)\ki\wVk = 0
send(i)\ki\wScan = *char2\c
send(i)\ki\dwFlags = #KEYEVENTF_UNICODE
i + 1
send(i)\type = #INPUT_KEYBOARD
send(i)\ki\wVk = 0
send(i)\ki\wScan = *char\c
send(i)\ki\dwFlags = #KEYEVENTF_UNICODE | #KEYEVENTF_KEYUP
i + 1
send(i)\type = #INPUT_KEYBOARD
send(i)\ki\wVk = 0
send(i)\ki\wScan = *char2\c
send(i)\ki\dwFlags = #KEYEVENTF_UNICODE | #KEYEVENTF_KEYUP
i + 1
*char = *char2
EndIf
*char + SizeOf(Character)
Wend
ProcedureReturn SendInput_(nEvents, @send(), SizeOf(Input))
EndProcedure
Macro IsAsyncKeyDown (_VK_)
Bool((GetAsyncKeyState_(_VK_) & $8000) = $8000)
EndMacro
;-- Test
Enumeration
#WinMain
EndEnumeration
Enumeration
#edtGadget
#btnGadget
EndEnumeration
Define event.i, out$
If OpenWindow(#WinMain, 100, 100, 200, 140, "Demo") = 0
MessageRequester("Fatal error", "Can't open main window", #PB_MessageRequester_Error)
End
EndIf
EditorGadget(#edtGadget, 20, 30, 160, 25)
ButtonGadget(#btnGadget, 60, 80, 80, 25, "Klick")
Repeat
event = WaitWindowEvent()
Select event
Case #PB_Event_Gadget
Select EventGadget()
Case #btnGadget
out$ = "Text"
If IsAsyncKeyDown(#VK_SHIFT)
out$ + "+Shift"
EndIf
If IsAsyncKeyDown(#VK_CONTROL)
out$ + "+Ctrl"
EndIf
If IsAsyncKeyDown(#VK_MENU)
out$ + "+Alt"
EndIf
ClearGadgetItems(#edtGadget)
SetActiveGadget(#edtGadget)
SendString(out$)
EndSelect
EndSelect
Until event = #PB_Event_CloseWindow