diff --git a/client/client.go b/client/client.go index 1409d31..2ff0312 100644 --- a/client/client.go +++ b/client/client.go @@ -7,6 +7,8 @@ import ( "github.com/alex11br/gxhk/common" ) +// Just SendCommand, let the daemon do the heavy work, and get through the socket +// the readily formated response that you'll simply return. func SendCommand(args common.Args) (res common.Response) { conn, err := net.Dial("unix", args.SocketPath) if err != nil { diff --git a/common/response.go b/common/response.go index 33bcd5b..e4e0238 100644 --- a/common/response.go +++ b/common/response.go @@ -1,5 +1,8 @@ package common +// The Response stores the response which gets displayed. +// WARNING: Make sure that yout Message doesn't end in a newline!!! +// That's beacuse the client will display a newline after the Message. type Response struct { Status int Message string diff --git a/daemon/commands.go b/daemon/commands.go index 23e7f14..e3c10fd 100644 --- a/daemon/commands.go +++ b/daemon/commands.go @@ -7,10 +7,14 @@ import ( "github.com/alex11br/gxhk/common" ) +// Exec executes the given sh command string. This method is blocking. func Exec(command string) { exec.Command("sh", "-c", command).Run() } +// MakeDescription handles the logic behind generating a dummy description for the commands +// which don't come with a description (i.e. it is empty) from the command string, +// or returning the description if it isn't empty func MakeDescription(description string, command string) string { if description != "" { return description @@ -19,6 +23,8 @@ func MakeDescription(description string, command string) string { } } +// AddEventInfo handles the logic behind creating a new line and filling it +// with the infos necessary for the 'info' command for each bound hotkey func AddEventInfo(infos *string, hotkey string, eventName string, description string) { if *infos != "" { *infos += "\n" @@ -26,12 +32,16 @@ func AddEventInfo(infos *string, hotkey string, eventName string, description st *infos += fmt.Sprintf("On %s %s: %s", hotkey, eventName, description) } +// Bind does the heavy work of binding a hotkey (plus its eventual sisters) to a command. func Bind(bindArgs common.BindCmd) error { - hotkeys, err := HotkeyFromStr(bindArgs.Hotkey) + // First, we find the Hotkey's that correspond to the given hotkey string. + hotkeys, err := HotkeysFromStr(bindArgs.Hotkey) if err != nil { return err } + // Then, grab the matching keys which haven't been grabbed yet (i.e. those without commands). + // If any of these new keys fail to grab, we ungrab what we got to grab before and leave. newlyBound := make([]Hotkey, 0) for _, hotkey := range hotkeys { if KeyPressCommands.IsEmpty(hotkey) && KeyReleaseCommands.IsEmpty(hotkey) { @@ -47,6 +57,13 @@ func Bind(bindArgs common.BindCmd) error { } } + // Now we'll set all the appropiate values in the necessary places + // to successfully bind the hotkeys. + // It is worth noting that if there are multiple hotkeys for the same string, + // in the 'info' command only one of them should provide descriptions. As such: + // CONVENTION: Empty description of a Hotkey (description == "") MEANS ignore that Hotkey!!! + // We'll put a non-empty description for the first matching Hotkey (refer to MakeDescription) + // and for any eventual ones an empty description for i, hotkey := range hotkeys { var description string if i == 0 { @@ -67,8 +84,10 @@ func Bind(bindArgs common.BindCmd) error { return nil } +// Unbind does the not-so-heavy work of unbinding a hotkey (plus its eventual sisters), +// which consists in ungrabbing the keys, and deleting the keys in the HotkeyMap's func Unbind(unbindArgs common.UnbindCmd) error { - hotkeys, err := HotkeyFromStr(unbindArgs.Hotkey) + hotkeys, err := HotkeysFromStr(unbindArgs.Hotkey) if err != nil { return err } @@ -90,8 +109,13 @@ func Unbind(unbindArgs common.UnbindCmd) error { return nil } +// GetInfo returns the information about what is bound to the given hotkeyStr. +// It returns a Response structure to easily accomodate the need to mention +// parsing errors if the hotkeyStr is "naughty". +// The first Hotkey to be parsed should be the main one, +// which represents our needed description in the description maps. func GetInfo(hotkeyStr string) (res common.Response) { - hotkeys, err := HotkeyFromStr(hotkeyStr) + hotkeys, err := HotkeysFromStr(hotkeyStr) if err != nil { return common.Response{ Status: 1, @@ -113,6 +137,8 @@ func GetInfo(hotkeyStr string) (res common.Response) { return } +// GetAllInfo creates a string with all the bound hotkeys there are, +// both those bound on press and those bound on release. func GetAllInfo() (info string) { KeyPressDescriptions.ForEach(func(hotkey Hotkey, description string) { if description != "" { diff --git a/daemon/hotkeys.go b/daemon/hotkeys.go index 3af8963..ca4f69e 100644 --- a/daemon/hotkeys.go +++ b/daemon/hotkeys.go @@ -15,9 +15,12 @@ type Hotkey struct { key xproto.Keycode } -var NilHotkey Hotkey = Hotkey{0, 0} - -func HotkeyFromStr(str string) (hotkeys []Hotkey, err error) { +// HotkeysFromStr parses a hotkey string and returns the according Hotkey's. +// Mods are unambiguous (though we ignore here the Num and Caps Lock). +// Keycodes aren't, though. For instance, on some layouts, there are 2 keys with different keycodes +// which map to 'backslash' AKA '\'. And we want to handle them both. +// This is why we return an array of Hotkey's here. And an error if the string is "naughty". +func HotkeysFromStr(str string) (hotkeys []Hotkey, err error) { mods, keys, err := keybind.ParseString(X, str) if err != nil { return nil, err @@ -33,6 +36,8 @@ func HotkeyFromStr(str string) (hotkeys []Hotkey, err error) { return } +// ToStr converts the Hotkey into its string representation. +// This helps us show in a human-firendly way the bound hotkeys in the 'info' command. func (h Hotkey) ToStr() (str string) { str = keybind.ModifierString(h.mods) if str != "" {