wip shift handling

This commit is contained in:
Harald Albrecht 2019-01-06 19:42:21 +01:00
parent f565f5815f
commit f2682864fb
9 changed files with 171 additions and 134 deletions

View File

@ -5,6 +5,7 @@ busted.stub(keybow, "auto_lights")
busted.stub(keybow, "clear_lights") busted.stub(keybow, "clear_lights")
busted.stub(keybow, "load_pattern") busted.stub(keybow, "load_pattern")
busted.stub(keybow, "set_pixel") busted.stub(keybow, "set_pixel")
-- keybow.set_pixel = function(led, r, g, b) print("LED #"..led..", "..r..", "..g..", "..b) end
busted.stub(keybow, "set_key") busted.stub(keybow, "set_key")
busted.stub(keybow, "set_modifier") busted.stub(keybow, "set_modifier")
busted.stub(keybow, "tap_key") busted.stub(keybow, "tap_key")

View File

@ -28,21 +28,20 @@ local k = _G.kdenlive or {} -- module
local mb = require "snippets/multibow" local mb = require "snippets/multibow"
k = {} -- module
-- Key colors for unshifted and shifted keys; keep them rather muted in order -- Key colors for unshifted and shifted keys; keep them rather muted in order
-- to not distract your video editing work. -- to not distract your video editing work.
k.UNSHIFTED_COLOR = {r=0, g=50, b=0} k.UNSHIFTED_COLOR = {r=0, g=1, b=0}
k.SHIFTED_COLOR = {r=50, g=0, b=0} k.SHIFTED_COLOR = {r=1, g=0, b=0}
k.keymap = { k.keymap = {
name="kdenlive", name="kdenlive",
[9] = {c={0,1,0}} [9] = {c=k.UNSHIFTED_COLOR},
[6] = {c=k.UNSHIFTED_COLOR},
} }
k.keymap_shifted = { k.keymap_shifted = {
name="kdenlive-shifted", name="kdenlive-shifted",
secondary=true, secondary=true,
[9] = {c={1,0,0}} [6] = {c=k.SHIFTED_COLOR},
[3] = {c=k.SHIFTED_COLOR},
} }
k.keymap.shift_to = k.keymap_shifted k.keymap.shift_to = k.keymap_shifted
k.keymap_shifted.shift_to = k.keymap k.keymap_shifted.shift_to = k.keymap

View File

