Harald Albrecht
5 years ago
31 changed files with 493 additions and 266 deletions
@ -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 = { |
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" |
||||
} |
} |
||||
} |
} |
||||
|
|
||||
|
std = "max+multibow" |
||||
|
|
||||
|
exclude_files = { "spec/mock/keybow.lua" } |
||||
|
@ -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 |
@ -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 |
|
@ -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 |
@ -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 |
@ -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) |
Loading…
Reference in new issue