IMprovements.. attempts to fixup. Implemented Slow Jog, to allow you to send

nudge keybindings.
pull/5/head
Alexandre Bourget 2017-07-14 17:25:51 -04:00
rodzic cffc6fd992
commit 0e4e53ef54
5 zmienionych plików z 235 dodań i 147 usunięć

Wyświetl plik

@ -26,3 +26,22 @@ Buttons layout on the Contour Design Shuttle Pro v2:
See
TODO
----
* Fix up timings, make sure we properly support shortcuts with
Ctrl+Shift and it doesn't clog the program. Perhaps optimize and
keep certain keys pressed, until not needed anymore. Especially
using the Jog and Shuttle.
* Make sure we have a solution to ignore the device as a generic HID
under Ubuntu. We can't have mouse clicks on top of our bindings!
* Check udev, DISPLAY=:0.0 to start ?
* Retry ? Check the error message going out.
* Try the xdotool with the latest bindings, XTest-based.
* Use xgb's `xtest` package and send the FakeInput directly there.. should work
a lot better.

Wyświetl plik

@ -18,6 +18,7 @@ type Config struct {
type AppConfig struct {
Name string `json:"name"`
MatchWindowTitles []string `json:"match_window_titles"`
SlowJog int `json:"slow_jog"` // Time in millisecond to use slow jog
windowTitleRegexps []*regexp.Regexp
Bindings map[string]string `json:"bindings"`
bindings []*deviceBinding
@ -52,11 +53,12 @@ type deviceBinding struct {
// Output
holdButtons []string
pressButton string
original string
}
func (ac *AppConfig) parseBindings() error {
for key, value := range ac.Bindings {
newBinding := &deviceBinding{heldButtons: make(map[int]bool)}
newBinding := &deviceBinding{heldButtons: make(map[int]bool), original: value}
// Input
input := strings.Split(key, "+")
@ -82,19 +84,19 @@ func (ac *AppConfig) parseBindings() error {
}
// Output
output := strings.Split(value, "+")
for idx, part := range output {
cleanPart := strings.TrimSpace(part)
buttonName := strings.ToUpper(cleanPart)
if keyboardKeysUpper[buttonName] == 0 {
return fmt.Errorf("keyboard key unknown: %q", cleanPart)
}
if idx == len(output)-1 {
newBinding.pressButton = buttonName
} else {
newBinding.holdButtons = append(newBinding.holdButtons, buttonName)
}
}
// output := strings.Split(value, "+")
// for idx, part := range output {
// cleanPart := strings.TrimSpace(part)
// buttonName := strings.ToUpper(cleanPart)
// if keyboardKeysUpper[buttonName] == 0 {
// return fmt.Errorf("keyboard key unknown: %q", cleanPart)
// }
// if idx == len(output)-1 {
// newBinding.pressButton = buttonName
// } else {
// newBinding.holdButtons = append(newBinding.holdButtons, buttonName)
// }
// }
ac.bindings = append(ac.bindings, newBinding)

Wyświetl plik

@ -21,126 +21,131 @@ var shuttleKeys = map[string]int{
}
var otherShuttleKeys = map[string]bool{
"S-7": true,
"S-6": true,
"S-5": true,
"S-4": true,
"S-3": true,
"S-2": true,
"S-1": true,
"S0": true,
"S1": true,
"S2": true,
"S3": true,
"S4": true,
"S5": true,
"S6": true,
"S7": true,
"JogL": true,
"JogR": true,
"S-7": true,
"S-6": true,
"S-5": true,
"S-4": true,
"S-3": true,
"S-2": true,
"S-1": true,
"S0": true,
"S1": true,
"S2": true,
"S3": true,
"S4": true,
"S5": true,
"S6": true,
"S7": true,
"JogL": true,
"JogR": true,
"SlowJogL": true,
"SlowJogR": true,
}
var keyboardKeys = map[string]int{
"Esc": 1,
"1": 2,
"2": 3,
"3": 4,
"4": 5,
"5": 6,
"6": 7,
"7": 8,
"8": 9,
"9": 10,
"0": 11,
"Minus": 12,
"-": 12,
"Equal": 13,
"=": 13,
"Backspace": 14,
"Tab": 15,
"Q": 16,
"W": 17,
"E": 18,
"R": 19,
"T": 20,
"Y": 21,
"U": 22,
"I": 23,
"O": 24,
"P": 25,
"LeftBrace": 26,
"RightBrace": 27,
"{": 26,
"}": 27,
"Enter": 28,
"LeftCtrl": 29,
"Ctrl": 29,
"A": 30,
"S": 31,
"D": 32,
"F": 33,
"G": 34,
"H": 35,
"J": 36,
"K": 37,
"L": 38,
"Semicolon": 39,
";": 39,
"Apostrophe": 40,
"'": 40,
"Grave": 41,
"LeftShift": 42,
"Shift": 42,
"Backslash": 43,
"\\": 43,
"Z": 44,
"X": 45,
"C": 46,
"V": 47,
"B": 48,
"N": 49,
"M": 50,
"Comma": 51,
",": 51,
"Dot": 52,
".": 52,
"Slash": 53,
"/": 53,
"RightShift": 54,
"RShift": 54,
"KPAsterisk": 55,
"*": 55,
"LeftAlt": 56,
"Alt": 56,
"Space": 57,
"CapsLock": 58,
"F1": 59,
"F2": 60,
"F3": 61,
"F4": 62,
"F5": 63,
"F6": 64,
"F7": 65,
"F8": 66,
"F9": 67,
"F10": 68,
"NumLock": 69,
"ScrollLock": 70,
"KP7": 71,
"KP8": 72,
"KP9": 73,
"KPMinus": 74,
"KP4": 75,
"KP5": 76,
"KP6": 77,
"KPPlus": 78,
"KP1": 79,
"KP2": 80,
"KP3": 81,
"KP0": 82,
"KPDot": 83,
"F11": 87,
"F12": 88,
"Esc": 1,
"1": 2,
"2": 3,
"3": 4,
"4": 5,
"5": 6,
"6": 7,
"7": 8,
"8": 9,
"9": 10,
"0": 11,
"Minus": 12,
"-": 12,
"Equal": 13,
"=": 13,
"Backspace": 14,
"Tab": 15,
"Q": 16,
"W": 17,
"E": 18,
"R": 19,
"T": 20,
"Y": 21,
"U": 22,
"I": 23,
"O": 24,
"P": 25,
"LeftBrace": 26,
"RightBrace": 27,
"{": 26,
"}": 27,
"Enter": 28,
"LeftCtrl": 29,
"Ctrl": 29,
"A": 30,
"S": 31,
"D": 32,
"F": 33,
"G": 34,
"H": 35,
"J": 36,
"K": 37,
"L": 38,
"Semicolon": 39,
";": 39,
"Apostrophe": 40,
"'": 40,
"Grave": 41,
"LeftShift": 42,
"Shift": 42,
"Backslash": 43,
"\\": 43,
"Z": 44,
"X": 45,
"C": 46,
"V": 47,
"B": 48,
"N": 49,
"M": 50,
"Comma": 51,
",": 51,
"Dot": 52,
".": 52,
"Slash": 53,
"/": 53,
"RightShift": 54,
"RShift": 54,
"KPAsterisk": 55,
"*": 55,
"LeftAlt": 56,
"Alt": 56,
"Space": 57,
"CapsLock": 58,
"F1": 59,
"F2": 60,
"F3": 61,
"F4": 62,
"F5": 63,
"F6": 64,
"F7": 65,
"F8": 66,
"F9": 67,
"F10": 68,
"NumLock": 69,
"ScrollLock": 70,
"KP7": 71,
"KP8": 72,
"KP9": 73,
"KPMinus": 74,
"KP4": 75,
"KP5": 76,
"KP6": 77,
"KPPlus": 78,
"KP1": 79,
"KP2": 80,
"KP3": 81,
"KP0": 82,
"KPDot": 83,
"F11": 87,
"F12": 88,
"Henkan": 92,
"KPEnter": 96,
"RightCtrl": 97,
"RCtrl": 97,
@ -280,14 +285,14 @@ var keyboardKeys = map[string]int{
"Micmute": 248, /*Mute/UnmuteTheMicrophone*/
}
//var reverseShuttleKeys map[int]string
var reverseShuttleKeys = map[int]string{}
var keyboardKeysUpper = map[string]int{}
var otherShuttleKeysUpper = map[string]bool{}
func init() {
// for k, v := range shuttleKeys {
// reverseShuttleKeys[v] = k
// }
for k, v := range shuttleKeys {
reverseShuttleKeys[v] = k
}
for k, v := range keyboardKeys {
keyboardKeysUpper[strings.ToUpper(k)] = v
}

Wyświetl plik

@ -51,6 +51,7 @@ func main() {
fmt.Println("ready")
mapper := NewMapper(vk, dev)
mapper.watcher = watcher
for {
if err := mapper.Process(); err != nil {
fmt.Println("Error processing input events (continuing):", err)

Wyświetl plik

@ -2,8 +2,10 @@ package main
import (
"fmt"
"os/exec"
"reflect"
"strings"
"time"
"github.com/bendahl/uinput"
evdev "github.com/gvalkov/golang-evdev"
@ -15,12 +17,14 @@ type Mapper struct {
virtualKeyboard uinput.Keyboard
inputDevice *evdev.InputDevice
state buttonsState
watcher *watcher
}
type buttonsState struct {
jog int
shuttle int
buttonsHeld map[int]bool
lastJog time.Time
}
func NewMapper(virtualKeyboard uinput.Keyboard, inputDevice *evdev.InputDevice) *Mapper {
@ -39,7 +43,6 @@ func (m *Mapper) Process() error {
return err
}
fmt.Println("---")
m.dispatch(evs)
return nil
@ -49,17 +52,27 @@ func (m *Mapper) dispatch(evs []evdev.InputEvent) {
newJogVal := jogVal(evs)
if m.state.jog != newJogVal {
if m.state.jog != -1 {
if m.state.lastJog.IsZero() {
m.state.lastJog = time.Now()
}
slow := ""
if time.Since(m.state.lastJog) > slowJogTiming() {
slow = "Slow"
}
// Trigger JL or JR if we're advancing or not..
delta := newJogVal - m.state.jog
if (delta > 0 || delta < -200) && (delta < 200) {
if err := m.EmitOther("JogR"); err != nil {
if err := m.EmitOther(slow + "JogR"); err != nil {
fmt.Println("Jog right:", err)
}
} else {
if err := m.EmitOther("JogL"); err != nil {
if err := m.EmitOther(slow + "JogL"); err != nil {
fmt.Println("Jog left:", err)
}
}
m.state.lastJog = time.Now()
}
m.state.jog = newJogVal
}
@ -67,6 +80,7 @@ func (m *Mapper) dispatch(evs []evdev.InputEvent) {
newShuttleVal := shuttleVal(evs)
if m.state.shuttle != newShuttleVal {
keyName := fmt.Sprintf("S%d", newShuttleVal)
fmt.Println("SHUTTLE", keyName)
if err := m.EmitOther(keyName); err != nil {
fmt.Println("Shuttle movement %q: %s\n", keyName, err)
}
@ -89,12 +103,24 @@ func (m *Mapper) dispatch(evs []evdev.InputEvent) {
m.state.buttonsHeld = heldButtons
}
//fmt.Printf("TYPE: %d\tCODE: %d\tVALUE: %d\n", ev.Type, ev.Code, ev.Value)
fmt.Println("---")
for _, ev := range evs {
fmt.Printf("TYPE: %d\tCODE: %d\tVALUE: %d\n", ev.Type, ev.Code, ev.Value)
}
// TODO: Lock on configuration changes
return
}
func slowJogTiming() time.Duration {
conf := currentConfiguration
if conf == nil {
return 200 * time.Millisecond
}
return time.Duration(conf.SlowJog) * time.Millisecond
}
func (m *Mapper) EmitOther(key string) error {
conf := currentConfiguration
if conf == nil {
@ -103,9 +129,11 @@ func (m *Mapper) EmitOther(key string) error {
upperKey := strings.ToUpper(key)
fmt.Println("EmitOther:", key)
for _, binding := range conf.bindings {
if binding.otherKey == upperKey {
return m.executeBinding(binding.holdButtons, binding.pressButton)
return m.executeBinding(binding)
}
}
@ -118,33 +146,63 @@ func (m *Mapper) EmitKeys(modifiers map[int]bool, keyDown int) error {
return fmt.Errorf("No configuration for this Window")
}
fmt.Println("Emit Keys", modifiers, reverseShuttleKeys[keyDown])
for _, binding := range conf.bindings {
if reflect.DeepEqual(binding.heldButtons, modifiers) && binding.buttonDown == keyDown {
return m.executeBinding(binding.holdButtons, binding.pressButton)
return m.executeBinding(binding)
}
}
return fmt.Errorf("No binding for these keys")
}
func (m *Mapper) executeBinding(holdButtons []string, pressButton string) error {
func (m *Mapper) executeBinding(binding *deviceBinding) error {
holdButtons := binding.holdButtons
pressButton := binding.pressButton
//xtest.FakeInputChecked(m.watcher.conn, m.watcher.rootWin)
fmt.Println("xdotool key --clearmodifiers", binding.original)
return exec.Command("xdotool", "key", "--clearmodifiers", binding.original).Run()
fmt.Println("Executing bindings:", holdButtons, pressButton)
time.Sleep(10 * time.Millisecond)
for _, button := range holdButtons {
fmt.Println("Key down", button)
time.Sleep(10 * time.Millisecond)
if err := m.virtualKeyboard.KeyDown(keyboardKeysUpper[button]); err != nil {
return err
}
}
if err := m.virtualKeyboard.KeyPress(keyboardKeysUpper[pressButton]); err != nil {
time.Sleep(10 * time.Millisecond)
fmt.Println("Key press", pressButton)
if err := m.virtualKeyboard.KeyDown(keyboardKeysUpper[pressButton]); err != nil {
return err
}
time.Sleep(10 * time.Millisecond)
if err := m.virtualKeyboard.KeyUp(keyboardKeysUpper[pressButton]); err != nil {
return err
}
time.Sleep(10 * time.Millisecond)
for _, button := range holdButtons {
fmt.Println("Key up", button)
time.Sleep(10 * time.Millisecond)
if err := m.virtualKeyboard.KeyUp(keyboardKeysUpper[button]); err != nil {
return err
}
}
time.Sleep(50 * time.Millisecond)
return nil
}
@ -157,13 +215,16 @@ func jogVal(evs []evdev.InputEvent) int {
return 0
}
func shuttleVal(evs []evdev.InputEvent) int {
for _, ev := range evs {
func shuttleVal(evs []evdev.InputEvent) (out int) {
for idx, ev := range evs {
if ev.Type == 0 && idx != len(evs)-1 {
out = 0
}
if ev.Type == 2 && ev.Code == 8 {
return int(ev.Value)
out = int(ev.Value)
}
}
return 0
return
}
func buttonVals(current map[int]bool, ev evdev.InputEvent) (out map[int]bool, lastDown int) {