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 }