From cb792838efc260af1f06946bfed8d633701d62b4 Mon Sep 17 00:00:00 2001 From: Alexandre Bourget Date: Fri, 14 Jul 2017 23:42:56 -0400 Subject: [PATCH] Improve slowjog. --- README.md | 37 ++++++++++++++++++++------ config.go | 2 +- mapper.go | 78 ++++++++++++++++++++++++++++++++----------------------- watch.go | 8 ++++++ 4 files changed, 83 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index e6c0891..8aa6379 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,25 @@ Linux driver for Contour Design Shuttle Pro V2 ============================================== -My goal is to set it up for the Lightworks Non-Linear Editor. +The goal of this project is to use the Shuttle Pro V2 with the +Lightworks Non-Linear Video Editor. I'm using v14. -This program supports having modifiers for your Shuttle Pro V2 -buttons. Avoid Lightworks key bindings with modifiers however. Capital +This program supports having **modifiers** for your Shuttle Pro V2 +buttons. So you can multiple the functionality of your buttons. For +example, you can have different bindings for +B1+F1 and F1. + +Avoid Lightworks key bindings with modifiers however. Capital letters are great as they cannot be combined, and are more direct and they are less likely to conflict with your other bindings and -Lightworks recognizes them. All key names used here will work: -http://www.tcl.tk/man/tcl8.4/TkCmd/keysyms.htm +Lightworks recognizes them. -Right now, you need to install `xdotool` from your package -repositories. Eventually, we'll get rid of this dependency. +The key names to use in the X11 bindings are found here: +https://www.cl.cam.ac.uk/~mgk25/ucs/keysymdef.h or you can view them +locally in `/usr/include/X11/keysymdef.h` (stripped of the `XK_` +prefix). + +You need to install the `xdotool` package before using this program. Buttons layout on the Contour Design Shuttle Pro v2: @@ -31,7 +39,18 @@ Buttons layout on the Contour Design Shuttle Pro v2: B2 B3 B1 B4 -You can also use `SlowJogL` and `SlowJogR`, to use Frame nudge for example. + +## Slow Jog + +In addition to `JogL` and `JogR`, you can define bindings for +`SlowJogL` and `SlowJogR`. For example, you can use a slow jog use to +nudge by one frame at a time. + +If you wish to not use slow jog, set the `slow_jog` key to `0` in the +configuration for this app. Otherwise, `slow_jog` represents the +minimum number of milliseconds between two events to be considered +slow. It defaults to 200 ms. + ## Disable the native mouse pointer @@ -67,3 +86,5 @@ TODO * Check udev, DISPLAY=:0.0 to start ? * Retry ? Check the error message going out. + +* Have a default SlowJog configuration. diff --git a/config.go b/config.go index a9e4c29..9157048 100644 --- a/config.go +++ b/config.go @@ -18,7 +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 + SlowJog *int `json:"slow_jog"` // Time in millisecond to use slow jog windowTitleRegexps []*regexp.Regexp Bindings map[string]string `json:"bindings"` bindings []*deviceBinding diff --git a/mapper.go b/mapper.go index 1cabfc2..e241d9f 100644 --- a/mapper.go +++ b/mapper.go @@ -118,7 +118,12 @@ func slowJogTiming() time.Duration { if conf == nil { return 200 * time.Millisecond } - return time.Duration(conf.SlowJog) * time.Millisecond + slowJog := 200 + if conf.SlowJog != nil { + slowJog = *conf.SlowJog + } + + return time.Duration(slowJog) * time.Millisecond } func (m *Mapper) EmitOther(key string) error { @@ -158,54 +163,61 @@ func (m *Mapper) EmitKeys(modifiers map[int]bool, keyDown int) error { } func (m *Mapper) executeBinding(binding *deviceBinding) error { - holdButtons := binding.holdButtons - pressButton := binding.pressButton - time.Sleep(100 * time.Millisecond) - //xtest.FakeInputChecked(m.watcher.conn, m.watcher.rootWin) + // cookie := xtest.FakeInputChecked(m.watcher.conn, 2, 0x7b00, 0, m.watcher.lastWindowID, 0, 0, 0x00) + // if err := cookie.Check(); err != nil { + // return nil + // } + + // cookie = xtest.FakeInputChecked(m.watcher.conn, 3, 0x7b00, 0, m.watcher.lastWindowID, 0, 0, 0x00) + // return cookie.Check() + fmt.Println("xdotool key --clearmodifiers", binding.original) return exec.Command("xdotool", "key", "--clearmodifiers", binding.original).Run() - fmt.Println("Executing bindings:", holdButtons, pressButton) + // holdButtons := binding.holdButtons + // pressButton := binding.pressButton - time.Sleep(10 * time.Millisecond) + // fmt.Println("Executing bindings:", holdButtons, pressButton) - for _, button := range holdButtons { - fmt.Println("Key down", button) - time.Sleep(10 * time.Millisecond) + // time.Sleep(10 * time.Millisecond) - if err := m.virtualKeyboard.KeyDown(keyboardKeysUpper[button]); err != nil { - return err - } - } + // for _, button := range holdButtons { + // fmt.Println("Key down", button) + // time.Sleep(10 * time.Millisecond) - time.Sleep(10 * time.Millisecond) + // if err := m.virtualKeyboard.KeyDown(keyboardKeysUpper[button]); err != nil { + // return err + // } + // } - fmt.Println("Key press", pressButton) - if err := m.virtualKeyboard.KeyDown(keyboardKeysUpper[pressButton]); err != nil { - return err - } + // time.Sleep(10 * time.Millisecond) - time.Sleep(10 * time.Millisecond) + // fmt.Println("Key press", pressButton) + // if err := m.virtualKeyboard.KeyDown(keyboardKeysUpper[pressButton]); err != nil { + // return err + // } - if err := m.virtualKeyboard.KeyUp(keyboardKeysUpper[pressButton]); err != nil { - return err - } + // time.Sleep(10 * time.Millisecond) - time.Sleep(10 * time.Millisecond) + // if err := m.virtualKeyboard.KeyUp(keyboardKeysUpper[pressButton]); err != nil { + // return err + // } - 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(10 * time.Millisecond) - time.Sleep(50 * 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 + // } + // } - return nil + // time.Sleep(50 * time.Millisecond) + + // return nil } func jogVal(evs []evdev.InputEvent) int { diff --git a/watch.go b/watch.go index 86e750d..e15bcf1 100644 --- a/watch.go +++ b/watch.go @@ -7,6 +7,7 @@ import ( "github.com/BurntSushi/xgb" "github.com/BurntSushi/xgb/xproto" + "github.com/BurntSushi/xgb/xtest" ) type watcher struct { @@ -14,6 +15,7 @@ type watcher struct { root xproto.Window activeAtom, nameAtom xproto.Atom prevWindowName string + lastWindowID xproto.Window } func NewWindowWatcher() *watcher { @@ -29,6 +31,10 @@ func (w *watcher) Setup() error { // Get the window id of the root window. setup := xproto.Setup(X) + if err := xtest.Init(X); err != nil { + return err + } + w.conn = X w.root = setup.DefaultScreen(X).Root @@ -76,6 +82,8 @@ func (w *watcher) watch() { log.Fatal(err) } + w.lastWindowID = windowID + windowName := string(reply.Value) if w.prevWindowName != windowName { w.prevWindowName = windowName