...

Source file src/codeberg.org/tslocum/cbind/configuration.go

Documentation: codeberg.org/tslocum/cbind

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

View as plain text