@ -59,11 +59,10 @@ shift.KEY_BRIGHTNESS = shift.KEY_BRIGHTNESS or 5
-- Internal flag for detecting SHIFT press-release sequences without any SHIFTed -- Internal flag for detecting SHIFT press-release sequences without any SHIFTed
-- function. -- function.
local shift_only = false local shift_only = false
local in_shift = false local grabbed_key_count = 0
local other_key = false
-- Switch to the next SHIFT layer within the currently active keyboard layout. -- Switches to the next SHIFT layer within the currently active keyboard layout.
-- SHIFT layer(s) are wired up as a circular list of keymaps, linked using their -- SHIFT layer(s) are wired up as a circular list of keymaps, linked using their
-- "shift_to" elements. -- "shift_to" elements.
function shift.shift_secondary_keymap() function shift.shift_secondary_keymap()
@ -74,40 +73,42 @@ function shift.shift_secondary_keymap()
end end
function shift.release_other() -- Remember how many grabbed keys are pressed, so we won't ungrab later until
other_key = false -- all keys have been released.
if not in_shift then function shift.any_press(keyno)
mb.ungrab() grabbed_key_count = grabbed_key_count + 1
end
-- Only ungrab after last key has been released
function shift.any_release(keyno)
if grabbed_key_count > 0 then
grabbed_key_count = grabbed_key_count - 1
if grabbed_key_count == 0 then
-- Ungrabs after last key released.
mb.ungrab()
-- And switches between keymaps within the same set.
if shift_only then
shift.shift_secondary_keymap()
end
end
end end
end end
-- SHIFT press: switches into grabbed SHIFT mode, activating brightness change, -- SHIFT press: switches into grabbed SHIFT mode, activating the in-SHIFT keys
-- keymap cycling, et cetera. -- for brightness change, keymap cycling, et cetera.
function shift.grab(key) function shift.shift(key)
mb.grab("shift-shifted") grabbed_keys = 1 -- includes myself; this is necessary as the grab "any"
in_shift = true -- handler will not register the SHIFT press, because it
other_key = false -- play safe. -- wasn't grabbed yet.
shift_only = true shift_only = true
end shift.any_press(key)
mb.grab(shift.keymap_shifted.name)
-- SHIFT release: leaves (grabbed) SHIFT mode, but only if there is no other
-- (bound) key currently being held.
function shift.release(key)
in_shift = false
if not other_key then
mb.ungrab()
end
if shift_only then
shift.shift_secondary_keymap()
end
end end
-- Cycles to the next primary keyboard layout (keymap) -- Cycles to the next primary keyboard layout (keymap)
function shift.cycle(key) function shift.cycle(key)
other_key = true
shift_only = false shift_only = false
mb.cycle_primary_keymaps() mb.cycle_primary_keymaps()
end end
@ -116,7 +117,6 @@ end
-- Changes the Keybow LED brightness, by cycling through different brightness -- Changes the Keybow LED brightness, by cycling through different brightness
-- levels -- levels
function shift.brightness(key) function shift.brightness(key)
other_key = true
shift_only = false shift_only = false
local b = mb.brightness + 0.3 local b = mb.brightness + 0.3
if b > 1 then; b = 0.4; end if b > 1 then; b = 0.4; end
@ -129,12 +129,13 @@ end
shift.keymap = { shift.keymap = {
name="shift", name="shift",
permanent=true, permanent=true,
[shift.KEY_SHIFT] = {c={r=1, g=1, b=1}, press=shift.grab, release=shift.release}, [shift.KEY_SHIFT] = {c={r=1, g=1, b=1}, press=shift.shift},
} }
shift.keymap_shifted = { shift.keymap_shifted = {
name="shift-shifted", name="shift-shifted",
secondary=true, secondary=true,
[shift.KEY_SHIFT] = {c={r=1, g=1, b=1}, press=shift.grab, release=shift.release}, [-1] = {press=shift.any_press, release=shift.any_release},
[shift.KEY_SHIFT] = {c={r=1, g=1, b=1}},
[shift.KEY_LAYOUT] = {c={r=0, g=1, b=1}, press=shift.cycle, release=shift.release_other}, [shift.KEY_LAYOUT] = {c={r=0, g=1, b=1}, press=shift.cycle, release=shift.release_other},
[shift.KEY_BRIGHTNESS] = {c={r=0.5, g=0.5, b=0.5}, press=shift.brightness, release=shift.release_other} [shift.KEY_BRIGHTNESS] = {c={r=0.5, g=0.5, b=0.5}, press=shift.brightness, release=shift.release_other}

View File

@ -24,10 +24,11 @@ SOFTWARE.
-- their correct handlers, depending on which keyboard layout currently -- their correct handlers, depending on which keyboard layout currently
-- is active. -- is active.
function mb.route(keyno, pressed) function mb.route(keyno, pressed)
local keydef local keydef, grabbed_any_keydef
-- Checks for a keymap grab being enforced at this time... -- Checks for a keymap grab being enforced at this time...
if mb.grab_keymap then if mb.grab_keymap then
keydef = mb.grab_keymap[keyno] keydef = mb.grab_keymap[keyno]
grabbed_any_keydef = mb.grab_keymap[-1]
else else
-- Checks for key in permanent keymaps first... -- Checks for key in permanent keymaps first...
for name, keymap in pairs(mb.keymaps) do for name, keymap in pairs(mb.keymaps) do
@ -45,7 +46,7 @@ function mb.route(keyno, pressed)
end end
-- Bails out if no key definition to route to could be found. -- Bails out if no key definition to route to could be found.
if not keydef then if not (keydef or grabbed_any_keydef) then
return return
end end
@ -57,11 +58,17 @@ function mb.route(keyno, pressed)
mb.led(led, {r = 0, g = 0, b = 0}) mb.led(led, {r = 0, g = 0, b = 0})
end end
end end
if keydef.press then if grabbed_any_keydef and grabbed_any_keydef.press then
grabbed_any_keydef.press(keyno)
end
if keydef and keydef.press then
keydef.press(keyno) keydef.press(keyno)
end end
else else
if keydef.release then if grabbed_any_keydef and grabbed_any_keydef.release then
grabbed_any_keydef.release(keyno)
end
if keydef and keydef.release then
keydef.release(keyno) keydef.release(keyno)
end end
mb.activate_leds() mb.activate_leds()

View File

@ -36,7 +36,9 @@ local hwk = require("spec/hwkeys")
describe("final Multibow integration", function() describe("final Multibow integration", function()
it("correctly integrates", function() _G.setup()
it("integrates all keymaps", function()
local kms = mb.registered_keymaps() local kms = mb.registered_keymaps()
-- shift: 2 registered keymaps -- shift: 2 registered keymaps
-- vsc-golang: 1 reg keymap -- vsc-golang: 1 reg keymap

View File

@ -38,7 +38,7 @@ describe("empty multibow keymap", function()
-- empty must register exactly one keymap, and it must be -- empty must register exactly one keymap, and it must be
-- a primary keymap, not permanent or secondary. -- a primary keymap, not permanent or secondary.
local kms = mb.registered_keymaps() local kms = mb.registered_keymaps()
assert.is.equal(#kms, 1) assert.is.equal(1, #kms)
local keymap = kms[1] local keymap = kms[1]
assert.is_falsy(keymap.permanent) assert.is_falsy(keymap.permanent)
assert.is_falsy(keymap.secondary) assert.is_falsy(keymap.secondary)

View File

@ -20,16 +20,36 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.
]]-- ]]--
require "mocked-keybow"
local hwk = require("spec/hwkeys") local hwk = require("spec/hwkeys")
local mb = require("snippets/multibow")
local k = require("layouts/kdenlive")
describe("Kdenlive keymap", function() describe("Kdenlive keymap", function()
it("...", function() it("...", function()
local mb = require("snippets/multibow")
local k = require("layouts/kdenlive")
assert.is.equal(k.keymap.name, mb.current_keymap.name)
local kms = mb.registered_keymaps() local kms = mb.registered_keymaps()
assert.is.equal(2, #kms) assert.is.equal(2, #kms)
end) end)
describe("with setup", function()
local hwk, mb, k
before_each(function()
mb = require("snippets/multibow")
require("layouts/shift")
k = require("layouts/kdenlive")
_G.setup()
end)
inslit("", function()
assert.is.equal(k.keymap.name, mb.current_keymap.name)
end)
end)
end) end)

View File

@ -27,44 +27,36 @@ local mb = require("snippets/multibow")
describe("SHIFT multibow keymap", function() describe("SHIFT multibow keymap", function()
insl(function() inslit("installs the SHIFT keymap", function()
-- Sanity check that there are no registered keymaps yet.
assert.is.equal(#mb.registered_keymaps(), 0)
it("installs the SHIFT keymap", function() local shift = require("layouts/shift")
-- Sanity check that there are no registered keymaps yet. assert.is_not_nil(shift) -- we're going slightly over the top here...
assert.is.equal(#mb.registered_keymaps(), 0) assert.is_not_nil(shift.keymap)
local shift = require("layouts/shift") -- SHIFT must register exactly two keymaps, a primary and a secondary one.
assert.is_not_nil(shift) -- we're going slightly over the top here... local kms = mb.registered_keymaps()
assert.is_not_nil(shift.keymap) assert.is.equal(#kms, 2)
for idx, keymap in ipairs(kms) do
-- SHIFT must register exactly two keymaps, a primary and a secondary one. if keymap == "shift" then
local kms = mb.registered_keymaps() assert.is_falsy(keymap.permanent)
assert.is.equal(#kms, 2) assert.is_falsy(keymap.secondary)
for idx, keymap in ipairs(kms) do elseif keymap == "shift-shifted" then
if keymap == "shift" then assert.is_falsy(keymap.permanent)
assert.is_falsy(keymap.permanent) assert.is_true(keymap.secondary)
assert.is_falsy(keymap.secondary)
elseif keymap == "shift-shifted" then
assert.is_falsy(keymap.permanent)
assert.is_true(keymap.secondary)
end
end end
end
default_key_shift = shift.KEY_SHIFT default_key_shift = shift.KEY_SHIFT
end)
end) end)
insl(function() inslit("accepts changes form default", function()
local override = 42
it("accepts changes form default", function()
local override = 42
_G.shift = { KEY_SHIFT=override }
local shift = require("layouts/shift")
assert.is.equal(shift.KEY_SHIFT, override)
end)
_G.shift = { KEY_SHIFT=override }
local shift = require("layouts/shift")
assert.is.equal(shift.KEY_SHIFT, override)
end) end)
describe("SHIFTY", function() describe("SHIFTY", function()
@ -77,74 +69,81 @@ describe("SHIFT multibow keymap", function()
shift = require("layouts/shift") shift = require("layouts/shift")
end) end)
insl(function() inslit("SHIFT grabs", function()
it("SHIFT grabs", function() spy.on(mb, "grab")
spy.on(mb, "grab") spy.on(mb, "ungrab")
spy.on(mb, "ungrab")
-- route in the SHIFT permanent keymap -- route in the SHIFT permanent keymap
hwk.press(shift.KEY_SHIFT)
assert.spy(mb.grab).was.called(1)
assert.spy(mb.grab).was.called_with(shift.keymap_shifted.name)
-- route in the shifted(!) SHIFT keymap, so this checks
-- that we ungrab correctly
mb.grab:clear()
hwk.release(shift.KEY_SHIFT)
assert.spy(mb.grab).was_not.called()
assert.spy(mb.ungrab).was.called(1)
mb.grab:revert()
mb.ungrab:revert()
end)
inslit("only lonely SHIFT triggers shift and no dangling grabs", function()
stub(shift, "shift_secondary_keymap")
-- test that lonely SHIFT triggers...
hwk.tap(shift.KEY_SHIFT)
assert.is_nil(mb.grab_keymap)
assert.stub(shift.shift_secondary_keymap).was.called(1)
-- but that SHIFT followed by another function doesn't shift.
shift.shift_secondary_keymap:clear()
for idx, key in ipairs({
shift.KEY_LAYOUT,
shift.KEY_BRIGHTNESS
}) do
hwk.press(shift.KEY_SHIFT) hwk.press(shift.KEY_SHIFT)
assert.spy(mb.grab).was.called(1) hwk.tap(key)
assert.spy(mb.grab).was.called_with(shift.keymap_shifted.name)
-- route in the shifted(!) SHIFT keymap, so this checks
-- that we ungrab correctly
mb.grab:clear()
hwk.release(shift.KEY_SHIFT) hwk.release(shift.KEY_SHIFT)
assert.spy(mb.grab).was_not.called() assert.is_nil(mb.grab_keymap)
assert.spy(mb.ungrab).was.called(1) assert.stub(shift.shift_secondary_keymap).was_not.called()
end
mb.grab:revert()
mb.ungrab:revert()
end)
end) end)
insl(function() inslit("lonly SHIFTs shift around", function()
it("only lonely SHIFT triggers shift", function() local keymap = {
stub(shift, "shift_secondary_keymap") name="test"
}
local keymap_shifted = {
name="test-shifted",
[0]={press=function(key) end}
}
keymap.shift_to = keymap_shifted
keymap_shifted.shift_to = keymap
mb.register_keymap(keymap)
mb.register_keymap(keymap_shifted)
assert.is.equal(mb.current_keymap, keymap)
-- test that lonely SHIFT triggers... spy.on(mb, "activate_keymap")
hwk.tap(shift.KEY_SHIFT) local s = stub(keymap_shifted[0], "press")
assert.stub(shift.shift_secondary_keymap).was.called(1)
-- but that SHIFT followed by another function doesn't shift. hwk.tap(shift.KEY_SHIFT)
shift.shift_secondary_keymap:clear() assert.spy(mb.activate_keymap).was.called_with(keymap_shifted.name)
for idx, key in ipairs({ assert.is.equal(mb.current_keymap, keymap_shifted)
shift.KEY_LAYOUT,
shift.KEY_BRIGHTNESS
}) do
hwk.press(shift.KEY_SHIFT)
hwk.tap(key)
hwk.release(shift.KEY_SHIFT)
assert.stub(shift.shift_secondary_keymap).was_not.called()
end
end)
end)
insl(function() hwk.tap(0)
it("lonly SHIFTs shift around", function() assert.stub(s).was.called(1)
local keymap = {
name="test"
}
local keymap_shifted = {
name="test-shifted"
}
keymap.shift_to = keymap_shifted
keymap_shifted.shift_to = keymap
mb.register_keymap(keymap)
mb.register_keymap(keymap_shifted)
assert.is.equal(mb.current_keymap, keymap)
spy.on(mb, "activate_keymap") hwk.tap(shift.KEY_SHIFT)
assert.is.equal(mb.current_keymap, keymap)
hwk.tap(shift.KEY_SHIFT) s:clear()
assert.spy(mb.activate_keymap).was.called_with(keymap_shifted.name) hwk.tap(0)
assert.is.equal(mb.current_keymap, keymap_shifted) assert.stub(s).was_not.called()
hwk.tap(shift.KEY_SHIFT)
assert.is.equal(mb.current_keymap, keymap)
mb.activate_keymap:revert() mb.activate_keymap:revert()
end) s:revert()
end) end)
insl(function() insl(function()

View File

@ -62,6 +62,7 @@ describe("routehandlers", function()
} }
local grab_keymap = { local grab_keymap = {
name="grab", name="grab",
[-1]={press=spies.grab_key_press, release=spies.grab_key_release},
[0]={press=spies.grab_key_press, release=spies.grab_key_release} [0]={press=spies.grab_key_press, release=spies.grab_key_release}
} }
@ -172,11 +173,18 @@ describe("routehandlers", function()
mb.register_keymap(grab_keymap) mb.register_keymap(grab_keymap)
mb.grab(grab_keymap.name) mb.grab(grab_keymap.name)
-- grab routes to grab handler *AND* grab any handler
assert.spy(spies.grab_key_press).was.called(0) assert.spy(spies.grab_key_press).was.called(0)
hwk.press(0) hwk.press(0)
assert.spy(spies.grab_key_press).was.called(1) -- remember: this grab has an "any" handler
assert.spy(spies.grab_key_press).was.called(2)
assert.spy(spies.grab_key_press).was.called_with(0) assert.spy(spies.grab_key_press).was.called_with(0)
spies.grab_key_press:clear()
hwk.press(1)
assert.spy(spies.grab_key_press).was.called(1)
assert.spy(spies.grab_key_press).was.called_with(1)
spies.grab_key_press:clear() spies.grab_key_press:clear()
mb.ungrab() mb.ungrab()
hwk.press(0) hwk.press(0)