From 7328db8666d5fd7e522f8b3a57fc0daad5d8bb06 Mon Sep 17 00:00:00 2001 From: Harald Albrecht Date: Mon, 7 Jan 2019 20:45:05 +0100 Subject: [PATCH] improves readme; updates kdenlive keymap --- README.md | 56 ++++++++++++++++++++ sdcard/layouts/empty.lua | 2 +- sdcard/layouts/kdenlive.lua | 74 ++++++++++++++++++++++----- sdcard/layouts/keymap-template.lua | 69 +++++++++++++++++++++++++ spec/layouts/kdenlive_spec.lua | 10 ++++ spec/layouts/keymap-template_spec.lua | 55 ++++++++++++++++++++ 6 files changed, 253 insertions(+), 13 deletions(-) create mode 100644 sdcard/layouts/keymap-template.lua create mode 100644 spec/layouts/keymap-template_spec.lua diff --git a/README.md b/README.md index c476327..2c65feb 100644 --- a/README.md +++ b/README.md @@ -103,6 +103,62 @@ layout by courtesy of Margaret Thatcher._) └╌╌╌╌┘ └╌╌╌╌┘ └╌╌╌╌┘ └╌╌╌╌┘ ``` +## Your Own Multikey Keyboard Layout + +You may want to start from our template in `layouts/keymap-template.lua`. + +1. copy and rename the new layout file name to something more meaningful. + +2. edit your new layout file and change its name which is specified in the + `kmt.name` element: + + ```lua + km.keymap = { + -- IMPORTANT: Make sure to change the keymap name to make it unique! + name="my-cool-layout", + -- ... + } + ``` + +3. add key definitions for colors and handlers as necessary, see next for examples. + + * you can specify key handlers either "inline", as you can see from the + example mapping for key #0: + + ```lua + km.keymap = { + -- ... + [0] = { c={r=1, g=1, b=1}, press=function() mb.tap("a") end}, + } + ``` + + This sets the key #0's LED color to white, and emits an "a" press everytime + you tap key #0. + + * for more complex handling, you may want to use a dedicated function instead: + + ```lua + function km.mypress(keyno) + mb.tap("a") + end + + km.keymap = { + -- ... + [1] = { c={r=1, g=1, b=1}, press=km.mypress} + } + + * you can also do things on key releases: + + ```lua + km.keymap = { + -- ... + [2] = { c={r=1, g=1, b=1}, release=function() mb.tap("x") end}, + } + ``` + +For more details and examples, please have a look at the keyboard layouts in +`layouts/vsc-golang.lua` and `layouts/kdenlive.lua`. + ## Licenses Multibow is (c) 2019 Harald Albrecht and is licensed under the MIT license, see diff --git a/sdcard/layouts/empty.lua b/sdcard/layouts/empty.lua index cdb9d33..604c770 100644 --- a/sdcard/layouts/empty.lua +++ b/sdcard/layouts/empty.lua @@ -44,7 +44,7 @@ cable going off "northwards": ]]-- -empty.keymap = {name="empty"} +empty.keymap = { name="empty" } mb.register_keymap(empty.keymap) return empty -- module diff --git a/sdcard/layouts/kdenlive.lua b/sdcard/layouts/kdenlive.lua index bea8ba4..c9d16ab 100644 --- a/sdcard/layouts/kdenlive.lua +++ b/sdcard/layouts/kdenlive.lua @@ -29,36 +29,86 @@ require("keybow") local mk = require("snippets/morekeys") local mb = require("snippets/multibow") +--[[ +The Keybow layout is as follows when in landscape orientation, with the USB +cable going off "northwards": -k.KEY_CLIP_BEGIN = k.KEY_CLIP_BEGIN or 9 -k.KEY_PROJECT_BEGIN = k.KEY_PROJECT_BEGIN or 9 + ┋┋ +┌╌╌╌╌┐ ┌╌╌╌╌┐ ┌╌╌╌╌┐ ┌╌╌╌╌┐ +┊ 11 ┊ ┊ 8 ┊ ┊ 5 ┊ ┊ 2 ┊ +└╌╌╌╌┘ └╌╌╌╌┘ └╌╌╌╌┘ └╌╌╌╌┘ -k.KEY_CLIP_END = k.KEY_CLIP_END or 0 -k.KEY_PROJECT_END = k.KEY_PROJECT_END or 0 +┌╌╌╌╌┐ ┌╌╌╌╌┐ ┌╌╌╌╌┐ ┌╌╌╌╌┐ +┊ 10 ┊ ┊ 7 ┊ ┊ 4 ┊ ┊ 1 ┊ +└╌╌╌╌┘ └╌╌╌╌┘ └╌╌╌╌┘ └╌╌╌╌┘ + +┌╌╌╌╌┐ ┌╌╌╌╌┐ ┌╌╌╌╌┐ ┌╌╌╌╌┐ +┊ 9 ┊ ┊ 6 ┊ ┊ 3 ┊ ┊ 0 ┊ +└╌╌╌╌┘ └╌╌╌╌┘ └╌╌╌╌┘ └╌╌╌╌┘ + ⍇ ⍈ + (⯬) (⯮) + +]]-- + +k.KEY_PLAY_AROUND_MOUSE = k.KEY_PLAY_AROUND_MOUSE or 10 + +k.KEY_ZONE_BEGIN = k.KEY_ZONE_BEGIN or 7 +k.KEY_ZONE_END = k.KEY_ZONE_END or 4 + +k.KEY_CLIP_BEGIN = k.KEY_CLIP_BEGIN or 6 +k.KEY_CLIP_END = k.KEY_CLIP_END or 3 +k.KEY_PROJECT_BEGIN = k.KEY_PROJECT_BEGIN or 6 +k.KEY_PROJECT_END = k.KEY_PROJECT_END or 3 -- (Default) key colors for unshifted and shifted keys. k.COLOR_UNSHIFTED = k.COLOR_UNSHIFTED or {r=0, g=1, b=0} k.COLOR_SHIFTED = k.COLOR_SHIFTED or {r=1, g=0, b=0} +function k.play_around_mouse(...) + mb.tap("p") + mb.tap_times(keybow.LEFT_ARROW, 3, keybow.LEFT_SHIFT) + mb.tap("i") + mb.tap_times(keybow.RIGHT_ARROW, 3, keybow.LEFT_SHIFT) + mb.tap("o") + mb.tap(...) +end + + -- Unshift to primary keymap. For simplification, use it with the "anykey" -- release handlers, see below. function k.unshift(keyno) mb.activate_keymap(k.keymap.name) end -k.keymap = { +-- Helps avoiding individual color setting... +function k.init_color(keymap, color) + for keyno, keydef in pairs(keymap) do + if type(keyno) == "number" and keyno >= 0 then + if not keydef.c then + keydef.c = color + end + end + end + return keymap +end + +k.keymap = k.init_color({ name="kdenlive", - [k.KEY_CLIP_BEGIN] = {c=k.COLOR_UNSHIFTED, press=function() mb.tap(mk.HOME) end}, - [k.KEY_CLIP_END] = {c=k.COLOR_UNSHIFTED, press=function() mb.tap(mk.END) end}, -} -k.keymap_shifted = { + [k.KEY_ZONE_BEGIN] = {press=function() mb.tap("I") end}, + [k.KEY_ZONE_END] = {press=function() mb.tap("O") end}, + [k.KEY_CLIP_BEGIN] = {press=function() mb.tap(mk.HOME) end}, + [k.KEY_CLIP_END] = {press=function() mb.tap(mk.END) end}, + [k.KEY_PLAY_AROUND_MOUSE] = {press=function() k.play_around_mouse(keybow.SPACE, keybow.LEFT_CTRL) end}, +}, k.COLOR_UNSHIFTED) +k.keymap_shifted = k.init_color({ name="kdenlive-shifted", secondary=true, - [k.KEY_PROJECT_BEGIN] = {c=k.COLOR_SHIFTED, press=function() mb.tap(mk.HOME, keybow.LEFT_CTRL) end}, - [k.KEY_PROJECT_END] = {c=k.COLOR_SHIFTED, press=function() mb.tap(mk.END, keybow.LEFT_CTRL) end}, + [k.KEY_PROJECT_BEGIN] = {press=function() mb.tap(mk.HOME, keybow.LEFT_CTRL) end}, + [k.KEY_PROJECT_END] = {press=function() mb.tap(mk.END, keybow.LEFT_CTRL) end}, + [k.KEY_PLAY_AROUND_MOUSE] = {press=function() k.play_around_mouse(keybow.SPACE, keybow.LEFT_ALT) end}, [-1] = {release=k.unshift}, -} +}, k.COLOR_SHIFTED) k.keymap.shift_to = k.keymap_shifted k.keymap_shifted.shift_to = k.keymap diff --git a/sdcard/layouts/keymap-template.lua b/sdcard/layouts/keymap-template.lua new file mode 100644 index 0000000..4c31482 --- /dev/null +++ b/sdcard/layouts/keymap-template.lua @@ -0,0 +1,69 @@ +-- An empty Multibow Keybow layout. Useful for "switching off" any active +-- keymaps, with only the permanent keymaps (SHIFT, etc) being still in place. + +--[[ +Copyright 2019 Harald Albrecht + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +]]-- + +local km = {} -- module + +local mb = require("snippets/multibow") + +--[[ +The Keybow layout is as follows when in landscape orientation, with the USB +cable going off "northwards": + + ┋┋ +┌╌╌╌╌┐ ┌╌╌╌╌┐ ┌╌╌╌╌┐ ┌╌╌╌╌┐ +┊ 11 ┊ ┊ 8 ┊ ┊ 7 ┊ ┊ 6 ┊ +└╌╌╌╌┘ └╌╌╌╌┘ └╌╌╌╌┘ └╌╌╌╌┘ +┌╌╌╌╌┐ ┌╌╌╌╌┐ ┌╌╌╌╌┐ ┌╌╌╌╌┐ +┊ 10 ┊ ┊ 7 ┊ ┊ 4 ┊ ┊ 1 ┊ +└╌╌╌╌┘ └╌╌╌╌┘ └╌╌╌╌┘ └╌╌╌╌┘ +┌╌╌╌╌┐ ┌╌╌╌╌┐ ┌╌╌╌╌┐ ┌╌╌╌╌┐ +┊ 9 ┊ ┊ 6 ┊ ┊ 3 ┊ ┊ 0 ┊ +└╌╌╌╌┘ └╌╌╌╌┘ └╌╌╌╌┘ └╌╌╌╌┘ + +]]-- + +-- Some action on a certain key press... +function km.mypress(keyno) +end + +-- Some action on a certain key release... +function km.myrelease(keyno) +end + +-- The keymap layout... +km.keymap = { + -- IMPORTANT: Make sure to change the keymap name to make it unique! + name="keymap-template", + + -- The index entries below are defining keys as to their LED color and + -- what key taps should be send to the USB host to which your Keybow is + -- connected to. + [0] = { c={r=1, g=1, b=1}, press=function() mb.tap("a") end}, + [1] = { c={r=1, g=1, b=1}, press=km.mypress}, + [2] = { c={r=1, g=1, b=1}, release=km.myrelease}, +} +mb.register_keymap(km.keymap) + +return km -- module diff --git a/spec/layouts/kdenlive_spec.lua b/spec/layouts/kdenlive_spec.lua index 9cea069..061555a 100644 --- a/spec/layouts/kdenlive_spec.lua +++ b/spec/layouts/kdenlive_spec.lua @@ -95,6 +95,16 @@ describe("Kdenlive keymap", function() assert.spy(sm).was.called() end) + inslit("taps", function() + local s = spy.on(mb, "tap") + + hwk.tap(k.KEY_PLAY_AROUND_MOUSE) + assert.spy(s).was.called() + + hwk.tap(shift.KEY_SHIFT) + hwk.tap(k.KEY_PLAY_AROUND_MOUSE) + end) + end) end) diff --git a/spec/layouts/keymap-template_spec.lua b/spec/layouts/keymap-template_spec.lua new file mode 100644 index 0000000..fa1d60e --- /dev/null +++ b/spec/layouts/keymap-template_spec.lua @@ -0,0 +1,55 @@ +--[[ +Copyright 2019 Harald Albrecht + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +]]-- + +require "mocked-keybow" + +describe("template multibow keymap", function() + + local mb = require("snippets/multibow") + local hwk = require("spec/hwkeys") + local kmt = require("layouts/keymap-template") + + inslit("installs a single primary keymap", function() + assert.is_not_nil(kmt) -- we're going over the top here... + assert.is_not_nil(kmt.keymap) -- ...even more so. + + -- empty must register exactly one keymap, and it must be + -- a primary keymap, not permanent or secondary. + local kms = mb.registered_keymaps() + assert.is.equal(1, #kms) + local keymap = kms[1] + assert.is_falsy(keymap.permanent) + assert.is_falsy(keymap.secondary) + end) + + + inslit("calls press and release handlers", function() + local mp = spy.on(kmt.keymap[1], "press") + local mr = spy.on(kmt.keymap[2], "release") + + hwk.tap(1) + assert.spy(mp).was.called(1) + hwk.tap(2) + assert.spy(mr).was.called(1) + end) + +end)