Jump to content

Block keyboard input without admin rights


Recommended Posts

Hi guys. This time the problem is quite complex: part of the code is handled in AutoIt scripts, part in VBScript, part are AutoIt commands executed in VBScript via "AutoIt3ExecuteLine", and in addition PSPad is also involved with its internal commands. :wacko:  Therefore it is a bit difficult to post an example script. I hope we can find a solution without an example script.

"Gui_1" has an edit, is an AutoIt gui and has PSPad as parent window, so it is displayed modal to PSPad.

GUICreate("Gui_1",  ... , $GUI_SS_DEFAULT_GUI - $WS_MINIMIZEBOX, -1, $g_hPSPad)

If you have executed a script in PSPad, after e.g. 4 seconds the LogWin (Output-Console) of PSPad is automatically hidden. The hiding is an internal PSPad command, which unfortunately takes the focus away from Gui_1. If a user writes to Gui_1's edit at that very moment, the input ends up in PSPad's edit field instead of Gui_1's edit. Although I let Gui_1 reactivate immediately, a few characters can still end up in the PSPad editor.

Now I want to block keyboard input (or redirect to Gui_1?) for that brief moment when the active window changes. I tried blocking with BlockInput(), but that only works with admin rights, which my script doesn't have.

Is it possible to block or redirect the keyboard input for this short moment, without admin rights? Please consider that for a solution only very short AutoIt commands should be used, because they are called from VBScript via "AutoIt3ExecuteLine". 

Link to comment
Share on other sites

Hello JockoDundee.

There is no send or other command from outside. PSPad gets the command internally to close the LogWin. PSPad is a closed source Delphi program, so I don't know what is done internally, I can only see that closing the LogWin takes the focus away from the child (Gui_1) and puts it on the parent (PSPad). In other words:

- Gui_1 has the focus and the user writes with the keyboard in the edit of Gui_1. <= Edit: Better description (hopefully).
- After 4 seconds, the LogWin is automatically closed by PSPad's VBScript. <= Edit: The LogWin is in PSPad, NOT in Gui_1.
- The automatic closing takes the focus away from Gui_1 (Child) and puts it on PSPad (Parent) without me being able to do anything about it.
- If the user writes to the edit of Gui_1 at this moment, characters can end up in PSPad instead of Gui_1.

I then use VBScript (user interface in PSPad) to quickly set the focus back to Gui_1, but unfortunately there is a small delay and a few characters can end up in the PSPad editor.

As I said, it's complicated and it's not easy to explain. That's why I really appreciate your attempt to help! 👍

I tried to describe the problem with the needed information without going into too much detail. If further info is needed, I'll be happy to provide it!

Edited by Professor_Bernd
Link to comment
Share on other sites

Ok, thx for the clarification.

But my second suggestion still stands,

why don’t you, when Gui_1 is created,  hide or minimize the pspad logwin window?

so maybe then it won’t need to steal the focus.

Another thing you can do that might work, as a last resort, is to have a separate process like this:

While WinWaitNotActive("[TITLE:Gui_1]")
   WinActivate("TITLE:Gui_1")
   WinWaitActive("[TITLE:Gui_1")
WEnd

though you must setup some mechanism to disable the logic when not needed.

you may be able to put this code in the gui_event loop as well, with some mods.

Code hard, but don’t hard code...

Link to comment
Share on other sites

7 minutes ago, Earthshine said:

UIAutomation might be able to Manipulate your Delphi controls. That way you could keep it in auto IT

I don't quite understand. Can you explain how that is meant?

10 minutes ago, JockoDundee said:

why don’t you, when Gui_1 is created,  hide or minimize the pspad logwin window?

It is no use to close the LogWin when Gui_1 (RunParamsDialog) is created, because the LogWin will be opened again with every "Run".

More details.

Gui_1 is specifically "RunParamsDialog", a window where the user can enter parameters. These parameters are passed to the script when the script is run in PSPad ("Run" = F5).

Screenshot of the RunParamsDialog

Spoiler

RunParamsDialog.jpg.cf94054770953c5fa0770195cdea37f0.jpg

RunParamsDialog is opened by the user and closed by the user, it runs as long as the user wants. ;) When the user presses F5 for "Run" the script will be executed and the LogWin will be opened each time. I think everyone knows this from SciTE. When the script is finished, the LogWin is closed automatically in PSPad (if the user wants it).

 

27 minutes ago, JockoDundee said:

Another thing you can do that might work, as a last resort, is to have a separate process like this:

While WinWaitNotActive("[TITLE:Gui_1]")
   WinActivate("TITLE:Gui_1")
   WinWaitActive("[TITLE:Gui_1")
WEnd

though you must setup some mechanism to disable the logic when not needed.

