From b09ef80d9fc13394e5bbf785380586fe688676cb Mon Sep 17 00:00:00 2001 From: Chris Waldon Date: Mon, 13 Mar 2023 10:13:40 -0400 Subject: [PATCH] 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 --- widget/editor.go | 57 ++++++++++++++++++++++++-------------------- widget/selectable.go | 23 +++++++++++------- 2 files changed, 45 insertions(+), 35 deletions(-) diff --git a/widget/editor.go b/widget/editor.go index 39237dbf..a05c3ce7 100644 --- a/widget/editor.go +++ b/widget/editor.go @@ -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() - } - } } } diff --git a/widget/selectable.go b/widget/selectable.go index 8af50c2c..162156a2 100644 --- a/widget/selectable.go +++ b/widget/selectable.go @@ -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()) } }