key.go raw

   1  // SPDX-License-Identifier: Unlicense OR MIT
   2  
   3  /*
   4  Package key implements key and text events and operations.
   5  
   6  The InputOp operations is used for declaring key input handlers. Use
   7  an implementation of the Queue interface from package ui to receive
   8  events.
   9  */
  10  package key
  11  
  12  import (
  13  	"fmt"
  14  	"strings"
  15  
  16  	"github.com/p9c/p9/pkg/gel/gio/internal/opconst"
  17  	"github.com/p9c/p9/pkg/gel/gio/io/event"
  18  	"github.com/p9c/p9/pkg/gel/gio/op"
  19  )
  20  
  21  // InputOp declares a handler ready for key events.
  22  // Key events are in general only delivered to the
  23  // focused key handler.
  24  type InputOp struct {
  25  	Tag event.Tag
  26  }
  27  
  28  // SoftKeyboardOp shows or hide the on-screen keyboard, if available.
  29  // It replaces any previous SoftKeyboardOp.
  30  type SoftKeyboardOp struct {
  31  	Show bool
  32  }
  33  
  34  // FocusOp sets or clears the keyboard focus. It replaces any previous
  35  // FocusOp in the same frame.
  36  type FocusOp struct {
  37  	// Tag is the new focus. The focus is cleared if Tag is nil, or if Tag
  38  	// has no InputOp in the same frame.
  39  	Tag event.Tag
  40  }
  41  
  42  // A FocusEvent is generated when a handler gains or loses
  43  // focus.
  44  type FocusEvent struct {
  45  	Focus bool
  46  }
  47  
  48  // An Event is generated when a key is pressed. For text input
  49  // use EditEvent.
  50  type Event struct {
  51  	// Name of the key. For letters, the upper case form is used, via
  52  	// unicode.ToUpper. The shift modifier is taken into account, all other
  53  	// modifiers are ignored. For example, the "shift-1" and "ctrl-shift-1"
  54  	// combinations both give the Name "!" with the US keyboard layout.
  55  	Name string
  56  	// Modifiers is the set of active modifiers when the key was pressed.
  57  	Modifiers Modifiers
  58  	// State is the state of the key when the event was fired.
  59  	State State
  60  }
  61  
  62  // An EditEvent is generated when text is input.
  63  type EditEvent struct {
  64  	Text string
  65  }
  66  
  67  // State is the state of a key during an event.
  68  type State uint8
  69  
  70  const (
  71  	// Press is the state of a pressed key.
  72  	Press State = iota
  73  	// Release is the state of a key that has been released.
  74  	//
  75  	// Note: release events are only implemented on the following platforms:
  76  	// macOS, Linux, Windows, WebAssembly.
  77  	Release
  78  )
  79  
  80  // Modifiers
  81  type Modifiers uint32
  82  
  83  const (
  84  	// ModCtrl is the ctrl modifier key.
  85  	ModCtrl Modifiers = 1 << iota
  86  	// ModCommand is the command modifier key
  87  	// found on Apple keyboards.
  88  	ModCommand
  89  	// ModShift is the shift modifier key.
  90  	ModShift
  91  	// ModAlt is the alt modifier key, or the option
  92  	// key on Apple keyboards.
  93  	ModAlt
  94  	// ModSuper is the "logo" modifier key, often
  95  	// represented by a Windows logo.
  96  	ModSuper
  97  )
  98  
  99  const (
 100  	// Names for special keys.
 101  	NameLeftArrow      = "←"
 102  	NameRightArrow     = "→"
 103  	NameUpArrow        = "↑"
 104  	NameDownArrow      = "↓"
 105  	NameReturn         = "⏎"
 106  	NameEnter          = "⌤"
 107  	NameEscape         = "⎋"
 108  	NameHome           = "⇱"
 109  	NameEnd            = "⇲"
 110  	NameDeleteBackward = "⌫"
 111  	NameDeleteForward  = "⌦"
 112  	NamePageUp         = "⇞"
 113  	NamePageDown       = "⇟"
 114  	NameTab            = "⇥"
 115  	NameSpace          = "Space"
 116  )
 117  
 118  // Contain reports whether m contains all modifiers
 119  // in m2.
 120  func (m Modifiers) Contain(m2 Modifiers) bool {
 121  	return m&m2 == m2
 122  }
 123  
 124  func (h InputOp) Add(o *op.Ops) {
 125  	if h.Tag == nil {
 126  		panic("Tag must be non-nil")
 127  	}
 128  	data := o.Write1(opconst.TypeKeyInputLen, h.Tag)
 129  	data[0] = byte(opconst.TypeKeyInput)
 130  }
 131  
 132  func (h SoftKeyboardOp) Add(o *op.Ops) {
 133  	data := o.Write(opconst.TypeKeySoftKeyboardLen)
 134  	data[0] = byte(opconst.TypeKeySoftKeyboard)
 135  	if h.Show {
 136  		data[1] = 1
 137  	}
 138  }
 139  
 140  func (h FocusOp) Add(o *op.Ops) {
 141  	data := o.Write1(opconst.TypeKeyFocusLen, h.Tag)
 142  	data[0] = byte(opconst.TypeKeyFocus)
 143  }
 144  
 145  func (EditEvent) ImplementsEvent()  {}
 146  func (Event) ImplementsEvent()      {}
 147  func (FocusEvent) ImplementsEvent() {}
 148  
 149  func (e Event) String() string {
 150  	return fmt.Sprintf("%v %v %v}", e.Name, e.Modifiers, e.State)
 151  }
 152  
 153  func (m Modifiers) String() string {
 154  	var strs []string
 155  	if m.Contain(ModCtrl) {
 156  		strs = append(strs, "ModCtrl")
 157  	}
 158  	if m.Contain(ModCommand) {
 159  		strs = append(strs, "ModCommand")
 160  	}
 161  	if m.Contain(ModShift) {
 162  		strs = append(strs, "ModShift")
 163  	}
 164  	if m.Contain(ModAlt) {
 165  		strs = append(strs, "ModAlt")
 166  	}
 167  	if m.Contain(ModSuper) {
 168  		strs = append(strs, "ModSuper")
 169  	}
 170  	return strings.Join(strs, "|")
 171  }
 172  
 173  func (s State) String() string {
 174  	switch s {
 175  	case Press:
 176  		return "Press"
 177  	case Release:
 178  		return "Release"
 179  	default:
 180  		panic("invalid State")
 181  	}
 182  }
 183