This is not possible, because the user can't write in his script in PSPad, as long as RunParamsDialog is shown. :(

Link to comment
Share on other sites

Ok, here is the POC.  Its ugly, but it seems to work.

2 Files to download - RunParams.au3 and RunNotepad.au3 (RunNotepad must be compiled to .exe)

1) RunParams.au3 

  This is the RunParams mock up.  This has the code that you can incorporate in your .au3.  Go ahead and run it either in interpretive mode or compiled.  When you press F5 it will launch a new Notepad to simulate the PSPad log window (it also kills any notepad window first).  Then after 4 secs the focus should change to the Notepad window, although you may not notice it because keystrokes are never lost to it, and in any event the focus will return to the RunParams, if that's what had focus when you pressed F5.

2) RunNotepad.au3/.exe

This file exists only to launch Notepad in the background and then wait 4 secs before setting the focus to Notepad.  Then it terminates.

Here is RunParams.au3

#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>

HotkeySet("{F5}", "RunNotePad")

Local $hWnd=GUICreate("Run - params dialog", 325, 70)
Local $hEdit=GUICtrlCreateEdit("param1 param2", 5, 3, 300, 50, $WS_VSCROLL)
GUISetState(@SW_SHOW)
SetKeys()
GUIRegisterMsg($WM_ACTIVATE, "FocusChange")

While True
   Switch GUIGetMsg()
      Case $GUI_EVENT_CLOSE
          ExitLoop
   EndSwitch
WEnd
GUIDelete()

Exit

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Func RunNotePad()
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Run("RunNotePad.exe")

EndFunc

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Func FocusChange($hWnd, $iMsg, $wParam, $lParam)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

If $wParam Then
   SetKeys(True)
Else
   If WinGetHandle("[ACTIVE]")=WinGetHandle("[CLASS:Notepad]") Then
       WinActivate($hWnd)
    Else
       SetKeys(False)
    EndIf
EndIf
Return $GUI_RUNDEFMSG

EndFunc

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Func SetKeys($bSet=True)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Local $sFunc

For $n=32 To 126
   If $bSet Then
      HotkeySet(Chr($n), "SendToControl")
   Else
      HotkeySet(Chr($n))
   EndIf
Next

EndFunc

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Func SendToControl()
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

HotkeySet(@HotKeyPressed)
ControlSend($hWnd, "", $hEdit, @HotKeyPressed)
HotkeySet(@HotKeyPressed,"SendToControl")

EndFunc

Here is RunNotepad.au3

ProcessClose("Notepad.exe")
Run("Notepad.exe", @WorkingDir, @SW_SHOWNOACTIVATE)
Sleep(4000)
WinActivate("[CLASS:Notepad]")

P.S. Its pretty ugly stuff generally, I can't say I'm proud.

Code hard, but don’t hard code...

Link to comment
Share on other sites

46 minutes ago, JockoDundee said:

Ok, here is the POC.  Its ugly, but it seems to work.

Thank you so much for the effort you put in. 👍

I have tested your code and it seems to work in the replacement environment.

I will create a Pau3 test environment where we can test if it works under real conditions. Please be patient, this will take some time. ;)

Link to comment
Share on other sites

The test version is ready. I have created quick&dirty and it may contain errors. For test it should be enough. The zip contains a test script "Hello world.au3" and the following steps for testing.

Spoiler

LogWin AutoClose is set to 3 seconds.

Steps to test.

- Open PSPad.

- Load "Hello world.au3", e.g. by drag&drop.

- In the right panel double click "Run - parameters" => RunParamsDialog appears.

- Click into PSPad editor and press F5 => Script will be executed, MsgBox appears.

- Close the MsgBox => Script will be finished => 3 seconds until LogWin AutoClose.

- Click into the Edit of RunParamsDialog => Dialog becomes active, Edit has the input focus.

- Press any key (e.g. "a") on the keyboard and hold it until the LogWin is closed.

- When the 3 seconds are over, the LogWin is closed automatically, PSPad is activated and the editor gets the input focus.
=> 2 or 3 characters may have ended up in the editor of PSPad.

- RunParamsDialog gets the input focus = more characters end up in the edit of RunParamsDialog.

.

Now I have to leave and when I'm back I'll look for some relevant places in the code and post them in the next post.

Download the test version from the DE AutoIt forum.

Link to comment
Share on other sites

Here is a listing of the scripts involved and relevant code locations.

Spoiler


