github.com/cybriq/giocore@v0.0.7-0.20210703034601-cfb9cb5f3900/io/key/key.go (about)

     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/cybriq/giocore/internal/opconst"
    17  	"github.com/cybriq/giocore/io/event"
    18  	"github.com/cybriq/giocore/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  	Hint InputHint
    27  }
    28  
    29  // SoftKeyboardOp shows or hide the on-screen keyboard, if available.
    30  // It replaces any previous SoftKeyboardOp.
    31  type SoftKeyboardOp struct {
    32  	Show bool
    33  }
    34  
    35  // FocusOp sets or clears the keyboard focus. It replaces any previous
    36  // FocusOp in the same frame.
    37  type FocusOp struct {
    38  	// Tag is the new focus. The focus is cleared if Tag is nil, or if Tag
    39  	// has no InputOp in the same frame.
    40  	Tag event.Tag
    41  }
    42  
    43  // A FocusEvent is generated when a handler gains or loses
    44  // focus.
    45  type FocusEvent struct {
    46  	Focus bool
    47  }
    48  
    49  // An Event is generated when a key is pressed. For text input
    50  // use EditEvent.
    51  type Event struct {
    52  	// Name of the key. For letters, the upper case form is used, via
    53  	// unicode.ToUpper. The shift modifier is taken into account, all other
    54  	// modifiers are ignored. For example, the "shift-1" and "ctrl-shift-1"
    55  	// combinations both give the Name "!" with the US keyboard layout.
    56  	Name string
    57  	// Modifiers is the set of active modifiers when the key was pressed.
    58  	Modifiers Modifiers
    59  	// State is the state of the key when the event was fired.
    60  	State State
    61  }
    62  
    63  // An EditEvent is generated when text is input.
    64  type EditEvent struct {
    65  	Text string
    66  }
    67  
    68  // InputHint changes the on-screen-keyboard type. That hints the
    69  // type of data that might be entered by the user.
    70  type InputHint uint8
    71  
    72  const (
    73  	// HintAny hints that any input is expected.
    74  	HintAny InputHint = iota
    75  	// HintText hints that text input is expected. It may activate auto-correction and suggestions.
    76  	HintText
    77  	// HintNumeric hints that numeric input is expected. It may activate shortcuts for 0-9, "." and ",".
    78  	HintNumeric
    79  	// HintEmail hints that email input is expected. It may activate shortcuts for common email characters, such as "@" and ".com".
    80  	HintEmail
    81  	// HintURL hints that URL input is expected. It may activate shortcuts for common URL fragments such as "/" and ".com".
    82  	HintURL
    83  	// HintTelephone hints that telephone number input is expected. It may activate shortcuts for 0-9, "#" and "*".
    84  	HintTelephone
    85  )
    86  
    87  // State is the state of a key during an event.
    88  type State uint8
    89  
    90  const (
    91  	// Press is the state of a pressed key.
    92  	Press State = iota
    93  	// Release is the state of a key that has been released.
    94  	//
    95  	// Note: release events are only implemented on the following platforms:
    96  	// macOS, Linux, Windows, WebAssembly.
    97  	Release
    98  )
    99  
   100  // Modifiers
   101  type Modifiers uint32
   102  
   103  const (
   104  	// ModCtrl is the ctrl modifier key.
   105  	ModCtrl Modifiers = 1 << iota
   106  	// ModCommand is the command modifier key
   107  	// found on Apple keyboards.
   108  	ModCommand
   109  	// ModShift is the shift modifier key.
   110  	ModShift
   111  	// ModAlt is the alt modifier key, or the option
   112  	// key on Apple keyboards.
   113  	ModAlt
   114  	// ModSuper is the "logo" modifier key, often
   115  	// represented by a Windows logo.
   116  	ModSuper
   117  )
   118  
   119  const (
   120  	// Names for special keys.
   121  	NameLeftArrow      = "←"
   122  	NameRightArrow     = "→"
   123  	NameUpArrow        = "↑"
   124  	NameDownArrow      = "↓"
   125  	NameReturn         = "⏎"
   126  	NameEnter          = "⌤"
   127  	NameEscape         = "⎋"
   128  	NameHome           = "⇱"
   129  	NameEnd            = "⇲"
   130  	NameDeleteBackward = "⌫"
   131  	NameDeleteForward  = "⌦"
   132  	NamePageUp         = "⇞"
   133  	NamePageDown       = "⇟"
   134  	NameTab            = "⇥"
   135  	NameSpace          = "Space"
   136  )
   137  
   138  // Contain reports whether m contains all modifiers
   139  // in m2.
   140  func (m Modifiers) Contain(m2 Modifiers) bool {
   141  	return m&m2 == m2
   142  }
   143  
   144  func (h InputOp) Add(o *op.Ops) {
   145  	if h.Tag == nil {
   146  		panic("Tag must be non-nil")
   147  	}
   148  	data := o.Write1(opconst.TypeKeyInputLen, h.Tag)
   149  	data[0] = byte(opconst.TypeKeyInput)
   150  	data[1] = byte(h.Hint)
   151  }
   152  
   153  func (h SoftKeyboardOp) Add(o *op.Ops) {
   154  	data := o.Write(opconst.TypeKeySoftKeyboardLen)
   155  	data[0] = byte(opconst.TypeKeySoftKeyboard)
   156  	if h.Show {
   157  		data[1] = 1
   158  	}
   159  }
   160  
   161  func (h FocusOp) Add(o *op.Ops) {
   162  	data := o.Write1(opconst.TypeKeyFocusLen, h.Tag)
   163  	data[0] = byte(opconst.TypeKeyFocus)
   164  }
   165  
   166  func (EditEvent) ImplementsEvent()  {}
   167  func (Event) ImplementsEvent()      {}
   168  func (FocusEvent) ImplementsEvent() {}
   169  
   170  func (e Event) String() string {
   171  	return fmt.Sprintf("%v %v %v}", e.Name, e.Modifiers, e.State)
   172  }
   173  
   174  func (m Modifiers) String() string {
   175  	var strs []string
   176  	if m.Contain(ModCtrl) {
   177  		strs = append(strs, "ModCtrl")
   178  	}
   179  	if m.Contain(ModCommand) {
   180  		strs = append(strs, "ModCommand")
   181  	}
   182  	if m.Contain(ModShift) {
   183  		strs = append(strs, "ModShift")
   184  	}
   185  	if m.Contain(ModAlt) {
   186  		strs = append(strs, "ModAlt")
   187  	}
   188  	if m.Contain(ModSuper) {
   189  		strs = append(strs, "ModSuper")
   190  	}
   191  	return strings.Join(strs, "|")
   192  }
   193  
   194  func (s State) String() string {
   195  	switch s {
   196  	case Press:
   197  		return "Press"
   198  	case Release:
   199  		return "Release"
   200  	default:
   201  		panic("invalid State")
   202  	}
   203  }