I have run into an issue with UCR, and am not sure how to proceed, so am seeking any advice on how to work around this issue.
The scenario is thus:
Each profile in UCR has it's own "Input thread" that contains all hotkey mappings for that profile. When a profile becomes active, the main thread calls the input thread for the current profile and has it Suspend, On all it's hotkeys, then the main thread calls the input thread for the new active profile and has it Suspend, Off all it's hotkeys. When an input thread's hotkey is triggered, it calls the main thread to have it take the appropriate action.
The problem has arisen when I try to make a plugin that allows you to use a hotkey to change profile.
The below code simulates a setup with two profiles - both profiles are rigged such that F12 changes to the other profile. Each profile is rigged such that F11 produces a beep (To simulate work).
If you spam F11 and F12 simultaneously and rapidly, you can cause the error.
Main thread:
Code: Select all
#SingleInstance force
#Persistent
OutputDebug DBGVIEWCLEAR
global UCR
new MainClass()
return
Class MainClass {
Profiles := {}
CurrentProfile := ""
__New(){
global UCR := this
this.Profiles.Profile1 := new _Profile(this, "Profile1", "Profile2", 1000)
this.Profiles.Profile2 := new _Profile(this, "Profile2", "Profile1", 500)
this.ChangeProfile("Profile1")
}
ChangeProfile(name){
CurrentProfile := this.Profiles[this.CurrentProfile]
if (IsObject(CurrentProfile))
CurrentProfile.DeActivate()
this.CurrentProfile := name
this.Profiles[name].Activate()
}
}
Class _Profile {
__New(parent, name, switchto, beepfreq){
this.Parent := parent
this.Name := name
this.SwitchTo := switchto
this.BeepFreq := beepfreq
this._InputThread := AhkThread(A_ScriptDir "\inputthread.ahk",,1) ; Loads the AutoHotkey module and starts the script.
While !this._InputThread.ahkgetvar.autoexecute_done
Sleep 50 ; wait until variable has been set.
str := "InputThread := new _InputThread(" ObjShare(this.InputEvent.Bind(this)) ", """ this.Name """)"
this._InputThread.ahkExec(str)
}
InputEvent(evt){
OutputDebug, % "Profile " this.Name " InputEvent - " evt
if (evt == 1){
; Simulate some work
SoundBeep % this.BeepFreq, 500
} else {
; Change profile
UCR.ChangeProfile(this.SwitchTo)
}
}
Activate(){
str := "InputThread.SetState(1)"
this._InputThread.ahkExec(str)
}
DeActivate(){
str := "InputThread.SetState(0)"
this._InputThread.ahkExec(str)
}
}
Code: Select all
#Persistent
#NoTrayIcon
#MaxHotkeysPerInterval 9999
autoexecute_done := 1
return
class _InputThread {
__New(CallbackPtr, name){
this.Name := name
this.Callback := ObjShare(CallbackPtr)
this.MasterThread := AhkExported()
}
InputEvent(evt){
this.Callback.Call(evt)
}
Setstate(state){
OutputDebug % "Thread " this.Name " " (state ? "On" : "Off")
if (state){
; Hotkey makes a beep
fn := this.InputEvent.Bind(this, 1)
hotkey, F11, % fn, On
; hotkey switches profile
fn := this.InputEvent.Bind(this, 2)
hotkey, F12, % fn, On
} else {
fn := this.InputEvent.Bind(this, 1)
hotkey, F11, % fn, Off
fn := this.InputEvent.Bind(this, 2)
hotkey, F12, % fn, Off
}
}
}
I guess the problem is to do with the somewhat cyclical nature of the change profile hotkey: The input thread calls the main thread to notify it of hotkey down, the main thread recognizes it as a change profile hotkey and changes the profile, which then notifies the same input thread to turn off it's hotkeys.
However, it seems a little more complicated than that.
Can anyone shed any more light on the subject?