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.
This commit is contained in:
Sasha Koshka 2023-01-20 17:40:28 -05:00
parent 2f53c942ac
commit 72f604e819
7 changed files with 56 additions and 64 deletions

View File

@ -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 ( func (window *Window) handleKeyPress (
connection *xgbutil.XUtil, connection *xgbutil.XUtil,
event xevent.KeyPressEvent, event xevent.KeyPressEvent,
@ -75,17 +92,8 @@ func (window *Window) handleKeyPress (
keyEvent := *event.KeyPressEvent keyEvent := *event.KeyPressEvent
key, numberPad := window.backend.keycodeToKey(keyEvent.Detail, keyEvent.State) key, numberPad := window.backend.keycodeToKey(keyEvent.Detail, keyEvent.State)
modifiers := tomo.Modifiers { modifiers := window.modifiersFromState(keyEvent.State)
Shift: modifiers.NumberPad = numberPad
(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,
}
if key == tomo.KeyTab && modifiers.Alt { if key == tomo.KeyTab && modifiers.Alt {
if child, ok := window.child.(tomo.Selectable); ok { 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 { } else if child, ok := window.child.(tomo.KeyboardTarget); ok {
// FIXME: pass correct value for repeated child.HandleKeyDown(key, modifiers)
child.HandleKeyDown(key, modifiers, false)
} }
} }
@ -111,18 +118,27 @@ func (window *Window) handleKeyRelease (
if window.child == nil { return } if window.child == nil { return }
keyEvent := *event.KeyReleaseEvent keyEvent := *event.KeyReleaseEvent
key, numberPad := window.backend.keycodeToKey(keyEvent.Detail, keyEvent.State)
modifiers := tomo.Modifiers { // do not process this event if it was generated from a key repeat
Shift: nextEvents := xevent.Peek(window.backend.connection)
(keyEvent.State & xproto.ModMaskShift) > 0 || if len(nextEvents) > 0 {
(keyEvent.State & window.backend.modifierMasks.shiftLock) > 0, untypedEvent := nextEvents[0]
Control: (keyEvent.State & xproto.ModMaskControl) > 0, if untypedEvent.Err == nil {
Alt: (keyEvent.State & window.backend.modifierMasks.alt) > 0, typedEvent, ok :=
Meta: (keyEvent.State & window.backend.modifierMasks.meta) > 0, untypedEvent.Event.(xproto.KeyReleaseEvent)
Super: (keyEvent.State & window.backend.modifierMasks.super) > 0,
Hyper: (keyEvent.State & window.backend.modifierMasks.hyper) > 0, if ok && typedEvent.Detail == keyEvent.Detail &&
NumberPad: numberPad, 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 { if child, ok := window.child.(tomo.KeyboardTarget); ok {
child.HandleKeyUp(key, modifiers) child.HandleKeyUp(key, modifiers)

View File

@ -86,12 +86,12 @@ type Selectable interface {
type KeyboardTarget interface { type KeyboardTarget interface {
Element Element
// HandleKeyDown is called when a key is pressed down while this element // HandleKeyDown is called when a key is pressed down or repeated while
// has keyboard focus. It is important to note that not every key down // this element has keyboard focus. It is important to note that not
// event is guaranteed to be paired with exactly one key up event. This // every key down event is guaranteed to be paired with exactly one key
// is the reason a list of modifier keys held down at the time of the // up event. This is the reason a list of modifier keys held down at the
// key press is given. // time of the key press is given.
HandleKeyDown (key Key, modifiers Modifiers, repeated bool) HandleKeyDown (key Key, modifiers Modifiers)
// HandleKeyUp is called when a key is released while this element has // HandleKeyUp is called when a key is released while this element has
// keyboard focus. // keyboard focus.

View File

@ -68,11 +68,7 @@ func (element *Button) HandleMouseUp (x, y int, button tomo.Button) {
func (element *Button) HandleMouseMove (x, y int) { } func (element *Button) HandleMouseMove (x, y int) { }
func (element *Button) HandleMouseScroll (x, y int, deltaX, deltaY float64) { } func (element *Button) HandleMouseScroll (x, y int, deltaX, deltaY float64) { }
func (element *Button) HandleKeyDown ( func (element *Button) HandleKeyDown (key tomo.Key, modifiers tomo.Modifiers) {
key tomo.Key,
modifiers tomo.Modifiers,
repeated bool,
) {
if !element.enabled { return } if !element.enabled { return }
if key == tomo.KeyEnter { if key == tomo.KeyEnter {
element.pressed = true element.pressed = true

View File

@ -70,11 +70,7 @@ func (element *Checkbox) HandleMouseUp (x, y int, button tomo.Button) {
func (element *Checkbox) HandleMouseMove (x, y int) { } func (element *Checkbox) HandleMouseMove (x, y int) { }
func (element *Checkbox) HandleMouseScroll (x, y int, deltaX, deltaY float64) { } func (element *Checkbox) HandleMouseScroll (x, y int, deltaX, deltaY float64) { }
func (element *Checkbox) HandleKeyDown ( func (element *Checkbox) HandleKeyDown (key tomo.Key, modifiers tomo.Modifiers) {
key tomo.Key,
modifiers tomo.Modifiers,
repeated bool,
) {
if key == tomo.KeyEnter { if key == tomo.KeyEnter {
element.pressed = true element.pressed = true
if element.core.HasImage() { if element.core.HasImage() {

View File

@ -235,15 +235,11 @@ func (element *Container) HandleMouseScroll (x, y int, deltaX, deltaY float64) {
child.HandleMouseScroll(x - childPosition.X, y - childPosition.Y, deltaX, deltaY) child.HandleMouseScroll(x - childPosition.X, y - childPosition.Y, deltaX, deltaY)
} }
func (element *Container) HandleKeyDown ( func (element *Container) HandleKeyDown (key tomo.Key, modifiers tomo.Modifiers) {
key tomo.Key,
modifiers tomo.Modifiers,
repeated bool,
) {
element.forSelected (func (child tomo.Selectable) bool { element.forSelected (func (child tomo.Selectable) bool {
child0, handlesKeyboard := child.(tomo.KeyboardTarget) child0, handlesKeyboard := child.(tomo.KeyboardTarget)
if handlesKeyboard { if handlesKeyboard {
child0.HandleKeyDown(key, modifiers, repeated) child0.HandleKeyDown(key, modifiers)
} }
return true return true
}) })

View File

@ -93,13 +93,9 @@ func (element *ScrollContainer) Adopt (child tomo.Scrollable) {
} }
} }
func (element *ScrollContainer) HandleKeyDown ( func (element *ScrollContainer) HandleKeyDown (key tomo.Key, modifiers tomo.Modifiers) {
key tomo.Key,
modifiers tomo.Modifiers,
repeated bool,
) {
if child, ok := element.child.(tomo.KeyboardTarget); ok { if child, ok := element.child.(tomo.KeyboardTarget); ok {
child.HandleKeyDown(key, modifiers, repeated) child.HandleKeyDown(key, modifiers)
} }
} }

View File

@ -23,7 +23,7 @@ type TextBox struct {
placeholderDrawer artist.TextDrawer placeholderDrawer artist.TextDrawer
valueDrawer 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 () onChange func ()
onSelectionRequest func () (granted bool) onSelectionRequest func () (granted bool)
onSelectionMotionRequest func (tomo.SelectionDirection) (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) HandleMouseMove (x, y int) { }
func (element *TextBox) HandleMouseScroll (x, y int, deltaX, deltaY float64) { } func (element *TextBox) HandleMouseScroll (x, y int, deltaX, deltaY float64) { }
func (element *TextBox) HandleKeyDown ( func (element *TextBox) HandleKeyDown(key tomo.Key, modifiers tomo.Modifiers) {
key tomo.Key, if element.onKeyDown != nil && element.onKeyDown(key, modifiers) {
modifiers tomo.Modifiers,
repeated bool,
) {
if element.onKeyDown != nil && element.onKeyDown(key, modifiers, repeated) {
return return
} }
@ -232,11 +228,7 @@ func (element *TextBox) Filled () (filled bool) {
} }
func (element *TextBox) OnKeyDown ( func (element *TextBox) OnKeyDown (
callback func ( callback func (key tomo.Key, modifiers tomo.Modifiers) (handled bool),
key tomo.Key, modifiers tomo.Modifiers, repeated bool,
) (
handled bool,
),
) { ) {
element.onKeyDown = callback element.onKeyDown = callback
} }