From 72f604e8199ce9d8997975befe5a7f19fdeba79c Mon Sep 17 00:00:00 2001 From: Sasha Koshka Date: Fri, 20 Jan 2023 17:40:28 -0500 Subject: [PATCH] Repeated keys are detected properly The repeated bool was removed and instead key release events are *only* sent when the key is actually let go. If an element wants to listen to repeat presses, it can just listen to press events. --- backends/x/event.go | 64 +++++++++++++++++++------------ element.go | 12 +++--- elements/basic/button.go | 6 +-- elements/basic/checkbox.go | 6 +-- elements/basic/container.go | 8 +--- elements/basic/scrollcontainer.go | 8 +--- elements/basic/textbox.go | 16 ++------ 7 files changed, 56 insertions(+), 64 deletions(-) diff --git a/backends/x/event.go b/backends/x/event.go index 271e744..d4e7017 100644 --- a/backends/x/event.go +++ b/backends/x/event.go @@ -67,6 +67,23 @@ func (window *Window) handleConfigureNotify ( } } +func (window *Window) modifiersFromState ( + state uint16, +) ( + modifiers tomo.Modifiers, +) { + return tomo.Modifiers { + Shift: + (state & xproto.ModMaskShift) > 0 || + (state & window.backend.modifierMasks.shiftLock) > 0, + Control: (state & xproto.ModMaskControl) > 0, + Alt: (state & window.backend.modifierMasks.alt) > 0, + Meta: (state & window.backend.modifierMasks.meta) > 0, + Super: (state & window.backend.modifierMasks.super) > 0, + Hyper: (state & window.backend.modifierMasks.hyper) > 0, + } +} + func (window *Window) handleKeyPress ( connection *xgbutil.XUtil, event xevent.KeyPressEvent, @@ -75,17 +92,8 @@ func (window *Window) handleKeyPress ( keyEvent := *event.KeyPressEvent key, numberPad := window.backend.keycodeToKey(keyEvent.Detail, keyEvent.State) - modifiers := tomo.Modifiers { - Shift: - (keyEvent.State & xproto.ModMaskShift) > 0 || - (keyEvent.State & window.backend.modifierMasks.shiftLock) > 0, - Control: (keyEvent.State & xproto.ModMaskControl) > 0, - Alt: (keyEvent.State & window.backend.modifierMasks.alt) > 0, - Meta: (keyEvent.State & window.backend.modifierMasks.meta) > 0, - Super: (keyEvent.State & window.backend.modifierMasks.super) > 0, - Hyper: (keyEvent.State & window.backend.modifierMasks.hyper) > 0, - NumberPad: numberPad, - } + modifiers := window.modifiersFromState(keyEvent.State) + modifiers.NumberPad = numberPad if key == tomo.KeyTab && modifiers.Alt { if child, ok := window.child.(tomo.Selectable); ok { @@ -99,8 +107,7 @@ func (window *Window) handleKeyPress ( } } } else if child, ok := window.child.(tomo.KeyboardTarget); ok { - // FIXME: pass correct value for repeated - child.HandleKeyDown(key, modifiers, false) + child.HandleKeyDown(key, modifiers) } } @@ -111,19 +118,28 @@ func (window *Window) handleKeyRelease ( if window.child == nil { return } keyEvent := *event.KeyReleaseEvent - key, numberPad := window.backend.keycodeToKey(keyEvent.Detail, keyEvent.State) - modifiers := tomo.Modifiers { - Shift: - (keyEvent.State & xproto.ModMaskShift) > 0 || - (keyEvent.State & window.backend.modifierMasks.shiftLock) > 0, - Control: (keyEvent.State & xproto.ModMaskControl) > 0, - Alt: (keyEvent.State & window.backend.modifierMasks.alt) > 0, - Meta: (keyEvent.State & window.backend.modifierMasks.meta) > 0, - Super: (keyEvent.State & window.backend.modifierMasks.super) > 0, - Hyper: (keyEvent.State & window.backend.modifierMasks.hyper) > 0, - NumberPad: numberPad, + + // do not process this event if it was generated from a key repeat + nextEvents := xevent.Peek(window.backend.connection) + if len(nextEvents) > 0 { + untypedEvent := nextEvents[0] + if untypedEvent.Err == nil { + typedEvent, ok := + untypedEvent.Event.(xproto.KeyReleaseEvent) + + if ok && typedEvent.Detail == keyEvent.Detail && + typedEvent.Event == keyEvent.Event && + typedEvent.State == keyEvent.State { + + return + } + } } + key, numberPad := window.backend.keycodeToKey(keyEvent.Detail, keyEvent.State) + modifiers := window.modifiersFromState(keyEvent.State) + modifiers.NumberPad = numberPad + if child, ok := window.child.(tomo.KeyboardTarget); ok { child.HandleKeyUp(key, modifiers) } diff --git a/element.go b/element.go index 390e451..cc932f9 100644 --- a/element.go +++ b/element.go @@ -86,12 +86,12 @@ type Selectable interface { type KeyboardTarget interface { Element - // HandleKeyDown is called when a key is pressed down while this element - // has keyboard focus. It is important to note that not every key down - // event is guaranteed to be paired with exactly one key up event. This - // is the reason a list of modifier keys held down at the time of the - // key press is given. - HandleKeyDown (key Key, modifiers Modifiers, repeated bool) + // HandleKeyDown is called when a key is pressed down or repeated while + // this element has keyboard focus. It is important to note that not + // every key down event is guaranteed to be paired with exactly one key + // up event. This is the reason a list of modifier keys held down at the + // time of the key press is given. + HandleKeyDown (key Key, modifiers Modifiers) // HandleKeyUp is called when a key is released while this element has // keyboard focus. diff --git a/elements/basic/button.go b/elements/basic/button.go index 06c7edd..b028c09 100644 --- a/elements/basic/button.go +++ b/elements/basic/button.go @@ -68,11 +68,7 @@ func (element *Button) HandleMouseUp (x, y int, button tomo.Button) { func (element *Button) HandleMouseMove (x, y int) { } func (element *Button) HandleMouseScroll (x, y int, deltaX, deltaY float64) { } -func (element *Button) HandleKeyDown ( - key tomo.Key, - modifiers tomo.Modifiers, - repeated bool, -) { +func (element *Button) HandleKeyDown (key tomo.Key, modifiers tomo.Modifiers) { if !element.enabled { return } if key == tomo.KeyEnter { element.pressed = true diff --git a/elements/basic/checkbox.go b/elements/basic/checkbox.go index 94ae92b..ad45b20 100644 --- a/elements/basic/checkbox.go +++ b/elements/basic/checkbox.go @@ -70,11 +70,7 @@ func (element *Checkbox) HandleMouseUp (x, y int, button tomo.Button) { func (element *Checkbox) HandleMouseMove (x, y int) { } func (element *Checkbox) HandleMouseScroll (x, y int, deltaX, deltaY float64) { } -func (element *Checkbox) HandleKeyDown ( - key tomo.Key, - modifiers tomo.Modifiers, - repeated bool, -) { +func (element *Checkbox) HandleKeyDown (key tomo.Key, modifiers tomo.Modifiers) { if key == tomo.KeyEnter { element.pressed = true if element.core.HasImage() { diff --git a/elements/basic/container.go b/elements/basic/container.go index f494192..2466e54 100644 --- a/elements/basic/container.go +++ b/elements/basic/container.go @@ -235,15 +235,11 @@ func (element *Container) HandleMouseScroll (x, y int, deltaX, deltaY float64) { child.HandleMouseScroll(x - childPosition.X, y - childPosition.Y, deltaX, deltaY) } -func (element *Container) HandleKeyDown ( - key tomo.Key, - modifiers tomo.Modifiers, - repeated bool, -) { +func (element *Container) HandleKeyDown (key tomo.Key, modifiers tomo.Modifiers) { element.forSelected (func (child tomo.Selectable) bool { child0, handlesKeyboard := child.(tomo.KeyboardTarget) if handlesKeyboard { - child0.HandleKeyDown(key, modifiers, repeated) + child0.HandleKeyDown(key, modifiers) } return true }) diff --git a/elements/basic/scrollcontainer.go b/elements/basic/scrollcontainer.go index 24793f7..ed36572 100644 --- a/elements/basic/scrollcontainer.go +++ b/elements/basic/scrollcontainer.go @@ -93,13 +93,9 @@ func (element *ScrollContainer) Adopt (child tomo.Scrollable) { } } -func (element *ScrollContainer) HandleKeyDown ( - key tomo.Key, - modifiers tomo.Modifiers, - repeated bool, -) { +func (element *ScrollContainer) HandleKeyDown (key tomo.Key, modifiers tomo.Modifiers) { if child, ok := element.child.(tomo.KeyboardTarget); ok { - child.HandleKeyDown(key, modifiers, repeated) + child.HandleKeyDown(key, modifiers) } } diff --git a/elements/basic/textbox.go b/elements/basic/textbox.go index e7c041d..f3d3854 100644 --- a/elements/basic/textbox.go +++ b/elements/basic/textbox.go @@ -23,7 +23,7 @@ type TextBox struct { placeholderDrawer artist.TextDrawer valueDrawer artist.TextDrawer - onKeyDown func (tomo.Key, tomo.Modifiers, bool) (bool) + onKeyDown func (key tomo.Key, modifiers tomo.Modifiers) (handled bool) onChange func () onSelectionRequest func () (granted bool) onSelectionMotionRequest func (tomo.SelectionDirection) (granted bool) @@ -63,12 +63,8 @@ func (element *TextBox) HandleMouseUp (x, y int, button tomo.Button) { } func (element *TextBox) HandleMouseMove (x, y int) { } func (element *TextBox) HandleMouseScroll (x, y int, deltaX, deltaY float64) { } -func (element *TextBox) HandleKeyDown ( - key tomo.Key, - modifiers tomo.Modifiers, - repeated bool, -) { - if element.onKeyDown != nil && element.onKeyDown(key, modifiers, repeated) { +func (element *TextBox) HandleKeyDown(key tomo.Key, modifiers tomo.Modifiers) { + if element.onKeyDown != nil && element.onKeyDown(key, modifiers) { return } @@ -232,11 +228,7 @@ func (element *TextBox) Filled () (filled bool) { } func (element *TextBox) OnKeyDown ( - callback func ( - key tomo.Key, modifiers tomo.Modifiers, repeated bool, - ) ( - handled bool, - ), + callback func (key tomo.Key, modifiers tomo.Modifiers) (handled bool), ) { element.onKeyDown = callback }