[Library] AppFactory - Custom Hotkey GuiControl + Persistent regular GuiControls

Post AHK_H specific scripts & libraries and discuss the usage and development of HotKeyIt's fork/branch
User avatar
evilC
Posts: 4823
Joined: 27 Feb 2014, 12:30

[Library] AppFactory - Custom Hotkey GuiControl + Persistent regular GuiControls

13 Jun 2017, 18:09

GitHub Page (Downloads)

This is a library that makes it easy to add user-configurable hotkeys and settings to your script.
It's basically a cut-down version of UCR (See Signature). Sometimes I just want something simpler than full-blown UCR, and also I am starting to move towards implementing UCR in C# (But still allowing AHK plugins, of course...), so I thought it would be cool to distill down what UCR does into as simple a script as possible, so people can easily understand and improve the basic techniques I used.

The only external library is CoCo's JSON library, used for reading and writing settings

It has the following features:
Custom Hotkey GuiControl that accepts:
  • Any legal AHK hotkey combination
  • Normal options available for AHK hotkeys (Block ~, Wild *)
  • "Suppress Repeats" option to suppress repeat down events for keyboard keys
  • Bind joystick POV (Hat) directions as if they were buttons
  • Accurate notification of release of joystick buttons
Add standard GuiControls (Editboxes, DDLs etc) and have their contents remembered between runs

Image

Code for this example:

Code: Select all

#SingleInstance force
#NoEnv
#Include AppFactory.ahk

factory := new AppFactory()
factory.AddInputButton("HK1", "w200", Func("InputEvent").Bind("1"))
factory.AddInputButton("HK2", "xm w200", Func("InputEvent").Bind("2"))
factory.AddControl("MyEdit", "Edit", "xm w200", "Default Value", Func("GuiEvent").Bind("MyEdit"))
factory.AddControl("MyDDL", "DDL", "xm w200 AltSubmit", "One||Two|Three", Func("GuiEvent").Bind("MyDDL"))

Gui, Show, x0 y0
return

InputEvent(ctrl, state){
	Global factory
	Tooltip % "Input " ctrl " changed state to: " state " after " A_TickCount " ticks while MyEdit was '" factory.GuiControls.MyEdit.Get() "'"
}

GuiEvent(ctrl, state){
	Tooltip % "GuiControl " ctrl " changed state to: '" state "' after " A_TickCount " ticks"
}

^Esc::
GuiClose:
	ExitApp
Components
AppFactory comprises of 3 main parts (Classes):

AppFactory
This is the main class. It handles injecting the custom GuiControls, and spins up AHK_H threads for the other two classes

BindModeThread
Handles "Bind Mode". When the user wishes to select a new hotkey, they select Bind Mode, a dialog appears, and they hit the button they wish to use.
Declares a hotkey to every keyboard key, mouse button, joystick button and watches joystick hats

InputThread
Handles input detection for all Hotkey controls in the script.
Normal hotkeys, plus fixes and enhancements to default AHK functionality, ie:
Up events for joystick buttons now fire accurately
POV hat directions (Up, Down, Left, Right) can be mapped as if they were a button.

Multiple threads are used as AHK does not support "Hotkey Sets" - ie there is no way to quickly turn on or off lots of hotkeys.
Seeing as bind mode needs to bind to every key on the keyboard, entering bind mode without being able to just Suspend, Off is much slower.

Also, were the input handler in the same thread as the bind handler, to enter bind mode you would have to redeclare all hotkeys (For Bind Mode), then undeclare them all, then re-declare all the user's hotkeys.

The InputThread could conceivably be in the main thread in this incarnation (In UCR, you can switch profiles, so I have one InputThread per profile), but this would make debugging of users scripts annoying if you step in, as the timers used for hat and button release detection would get hit.

Compilation
Place the following two lines at the start of your script

Code: Select all

FileInstall, ..\Source\BindModeThread.ahk, BindModeThread.ahk
FileInstall, ..\Source\InputThread.ahk, InputThread.ahk
You may need to alter the first parameter of each command to point to the correct location of the two files
If you download the included zip and your script is in the same folder as Example.ahk, this code should work as-is
Last edited by evilC on 08 Jan 2018, 10:42, edited 4 times in total.
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: [Library] AppFactory - Custom Hotkey GuiControl + Persistent regular GuiControls

