From 6fd78c1bf145f39e15df5ae13801ce2bd50890c4 Mon Sep 17 00:00:00 2001 From: Harald Albrecht Date: Tue, 8 Jan 2019 12:48:34 +0100 Subject: [PATCH] changes due to linting; refactors keybow mock stuff to go inside spec/ --- .busted | 4 +- .luacheckrc | 38 ++++++- README.md | 66 ++++++----- check.sh | 12 ++ mock/mocked-keybow.lua | 16 --- sdcard/layouts/empty.lua | 4 +- sdcard/layouts/kdenlive.lua | 17 +-- sdcard/layouts/keymap-template.lua | 7 +- sdcard/layouts/shift.lua | 16 +-- sdcard/layouts/vsc-golang.lua | 39 +++++-- sdcard/snippets/mb/keymaps.lua | 158 ++++++++++++++++++++++++++ sdcard/snippets/mb/keys.lua | 22 +++- sdcard/snippets/mb/leds.lua | 12 +- sdcard/snippets/{ => mb}/morekeys.lua | 15 ++- sdcard/snippets/mb/routehandlers.lua | 9 +- sdcard/snippets/multibow.lua | 139 ++-------------------- setup-tests.sh | 2 + spec/hwkeys.lua | 2 +- spec/hwkeys_spec.lua | 4 +- spec/layouts/empty_spec.lua | 4 +- spec/layouts/kdenlive_spec.lua | 12 +- spec/layouts/keymap-template_spec.lua | 2 +- spec/layouts/shift_spec.lua | 10 +- spec/layouts/vsc-golang_spec.lua | 2 +- {mock => spec/mock}/keybow.lua | 0 spec/mock/mocked-keybow.lua | 54 +++++++++ spec/mocked-keybow_spec.lua | 50 ++++++++ spec/snippets/keys_spec.lua | 4 +- spec/snippets/leds_spec.lua | 2 +- spec/snippets/multibow_spec.lua | 6 +- spec/snippets/routehandlers_spec.lua | 31 +++-- 31 files changed, 493 insertions(+), 266 deletions(-) create mode 100755 check.sh delete mode 100644 mock/mocked-keybow.lua create mode 100644 sdcard/snippets/mb/keymaps.lua rename sdcard/snippets/{ => mb}/morekeys.lua (87%) rename {mock => spec/mock}/keybow.lua (100%) create mode 100644 spec/mock/mocked-keybow.lua create mode 100644 spec/mocked-keybow_spec.lua diff --git a/.busted b/.busted index e1b6b02..cff5581 100644 --- a/.busted +++ b/.busted @@ -1,4 +1,4 @@ --- Configuration for "busted" TDD tool +-- Configuration for "busted" TDD tool to unit test Multibow --[[ Copyright 2019 Harald Albrecht @@ -24,7 +24,7 @@ SOFTWARE. return { default = { - lpath = "./sdcard/?.lua;./mock/?.lua", + lpath = "./sdcard/?.lua;./spec/mock/?.lua", -- Provides an "insl" convenience replacement for busted's insulate() using -- a fixed descriptive text ... or rather, icon. Please not that "insl" -- not only rhymes with "insulation", but even more so with the German diff --git a/.luacheckrc b/.luacheckrc index 337f939..e5439be 100644 --- a/.luacheckrc +++ b/.luacheckrc @@ -1,5 +1,37 @@ -std = { +-- Configuration for "luacheck"ing Multibow + +--[[ +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. +]]-- + +stds.multibow = { read_globals = { - "insl", "require" + -- 3rd party stuff that doesn't exactly play by the new Lua module rules... + "keybow", + + -- our unit testing setup + "insl", "inslit" } -} \ No newline at end of file +} + +std = "max+multibow" + +exclude_files = { "spec/mock/keybow.lua" } diff --git a/README.md b/README.md index 2c65feb..ab73e0c 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,34 @@ And yes, this is probably a New Year's project slightly gone overboard ... what sane reason is there to end up with a Lua-scripted multi-layout keyboard "operating" system and a bunch of automated unit test cases? +## Installation + +1. Download the [Pibow + firmware](https://github.com/pimoroni/keybow-firmware/releases) and copy + all files inside its `sdcard/` subdirectory onto an empty, FAT32 formatted + microSD card. Copy only the files **inside** `sdcard/`, but do **not** + place them into a ~~`sdcard`~~ directory on your microSD card. + +2. Download all files from the `sdcard/` subdirectory of this repository and + then copy them onto the microSD card. This will overwrite but one file + `key.lua`, all other files are new. + +## Multiple Keyboard Layouts + +To enable one or more multibow keyboard layouts, edit `sdcard/keys.lua` +accordingly in order to "`require`" them. The default configuration looks as +follows: + +```lua +require "layouts/shift" -- for cycling between layouts. +require "layouts/vsc-golang" -- debugging Go programs in VisualStudio Code. +require "layouts/kdenlive" -- editing video using Kdenlive. +require "layouts/empty" -- empty, do-nothing layout. +``` + +> You can disable a specific keyboard layout by simply putting two dashes `--` +> in front of the `require "..."`, making it look like `--require "..."`. + ## Layouts The default setup activates the following macro keyboard layouts shown below. @@ -56,13 +84,19 @@ Debug Go programs and packages in VisualStudio Code with its Go extension. _coming soon..._ -### SHIFT +### SHIFT Overlay -A SHIFT key, with Keybow LED brightness and keyboard layout cycle control. +This layout provides a SHIFT key. Only when pressed and held, two additional +keys become active for controlling the brightness of the Keybow LEDs and for +switching between multiple keyboard layouts. + +Simply pressing and then immediately releasing the SHIFT key without pressing +any of the other keys activates the SHIFT layer in other Multibow keyboard +layouts that are SHIFT-aware. > **NOTE:** press and hold SHIFT, then use β†’LAYOUT and πŸ”†BRIGHT. The SHIFT key -> is always active, regardless of keyboard layout. The other keys in this layout -> only become active _while_ holding SHIFT. +> is always active, regardless of keyboard layout. The other keys in this +> layout become only active _while_ holding SHIFT. ```text ╔════╗ β•”β•Œβ•Œβ•Œβ•Œβ•— β•”β•Œβ•Œβ•Œβ•Œβ•— β”Œβ•Œβ•Œβ•Œβ•Œβ” @@ -169,30 +203,6 @@ The file `keybow.lua` included from testing purposes is licensed under the MIT license, as declared by Pimoroni's keybow-firmware GitHub repository. -## Installation - -1. Download the [Pibow - firmware](https://github.com/pimoroni/keybow-firmware/releases) and copy - all files inside its `sdcard/` subdirectory onto an empty, FAT32 formatted - microSD card. Copy only the files **inside** `sdcard/`, but do **not** - place them into a ~~`sdcard`~~ directory on your microSD card. - -2. Download all files from the `sdcard/` subdirectory of this repository and - then copy them onto the microSD card. This will overwrite but one file - `key.lua`, all other files are new. - -## Multiple Keyboard Layouts - -To enable one or more multibow keyboard layouts, edit `sdcard/keys.lua` -accordingly to require them. The default configuration is as follows: - -```lua -require "layouts/shift" -- for cycling between layouts. -require "layouts/vsc-golang" -- debugging Go programs in VisualStudio Code. -require "layouts/kdenlive" -- editing video using Kdenlive. -require "layouts/empty" -- empty, do-nothing layout. -``` - ## Developing Whether you want to dry-run your own keyboard layout or to hack Multibow: use diff --git a/check.sh b/check.sh new file mode 100755 index 0000000..44496db --- /dev/null +++ b/check.sh @@ -0,0 +1,12 @@ +#!/bin/bash +hascmd() { + command -v "$1" >/dev/null +} +if ! hascmd busted || ! hascmd luacheck ; then + echo "missing busted TDD library and luacheck Lua static source code checker; trying to install..." + bash ./setup-tests.sh +fi +echo "testing..." +busted +echo "linting..." +luacheck -q ./sdcard ./spec diff --git a/mock/mocked-keybow.lua b/mock/mocked-keybow.lua deleted file mode 100644 index b3c3351..0000000 --- a/mock/mocked-keybow.lua +++ /dev/null @@ -1,16 +0,0 @@ -local busted=require "busted" - -require "keybow" -busted.stub(keybow, "auto_lights") -busted.stub(keybow, "clear_lights") -busted.stub(keybow, "load_pattern") -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_modifier") -busted.stub(keybow, "tap_key") - -busted.stub(keybow, "sleep") -- FIXME -busted.stub(keybow, "usleep") -- FIXME - -return keybow \ No newline at end of file diff --git a/sdcard/layouts/empty.lua b/sdcard/layouts/empty.lua index 604c770..99cea45 100644 --- a/sdcard/layouts/empty.lua +++ b/sdcard/layouts/empty.lua @@ -1,5 +1,5 @@ --- An empty Multibow Keybow layout. Useful for "switching off" any active --- keymaps, with only the permanent keymaps (SHIFT, etc) being still in place. +-- An empty Multibow layout. Useful for "switching off" any active keymaps, +-- with only the permanent keymaps (SHIFT, etc) being still in place. --[[ Copyright 2019 Harald Albrecht diff --git a/sdcard/layouts/kdenlive.lua b/sdcard/layouts/kdenlive.lua index c9d16ab..e9bed9b 100644 --- a/sdcard/layouts/kdenlive.lua +++ b/sdcard/layouts/kdenlive.lua @@ -1,3 +1,6 @@ +-- A Multibow keyboard layout for the Kdenlive (https://kdenlive.org/) open +-- source non-linear video editor. + --[[ Copyright 2019 Harald Albrecht @@ -20,15 +23,15 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ]]-- + -- allow users to set their own configuration before req'ing this -- module, in order to control the key layout. For defaults, please see -- below. local k = _G.kdenlive or {} -- module -require("keybow") -local mk = require("snippets/morekeys") local mb = require("snippets/multibow") +-- luacheck: ignore 614 --[[ The Keybow layout is as follows when in landscape orientation, with the USB cable going off "northwards": @@ -77,7 +80,7 @@ end -- Unshift to primary keymap. For simplification, use it with the "anykey" -- release handlers, see below. -function k.unshift(keyno) +function k.unshift(_) mb.activate_keymap(k.keymap.name) end @@ -97,15 +100,15 @@ k.keymap = k.init_color({ name="kdenlive", [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_CLIP_BEGIN] = {press=function() mb.tap(keybow.HOME) end}, + [k.KEY_CLIP_END] = {press=function() mb.tap(keybow.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] = {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_PROJECT_BEGIN] = {press=function() mb.tap(keybow.HOME, keybow.LEFT_CTRL) end}, + [k.KEY_PROJECT_END] = {press=function() mb.tap(keybow.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) diff --git a/sdcard/layouts/keymap-template.lua b/sdcard/layouts/keymap-template.lua index 4c31482..152a0d1 100644 --- a/sdcard/layouts/keymap-template.lua +++ b/sdcard/layouts/keymap-template.lua @@ -1,5 +1,4 @@ --- An empty Multibow Keybow layout. Useful for "switching off" any active --- keymaps, with only the permanent keymaps (SHIFT, etc) being still in place. +-- A Multibow template layout, useful for starting your own keymap layouts. --[[ Copyright 2019 Harald Albrecht @@ -45,11 +44,11 @@ cable going off "northwards": ]]-- -- Some action on a certain key press... -function km.mypress(keyno) +function km.mypress(keyno) -- luacheck: ignore 212 end -- Some action on a certain key release... -function km.myrelease(keyno) +function km.myrelease(keyno) -- luacheck: ignore 212 end -- The keymap layout... diff --git a/sdcard/layouts/shift.lua b/sdcard/layouts/shift.lua index 8c4625a..21e57cb 100644 --- a/sdcard/layouts/shift.lua +++ b/sdcard/layouts/shift.lua @@ -1,4 +1,6 @@ --- A permanent "SHIFT" keymap for cycling keymaps and LED brightness control. +-- A permanent "SHIFT" Multibow keymap layout for cycling keymaps, LED +-- brightness control, and adding SHIFT layers to other Multibow keyboard +-- (multi) layouts. --[[ Copyright 2019 Harald Albrecht @@ -29,6 +31,7 @@ local shift = _G.shift or {} -- module local mb = require "snippets/multibow" +-- luacheck: ignore 614 --[[ The Keybow layout is as follows when in landscape orientation, with the USB cable going off "northwards": @@ -55,7 +58,7 @@ shift.KEY_SHIFT = shift.KEY_SHIFT or 11 shift.KEY_LAYOUT = shift.KEY_LAYOUT or 8 shift.KEY_BRIGHTNESS = shift.KEY_BRIGHTNESS or 5 -shift.BRIGHTNESS_LEVELS = shift.BRIGHTNESS_LEVELS or { 70, 100, 40 } +shift.BRIGHTNESS_LEVELS = shift.BRIGHTNESS_LEVELS or { 70, 100, 40 } -- Internal flag for detecting SHIFT press-release sequences without any SHIFTed @@ -79,12 +82,12 @@ end -- Remember how many grabbed keys are pressed, so we won't ungrab later until -- all keys have been released. -function shift.any_press(keyno) +function shift.any_press(_) grabbed_key_count = grabbed_key_count + 1 end -- Only ungrab after last key has been released -function shift.any_release(keyno) +function shift.any_release(_) if grabbed_key_count > 0 then grabbed_key_count = grabbed_key_count - 1 if grabbed_key_count == 0 then @@ -101,16 +104,13 @@ end -- SHIFT press: switches into grabbed SHIFT mode, activating the in-SHIFT keys -- for brightness change, keymap cycling, et cetera. function shift.shift(key) - grabbed_keys = 1 -- includes myself; this is necessary as the grab "any" - -- handler will not register the SHIFT press, because it - -- wasn't grabbed yet. shift_only = true shift.any_press(key) mb.grab(shift.keymap_shifted.name) end -- Cycles to the next primary keyboard layout (keymap) -function shift.cycle(key) +function shift.cycle(_) shift_only = false mb.cycle_primary_keymaps() end diff --git a/sdcard/layouts/vsc-golang.lua b/sdcard/layouts/vsc-golang.lua index 69ca695..9dac960 100644 --- a/sdcard/layouts/vsc-golang.lua +++ b/sdcard/layouts/vsc-golang.lua @@ -1,4 +1,27 @@ --- VSC Go extension debug Keybow layout +-- A Multibow keyboard layout for the VisualStudio Go extension +-- (https://github.com/Microsoft/vscode-go). + +--[[ +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 vscgo = _G.vscgo or {} -- module @@ -52,31 +75,31 @@ vscgo.COLOR_STEPOUT = vscgo.COLOR_STEPOUT or vscgo.BLUEGRAY -- AND NOW FOR SOMETHING DIFFERENT: THE REAL MEAT -- -function vscgo.debug_stop(key) +function vscgo.debug_stop(_) mb.tap(keybow.F5, keybow.LEFT_SHIFT) end -function vscgo.debug_restart(key) +function vscgo.debug_restart(_) mb.tap(keybow.F5, keybow.LEFT_SHIFT, keybow.LEFT_CTRL) end -function vscgo.debug_continue(key) +function vscgo.debug_continue(_) mb.tap(keybow.F5) end -function vscgo.debug_stepover(key) +function vscgo.debug_stepover(_) mb.tap(keybow.F10) end -function vscgo.debug_stepinto(key) +function vscgo.debug_stepinto(_) mb.tap(keybow.F11) end -function vscgo.debug_stepout(key) +function vscgo.debug_stepout(_) mb.tap(keybow.F11, keybow.LEFT_SHIFT) end -function vscgo.go_test_package(key) +function vscgo.go_test_package(_) mb.tap("P", keybow.LEFT_SHIFT, keybow.LEFT_CTRL) keybow.sleep(250) keybow.text("go test package") diff --git a/sdcard/snippets/mb/keymaps.lua b/sdcard/snippets/mb/keymaps.lua new file mode 100644 index 0000000..e4046a5 --- /dev/null +++ b/sdcard/snippets/mb/keymaps.lua @@ -0,0 +1,158 @@ +-- Multibow internal "module" implementing keymap-related management and +-- handling. + +--[[ +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. +]]-- + +-- luacheck: globals mb + +-- Internal variables for housekeeping... + +-- The registered keymaps, indexed by their names (.name field). +mb.keymaps = {} +-- The ordered sequence of primary keymap, in the sequence they were +-- registered. +mb.primary_keymaps = {} +-- The currently activated keymap. +mb.current_keymap = nil +-- A temporary keymap while grabbing. +mb.grab_keymap = nil + +-- Registers a keymap (by name), so it can be easily activated later by its name. +-- Multiple keymaps can be registered. Keymaps can be either "primary" by +-- default, or permanent or secondary keymaps. +-- +-- A primary keymap is any keymap without either a "permanent" or "secondary" +-- table element. Users can cycle through primary keymaps using the "shift" +-- permanent keyboard layout. +-- +-- permanent keymaps (marked by table element "permanent=true") are always +-- active, thus they don't need to be activated. +-- +-- Secondary keymaps (marked by table element "secondary=true") are intended +-- as SHIFT/modifier layers. As such the get ignored by cycling, but instead +-- need to be activated explicitly. The "shift" permanent keyboard layout +-- automates this. +-- +-- If this is the first keymap getting registered, then it will also made +-- activated. +function mb.register_keymap(keymap) + local name = keymap.name + -- register + mb.keymaps[name] = keymap + -- ensure that first registered keymap also automatically gets activated + -- (albeit the LEDs will only update later). Also maintain the (ordered) + -- sequence of registered primary keymaps. + if not (keymap.permanent or keymap.secondary) then + mb.current_keymap = mb.current_keymap or keymap + table.insert(mb.primary_keymaps, keymap) + end +end + +-- Returns the list of currently registered keymaps; this list is a table, +-- with its registered keymaps at indices 1, 2, ... +function mb.registered_keymaps() + local keymaps = {} + for _, keymap in pairs(mb.keymaps) do + table.insert(keymaps, keymap) + end + return keymaps +end + +-- Returns the list of currently registered *primary* keymaps, in the same order +-- as they were registered. First primary is at index 1, second at 2, ... +function mb.registered_primary_keymaps() + return mb.primary_keymaps +end + +-- Cycles through the available (primary) keymaps, ignoring secondary and +-- permanent keymaps. This is convenient for assigning primary keymap switching +-- using a key on the Keybow device itself. +function mb.cycle_primary_keymaps() + local km = mb.current_keymap + if km == nil then return end + -- If this is a secondary keymap, locate its corresponding primary keymap. + if km.secondary then + if not km.shift_to then + -- No SHIFT's shift_to cyclic chain available, so rely on the naming + -- schema instead and try to locate the primary keymap with the first + -- match instead. This assumes that the name of the secondary keymaps + -- have some suffix and thus are longer than the name of their + -- corresponding primary keymap. + for _, pkm in ipairs(mb.primary_keymaps) do + if string.sub(km.name, 1, #pkm.name) == pkm.name then + km = pkm + break + end + end + -- Checks if locating the primary keymap failed and then bails out + -- immediately. + if km.secondary then return end + else + -- Follows the cyclic chain of SHIFT's shift_to keymaps, until we get + -- to the primary keymap in the cycle, or until we have completed one + -- cycle. + repeat + km = km.shift_to + if not km or km == mb.current_keymap then + return + end + until not(km.secondary) + end + end + -- Move on to the next primary keymap, rolling over at the end of our list. + for idx, pkm in ipairs(mb.primary_keymaps) do + if pkm == km then + idx = idx + 1 + if idx > #mb.primary_keymaps then idx = 1 end + mb.activate_keymap(mb.primary_keymaps[idx].name) + end + end +end + +-- Activates a specific keymap by name. Please note that it isn't necessary +-- to "activate" permanent keymaps at all (and thus this deed cannot be done). +function mb.activate_keymap(name) + name = type(name) == "table" and name.name or name + local keymap = mb.keymaps[name] + if keymap and not keymap.permanent then + mb.current_keymap = keymap + mb.activate_leds() + end +end + +-- Sets a "grabbing" keymap that takes (temporarily) grabs all keys. While a +-- grab keymap is in place, key presses and releases will only be routed to +-- the grab keymap, but never to the permanent keymaps, nor the previously +-- "active" primary keymap. +function mb.grab(name) + name = type(name) == "table" and name.name or name + mb.grab_keymap = mb.keymaps[name] + mb.activate_leds() +end + +-- Removes a "grabbing" keymap, thus reactivating the permanent keymaps, as +-- well as the previously active primary keymap. +function mb.ungrab() + mb.grab_keymap = nil + mb.activate_leds() +end diff --git a/sdcard/snippets/mb/keys.lua b/sdcard/snippets/mb/keys.lua index 68721ea..7e8ae91 100644 --- a/sdcard/snippets/mb/keys.lua +++ b/sdcard/snippets/mb/keys.lua @@ -1,4 +1,5 @@ --- Part of Multibow +-- Multibow internal "module" implementing convenience functions for sending +-- key presses to the USB host to which the Keybow device is connected to. --[[ Copyright 2019 Harald Albrecht @@ -22,6 +23,16 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ]]-- +-- luacheck: globals mb + +-- Default delay between rapidly (repeated) key presses, can be overridden. +mb.KEY_DELAY_MS = mb.KEY_DELAY_MS or 100 + +-- Delay between key presses +function mb.delay() + keybow.sleep(mb.KEY_DELAY_MS) +end + -- Sends a single key tap to the USB host, optionally with modifier keys, such -- as SHIFT (keybow.LEFT_SHIFT), CTRL (keybow.LEFT_CTRL), et cetera. The "key" -- parameter can be a string or a Keybow key code, such as keybow.HOME, et @@ -36,15 +47,14 @@ end function mb.tap_times(key, times, ...) for modifier_argno = 1, select("#", ...) do local modifier = select(modifier_argno, ...) - if modifier then; keybow.set_modifier(modifier, keybow.KEY_DOWN); end + if modifier then keybow.set_modifier(modifier, keybow.KEY_DOWN) end end - for tap = 1, times do + for _ = 1, times do keybow.tap_key(key) - keybow.sleep(100) + mb.delay() end for modifier_argno = 1, select("#", ...) do local modifier = select(modifier_argno, ...) - if modifier then; keybow.set_modifier(modifier, keybow.KEY_UP); end + if modifier then keybow.set_modifier(modifier, keybow.KEY_UP) end end end - \ No newline at end of file diff --git a/sdcard/snippets/mb/leds.lua b/sdcard/snippets/mb/leds.lua index 1fedab6..582809c 100644 --- a/sdcard/snippets/mb/leds.lua +++ b/sdcard/snippets/mb/leds.lua @@ -1,4 +1,5 @@ --- Part of Multibow +-- Multibow internal "module" implementing Keybow LED-related functionality, +-- such as brightness control and "lighting up" a (multibow) keymap. --[[ Copyright 2019 Harald Albrecht @@ -23,6 +24,8 @@ SOFTWARE. ]]-- +-- luacheck: globals mb + mb.MIN_BRIGHTNESS = mb.MIN_BRIGHTNESS or 0.1 -- Default LED brightness in the [0.1..1] range. @@ -60,7 +63,7 @@ function mb.led(keyno, color) keybow.set_pixel(keyno, 0, 0, 0) end end - + -- Restores Keybow LEDs according to current keymap and the permanent keymaps. function mb.activate_leds() keybow.clear_lights() @@ -74,14 +77,14 @@ function mb.activate_leds() end -- ...then update LEDs from permanent keymap(s), as this ensures that -- the permanent keymaps take precedence. - for name, keymap in pairs(mb.keymaps) do + for _, keymap in pairs(mb.keymaps) do if keymap.permanent then mb.activate_keymap_leds(keymap) end end end end - + -- Helper function that iterates over all keymap elements but skipping non-key -- bindings. function mb.activate_keymap_leds(keymap) @@ -93,4 +96,3 @@ function mb.activate_keymap_leds(keymap) end end end - diff --git a/sdcard/snippets/morekeys.lua b/sdcard/snippets/mb/morekeys.lua similarity index 87% rename from sdcard/snippets/morekeys.lua rename to sdcard/snippets/mb/morekeys.lua index eb84eb2..0e25e24 100644 --- a/sdcard/snippets/morekeys.lua +++ b/sdcard/snippets/mb/morekeys.lua @@ -1,9 +1,9 @@ ---[[ -Provide additional keybow USB HID key definitions. - -For more information about USB HID keyboard scan codes, for instance, -see: https://gist.github.com/MightyPork/6da26e382a7ad91b5496ee55fdc73db2 +-- Multibow module providing additional USB HID keycode definitions to augment +-- the existing keybow definitions. For more information about USB HID +-- keyboard scan codes, for instance, see: +-- https://gist.github.com/MightyPork/6da26e382a7ad91b5496ee55fdc73db2 +--[[ Copyright 2019 Harald Albrecht Permission is hereby granted, free of charge, to any person obtaining a copy @@ -27,6 +27,11 @@ SOFTWARE. require("keybow") +-- Tell luacheck that it is okay in this specific case to change the keybow +-- global. + +-- luacheck: globals keybow + keybow.SYSRQ = 0x46 keybow.SCROLLLOCK = 0x47 keybow.PAUSE = 0x48 diff --git a/sdcard/snippets/mb/routehandlers.lua b/sdcard/snippets/mb/routehandlers.lua index 55aa567..1a0755d 100644 --- a/sdcard/snippets/mb/routehandlers.lua +++ b/sdcard/snippets/mb/routehandlers.lua @@ -1,4 +1,6 @@ --- Part of Multibow +-- Multibow internal "module" implementing routing Keybow hardware key presses +-- and releases from the Keybow Lua firmware to our keymaps with their own key +-- handlers. --[[ Copyright 2019 Harald Albrecht @@ -22,6 +24,9 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ]] -- + +-- luacheck: globals mb + -- This all-key, central key router forwards Keybow key events to their -- correct handlers, depending on which keyboard layout currently is active. -- @@ -47,7 +52,7 @@ function mb.route(keyno, pressed) -- No grab in place, so continue checking for a matching key in the -- permanent keymaps first. Remember, there cannot be "any" handlers -- with permanent keymaps. - for name, keymap in pairs(mb.keymaps) do + for _, keymap in pairs(mb.keymaps) do if keymap.permanent then keydef = keymap[keyno] if keydef then diff --git a/sdcard/snippets/multibow.lua b/sdcard/snippets/multibow.lua index d8230a9..dbdadce 100644 --- a/sdcard/snippets/multibow.lua +++ b/sdcard/snippets/multibow.lua @@ -1,3 +1,6 @@ +-- "Multibow" is a Lua module for Pimoroni's Keybow firmware that offers and +-- manages multiple keyboard layouts. + --[[ Copyright 2019 Harald Albrecht @@ -20,149 +23,25 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ]]-- -mb = {} -- module +-- luacheck: globals mb +mb = mb or {} -- module require "keybow" +-- Pulls in the individual modules that make up Multibow. mb.path = (...):match("^(.-)[^%/]+$") -require(mb.path .. "morekeys") +require(mb.path .. "mb/morekeys") +require(mb.path .. "mb/keymaps") require(mb.path .. "mb/keys") require(mb.path .. "mb/routehandlers") require(mb.path .. "mb/leds") --- Internal variables for housekeeping... - --- The registered keymaps, indexed by their names (.name field). -mb.keymaps = {} --- The ordered sequence of primary keymap, in the sequence they were --- registered. -mb.primary_keymaps = {} --- The currently activated keymap. -mb.current_keymap = nil --- A temporary keymap while grabbing. -mb.grab_keymap = nil - - --- Registers a keymap (by name), so it can be easily activated later by its name. --- Multiple keymaps can be registered. Keymaps can be either "primary" by --- default, or permanent or secondary keymaps. --- --- A primary keymap is any keymap without either a "permanent" or "secondary" --- table element. Users can cycle through primary keymaps using the "shift" --- permanent keyboard layout. --- --- permanent keymaps (marked by table element "permanent=true") are always --- active, thus they don't need to be activated. --- --- Secondary keymaps (marked by table element "secondary=true") are intended --- as SHIFT/modifier layers. As such the get ignored by cycling, but instead --- need to be activated explicitly. The "shift" permanent keyboard layout --- automates this. --- --- If this is the first keymap getting registered, then it will also made --- activated. -function mb.register_keymap(keymap) - local name = keymap.name - -- register - mb.keymaps[name] = keymap - -- ensure that first registered keymap also automatically gets activated - -- (albeit the LEDs will only update later). Also maintain the (ordered) - -- sequence of registered primary keymaps. - if not (keymap.permanent or keymap.secondary) then - mb.current_keymap = mb.current_keymap or keymap - table.insert(mb.primary_keymaps, keymap) - end -end - --- Returns the list of currently registered keymaps; this list is a table, --- with its registered keymaps at indices 1, 2, ... -function mb.registered_keymaps() - local keymaps = {} - for name, keymap in pairs(mb.keymaps) do - table.insert(keymaps, keymap) - end - return keymaps -end - --- Returns the list of currently registered primary keymaps, in the same order --- as they were registered. First primary is at index 1, second at 2, ... -function mb.registered_primary_keymaps() - return mb.primary_keymaps -end - --- Cycles through the available (primary) keymaps, ignoring secondary and --- permanent keymaps. This is convenient for assigning primary keymap switching --- using a key on the Keybow device itself. -function mb.cycle_primary_keymaps() - local km = mb.current_keymap - if km == nil then return end - -- If this is a secondary keymap, locate its corresponding primary keymap. - if km.secondary then - if not km.shift_to then - -- No SHIFT's shift_to cyclic chain available, so rely on the naming - -- schema instead and try to locate the primary keymap with the first - -- match instead. This assumes that the name of the secondary keymaps - -- have some suffix and thus are longer than the name of their - -- corresponding primary keymap. - for idx, pkm in ipairs(mb.primary_keymaps) do - if string.sub(km.name, 1, #pkm.name) == pkm.name then - km = pkm - break - end - end - -- Checks if locating the primary keymap failed and then bails out - -- immediately. - if km.secondary then return end - else - -- Follows the cyclic chain of SHIFT's shift_to keymaps, until we get - -- to the primary keymap in the cycle, or until we have completed one - -- cycle. - repeat - km = km.shift_to - if not km or km == mb.current_keymap then - return - end - until not(km.secondary) - end - end - -- Move on to the next primary keymap, rolling over at the end of our list. - for idx, pkm in ipairs(mb.primary_keymaps) do - if pkm == km then - idx = idx + 1 - if idx > #mb.primary_keymaps then idx = 1 end - mb.activate_keymap(mb.primary_keymaps[idx].name) - end - end -end - --- Activates a specific keymap by name. Please note that it isn't necessary --- to "activate" permanent keymaps at all (and thus this deed cannot be done). -function mb.activate_keymap(name) - local keymap = mb.keymaps[name] - if keymap and not keymap.permanent then - mb.current_keymap = keymap - mb.activate_leds() - end -end - - --- -function mb.grab(name) - mb.grab_keymap = mb.keymaps[name] - mb.activate_leds() -end - -function mb.ungrab() - mb.grab_keymap = nil - mb.activate_leds() -end - - -- Disables the automatic Keybow lightshow and sets the key LED colors. This -- is a well-known (hook) function that gets called by the Keybow firmware -- after initialization immediately before waiting for key events. +-- luacheck: globals setup function setup() -- Disables the automatic keybow lightshow and switches all key LEDs off -- because the LEDs might be in a random state after power on. diff --git a/setup-tests.sh b/setup-tests.sh index d4bd1c7..16b8799 100755 --- a/setup-tests.sh +++ b/setup-tests.sh @@ -6,3 +6,5 @@ sudo apt-get install --yes lua5.3 liblua5.3-dev sudo update-alternatives --install /usr/bin/lua lua /usr/bin/lua5.3 10 sudo apt-get install --yes luarocks sudo luarocks install busted +sudo luarocks install luasocket +sudo luarocks install luacheck diff --git a/spec/hwkeys.lua b/spec/hwkeys.lua index b4cf860..8c5a4f3 100644 --- a/spec/hwkeys.lua +++ b/spec/hwkeys.lua @@ -24,7 +24,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ]]-- -hwk = {} -- module +local hwk = {} -- module -- Convenience: returns the name of a Keybow key handler function for the -- given key number. diff --git a/spec/hwkeys_spec.lua b/spec/hwkeys_spec.lua index d4e14a3..e01ffd4 100644 --- a/spec/hwkeys_spec.lua +++ b/spec/hwkeys_spec.lua @@ -20,6 +20,8 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ]]-- +-- luacheck: globals handle_key_00 handle_key_01 + local hwk = require("spec/hwkeys") describe("Keybow hardware key handler module", function() @@ -61,7 +63,7 @@ describe("Keybow hardware key handler module", function() assert.equals(2, #seq) assert.same({true, false}, seq) end) - + end) end) diff --git a/spec/layouts/empty_spec.lua b/spec/layouts/empty_spec.lua index 231e04b..44f29db 100644 --- a/spec/layouts/empty_spec.lua +++ b/spec/layouts/empty_spec.lua @@ -30,11 +30,11 @@ describe("empty multibow keymap", function() it("installs a single empty primary keymap", function() -- Sanity check that there are no registered keymaps yet. assert.is.equal(#mb.registered_keymaps(), 0) - + local empty = require("layouts/empty") assert.is_not_nil(empty) -- we're going over the top here... assert.is_not_nil(empty.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() diff --git a/spec/layouts/kdenlive_spec.lua b/spec/layouts/kdenlive_spec.lua index 061555a..95192d3 100644 --- a/spec/layouts/kdenlive_spec.lua +++ b/spec/layouts/kdenlive_spec.lua @@ -30,7 +30,7 @@ describe("Kdenlive keymap", 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() assert.is.equal(2, #kms) end) @@ -58,19 +58,19 @@ describe("Kdenlive keymap", function() end end end) - + inslit("automatically un-shifts after key press", function() local some_key = shift.KEY_SHIFT ~= 0 and 0 or 1 - for round = 1, 2 do - for round = 1, 2 do + for round = 1, 2 do -- luacheck: ignore 213 + for round = 1, 2 do -- luacheck: ignore 213 423 assert.equals(k.keymap.name, mb.current_keymap.name) hwk.tap(shift.KEY_SHIFT) assert.equals(k.keymap_shifted.name, mb.current_keymap.name) hwk.tap(some_key) assert.equals(k.keymap.name, mb.current_keymap.name) end - for round = 1, 2 do + for round = 1, 2 do -- luacheck: ignore 213 423 hwk.tap(shift.KEY_SHIFT) assert.equals(k.keymap_shifted.name, mb.current_keymap.name) hwk.tap(shift.KEY_SHIFT) @@ -100,7 +100,7 @@ describe("Kdenlive keymap", function() 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) diff --git a/spec/layouts/keymap-template_spec.lua b/spec/layouts/keymap-template_spec.lua index fa1d60e..19b82e3 100644 --- a/spec/layouts/keymap-template_spec.lua +++ b/spec/layouts/keymap-template_spec.lua @@ -31,7 +31,7 @@ describe("template multibow keymap", function() 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() diff --git a/spec/layouts/shift_spec.lua b/spec/layouts/shift_spec.lua index 9a5d962..f4bee94 100644 --- a/spec/layouts/shift_spec.lua +++ b/spec/layouts/shift_spec.lua @@ -38,7 +38,7 @@ describe("SHIFT multibow keymap", function() -- SHIFT must register exactly two keymaps, a primary and a secondary one. local kms = mb.registered_keymaps() assert.is.equal(#kms, 2) - for idx, keymap in ipairs(kms) do + for _, keymap in ipairs(kms) do if keymap == "shift" then assert.is_falsy(keymap.permanent) assert.is_falsy(keymap.secondary) @@ -47,8 +47,6 @@ describe("SHIFT multibow keymap", function() assert.is_true(keymap.secondary) end end - - default_key_shift = shift.KEY_SHIFT end) inslit("accepts changes form default", function() @@ -99,7 +97,7 @@ describe("SHIFT multibow keymap", function() -- but that SHIFT followed by another function doesn't shift. shift.shift_secondary_keymap:clear() - for idx, key in ipairs({ + for _, key in ipairs({ shift.KEY_LAYOUT, shift.KEY_BRIGHTNESS }) do @@ -117,7 +115,7 @@ describe("SHIFT multibow keymap", function() } local keymap_shifted = { name="test-shifted", - [0]={press=function(key) end} + [0]={press=function(_) end} } keymap.shift_to = keymap_shifted keymap_shifted.shift_to = keymap @@ -189,7 +187,7 @@ describe("SHIFT multibow keymap", function() s:clear() hwk.press(shift.KEY_SHIFT) assert.spy(s).was.called_with( - shift.KEY_BRIGHTNESS, + shift.KEY_BRIGHTNESS, shift.next_brightness_color()) -- cycles to next brightness hwk.tap(shift.KEY_BRIGHTNESS) diff --git a/spec/layouts/vsc-golang_spec.lua b/spec/layouts/vsc-golang_spec.lua index 9a26aea..5a7ccef 100644 --- a/spec/layouts/vsc-golang_spec.lua +++ b/spec/layouts/vsc-golang_spec.lua @@ -21,7 +21,7 @@ SOFTWARE. ]]-- require "mocked-keybow" -local hwk = require("spec/hwkeys") +require("spec/hwkeys") describe("VSC golang keymap", function() diff --git a/mock/keybow.lua b/spec/mock/keybow.lua similarity index 100% rename from mock/keybow.lua rename to spec/mock/keybow.lua diff --git a/spec/mock/mocked-keybow.lua b/spec/mock/mocked-keybow.lua new file mode 100644 index 0000000..60f3c9a --- /dev/null +++ b/spec/mock/mocked-keybow.lua @@ -0,0 +1,54 @@ +-- Mocks some parts of the Keybow Lua module during unit tests, so we can run +-- the tests outside the Keybow firmware on a standard (full-blown) Lua host +-- system. + +--[[ +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 busted=require("busted") +local sock=require("socket") + +require "keybow" +-- luacheck: globals keybow.no_delay +keybow.no_delay = keybow.no_delay or true + +busted.stub(keybow, "auto_lights") +busted.stub(keybow, "clear_lights") +busted.stub(keybow, "load_pattern") +busted.stub(keybow, "set_pixel") +busted.stub(keybow, "set_key") +busted.stub(keybow, "set_modifier") +busted.stub(keybow, "tap_key") + +-- luacheck: globals keybow.sleep +function keybow.sleep(ms) + if not keybow.no_delay then + sock.sleep(ms / 1000) + end +end + +-- luacheck: globals keybow.usleep +function keybow.usleep(us) + keybow.sleep(us / 1000) +end + +return keybow -- adhere to Lua's (new) module rules diff --git a/spec/mocked-keybow_spec.lua b/spec/mocked-keybow_spec.lua new file mode 100644 index 0000000..b73e2cc --- /dev/null +++ b/spec/mocked-keybow_spec.lua @@ -0,0 +1,50 @@ +--[[ +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. +]]-- + +-- luacheck: globals keybow.no_delay +require("mocked-keybow") + +describe("Mocked Keybow API", function() + + local sock=require("socket") + + local sleep = function(time, factor, sf, on) + local old = keybow.no_delay + keybow.no_delay = not on + local start = sock.gettime() + sf(time) + local delay = (sock.gettime() - start) * factor + keybow.no_delay = old + return delay + end + + it("delays ms or not", function() + assert.is_true(sleep(10, 1000, keybow.sleep, true) >= 10) + assert.is_true(sleep(10, 1000, keybow.sleep, false) < 10) + end) + + it("delays us or not", function() + assert.is_true(sleep(10, 1000*1000, keybow.usleep, true) >= 10) + assert.is_true(sleep(10, 1000*1000, keybow.usleep, false) < 10) + end) + +end) diff --git a/spec/snippets/keys_spec.lua b/spec/snippets/keys_spec.lua index 8025e65..9b6e462 100644 --- a/spec/snippets/keys_spec.lua +++ b/spec/snippets/keys_spec.lua @@ -44,7 +44,7 @@ describe("multibow keys", function() mb.tap("x", keybow.LEFT_CTRL, keybow.LEFT_SHIFT) assert.spy(tap).was.called(1) assert.spy(mod).was.called(4) - for _, ud in pairs({keybow.KEY_DOWN, keybow.KEY_UP}) do + for _, ud in pairs({keybow.KEY_DOWN, keybow.KEY_UP}) do assert.spy(mod).was.called_with(keybow.LEFT_CTRL, ud) assert.spy(mod).was.called_with(keybow.LEFT_SHIFT, ud) end @@ -61,7 +61,7 @@ describe("multibow keys", function() assert.spy(tap).was.called(3) assert.spy(tap).was.called_with("x") assert.spy(mod).was.called(2) - for _, ud in pairs({keybow.KEY_DOWN, keybow.KEY_UP}) do + for _, ud in pairs({keybow.KEY_DOWN, keybow.KEY_UP}) do assert.spy(mod).was.called_with(keybow.LEFT_CTRL, ud) end end) diff --git a/spec/snippets/leds_spec.lua b/spec/snippets/leds_spec.lua index cf4f219..6637f7e 100644 --- a/spec/snippets/leds_spec.lua +++ b/spec/snippets/leds_spec.lua @@ -40,7 +40,7 @@ describe("multibow LEDs", function() end) it("cycles brightness", function() - function f(b, scale) + local f = function(b, scale) local copy = table.pack(table.unpack(b)) local len = #b for i = 1, len do diff --git a/spec/snippets/multibow_spec.lua b/spec/snippets/multibow_spec.lua index 54ea98a..767583a 100644 --- a/spec/snippets/multibow_spec.lua +++ b/spec/snippets/multibow_spec.lua @@ -109,8 +109,8 @@ describe("multibow", function() -- on purpose, the names of the primary keymaps are in reverse lexical order, -- to make sure that cycling follows the registration order, but not the -- name order. - local prim1km = { name= "last" } - local sec1km = { name="last-shift", secondary=true, shift_to } + local prim1km = { name= "last", shift_to=nil } + local sec1km = { name="last-shift", secondary=true, shift_to=nil } prim1km.shift_to = sec1km local prim2km = { name= "first" } mb.register_keymap(prim1km) @@ -130,7 +130,7 @@ describe("multibow", function() inslit("sets up multibow, activates lights", function() local s = spy.on(_G, "setup") local al = spy.on(mb, "activate_leds") - + _G.setup() assert.spy(s).was.called(1) assert.spy(al).was.called(1) diff --git a/spec/snippets/routehandlers_spec.lua b/spec/snippets/routehandlers_spec.lua index aeb3bca..7177bf6 100644 --- a/spec/snippets/routehandlers_spec.lua +++ b/spec/snippets/routehandlers_spec.lua @@ -23,26 +23,26 @@ SOFTWARE. require "mocked-keybow" local hwk = require("spec/hwkeys") -describe("multibow routehandlers", function() +describe("Multibow route handlers", function() -- ensure to get a fresh multibow module instance each time we run -- an isolated test... local mb local spies = mock({ - prim_key_press=function(key) end, - prim_key_release=function(key) end, - prim_otherkey_press=function(key) end, - prim_otherkey_release=function(key) end, - - sec_key_press=function(key) end, - sec_key_release=function(key) end, - - perm_key_press=function(key) end, - perm_key_release=function(key) end, - - grab_key_press=function(key) end, - grab_key_release=function(key) end, + prim_key_press=function(_) end, + prim_key_release=function(_) end, + prim_otherkey_press=function(_) end, + prim_otherkey_release=function(_) end, + + sec_key_press=function(_) end, + sec_key_release=function(_) end, + + perm_key_press=function(_) end, + perm_key_release=function(_) end, + + grab_key_press=function(_) end, + grab_key_release=function(_) end, }) local primary_keymap = { @@ -67,10 +67,9 @@ describe("multibow routehandlers", function() } before_each(function() - require("keybow") mb = require("snippets/multibow") -- make sure to clear our spies - for name, schlapphut in pairs(spies) do + for _, schlapphut in pairs(spies) do schlapphut:clear() end end)