github.com/gop9/olt@v0.0.0-20200202132135-d956aad50b08/gio/app/internal/input/key.go (about)

     1  // SPDX-License-Identifier: Unlicense OR MIT
     2  
     3  package input
     4  
     5  import (
     6  	"github.com/gop9/olt/gio/internal/opconst"
     7  	"github.com/gop9/olt/gio/internal/ops"
     8  	"github.com/gop9/olt/gio/io/event"
     9  	"github.com/gop9/olt/gio/io/key"
    10  	"github.com/gop9/olt/gio/op"
    11  )
    12  
    13  type TextInputState uint8
    14  
    15  type keyQueue struct {
    16  	focus    event.Key
    17  	handlers map[event.Key]*keyHandler
    18  	reader   ops.Reader
    19  	state    TextInputState
    20  }
    21  
    22  type keyHandler struct {
    23  	active bool
    24  }
    25  
    26  type listenerPriority uint8
    27  
    28  const (
    29  	priNone listenerPriority = iota
    30  	priDefault
    31  	priCurrentFocus
    32  	priNewFocus
    33  )
    34  
    35  const (
    36  	TextInputKeep TextInputState = iota
    37  	TextInputClose
    38  	TextInputOpen
    39  )
    40  
    41  // InputState returns the last text input state as
    42  // determined in Frame.
    43  func (q *keyQueue) InputState() TextInputState {
    44  	return q.state
    45  }
    46  
    47  func (q *keyQueue) Frame(root *op.Ops, events *handlerEvents) {
    48  	if q.handlers == nil {
    49  		q.handlers = make(map[event.Key]*keyHandler)
    50  	}
    51  	for _, h := range q.handlers {
    52  		h.active = false
    53  	}
    54  	q.reader.Reset(root)
    55  	focus, pri, hide := q.resolveFocus(events)
    56  	for k, h := range q.handlers {
    57  		if !h.active {
    58  			delete(q.handlers, k)
    59  			if q.focus == k {
    60  				q.focus = nil
    61  				hide = true
    62  			}
    63  		}
    64  	}
    65  	if focus != q.focus {
    66  		if q.focus != nil {
    67  			events.Add(q.focus, key.FocusEvent{Focus: false})
    68  		}
    69  		q.focus = focus
    70  		if q.focus != nil {
    71  			events.Add(q.focus, key.FocusEvent{Focus: true})
    72  		} else {
    73  			hide = true
    74  		}
    75  	}
    76  	switch {
    77  	case pri == priNewFocus:
    78  		q.state = TextInputOpen
    79  	case hide:
    80  		q.state = TextInputClose
    81  	default:
    82  		q.state = TextInputKeep
    83  	}
    84  }
    85  
    86  func (q *keyQueue) Push(e event.Event, events *handlerEvents) {
    87  	if q.focus != nil {
    88  		events.Add(q.focus, e)
    89  	}
    90  }
    91  
    92  func (q *keyQueue) resolveFocus(events *handlerEvents) (event.Key, listenerPriority, bool) {
    93  	var k event.Key
    94  	var pri listenerPriority
    95  	var hide bool
    96  loop:
    97  	for encOp, ok := q.reader.Decode(); ok; encOp, ok = q.reader.Decode() {
    98  		switch opconst.OpType(encOp.Data[0]) {
    99  		case opconst.TypeKeyInput:
   100  			op := decodeKeyInputOp(encOp.Data, encOp.Refs)
   101  			var newPri listenerPriority
   102  			switch {
   103  			case op.Focus:
   104  				newPri = priNewFocus
   105  			case op.Key == q.focus:
   106  				newPri = priCurrentFocus
   107  			default:
   108  				newPri = priDefault
   109  			}
   110  			// Switch focus if higher priority or if focus requested.
   111  			if newPri.replaces(pri) {
   112  				k, pri = op.Key, newPri
   113  			}
   114  			h, ok := q.handlers[op.Key]
   115  			if !ok {
   116  				h = new(keyHandler)
   117  				q.handlers[op.Key] = h
   118  				// Reset the handler on (each) first appearance.
   119  				events.Set(op.Key, []event.Event{key.FocusEvent{Focus: false}})
   120  			}
   121  			h.active = true
   122  		case opconst.TypeHideInput:
   123  			hide = true
   124  		case opconst.TypePush:
   125  			newK, newPri, h := q.resolveFocus(events)
   126  			hide = hide || h
   127  			if newPri.replaces(pri) {
   128  				k, pri = newK, newPri
   129  			}
   130  		case opconst.TypePop:
   131  			break loop
   132  		}
   133  	}
   134  	return k, pri, hide
   135  }
   136  
   137  func (p listenerPriority) replaces(p2 listenerPriority) bool {
   138  	// Favor earliest default focus or latest requested focus.
   139  	return p > p2 || p == p2 && p == priNewFocus
   140  }
   141  
   142  func decodeKeyInputOp(d []byte, refs []interface{}) key.InputOp {
   143  	if opconst.OpType(d[0]) != opconst.TypeKeyInput {
   144  		panic("invalid op")
   145  	}
   146  	return key.InputOp{
   147  		Focus: d[1] != 0,
   148  		Key:   refs[0].(event.Key),
   149  	}
   150  }