github.com/utopiagio/gio@v0.0.8/io/key/key.go (about)

     1  // SPDX-License-Identifier: Unlicense OR MIT
     2  
     3  // Package key implements key and text events and operations.
     4  package key
     5  
     6  import (
     7  	"strings"
     8  
     9  	"github.com/utopiagio/gio/f32"
    10  	"github.com/utopiagio/gio/internal/ops"
    11  	"github.com/utopiagio/gio/io/event"
    12  	"github.com/utopiagio/gio/op"
    13  )
    14  
    15  // Filter matches any [Event] that matches the parameters.
    16  type Filter struct {
    17  	// Focus is the tag that must be focused for the filter to match. It has no effect
    18  	// if it is nil.
    19  	Focus event.Tag
    20  	// Required is the set of modifiers that must be included in events matched.
    21  	Required Modifiers
    22  	// Optional is the set of modifiers that may be included in events matched.
    23  	Optional Modifiers
    24  	// Name of the key to be matched. As a special case, the empty
    25  	// Name matches every key not matched by any other filter.
    26  	Name Name
    27  }
    28  
    29  // InputHintOp describes the type of text expected by a tag.
    30  type InputHintOp struct {
    31  	Tag  event.Tag
    32  	Hint InputHint
    33  }
    34  
    35  // SoftKeyboardCmd shows or hides the on-screen keyboard, if available.
    36  type SoftKeyboardCmd struct {
    37  	Show bool
    38  }
    39  
    40  // SelectionCmd updates the selection for an input handler.
    41  type SelectionCmd struct {
    42  	Tag event.Tag
    43  	Range
    44  	Caret
    45  }
    46  
    47  // SnippetCmd updates the content snippet for an input handler.
    48  type SnippetCmd struct {
    49  	Tag event.Tag
    50  	Snippet
    51  }
    52  
    53  // Range represents a range of text, such as an editor's selection.
    54  // Start and End are in runes.
    55  type Range struct {
    56  	Start int
    57  	End   int
    58  }
    59  
    60  // Snippet represents a snippet of text content used for communicating between
    61  // an editor and an input method.
    62  type Snippet struct {
    63  	Range
    64  	Text string
    65  }
    66  
    67  // Caret represents the position of a caret.
    68  type Caret struct {
    69  	// Pos is the intersection point of the caret and its baseline.
    70  	Pos f32.Point
    71  	// Ascent is the length of the caret above its baseline.
    72  	Ascent float32
    73  	// Descent is the length of the caret below its baseline.
    74  	Descent float32
    75  }
    76  
    77  // SelectionEvent is generated when an input method changes the selection.
    78  type SelectionEvent Range
    79  
    80  // SnippetEvent is generated when the snippet range is updated by an
    81  // input method.
    82  type SnippetEvent Range
    83  
    84  // A FocusEvent is generated when a handler gains or loses
    85  // focus.
    86  type FocusEvent struct {
    87  	Focus bool
    88  }
    89  
    90  // An Event is generated when a key is pressed. For text input
    91  // use EditEvent.
    92  type Event struct {
    93  	// Name of the key.
    94  	Name Name
    95  	// Modifiers is the set of active modifiers when the key was pressed.
    96  	Modifiers Modifiers
    97  	// State is the state of the key when the event was fired.
    98  	State State
    99  }
   100  
   101  // An EditEvent requests an edit by an input method.
   102  type EditEvent struct {
   103  	// Range specifies the range to replace with Text.
   104  	Range Range
   105  	Text  string
   106  }
   107  
   108  // FocusFilter matches any [FocusEvent], [EditEvent], [SnippetEvent],
   109  // or [SelectionEvent] with the specified target.
   110  type FocusFilter struct {
   111  	// Target is a tag specified in a previous event.Op.
   112  	Target event.Tag
   113  }
   114  
   115  // InputHint changes the on-screen-keyboard type. That hints the
   116  // type of data that might be entered by the user.
   117  type InputHint uint8
   118  
   119  const (
   120  	// HintAny hints that any input is expected.
   121  	HintAny InputHint = iota
   122  	// HintText hints that text input is expected. It may activate auto-correction and suggestions.
   123  	HintText
   124  	// HintNumeric hints that numeric input is expected. It may activate shortcuts for 0-9, "." and ",".
   125  	HintNumeric
   126  	// HintEmail hints that email input is expected. It may activate shortcuts for common email characters, such as "@" and ".com".
   127  	HintEmail
   128  	// HintURL hints that URL input is expected. It may activate shortcuts for common URL fragments such as "/" and ".com".
   129  	HintURL
   130  	// HintTelephone hints that telephone number input is expected. It may activate shortcuts for 0-9, "#" and "*".
   131  	HintTelephone
   132  	// HintPassword hints that password input is expected. It may disable autocorrection and enable password autofill.
   133  	HintPassword
   134  )
   135  
   136  // State is the state of a key during an event.
   137  type State uint8
   138  
   139  const (
   140  	// Press is the state of a pressed key.
   141  	Press State = iota
   142  	// Release is the state of a key that has been released.
   143  	//
   144  	// Note: release events are only implemented on the following platforms:
   145  	// macOS, Linux, Windows, WebAssembly.
   146  	Release
   147  )
   148  
   149  // Modifiers
   150  type Modifiers uint32
   151  
   152  const (
   153  	// ModCtrl is the ctrl modifier key.
   154  	ModCtrl Modifiers = 1 << iota
   155  	// ModCommand is the command modifier key
   156  	// found on Apple keyboards.
   157  	ModCommand
   158  	// ModShift is the shift modifier key.
   159  	ModShift
   160  	// ModAlt is the alt modifier key, or the option
   161  	// key on Apple keyboards.
   162  	ModAlt
   163  	// ModSuper is the "logo" modifier key, often
   164  	// represented by a Windows logo.
   165  	ModSuper
   166  )
   167  
   168  // Name is the identifier for a keyboard key.
   169  //
   170  // For letters, the upper case form is used, via unicode.ToUpper.
   171  // The shift modifier is taken into account, all other
   172  // modifiers are ignored. For example, the "shift-1" and "ctrl-shift-1"
   173  // combinations both give the Name "!" with the US keyboard layout.
   174  type Name string
   175  
   176  const (
   177  	// Names for special keys.
   178  	NameLeftArrow      Name = "←"
   179  	NameRightArrow     Name = "→"
   180  	NameUpArrow        Name = "↑"
   181  	NameDownArrow      Name = "↓"
   182  	NameReturn         Name = "⏎"
   183  	NameEnter          Name = "⌤"
   184  	NameEscape         Name = "⎋"
   185  	NameHome           Name = "⇱"
   186  	NameEnd            Name = "⇲"
   187  	NameDeleteBackward Name = "⌫"
   188  	NameDeleteForward  Name = "⌦"
   189  	NamePageUp         Name = "⇞"
   190  	NamePageDown       Name = "⇟"
   191  	NameTab            Name = "Tab"
   192  	NameSpace          Name = "Space"
   193  	NameCtrl           Name = "Ctrl"
   194  	NameShift          Name = "Shift"
   195  	NameAlt            Name = "Alt"
   196  	NameSuper          Name = "Super"
   197  	NameCommand        Name = "⌘"
   198  	NameF1             Name = "F1"
   199  	NameF2             Name = "F2"
   200  	NameF3             Name = "F3"
   201  	NameF4             Name = "F4"
   202  	NameF5             Name = "F5"
   203  	NameF6             Name = "F6"
   204  	NameF7             Name = "F7"
   205  	NameF8             Name = "F8"
   206  	NameF9             Name = "F9"
   207  	NameF10            Name = "F10"
   208  	NameF11            Name = "F11"
   209  	NameF12            Name = "F12"
   210  	NameBack           Name = "Back"
   211  )
   212  
   213  type FocusDirection int
   214  
   215  const (
   216  	FocusRight FocusDirection = iota
   217  	FocusLeft
   218  	FocusUp
   219  	FocusDown
   220  	FocusForward
   221  	FocusBackward
   222  )
   223  
   224  // Contain reports whether m contains all modifiers
   225  // in m2.
   226  func (m Modifiers) Contain(m2 Modifiers) bool {
   227  	return m&m2 == m2
   228  }
   229  
   230  // FocusCmd requests to set or clear the keyboard focus.
   231  type FocusCmd struct {
   232  	// Tag is the new focus. The focus is cleared if Tag is nil, or if Tag
   233  	// has no [event.Op] references.
   234  	Tag event.Tag
   235  }
   236  
   237  func (h InputHintOp) Add(o *op.Ops) {
   238  	if h.Tag == nil {
   239  		panic("Tag must be non-nil")
   240  	}
   241  	data := ops.Write1(&o.Internal, ops.TypeKeyInputHintLen, h.Tag)
   242  	data[0] = byte(ops.TypeKeyInputHint)
   243  	data[1] = byte(h.Hint)
   244  }
   245  
   246  func (EditEvent) ImplementsEvent()      {}
   247  func (Event) ImplementsEvent()          {}
   248  func (FocusEvent) ImplementsEvent()     {}
   249  func (SnippetEvent) ImplementsEvent()   {}
   250  func (SelectionEvent) ImplementsEvent() {}
   251  
   252  func (FocusCmd) ImplementsCommand()        {}
   253  func (SoftKeyboardCmd) ImplementsCommand() {}
   254  func (SelectionCmd) ImplementsCommand()    {}
   255  func (SnippetCmd) ImplementsCommand()      {}
   256  
   257  func (Filter) ImplementsFilter()      {}
   258  func (FocusFilter) ImplementsFilter() {}
   259  
   260  func (m Modifiers) String() string {
   261  	var strs []string
   262  	if m.Contain(ModCtrl) {
   263  		strs = append(strs, string(NameCtrl))
   264  	}
   265  	if m.Contain(ModCommand) {
   266  		strs = append(strs, string(NameCommand))
   267  	}
   268  	if m.Contain(ModShift) {
   269  		strs = append(strs, string(NameShift))
   270  	}
   271  	if m.Contain(ModAlt) {
   272  		strs = append(strs, string(NameAlt))
   273  	}
   274  	if m.Contain(ModSuper) {
   275  		strs = append(strs, string(NameSuper))
   276  	}
   277  	return strings.Join(strs, "-")
   278  }
   279  
   280  func (s State) String() string {
   281  	switch s {
   282  	case Press:
   283  		return "Press"
   284  	case Release:
   285  		return "Release"
   286  	default:
   287  		panic("invalid State")
   288  	}
   289  }