// keyResponse translates key board input into two different actions: canceling // the current prompt and making a choice in the cycle prompt. // Canceling a prompt corresponds to the "CycleConfig.CancelKey" being pressed. // Making a choice in the cycle prompt corresponds to releasing all of the // modifiers used to initiate showing the prompt (when "CycleConfig.AutoChoose" // is true). // If CancelKey is empty, then no cancel key functionality is provided. // If AutoChoose is false, then releasing the modifiers will have no effect. // // For thos interested in the X details: // The prompt cycle dialog needs to choose the selection when the // modifiers (i.e., "alt" in "alt-tab") are released. // The only way to do this (generally) is to check the raw KeyRelease event. // Namely, if the keycode *released* is a modifier, we have to and-out // that modifier from the key release event data. If the modifiers // remaining aren't up to snuff with the original grabbed modifiers, // then we can finally "choose" the selection. // TL;DR - This is how we "exit" the prompt cycle dialog. func (cycle *Cycle) keyResponse() xevent.KeyReleaseFun { f := func(X *xgbutil.XUtil, ev xevent.KeyReleaseEvent) { if !cycle.showing { return } mods, kc := keybind.DeduceKeyInfo(ev.State, ev.Detail) // If the key release is the cancel key, quit the prompt and // don't do anything. if keybind.KeyMatch(X, cycle.config.CancelKey, mods, kc) { cycle.Hide() return } mods &= ^keybind.ModGet(X, ev.Detail) if cycle.grabMods > 0 { if mods&cycle.grabMods == 0 { cycle.Choose() } } else { if keybind.KeyMatch(X, cycle.config.ConfirmKey, mods, kc) { cycle.Choose() } } } return xevent.KeyReleaseFun(f) }
func (ct *CommandTray) keyPress() xevent.KeyPressFun { f := func(X *xgbutil.XUtil, ev xevent.KeyPressEvent) { // print("Cake:\n") if !ct.is_focused { // print("Boom\n") return } mods, kc := keybind.DeduceKeyInfo(ev.State, ev.Detail) // print("Key Press:", mods, kc, "\n") switch { case keybind.KeyMatch(X, "Escape", mods, kc): ct.Blur() case keybind.KeyMatch(X, "Return", mods, kc): ct.activate() case keybind.KeyMatch(X, "Up", mods, kc): ct.selected -= 1 if ct.selected < 0 { ct.selected = len(ct.cmds) } ct.Draw() case keybind.KeyMatch(X, "Down", mods, kc): if len(ct.cmds) > 0 { ct.selected += 1 ct.selected %= len(ct.cmds) ct.Draw() } case keybind.KeyMatch(X, "BackSpace", mods, kc): if len(ct.input) > 0 { ct.input = ct.input[:len(ct.input)-1] ct.getCommands() ct.Draw() } default: s := keybind.LookupString(X, mods, kc) if len(s) == 1 { ct.input = append(ct.input, rune(strings.ToLower(s)[0])) ct.selected = 0 ct.getCommands() ct.Draw() } } } return xevent.KeyPressFun(f) }
func (slct *Select) keyResponse() xevent.KeyPressFun { f := func(X *xgbutil.XUtil, ev xevent.KeyPressEvent) { if !slct.showing { return } beforeLen := len(slct.input.Text) mods, kc := keybind.DeduceKeyInfo(ev.State, ev.Detail) slct.input.Add(mods, kc) switch { case keybind.KeyMatch(X, slct.config.BackspaceKey, mods, kc): slct.input.Remove() case keybind.KeyMatch(X, slct.config.CancelKey, mods, kc): slct.Hide() return case keybind.KeyMatch(X, slct.config.ConfirmKey, mods, kc): if slct.selected >= 0 && slct.selected < len(slct.items) { slct.items[slct.selected].choose() slct.Hide() } else if len(slct.items) == 1 { slct.items[0].choose() slct.Hide() } return case keybind.KeyMatch(X, "Tab", mods, kc) || keybind.KeyMatch(X, "ISO_Left_Tab", mods, kc): if len(slct.items) == 0 { break } if mods&xproto.ModMaskShift > 0 { if slct.selected == -1 { slct.selected++ } slct.selected = misc.Mod(slct.selected-1, len(slct.items)) } else { slct.selected = misc.Mod(slct.selected+1, len(slct.items)) } slct.highlight() } // If the length of the input changed, then re-evaluate completion if beforeLen != len(slct.input.Text) { slct.FilterItems(string(slct.input.Text)) slct.selected = -1 slct.highlight() } } return xevent.KeyPressFun(f) }
func (msg *Message) keyResponse() xevent.KeyPressFun { f := func(X *xgbutil.XUtil, ev xevent.KeyPressEvent) { if !msg.showing { return } mods, kc := keybind.DeduceKeyInfo(ev.State, ev.Detail) switch { case keybind.KeyMatch(X, msg.config.ConfirmKey, mods, kc): fallthrough case keybind.KeyMatch(X, msg.config.CancelKey, mods, kc): msg.Hide() } } return xevent.KeyPressFun(f) }
func (inp *Input) keyResponse() xevent.KeyPressFun { f := func(X *xgbutil.XUtil, ev xevent.KeyPressEvent) { if !inp.showing { return } mods, kc := keybind.DeduceKeyInfo(ev.State, ev.Detail) switch { case keybind.KeyMatch(X, "Up", mods, kc): if inp.historyIndex > 0 { inp.historyIndex-- inp.input.SetString(inp.history[inp.historyIndex]) } case keybind.KeyMatch(X, "Down", mods, kc): if inp.historyIndex < len(inp.history) { inp.historyIndex++ if inp.historyIndex < len(inp.history) { inp.input.SetString(inp.history[inp.historyIndex]) } else { inp.input.Reset() } } case keybind.KeyMatch(X, inp.config.BackspaceKey, mods, kc): inp.input.Remove() case keybind.KeyMatch(X, inp.config.ConfirmKey, mods, kc): if inp.do != nil { s := string(inp.input.Text) histLen := len(inp.history) // Don't added repeated entries. if histLen == 0 || s != inp.history[histLen-1] { inp.history = append(inp.history, s) } inp.do(inp, s) } case keybind.KeyMatch(X, inp.config.CancelKey, mods, kc): if inp.canceled != nil { inp.canceled(inp) } inp.Hide() default: inp.input.Add(mods, kc) } } return xevent.KeyPressFun(f) }
func newKeycodeInfo(shortcut string) (KeycodeInfo, bool) { if len(shortcut) < 1 { return KeycodeInfo{}, false } shortcut = convertKeysym2Weird(shortcut) mod, keys, err := keybind.ParseString(X, shortcut) if err != nil { logger.Warningf("newKeycodeInfo parse '%s' failed: %v", shortcut, err) return KeycodeInfo{}, false } if len(keys) < 1 { logger.Warningf("'%s' no details", shortcut) return KeycodeInfo{}, false } state, detail := keybind.DeduceKeyInfo(mod, keys[0]) return KeycodeInfo{State: state, Detail: detail}, true }