Harald Albrecht
5 years ago
commit
59850fd49b
13 changed files with 827 additions and 0 deletions
@ -0,0 +1,19 @@ |
|||
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. |
@ -0,0 +1,59 @@ |
|||
# Multibow |
|||
|
|||
GitHub: [github.com/thediveo/multibow](https://github.com/thediveo/multibow) |
|||
|
|||
Multibow turns a [Pimoroni Keybow](https://shop.pimoroni.com/products/keybow) |
|||
into a macro keyboard with multiple layouts, switchable at any time. (Keybow is |
|||
a solderless DIY 4x3 mechanical USB keyboard, powered by a Raspberry Pi. And |
|||
yes, these days even keyboards run Linux...) |
|||
|
|||
![Multibow on Keybow](multibow.jpg) |
|||
|
|||
Layouts included: |
|||
- Debug Go programs and packages in VisualStudio Code with its Go extension. |
|||
- "Empty" keyboard layout what does nothing, very useful when using cycling between different keyboard layouts to have one non-reacting layout. |
|||
- permanent layout for cycling between the other layouts and for changing the keybow LED brightness. |
|||
|
|||
## Licenses |
|||
|
|||
Multibow is (c) 2019 Harald Albrecht and is licensed under the MIT license, see |
|||
the [LICENSE](LICENSE) file. |
|||
|
|||
The file `keybow.lua` included from |
|||
[pimoroni/keybow-firmware](https://github.com/pimoroni/keybow-firmware) for |
|||
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/empty" -- empty, do-nothing layout. |
|||
``` |
|||
|
|||
|
|||
## Developing |
|||
|
|||
For some basic testing, run `lua test.lua` from the base directory of this |
|||
repository. It pulls in `keybow`, then mocks some functionality of it, and |
|||
finally starts `sdcard/keys.lua` as usual. |
|||
|
|||
This helps in detecting syntax and logic erros early, avoiding the |
|||
rinse-and-repeat cycle with copying to microSD card, starting the Keybow |
|||
hardware, and then wondering what went wrong, without any real clue. |
@ -0,0 +1,210 @@ |
|||
keybow = {} |
|||
|
|||
local KEYCODES = "abcdefghijklmnopqrstuvwxyz1234567890\n\a\b\t -=[]\\#;'`,./" |
|||
local SHIFTED_KEYCODES = "ABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()\a\a\a\a\a_+{}|~:\"~<>?" |
|||
|
|||
keybow.LEFT_CTRL = 0 |
|||
keybow.LEFT_SHIFT = 1 |
|||
keybow.LEFT_ALT = 2 |
|||
keybow.LEFT_META = 3 |
|||
|
|||
keybow.RIGHT_CTRL = 4 |
|||
keybow.RIGHT_SHIFT = 5 |
|||
keybow.RIGHT_ALT = 6 |
|||
keybow.RIGHT_META = 7 |
|||
|
|||
keybow.ENTER = 0x28 |
|||
keybow.ESC = 0x29 |
|||
keybow.BACKSPACE = 0x2a |
|||
keybow.TAB = 0x2b |
|||
keybow.SPACE = 0x2c |
|||
keybow.CAPSLOCK = 0x39 |
|||
|
|||
keybow.LEFT_ARROW = 0x50 |
|||
keybow.RIGHT_ARROW = 0x4f |
|||
keybow.UP_ARROW = 0x52 |
|||
keybow.DOWN_ARROW = 0x51 |
|||
|
|||
keybow.F1 = 0x3a |
|||
keybow.F2 = 0x3b |
|||
keybow.F3 = 0x3c |
|||
keybow.F4 = 0x3d |
|||
keybow.F5 = 0x3e |
|||
keybow.F6 = 0x3f |
|||
keybow.F7 = 0x40 |
|||
keybow.F8 = 0x41 |
|||
keybow.F9 = 0x42 |
|||
keybow.F10 = 0x43 |
|||
keybow.F11 = 0x44 |
|||
keybow.F12 = 0x45 |
|||
|
|||
keybow.KEY_DOWN = true |
|||
keybow.KEY_UP = false |
|||
|
|||
-- Functions exposed from C |
|||
|
|||
function keybow.set_modifier(key, state) |
|||
keybow_set_modifier(key, state) |
|||
end |
|||
|
|||
function keybow.sleep(time) |
|||
keybow_sleep(time) |
|||
end |
|||
|
|||
function keybow.usleep(time) |
|||
keybow_usleep(time) |
|||
end |
|||
|
|||
function keybow.text(text) |
|||
for i = 1, #text do |
|||
local c = text:sub(i, i) |
|||
keybow.tap_key(c) |
|||
end |
|||
|
|||
keybow.set_modifier(keybow.LEFT_SHIFT, false) |
|||
end |
|||
|
|||
-- Lighting control |
|||
|
|||
function keybow.set_pixel(x, r, g, b) |
|||
keybow_set_pixel(x, r, g, b) |
|||
end |
|||
|
|||
function keybow.auto_lights(state) |
|||
keybow_auto_lights(state) |
|||
end |
|||
|
|||
function keybow.clear_lights() |
|||
keybow_clear_lights() |
|||
end |
|||
|
|||
function keybow.load_pattern(file) |
|||
keybow_load_pattern(file) |
|||
end |
|||
|
|||
-- Meta keys - ctrl, shift, alt and win/apple |
|||
|
|||
function keybow.tap_left_ctrl() |
|||
keybow.set_modifier(keybow.LEFT_CTRL, keybow.KEY_DOWN) |
|||
keybow.set_modifier(keybow.LEFT_CTRL, keybow.KEY_UP) |
|||
end |
|||
|
|||
function keybow.tap_right_ctrl() |
|||
keybow.set_modifier(keybow.RIGHT_CTRL, keybow.KEY_DOWN) |
|||
keybow.set_modifier(keybow.RIGHT_CTRL, keybow.KEY_UP) |
|||
end |
|||
|
|||
function keybow.tap_left_shift() |
|||
keybow.set_modifier(keybow.LEFT_SHIFT, keybow.KEY_DOWN) |
|||
keybow.set_modifier(keybow.LEFT_SHIFT, keybow.KEY_UP) |
|||
end |
|||
|
|||
function keybow.tap_right_shift() |
|||
keybow.set_modifier(keybow.RIGHT_SHIFT, keybow.KEY_DOWN) |
|||
keybow.set_modifier(keybow.RIGHT_SHIFT, keybow.KEY_UP) |
|||
end |
|||
|
|||
function keybow.tap_left_alt() |
|||
keybow.set_modifier(keybow.LEFT_ALT, keybow.KEY_DOWN) |
|||
keybow.set_modifier(keybow.LEFT_ALT, keybow.KEY_UP) |
|||
end |
|||
|
|||
function keybow.tap_right_alt() |
|||
keybow.set_modifier(keybow.RIGHT_ALT, keybow.KEY_DOWN) |
|||
keybow.set_modifier(keybow.RIGHT_ALT, keybow.KEY_UP) |
|||
end |
|||
|
|||
function keybow.tap_left_meta() |
|||
keybow.set_modifier(keybow.LEFT_META, keybow.KEY_DOWN) |
|||
keybow.set_modifier(keybow.LEFT_META, keybow.KEY_UP) |
|||
end |
|||
|
|||
function keybow.tap_right_meta() |
|||
keybow.set_modifier(keybow.RIGHT_META, keybow.KEY_DOWN) |
|||
keybow.set_modifier(keybow.RIGHT_META, keybow.KEY_UP) |
|||
end |
|||
|
|||
-- Function keys |
|||
|
|||
function keybow.tap_function_key(index) |
|||
index = 57 + index -- Offset to 0x39 (F1 is 0x3a) |
|||
keybow.set_key(index, true) |
|||
keybow.set_key(index, false) |
|||
end |
|||
|
|||
function keybow.ascii_to_shift(key) |
|||
if not (type(key) == "string") then |
|||
return false |
|||
end |
|||
|
|||
return SHIFTED_KEYCODES.find(key) ~= nil |
|||
end |
|||
|
|||
function keybow.ascii_to_hid(key) |
|||
if not (type(key) == "string") then |
|||
return key |
|||
end |
|||
|
|||
key = key:lower() |
|||
|
|||
code = KEYCODES:find(key) |
|||
|
|||
if code == nil then return nil end |
|||
|
|||
return code + 3 |
|||
end |
|||
|
|||
function keybow.set_key(key, pressed) |
|||
if type(key) == "string" then |
|||
local hid_code = nil |
|||
local shifted = SHIFTED_KEYCODES:find(key, 1, true) ~= nil |
|||
|
|||
if shifted then |
|||
hid_code = SHIFTED_KEYCODES:find(key, 1, true) |
|||
else |
|||
hid_code = KEYCODES:find(key, 1, true) |
|||
end |
|||
|
|||
if not (hid_code == nil) then |
|||
hid_code = hid_code + 3 |
|||
if shifted then keybow.set_modifier(keybow.LEFT_SHIFT, pressed) end |
|||
keybow_set_key(hid_code, pressed) |
|||
end |
|||
|
|||
else -- already a key code |
|||
keybow_set_key(key, pressed) |
|||
end |
|||
end |
|||
|
|||
function keybow.tap_enter() |
|||
keybow.set_key(keybow.ENTER, true) |
|||
keybow.set_key(keybow.ENTER, false) |
|||
end |
|||
|
|||
function keybow.tap_space() |
|||
keybow.set_key(keybow.SPACE, true) |
|||
keybow.set_key(keybow.SPACE, false) |
|||
end |
|||
|
|||
function keybow.tap_shift() |
|||
keybow.set_key(keybow.LEFT_SHIFT, true) |
|||
keybow.set_key(keybow.LEFT_SHIFT, false) |
|||
end |
|||
|
|||
function keybow.tap_tab() |
|||
keybow.set_key(keybow.TAB, true) |
|||
keybow.set_key(keybow.TAB, false) |
|||
end |
|||
|
|||
function keybow.tap_key(key) |
|||
keybow.set_key(key, true) |
|||
keybow.set_key(key, false) |
|||
end |
|||
|
|||
function keybow.press_key(key) |
|||
keybow.set_key(key, true) |
|||
end |
|||
|
|||
function keybow.release_key(key) |
|||
keybow.set_key(key, false) |
|||
end |
@ -0,0 +1,24 @@ |
|||
require "keybow" |
|||
|
|||
function keybow.set_pixel(pix, r, g, b) |
|||
-- print("set_pixel", pix, r, g, b) |
|||
end |
|||
|
|||
function keybow.auto_lights(onoff) |
|||
-- print("auto_lights", onoff) |
|||
end |
|||
|
|||
function keybow.clear_lights() |
|||
-- print("clear_lights") |
|||
end |
|||
|
|||
function keybow.tap_key(key) |
|||
print("tap_key", key) |
|||
end |
|||
|
|||
function keybow.set_modifier(mod, key) |
|||
print("set_modifier", mod, key) |
|||
end |
|||
|
|||
require "keys" |
|||
setup() |
After Width: | Height: | Size: 25 KiB |
@ -0,0 +1,4 @@ |
|||
require "keybow" |
|||
require "layouts/shift" |
|||
require "layouts/vsc-golang" |
|||
require "layouts/empty" |
@ -0,0 +1,22 @@ |
|||
-- An empty Multibow Keybow layout. Useful for "switching off" the keyboard, |
|||
|
|||
require "snippets/multibow" |
|||
|
|||
--[[ |
|||
The Keybow layout is as follows when in landscape orientation, with the USB |
|||
cable going off "northwards": |
|||
|
|||
┋┋ |
|||
┌────┐ ┌────┐ ┌────┐ ┌────┐ |
|||
│ 11 │ │ 8 │ │ 5 │ │ 2 │ |
|||
└────┘ └────┘ └────┘ └────┘ |
|||
┌────┐ ┌────┐ ┌────┐ ┌────┐ |
|||
│ 10 │ │ 7 │ │ 4 │ │ 1 │ |
|||
└────┘ └────┘ └────┘ └────┘ |
|||
┌────┐ ┌────┐ ┌────┐ ┌────┐ |
|||
│ 9 │ │ 6 │ │ 3 │ │ 0 │ |
|||
└────┘ └────┘ └────┘ └────┘ |
|||
|
|||
]]-- |
|||
|
|||
mb.register_keymap({}, "empty") |
@ -0,0 +1,38 @@ |
|||
-- A permanent SHIFT layout toggler |
|||
|
|||
require "snippets/multibow" |
|||
|
|||
--[[ |
|||
The Keybow layout is as follows when in landscape orientation, with the USB |
|||
cable going off "northwards": |
|||
|
|||
┋┋ |
|||
┌────┐ ┌────┐ ┌────┐ ┌────┐ |
|||
│ 11 │ │ 8 │ │ 5 │ │ 2 │ |
|||
└────┘ └────┘ └────┘ └────┘ |
|||
┌────┐ ┌────┐ ┌────┐ ┌────┐ |
|||
│ 10 │ │ 7 │ │ 4 │ │ 1 │ |
|||
└────┘ └────┘ └────┘ └────┘ |
|||
┌────┐ ┌────┐ ┌────┐ ┌────┐ |
|||
│ 9 │ │ 6 │ │ 3 │ │ 0 │ |
|||
└────┘ └────┘ └────┘ └────┘ |
|||
|
|||
]]-- |
|||
|
|||
shift = {} |
|||
|
|||
function shift.cycle(key) |
|||
print("permanent SHIFT") |
|||
mb.cycle_keymaps() |
|||
end |
|||
|
|||
function shift.brightness(key) |
|||
local b = mb.brightness + 0.3 |
|||
if b > 1 then; b = 0.4; end |
|||
mb.set_brightness(b) |
|||
end |
|||
|
|||
mb.register_permanent_keymap({ |
|||
[11] = {c={r=1, g=1, b=1}, h=shift.cycle}, |
|||
[8] = {c={r=0.5, g=0.5, b=0.5}, h=shift.brightness} |
|||
}, "shift") |
@ -0,0 +1,74 @@ |
|||
-- VSC Go extension debug Keybow layout |
|||
|
|||
require "snippets/multibow" |
|||
|
|||
--[[ |
|||
The Keybow layout is as follows when in landscape orientation, with the USB |
|||
cable going off "northwards": |
|||
|
|||
┋┋ |
|||
┌────┐ ┌────┐ ┌────┐ ┌────┐ |
|||
│ 11 │ │ 8 │ │ 5 │ │ 2 │ |
|||
└────┘ └────┘ └────┘ └────┘ |
|||
┌────┐ ┌────┐ ┌────┐ ┌────┐ |
|||
│ 10 │ │ 7 │ │ 4 │ │ 1 │ |
|||
└────┘ └────┘ └────┘ └────┘ |
|||
┌────┐ ┌────┐ ┌────┐ ┌────┐ |
|||
│ 9 │ │ 6 │ │ 3 │ │ 0 │ |
|||
└────┘ └────┘ └────┘ └────┘ |
|||
|
|||
]]-- |
|||
|
|||
RED = { r=1, g=0, b=0 } |
|||
YELLOW = { r=1, g=0.8, b=0 } |
|||
GREEN = { r=0, g=1, b=0 } |
|||
BLUE = { r=0, g=0, b=1 } |
|||
BLUECYAN = { r=0, g=0.7, b=1 } |
|||
BLUEGRAY = { r=0.7, g=0.7, b=1 } |
|||
CYAN = { r=0, g=1, b=1 } |
|||
|
|||
|
|||
-- AND NOW FOR SOMETHING DIFFERENT: THE REAL MEAT -- |
|||
|
|||
function debug_stop(key) |
|||
mb.tap(key, keybow.F5, keybow.LEFT_SHIFT) |
|||
end |
|||
|
|||
function debug_restart(key) |
|||
mb.tap(key, keybow.F5, keybow.LEFT_SHIFT, keybow.LEFT_CTRL) |
|||
end |
|||
|
|||
function debug_continue(key) |
|||
mb.tap(key, keybow.F5) |
|||
end |
|||
|
|||
function debug_stepover(key) |
|||
mb.tap(key, keybow.F10) |
|||
end |
|||
|
|||
function debug_stepinto(key) |
|||
mb.tap(key, keybow.F11) |
|||
end |
|||
|
|||
function debug_stepout(key) |
|||
mb.tap(key, keybow.F11, keybow.LEFT_SHIFT) |
|||
end |
|||
|
|||
function go_test_package(key) |
|||
mb.tap(key, "P", keybow.LEFT_SHIFT, keybow.LEFT_CTRL) |
|||
keybow.sleep(250) |
|||
keybow.text("go test package") |
|||
keybow.tap_enter() |
|||
end |
|||
|
|||
|
|||
mb.register_keymap({ |
|||
[10] = {c=RED, h=debug_stop}, |
|||
[7] = {c=YELLOW, h=debug_restart}, |
|||
[1] = {c=CYAN, h=go_test_package}, |
|||
|
|||
[9] = {c=GREEN, h=debug_continue}, |
|||
[6] = {c=BLUECYAN, h=debug_stepinto}, |
|||
[3] = {c=BLUE, h=debug_stepover}, |
|||
[0] = {c=BLUEGRAY, h=debug_stepout}, |
|||
}, 'vsc-golang-debug') |
@ -0,0 +1,108 @@ |
|||
--[[ |
|||
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 |
|||
|
|||
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("keybow") |
|||
|
|||
keybow.SYSRQ = 0x46 |
|||
keybow.SCROLLLOCK = 0x47 |
|||
keybow.PAUSE = 0x48 |
|||
keybow.INSERT = 0x49 |
|||
keybow.DELETE = 0x4c |
|||
keybow.HOME = 0x4a |
|||
keybow.END = 0x4d |
|||
keybow.PAGEUP = 0x4b |
|||
keybow.PAGEOWN = 0x4e |
|||
|
|||
keybow.F13 = 0x68 |
|||
keybow.F14 = 0x69 |
|||
keybow.F15 = 0x6a |
|||
keybow.F16 = 0x6b |
|||
keybow.F17 = 0x6c |
|||
keybow.F18 = 0x6d |
|||
keybow.F19 = 0x6e |
|||
keybow.F20 = 0x6f |
|||
keybow.F21 = 0x70 |
|||
keybow.F22 = 0x71 |
|||
keybow.F23 = 0x72 |
|||
keybow.F24 = 0x73 |
|||
|
|||
keybow.KPSLASH = 0x54 |
|||
keybow.KPASTERISK = 0x55 |
|||
keybow.KPMINUS = 0x56 |
|||
keybow.KPPLUS = 0x57 |
|||
keybow.KPENTER = 0x58 |
|||
keybow.KP1 = 0x59 |
|||
keybow.KP2 = 0x5a |
|||
keybow.KP3 = 0x5b |
|||
keybow.KP4 = 0x5c |
|||
keybow.KP5 = 0x5d |
|||
keybow.KP6 = 0x5e |
|||
keybow.KP7 = 0x5f |
|||
keybow.KP8 = 0x60 |
|||
keybow.KP9 = 0x61 |
|||
keybow.KP0 = 0x62 |
|||
keybow.KPDOT = 0x63 |
|||
keybow.KPEQUAL = 0x67 |
|||
|
|||
keybow.COMPOSE = 0x65 |
|||
keybow.POWER = 0x66 |
|||
|
|||
keybow.OPEN = 0x74 |
|||
keybow.HELP = 0x75 |
|||
keybow.PROPS = 0x76 |
|||
keybow.FRONT = 0x77 |
|||
keybow.STOP = 0x78 |
|||
keybow.AGAIN = 0x79 |
|||
keybow.UNDO = 0x7a |
|||
keybow.CUT = 0x7b |
|||
keybow.COPY = 0x7c |
|||
keybow.PASTE = 0x7d |
|||
keybow.FIND = 0x7e |
|||
keybow.MUTE = 0x7f |
|||
keybow.VOLUMEUP = 0x80 |
|||
keybow.VOLUMEDOWN = 0x81 |
|||
|
|||
keybow.MEDIA_PLAYPAUSE = 0xe8 |
|||
keybow.MEDIA_STOPCD = 0xe9 |
|||
keybow.MEDIA_PREVIOUSSONG = 0xea |
|||
keybow.MEDIA_NEXTSONG = 0xeb |
|||
keybow.MEDIA_EJECTCD = 0xec |
|||
keybow.MEDIA_VOLUMEUP = 0xed |
|||
keybow.MEDIA_VOLUMEDOWN = 0xee |
|||
keybow.MEDIA_MUTE = 0xef |
|||
keybow.MEDIA_WWW = 0xf0 |
|||
keybow.MEDIA_BACK = 0xf1 |
|||
keybow.MEDIA_FORWARD = 0xf2 |
|||
keybow.MEDIA_STOP = 0xf3 |
|||
keybow.MEDIA_FIND = 0xf4 |
|||
keybow.MEDIA_SCROLLUP = 0xf5 |
|||
keybow.MEDIA_SCROLLDOWN = 0xf6 |
|||
keybow.MEDIA_EDIT = 0xf7 |
|||
keybow.MEDIA_SLEEP = 0xf8 |
|||
keybow.MEDIA_COFFEE = 0xf9 |
|||
keybow.MEDIA_REFRESH = 0xfa |
|||
keybow.MEDIA_CALC = 0xfb |
@ -0,0 +1,176 @@ |
|||
--[[ |
|||
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 "keybow" |
|||
|
|||
mb = {} |
|||
mb.path = (...):match("^(.-)[^%/]+$") |
|||
|
|||
require(mb.path .. "morekeys") |
|||
require(mb.path .. "routehandlers") |
|||
|
|||
|
|||
mb.brightness = 0.4 |
|||
mb.keymaps = {} |
|||
mb.permanent_keymaps = {} |
|||
mb.current_keymap_set = nil |
|||
mb.current_keymap_idx = 0 |
|||
|
|||
|
|||
-- |
|||
function mb.tap(keyno, key, ...) |
|||
for modifier_argno = 1, select('#', ...) do |
|||
local modifier = select(modifier_argno, ...) |
|||
if modifier then; keybow.set_modifier(modifier, keybow.KEY_DOWN); end |
|||
end |
|||
keybow.tap_key(key) |
|||
for modifier_argno = 1, select('#', ...) do |
|||
local modifier = select(modifier_argno, ...) |
|||
if modifier then; keybow.set_modifier(modifier, keybow.KEY_UP); end |
|||
end |
|||
end |
|||
|
|||
|
|||
-- Registers a keymap by name (and optional) index. The name is simply used |
|||
-- for allowing multiple SHIFT (modifier) levels for the same keyboard layout. |
|||
-- The indices are then used to differentiate between different SHIFT/modifier |
|||
-- levels of the same keyboard layout. |
|||
-- |
|||
-- Indices start at 0, this is the un-SHIFT-ed keymap for a layout. |
|||
-- |
|||
-- If this is the first keymap getting registered, then it will also made |
|||
-- activated. |
|||
function mb.register_keymap(keymap, name, index) |
|||
-- register |
|||
local kms = mb.keymaps[name] |
|||
kms = kms and kms or {} -- if name isn't known yet, create new keymap array for name |
|||
local index = index and #kms or 0 -- appends keymap if index is nil |
|||
kms[index] = keymap |
|||
mb.keymaps[name] = kms |
|||
-- ensure that first registered keymap also automatically gets activated |
|||
-- (albeit the LEDs will only update later). |
|||
if mb.current_keymap_set == nil then |
|||
mb.current_keymap_set = kms |
|||
mb.current_keymap_idx = index |
|||
end |
|||
end |
|||
|
|||
|
|||
-- Cycles through the available (non-permanent) keymaps. When switching to |
|||
-- the next keymap, we will always activate the index 0 layout. |
|||
function mb.cycle_keymaps() |
|||
local first_kms |
|||
local first_name |
|||
local next = false |
|||
local next_kms |
|||
local next_name |
|||
for name, kms in pairs(mb.keymaps) do |
|||
if first_kms == nil then |
|||
first_kms = kms; first_name = name |
|||
end |
|||
if kms == mb.current_keymap_set then |
|||
next = true |
|||
elseif next then |
|||
next_kms = kms; next_name = name |
|||
next = false |
|||
end |
|||
end |
|||
if next_kms == nil then |
|||
next_kms = first_kms; next_name = first_name |
|||
end |
|||
mb.activate_keymap(next_name, 0) |
|||
end |
|||
|
|||
|
|||
-- Activates a specific keymap by name and index. |
|||
function mb.activate_keymap(name, index) |
|||
print("activate_keymap", name, index) |
|||
local kms = mb.keymaps[name] |
|||
mb.current_keymap_set = kms |
|||
mb.current_keymap_idx = index |
|||
keybow.clear_lights() |
|||
mb.activate_leds() |
|||
end |
|||
|
|||
|
|||
-- Registers a permanent keymap (as opposed to switchable keymaps). As their |
|||
-- name suggest, permanent keymaps are permanently active and have priority |
|||
-- over any "standard" activated keymap. As they are permanent, there is no |
|||
-- "index" sub-layout mechanism, but instead all permanent keymaps are always |
|||
-- active. If permanent keymaps define overlapping keys, then the result is |
|||
-- undefined. |
|||
function mb.register_permanent_keymap(keymap, name) |
|||
-- register |
|||
mb.permanent_keymaps[name] = keymap |
|||
mb.activate_leds() |
|||
end |
|||
|
|||
|
|||
-- Sets the Keybow key LEDs maximum brightness, in the range [0.1..1]. |
|||
function mb.set_brightness(brightness) |
|||
if brightness < 0.1 then; brightness = 0.1; end |
|||
if brightness > 1 then; brightness = 1; end |
|||
mb.brightness = brightness |
|||
mb.activate_leds() |
|||
end |
|||
|
|||
|
|||
-- Sets key LED to specific color, taking brightness into consideration. |
|||
-- The color is a triple (table) with the elements r, g, and b. Each color |
|||
-- component is in the range [0..1]. |
|||
function mb.led(keyno, color) |
|||
if color ~= nil then |
|||
keybow.set_pixel(keyno, |
|||
color.r * mb.brightness * 255, color.g * mb.brightness * 255, color.b * mb.brightness * 255) |
|||
else |
|||
keybow.set_pixel(keyno, 0, 0, 0) |
|||
end |
|||
end |
|||
|
|||
|
|||
-- Restores Keybow LEDs according to current keymap and the permanent keymaps. |
|||
function mb.activate_leds() |
|||
-- current keymap |
|||
if mb.current_keymap_set ~= nil then |
|||
for keyno, keydef in pairs(mb.current_keymap_set[mb.current_keymap_idx]) do |
|||
print("LED", keyno) |
|||
mb.led(keyno, keydef.c) |
|||
end |
|||
end |
|||
-- permanent keymap(s) |
|||
for name, pkm in pairs(mb.permanent_keymaps) do |
|||
for keyno, keydef in pairs(pkm) do |
|||
print("pLED", keyno) |
|||
mb.led(keyno, keydef.c) |
|||
end |
|||
end |
|||
end |
|||
|
|||
|
|||
-- Disables the automatic Keybow lightshow and sets the key LED colors. |
|||
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. |
|||
keybow.auto_lights(false) |
|||
keybow.clear_lights() |
|||
mb.activate_leds() |
|||
end |
@ -0,0 +1,63 @@ |
|||
--[[ |
|||
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. |
|||
]]-- |
|||
|
|||
-- This all-key, central key router forwards Keybow key events to |
|||
-- their correct handlers, depending on which keyboard layout currently |
|||
-- is active. |
|||
function mb.route(keyno, pressed) |
|||
-- Check key in permanent keymaps |
|||
local keydef |
|||
for name, pkm in pairs(mb.permanent_keymaps) do |
|||
keydef = pkm[keyno] |
|||
if keydef ~= nil then; break; end |
|||
end |
|||
-- Check key in current keymap |
|||
if keydef == nil and mb.current_keymap_set ~= nil then |
|||
keydef = mb.current_keymap_set[mb.current_keymap_idx][keyno] |
|||
end |
|||
|
|||
if keydef == nil then; return; end |
|||
|
|||
if pressed then |
|||
for led = 0, 11 do |
|||
if led ~= keyno then; mb.led(led, {r=0, g=0, b=0}); end |
|||
end |
|||
print("route to key #", keyno) |
|||
keydef.h(keyno) |
|||
else |
|||
mb.activate_leds() |
|||
end |
|||
end |
|||
|
|||
-- Routes all keybow key handling through our central key router |
|||
function handle_key_00(pressed); mb.route(0, pressed); end |
|||
function handle_key_01(pressed); mb.route(1, pressed); end |
|||
function handle_key_02(pressed); mb.route(2, pressed); end |
|||
function handle_key_03(pressed); mb.route(3, pressed); end |
|||
function handle_key_04(pressed); mb.route(4, pressed); end |
|||
function handle_key_05(pressed); mb.route(5, pressed); end |
|||
function handle_key_06(pressed); mb.route(6, pressed); end |
|||
function handle_key_07(pressed); mb.route(7, pressed); end |
|||
function handle_key_08(pressed); mb.route(8, pressed); end |
|||
function handle_key_09(pressed); mb.route(9, pressed); end |
|||
function handle_key_10(pressed); mb.route(10, pressed); end |
|||
function handle_key_11(pressed); mb.route(11, pressed); end |
@ -0,0 +1,30 @@ |
|||
package.path = "./sdcard/?.lua;./mock/?.lua;" .. package.path |
|||
|
|||
require "mockkeybow" |
|||
|
|||
print() |
|||
print("**** key 00...") |
|||
handle_key_00(true) |
|||
handle_key_00(false) |
|||
print() |
|||
print("**** key 03...") |
|||
handle_key_03(true) |
|||
handle_key_03(false) |
|||
print() |
|||
|
|||
print("**** key 11...") |
|||
handle_key_11(true) |
|||
handle_key_11(false) |
|||
|
|||
print("**** key 00...") |
|||
handle_key_00(true) |
|||
handle_key_00(false) |
|||
|
|||
print() |
|||
print("**** key 11...") |
|||
handle_key_11(true) |
|||
handle_key_11(false) |
|||
|
|||
print("**** key 00...") |
|||
handle_key_00(true) |
|||
handle_key_00(false) |
Loading…
Reference in new issue