Involved scripts

  "...\<Pau3>\" is the folder where the PSPad.exe is located.

  VBScript
  - "...\<Pau3>\Script\VBScript\AutoIt3_CallTip.vbs"        <=   NOT relevant, only COM ROT object handling.
  - "...\<Pau3>\Script\VBScript\AutoIt3_CompRun_LogWin.vbs" <= RELEVANT!

  AutoIt
  - "...\<Pau3>\PSPad4Au3\Au3 scripts\CallTipViewer.au3"    <=   NOT relevant, only COM ROT object handling.
  - "...\<Pau3>\PSPad4Au3\Au3 scripts\CompilerRunner.au3"   <=   NOT relevant, COM ROT and Params handling.

  - "...\<Pau3>\PSPad4Au3\Au3 scripts\RunParamsDialog.au3"  <= RELEVANT!


Relevant code places

  - "...\<Pau3>\Script\VBScript\AutoIt3_CompRun_LogWin.vbs"

    Line  97 - 133: Sub Au3_RunParamsDialog()

      Nothing specific.


    Line 450 - 517: Sub LogWin_AutoCloseIfNoError(b_ErrWarnMsgFound, b_DebugMsgFound)

      Line 498 - 516:
      ===============

      If bLogWinCloseDelayed = True And logIsVisible() = True Then

        ' Delay of 3 seconds before the LogWin is closed.
        AutoIt3___Base.WaitForMilliSecs(sLogWinAutoCloseDelay * 1000) ' sec to ms

        If g_bStopLogWinAutoClose = False Then
          If CompilerRunnerIsRunning() = False Then

            sLastActiveWinHwnd = AutoIt3___Base.ExecuteAu3Line("WinGetHandle('[active]')", "/WaitForResult")
            sLastActiveWinTitle = AutoIt3___Base.ExecuteAu3Line("WinGetTitle(HWND('" & sLastActiveWinHwnd & "'))", "/WaitForResult")

            ' This is the most relevant place:
            ' --------------------------------
            '   This is where the LogWin is closed ("LogWin_Hide()"), which briefly puts the
            '   input focus on PSPad's editor and allows a few characters to end up there.
            LogWin_Hide() 
<= Line 508

            If sLastActiveWinTitle = gc_sRunParamsDlgTitle Then
              ' As soon as possible the focus will be back on the RunParamsDialog.
              Call AutoIt3___Base.ExecuteAu3Line("WinActivate(HWND('" & sLastActiveWinHwnd & "'))", "")

            End If
          End If
        End If

      End If ' If bLogWinCloseDelayed = True And logIsVisible() = True

I hope I have captured the most important parts. If you have any further questions, I'll be happy to add the info. :)

Edited by Professor_Bernd
Link to comment
Share on other sites

1 hour ago, Professor_Bernd said:

2 or 3 characters may have ended up in the editor of PSPad.

I’m not able to get to a PC right this sec,  but are you saying that 2 or 3 characters did actually get thru to the PSPad with my mod? Or just might when you test?  Or did when you tested before? Or?

Code hard, but don’t hard code...

Link to comment
Share on other sites

16 minutes ago, JockoDundee said:

but are you saying that 2 or 3 characters did actually get thru to the PSPad with my mod?

No, not in your replacement environment. It works fine! :) The info refers to the test version in the download three posts above. It happens in the real PSPad environment that 2 - 3 characters end up in the editor of PSPad instead of the edit of RunParamsDialog.

Link to comment
Share on other sites

15 hours ago, Professor_Bernd said:

Any news from you two? :graduated:

The English Army has just won the war?

Seriously though, is there still a problem with the keystroke leakage after you integrated my code?

I think maybe you are saying that my POC worked, but then when you tried to use it in your program, it didn’t?

Or are you just looking to initiate a topical discussion? :)

Code hard, but don’t hard code...

Link to comment
Share on other sites

4 hours ago, JockoDundee said:

The English Army has just won the war?

I'm not familiar with this, what does it mean? :huh2:

The problem persists. Unfortunately, I am not able to integrate your code in VBScript. Can you help me with this?

On 5/17/2021 at 3:26 PM, Professor_Bernd said:

            '   This is where the LogWin is closed ("LogWin_Hide()"), which briefly puts the
            '   input focus on PSPad's editor and allows a few characters to end up there.
            LogWin_Hide() 
<= Line 508

As I wrote a few posts above, this is the relevant place in my VBScript. What do I need to incorporate from your code there? I'm sorry I understand so little, but keep in mind that the above code is in VBScript and I don't know exactly how to integrate your AutoIt code there.

Currently there are 2 ways in PSPad's VBScript:
- Launching an Au3 script that can contain multiple lines of code.
- Execute a single line of AutoIt code via "/AutoIt3ExecuteLine".

So far, all my attempts to prevent the leak from keystrokes have failed. My idea is that the leak on keystrokes is caused by the delays, in the interaction of the various elements arises (VBScript, AutoIt, Delphi, WSH, ...). But I don't know how to integrate your code.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...