...

Source file src/code.rocketnine.space/tslocum/cbind/configuration.go

Documentation: code.rocketnine.space/tslocum/cbind

     1  package cbind
     2  
     3  import (
     4  	"fmt"
     5  	"sync"
     6  	"unicode"
     7  
     8  	"github.com/gdamore/tcell/v2"
     9  )
    10  
    11  type eventHandler func(ev *tcell.EventKey) *tcell.EventKey
    12  
    13  // Configuration maps keys to event handlers and processes key events.
    14  type Configuration struct {
    15  	handlers map[string]eventHandler
    16  	mutex    *sync.RWMutex
    17  }
    18  
    19  // NewConfiguration returns a new input configuration.
    20  func NewConfiguration() *Configuration {
    21  	c := Configuration{
    22  		handlers: make(map[string]eventHandler),
    23  		mutex:    new(sync.RWMutex),
    24  	}
    25  
    26  	return &c
    27  }
    28  
    29  // Set sets the handler for a key event string.
    30  func (c *Configuration) Set(s string, handler func(ev *tcell.EventKey) *tcell.EventKey) error {
    31  	mod, key, ch, err := Decode(s)
    32  	if err != nil {
    33  		return err
    34  	}
    35  
    36  	if key == tcell.KeyRune {
    37  		c.SetRune(mod, ch, handler)
    38  	} else {
    39  		c.SetKey(mod, key, handler)
    40  	}
    41  	return nil
    42  }
    43  
    44  // SetKey sets the handler for a key.
    45  func (c *Configuration) SetKey(mod tcell.ModMask, key tcell.Key, handler func(ev *tcell.EventKey) *tcell.EventKey) {
    46  	c.mutex.Lock()
    47  	defer c.mutex.Unlock()
    48  
    49  	if mod&tcell.ModShift != 0 && key == tcell.KeyTab {
    50  		mod ^= tcell.ModShift
    51  		key = tcell.KeyBacktab
    52  	}
    53  
    54  	if mod&tcell.ModCtrl == 0 && key != tcell.KeyBackspace && key != tcell.KeyTab && key != tcell.KeyEnter {
    55  		for _, ctrlKey := range ctrlKeys {
    56  			if key == ctrlKey {
    57  				mod |= tcell.ModCtrl
    58  				break
    59  			}
    60  		}
    61  	}
    62  
    63  	c.handlers[fmt.Sprintf("%d-%d", mod, key)] = handler
    64  }
    65  
    66  // SetRune sets the handler for a rune.
    67  func (c *Configuration) SetRune(mod tcell.ModMask, ch rune, handler func(ev *tcell.EventKey) *tcell.EventKey) {
    68  	// Some runes are identical to named keys. Set the bind on the matching
    69  	// named key instead.
    70  	switch ch {
    71  	case '\t':
    72  		c.SetKey(mod, tcell.KeyTab, handler)
    73  		return
    74  	case '\n':
    75  		c.SetKey(mod, tcell.KeyEnter, handler)
    76  		return
    77  	}
    78  
    79  	if mod&tcell.ModCtrl != 0 {
    80  		k, ok := ctrlKeys[unicode.ToLower(ch)]
    81  		if ok {
    82  			c.SetKey(mod, k, handler)
    83  			return
    84  		}
    85  	}
    86  
    87  	c.mutex.Lock()
    88  	defer c.mutex.Unlock()
    89  
    90  	c.handlers[fmt.Sprintf("%d:%d", mod, ch)] = handler
    91  }
    92  
    93  // Capture handles key events.
    94  func (c *Configuration) Capture(ev *tcell.EventKey) *tcell.EventKey {
    95  	c.mutex.RLock()
    96  	defer c.mutex.RUnlock()
    97  
    98  	if ev == nil {
    99  		return nil
   100  	}
   101  
   102  	var keyName string
   103  	if ev.Key() != tcell.KeyRune {
   104  		keyName = fmt.Sprintf("%d-%d", ev.Modifiers(), ev.Key())
   105  	} else {
   106  		keyName = fmt.Sprintf("%d:%d", ev.Modifiers(), ev.Rune())
   107  	}
   108  
   109  	handler := c.handlers[keyName]
   110  	if handler != nil {
   111  		return handler(ev)
   112  	}
   113  	return ev
   114  }
   115  
   116  // Clear removes all handlers.
   117  func (c *Configuration) Clear() {
   118  	c.mutex.Lock()
   119  	defer c.mutex.Unlock()
   120  
   121  	c.handlers = make(map[string]eventHandler)
   122  }
   123  

View as plain text