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:
		
							parent
							
								
									2f53c942ac
								
							
						
					
					
						commit
						72f604e819
					
				@ -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)
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										12
									
								
								element.go
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								element.go
									
									
									
									
									
								
							@ -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.
 | 
				
			||||||
 | 
				
			|||||||
@ -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
 | 
				
			||||||
 | 
				
			|||||||
@ -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() {
 | 
				
			||||||
 | 
				
			|||||||
@ -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
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
				
			|||||||
@ -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)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -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
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user