~eliasnaur/gio

b09ef80d9fc13394e5bbf785380586fe688676cb — Chris Waldon 1 year, 6 months ago 107401c
widget: ensure proper modifiers on key events

This commit extends the key event handling for text widgets to always check for
appropriate modifier keys. Previously this wasn't necessary, as the text widgets
would only ever receive key events it registered for, but now it may be the top-level
key event handler and thus receive all key events that aren't handled elsewhere.

Fixes: https://todo.sr.ht/~eliasnaur/gio/487
Signed-off-by: Chris Waldon <christopher.waldon.dev@gmail.com>
2 files changed, 45 insertions(+), 35 deletions(-)

M widget/editor.go
M widget/selectable.go
M widget/editor.go => widget/editor.go +31 -26
@@ 396,6 396,37 @@ func (e *Editor) command(gtx layout.Context, k key.Event) {
	if k.Modifiers.Contain(key.ModShift) {
		selAct = selectionExtend
	}
	if k.Modifiers.Contain(key.ModShortcut) {
		switch k.Name {
		// Initiate a paste operation, by requesting the clipboard contents; other
		// half is in Editor.processKey() under clipboard.Event.
		case "V":
			if !e.ReadOnly {
				clipboard.ReadOp{Tag: &e.eventKey}.Add(gtx.Ops)
			}
		// Copy or Cut selection -- ignored if nothing selected.
		case "C", "X":
			e.scratch = e.text.SelectedText(e.scratch)
			if text := string(e.scratch); text != "" {
				clipboard.WriteOp{Text: text}.Add(gtx.Ops)
				if k.Name == "X" && !e.ReadOnly {
					e.Delete(1)
				}
			}
		// Select all
		case "A":
			e.text.SetCaret(0, e.text.Len())
		case "Z":
			if !e.ReadOnly {
				if k.Modifiers.Contain(key.ModShift) {
					e.redo()
				} else {
					e.undo()
				}
			}
		}
		return
	}
	switch k.Name {
	case key.NameReturn, key.NameEnter:
		if !e.ReadOnly {


@@ 447,32 478,6 @@ func (e *Editor) command(gtx layout.Context, k key.Event) {
		e.text.MoveStart(selAct)
	case key.NameEnd:
		e.text.MoveEnd(selAct)
	// Initiate a paste operation, by requesting the clipboard contents; other
	// half is in Editor.processKey() under clipboard.Event.
	case "V":
		if !e.ReadOnly {
			clipboard.ReadOp{Tag: &e.eventKey}.Add(gtx.Ops)
		}
	// Copy or Cut selection -- ignored if nothing selected.
	case "C", "X":
		e.scratch = e.text.SelectedText(e.scratch)
		if text := string(e.scratch); text != "" {
			clipboard.WriteOp{Text: text}.Add(gtx.Ops)
			if k.Name == "X" && !e.ReadOnly {
				e.Delete(1)
			}
		}
	// Select all
	case "A":
		e.text.SetCaret(0, e.text.Len())
	case "Z":
		if !e.ReadOnly {
			if k.Modifiers.Contain(key.ModShift) {
				e.redo()
			} else {
				e.undo()
			}
		}
	}
}


M widget/selectable.go => widget/selectable.go +14 -9
@@ 296,6 296,20 @@ func (e *Selectable) command(gtx layout.Context, k key.Event) {
	if k.Modifiers.Contain(key.ModShift) {
		selAct = selectionExtend
	}
	if k.Modifiers == key.ModShortcut {
		switch k.Name {
		// Copy or Cut selection -- ignored if nothing selected.
		case "C", "X":
			e.scratch = e.text.SelectedText(e.scratch)
			if text := string(e.scratch); text != "" {
				clipboard.WriteOp{Text: text}.Add(gtx.Ops)
			}
		// Select all
		case "A":
			e.text.SetCaret(0, e.text.Len())
		}
		return
	}
	switch k.Name {
	case key.NameUpArrow:
		e.text.MoveLines(-1, selAct)


@@ 327,15 341,6 @@ func (e *Selectable) command(gtx layout.Context, k key.Event) {
		e.text.MoveStart(selAct)
	case key.NameEnd:
		e.text.MoveEnd(selAct)
	// Copy or Cut selection -- ignored if nothing selected.
	case "C", "X":
		e.scratch = e.text.SelectedText(e.scratch)
		if text := string(e.scratch); text != "" {
			clipboard.WriteOp{Text: text}.Add(gtx.Ops)
		}
	// Select all
	case "A":
		e.text.SetCaret(0, e.text.Len())
	}
}