I am trying to toggle a key with modifiers using robotgo. The function I am calling is KeyToggle; for me takes something like robotgo.KeyToggle(“a”, “up”, “alt”, “cmd”).
I have the code below that compiles and builds an array of strings, but I don’t know how to expand this in Go - I have tried using slices (as shown) but that fails at runtime. My previous approach was to call KeyToggle for each of the modifiers separately, but this is unreliable in applying the modifers
I’m hoping I’m missing some obvious way to do this. I might otherwise need to unpack the array or rely on KeyToggle allowing for empty strings which seems a dangerous approach.
Thank you in advance - Andy
func press_release(key keyJSON) {
modifiers := []string{}
if key.Shift {
modifiers = append(modifiers, "shift")
}
if key.Ctrl {
modifiers = append(modifiers, "ctrl")
}
if key.Alt {
modifiers = append(modifiers, "alt")
}
state := "up"
if key.Press {
state = "down"
}
robotgo.KeyToggle(key.Key, state, modifiers[:])
}
I don’t really see a problem with your code. Is it that you are trying to reduce the repetitive nature of your if key.Shift { checks? You could use reflection here. Something like this:
type keyJSON struct {
Key string
Shift bool `key:"shift"`
Ctrl bool `key:"ctrl"`
Alt bool `key:"alt"`
Press bool
}
func (k keyJSON) toKeyArgs() []string {
// We will build up a list of modifiers based on our struct values
modifiers := []string{}
// Get the type and value of the instance
v := reflect.ValueOf(k)
t := v.Type()
// Iterate over all available fields
for i := 0; i < t.NumField(); i++ {
// Get the field type info (for name and tag)
fieldType := t.Field(i)
// Get the field value info (for IsZero check)
fieldValue := v.Field(i)
// Check for the existence of our "key" tag
keyTag := fieldType.Tag.Get("key")
// Check if the field's value is its zero value
isZero := fieldValue.IsZero()
// We have a non-zero value and a key tag so add to our modifiers
if !isZero && len(keyTag) > 0 {
modifiers = append(modifiers, keyTag)
}
}
return modifiers
}
Sorry - I have obviously been unclear - I was trying to pass the arguments to KeyToggle in one go.
i.e. Robotgo allows this call KeyToggle('tab', 'down', 'alt') - and this will press the target and modifier virtual keys in the right order, in one call. Also ‘up’ could be passed to release in the right order.
My current working solution instead calls KeyToggle multiple times - in a different order based on whether ‘down’ or ‘up’ is passed. So the modifier keys (e.g. ‘alt’) are pressed down before the target key, or released ‘up’ after the target key is released.
But I don’t know how to get Go to compile the request to KeyToggle('tab', 'down', modifiers), where modifiers can be 0 to 3 strings.
Unfortunately I can’t change the KeyToggle parameters - they are in an external package with signature of func robotgo.KeyToggle(key string, args ...interface{}) error
Below is a compiling version that runs then throws interface conversion: interface {} is []string, not string, i.e. it’s expecting a string not []string. I’m not even sure this should compile?!
I think I’m going to have to give up on this and use my less simple way - since that actually works
Thank you for the feedback - Andy
func press_release(key keyJSON) {
state := "up"
if key.Press { // press modifiers before pressing key
state = "down"
}
modifiers := []string{}
modifiers = append(modifiers, state)
if key.Shift {
modifiers = append(modifiers, "shift")
}
if key.Ctrl {
modifiers = append(modifiers, "ctrl")
}
if key.Alt {
modifiers = append(modifiers, "alt")
}
robotgo.KeyToggle(key.Key, modifiers)
}
I solved it - by using any (interface{}) instead of string - also had to take a slice and pass that expanded - there’s a Go playground sample here Go Playground - The Go Programming Language and my code below.
func press_release(key keyJSON) {
modifiers := []any{} // REPLACED STRING
state := "up"
if key.Press {
state = "down"
}
modifiers = append(modifiers, state)
if key.Shift {
modifiers = append(modifiers, "shift")
}
if key.Ctrl {
modifiers = append(modifiers, "ctrl")
}
if key.Alt {
modifiers = append(modifiers, "alt")
}
robotgo.KeyToggle(key.Key, modifiers[:]...) // USING SLICE EXPANDED
}
Thank you for all the feedback - I would have given up otherwise - Andy