key.go 7.6 KB

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