Page 1 of 1

Listen to keystrokes during script execution

Posted: 01 Apr 2019, 06:20
by eitatetaata
Hi! I have a script which I want to execute in the background every now and then. However, the script needs to switch to a different (hidden) window for a couple of seconds, which is irritating, as I would like to be able to type in my original window at the same time. A workaround that I thought of would be to make the script record what I type when the hidden window is activated, and just paste it when it switches back to the original window. Problem is - I don’t know how to implement it.

Is there a way to listen to keystrokes during script execution if they appear (as opposed to waiting until a key is pressed)?

Re: Listen to keystrokes during script execution

Posted: 01 Apr 2019, 10:35
by evilC
You would need to declare a hotkey to every key on the keyboard.
When wishing to send input to an inactive window, the first port of call should be the ControlSend command.
Be aware though that ControlSend does not work with all apps
To bind a hotkey to all keys, you can use this code:

Code: Select all

#SingleInstance force

kb := new AllKeyBinder(Func("MyFunc"))
return

MyFunc(code, name, state){
	Tooltip % "Key Code: " code ", Name: " name ", State: " state
}

class AllKeyBinder{
	__New(callback, pfx := "~*"){
		keys := {}
		this.Callback := callback
		Loop 512 {
			i := A_Index
			code := Format("{:x}", i)
			n := GetKeyName("sc" code)
			if (!n || keys.HasKey(n))
				continue
			
			keys[n] := code
			
			fn := this.KeyEvent.Bind(this, i, n, 1)
			hotkey, % pfx n, % fn, On
			
			fn := this.KeyEvent.Bind(this, i, n, 0)
			hotkey, % pfx n " up", % fn, On		
		}
	}
	
	KeyEvent(code, name, state){
		this.Callback.Call(code, name, state)
	}
}

Re: Listen to keystrokes during script execution

Posted: 01 Apr 2019, 11:58
by eitatetaata
I am actually using ControlSend, but the script doesn’t work properly without activating the window anyway (it’s Chrome, and I guess it doesn’t always work great with AHK). I’ll be looking for other workarounds, but thanks a lot for this code.

Re: Listen to keystrokes during script execution

Posted: 01 Apr 2019, 17:08
by tidbit
chrome is a browser. Websites typically don't have "controls" as normal windows (like notepad) have them.
the website container itself is usually the control, everything in it is just... there. you need COM/selenium to directly interact with the site contents, or possibly SEND for the hacky brute-force but simpler method.

Re: Listen to keystrokes during script execution

Posted: 01 Apr 2019, 17:28
by gregster
For automation of the Chrome browser, there is also Geekdude's Chrome.ahk library available: https://www.autohotkey.com/boards/viewtopic.php?f=6&t=42890

Re: Listen to keystrokes during script execution

Posted: 02 Apr 2019, 06:48
by eitatetaata
I’ll check this out too, thanks!

Re: Listen to keystrokes during script execution

Posted: 18 Nov 2020, 21:32
by K0MPOT1K
evilC wrote:
01 Apr 2019, 10:35
You would need to declare a hotkey to every key on the keyboard.
When wishing to send input to an inactive window, the first port of call should be the ControlSend command.
Be aware though that ControlSend does not work with all apps
To bind a hotkey to all keys, you can use this code:

Code: Select all

#SingleInstance force

kb := new AllKeyBinder(Func("MyFunc"))
return

MyFunc(code, name, state){
	Tooltip % "Key Code: " code ", Name: " name ", State: " state
}

class AllKeyBinder{
	__New(callback, pfx := "~*"){
		keys := {}
		this.Callback := callback
		Loop 512 {
			i := A_Index
			code := Format("{:x}", i)
			n := GetKeyName("sc" code)
			if (!n || keys.HasKey(n))
				continue
			
			keys[n] := code
			
			fn := this.KeyEvent.Bind(this, i, n, 1)
			hotkey, % pfx n, % fn, On
			
			fn := this.KeyEvent.Bind(this, i, n, 0)
			hotkey, % pfx n " up", % fn, On		
		}
	}
	