15 Jun 2017, 11:24

Excellent, excellent, excellent! :bravo:
This is a real treat! It will make it very quick and easy to pass someone a working app, with minimal need for the recipient to read documentation and / or modify a script. (Read: I do not have to write (extensive) documentation or explain how to change hotkeys or whatever in a script :dance: )

I have comments:
There is a problem with the (lack of) handling of the default gui. See A_DefaultGui.
It seems you never do :?:

Code: Select all

Gui, new
Hence, in a script like this

Code: Select all

Gui, new, hwndMyOtherGui
Gui, % MyOtherGui ":Add", Text,, Hi
Gui, % MyOtherGui ":Show", w400 h100

app := new AppFactory
app.AddInputButton(...)
the InputButton will appear in MyOtherGui. Maybe do something like this,

Code: Select all

__new(){ ; I guess it would be here.
	Gui, new, hwndguiId
	this.guiId:=guiId
	; ...
}
someMethod(){
	Gui, % this.guiId: "cmd", ...
}
I made a simple workaround in my testing, this has the benefit of making sure the default gui is restored

Code: Select all

class AppFactory_dg extends AppFactory{
	__new(){
		dg:=A_DefaultGui
		Gui, new, hwndguiHwnd
		this.guiHwnd:=guiHwnd
		base.__new()
		this.setDefaultGui(dg)
		
	}
	setDefaultGui(guiHwnd:=""){
		if !guiHwnd
			guiHwnd:=this.guiHwnd, dg:=A_DefaultGui
		Gui, % guiHwnd ": Default"
		return dg
	}
	AddInputButton(p*){
		dg:=this.setDefaultGui()
		base.AddInputButton(p*)
		this.setDefaultGui(dg)
	}
	AddControl(p*){
		dg:=this.setDefaultGui()
		base.AddControl(p*)
		this.setDefaultGui(dg)
	}
	show(opt*){
		dg:=this.setDefaultGui()
		Gui, % this.guiHwnd ": Show", % opt[1], opt[2]
		this.setDefaultGui(dg)
	}
}
It would be nice to have a show() method. Eg, myApp.show("w400","Mytitle").
@Distrubution.
I just FileInstall threadScripts.ahk:ed, and compiled, one exe, seems to work fine.
Test example, I took a pretty useless script a made long ago and made gave it gui. I'm very happy with how smooth it went. I have very little experince with compiling ahk scripts, so I share this mostly for the purpose of getting it doesn't work-feedback :lol:
MouseMagnet.rar
Contains MouseMagnet.exe, the exe will extract some images in the A_ScriptDir\images and also the threasScripts.ahk.
(1.81 MiB) Downloaded 195 times
MouseMagnet.ahk
Source, requires AppFactory. Images not included.
(6.07 KiB) Downloaded 192 times

Cheers.
User avatar
evilC
Posts: 4823
Joined: 27 Feb 2014, 12:30

Re: [Library] AppFactory - Custom Hotkey GuiControl + Persistent regular GuiControls

15 Jun 2017, 12:50

You would not want to create a new Gui, because typically you want to inject the controls into the default Gui, but I accept that things were not ideal.
All Gui commands should have the hwnd of the parent prefixed - it's not a problem at load-time, but after load-time, another Gui may be the default one.
It's pretty simple to fix though.
User avatar
evilC
Posts: 4823
Joined: 27 Feb 2014, 12:30

Re: [Library] AppFactory - Custom Hotkey GuiControl + Persistent regular GuiControls

16 Jun 2017, 13:45

Updated to v0.0.2 - Helgef's comments about default GUIs should now be addressed - All commands which operate upon the GUI have had the hwnd of the Gui prefixed.
Also, now the constructor for AppFactory now accepts an optional parameter which can be the HWND to which to add controls.
If none is specified, it uses the default GUI.
Last edited by evilC on 17 Jun 2017, 04:57, edited 1 time in total.
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: [Library] AppFactory - Custom Hotkey GuiControl + Persistent regular GuiControls

17 Jun 2017, 04:09

Also, now the contructor for AppFactory now accepts an optional parameter which can be the HWND to which to add controls.
Very good solution.

Return to “AutoHotkey_H”

Who is online

Users browsing this forum: No registered users and 16 guests