	KeyEvent(code, name, state){
		this.Callback.Call(code, name, state)
	}
}
Great class!
Only I had a question.
Can I make it so that doesn't overwrite existing keyboard shortcuts ?

Re: Listen to keystrokes during script execution

Posted: 19 Nov 2020, 09:22
by evilC
By default it won't block the keys (Allowing existing shortcuts to work)

There's an optional 2nd parameter ("pfx") that is used as a prefix for all hotkeys it declares, and it defaults to ~

This can be overridden in the constructor

eg

kb := new AllKeyBinder(Func("MyFunc"), "*") to make keys block and use the * modifier

Re: Listen to keystrokes during script execution

Posted: 19 Nov 2020, 10:30
by K0MPOT1K
evilC wrote:
19 Nov 2020, 09:22
By default it won't block the keys (Allowing existing shortcuts to work)

There's an optional 2nd parameter ("pfx") that is used as a prefix for all hotkeys it declares, and it defaults to ~

This can be overridden in the constructor

eg

kb := new AllKeyBinder(Func("MyFunc"), "*") to make keys block and use the * modifier
Apparently this is due to the fact that some of the keyboard shortcuts I have are defined in #IfWinActive, ahk_group OtherGroup
I saw the pfx parameter, but I couldn't get the script to work properly.

Re: Listen to keystrokes during script execution

Posted: 19 Nov 2020, 10:41
by evilC
Oh, you mean AHK hotkeys, not normal windows shortcuts - totally different thing.
If the AHK hotkey definitions you have are context sensitive, then if the context is active, they will override the ones declared by AllKeyBinder

Re: Listen to keystrokes during script execution

Posted: 19 Nov 2020, 10:44
by K0MPOT1K
It doesn't seem to work.
Here is a simple example:

Code: Select all

kb := new AllKeyBinder(Func("KeyPress"), "~+")

KeyPress(type, code, name, state) {
	Tooltip % "Type: " type ", Code: " code ", Name: " name ", State: " state
}

#IfWinActive ahk_class Notepad++
F1::
	MsgBox, F1 Pressed
return
#IfWinActive
In this example, when you press F1, the message does not appear, although it seems like it should.

Re: Listen to keystrokes during script execution

Posted: 19 Nov 2020, 10:51
by evilC
With that code, KeyPress() is never getting called because you changed the signature - you have 4 parameters (extra type parameter) instead of 3

Re: Listen to keystrokes during script execution

Posted: 24 Nov 2020, 08:23
by K0MPOT1K
evilC wrote:
19 Nov 2020, 10:51
With that code, KeyPress() is never getting called because you changed the signature - you have 4 parameters (extra type parameter) instead of 3
Looks like I have slightly different class from another thread.

Code: Select all

class AllKeyBinder{
    __New(callback, pfx := "~*"){
        static mouseButtons := ["LButton", "RButton", "MButton", "XButton1", "XButton2"]
        keys := {}
        this.Callback := callback
        Loop 512 {
            i := A_Index
            code := Format("{:x}", i)
            n := GetKeyName("sc" code)
            if (!n || keys.HasKey(n))
                continue
            keys[n] := code
            
            fn := this.KeyEvent.Bind(this, "Key", i, n, 1)
            hotkey, % pfx "SC" code, % fn, On
            
            fn := this.KeyEvent.Bind(this, "Key", i, n, 0)
            hotkey, % pfx "SC" code " up", % fn, On             
        }
        
        for i, k in mouseButtons {
            fn := this.KeyEvent.Bind(this, "Mouse", i, n, 1)
            hotkey, % pfx k, % fn, On
            
            fn := this.KeyEvent.Bind(this, "Mouse", i, n, 0)
            hotkey, % pfx k " up", % fn, On             
        }
    }
    
    KeyEvent(type, code, name, state){
        this.Callback.Call(type, code, name, state)
    }
}