Support fn layer and arbitrary functions in layouts.

There is still a bug when you release the fn key but still have
another key held down, along with a failing test case.
This commit is contained in:
Phil Hagelberg 2019-07-02 18:11:04 -07:00
parent 66406219ac
commit 6fff51cc5f
5 changed files with 137 additions and 34 deletions

View file

@ -14,8 +14,9 @@ upload: $(TARGET).hex
test: ; racket test.rkt
clean:
-rm -f $(TARGET){,.hex} *.o *.elf *.s
clean: ; -rm -f $(TARGET){,.hex} *.o *.elf *.s
count: ; cloc *.scm
$(TARGET).hex: $(TARGET).elf
avr-size $(TARGET).elf
@ -31,4 +32,4 @@ usb_keyboard.s: usb_keyboard.h usb_keyboard.c
avr-gcc -std=gnu99 -S -D F_CPU=$(F_CPU)UL -mmcu=$(MCU) -c \
-o usb_keyboard.s usb_keyboard.c
.PHONY: build upload test clean
.PHONY: build upload test clean count

View file

@ -26,13 +26,38 @@
(define key-x 27)
(define key-y 28)
(define key-z 29)
(define key-semicolon 51)
(define key-1 30)
(define key-2 31)
(define key-3 32)
(define key-4 33)
(define key-5 34)
(define key-6 35)
(define key-7 36)
(define key-8 37)
(define key-9 38)
(define key-0 39)
(define key-up 82)
(define key-down 81)
(define key-left 80)
(define key-right 79)
(define key-page-up 75)
(define key-page-down 78)
(define key-home 74)
(define key-end 77)
(define key-insert 73)
(define key-semicolon 51)
(define key-comma 54)
(define key-period 55)
(define key-slash 56)
(define key-dash 45)
(define key-quote 52)
(define key-equal 46)
(define key-left-bracket 47)
(define key-right-bracket 48)
(define key-space 44)
(define key-backspace 42)
@ -43,12 +68,18 @@
(define key-backslash 49)
(define key-backtick 53)
(define key-vol-up 128)
(define key-vol-down 129)
(define (modifier? keycode) (list? keycode))
(define (modify keycode) (list keycode))
(define (unmodify keycode) (car keycode))
;; currently you can only combo with one modifier and one normal key
(define (combo modifier keycode) (list (car modifier) keycode))
(define (uncombo keycode) (and (= 2 (length keycode)) (car (cdr keycode))))
(define mod-ctrl (modify #x01))
(define mod-shift (modify #x02))
(define mod-alt (modify #x04))
(define mod-gui (modify #x08))
(define mod-fn (modify #x16))
(define mod-super (modify #x08))

View file

@ -1,4 +1,21 @@
(define layout
;;; this is the multidvorak layout
;; we have to declare this up front and set it later because of circularity
(define layers (vector #f #f #f))
(define current-layer #f)
(define momentary-layer #f)
(define (fn)
(set! momentary-layer (vector-ref layers 1)))
(define (set-layer-2)
(set! current-layer (vector-ref layers 2)))
(define (set-layer-0)
(set! current-layer (vector-ref layers 0)))
(vector-set!
layers 0
(vector key-q key-w key-e key-r key-t key-backslash
key-y key-u key-i key-o key-p
@ -8,5 +25,26 @@
key-z key-x key-c key-v key-b mod-alt
key-n key-m key-comma key-period key-slash
key-esc key-tab mod-gui mod-shift key-backspace mod-ctrl
key-space mod-fn key-dash key-quote key-enter))
key-esc key-tab mod-super mod-shift key-backspace mod-ctrl
key-space fn key-quote key-right-bracket key-enter))
(vector-set!
layers 1
(vector (combo mod-shift key-1) (combo mod-shift key-2) key-up
(combo mod-shift key-dash) (combo mod-shift key-equal)
0 key-page-up key-7 key-8 key-9 (combo mod-shift key-8)
(combo mod-shift key-3) key-left key-down key-right
(combo mod-shift key-4) 0
key-page-down key-4 key-5 key-6 (combo mod-shift key-right-bracket)
key-dash key-equal (combo mod-shift key-9)
(combo mod-shift key-0) (combo mod-shift key-7) mod-alt
key-backtick key-1 key-2 key-3 key-backslash
set-layer-2 key-insert mod-super mod-shift key-backspace mod-ctrl
key-space fn key-dash key-e key-0 key-right-bracket))
(vector-set!
layers 2 ; TODO
(vector 0))

View file

@ -8,7 +8,7 @@
(define max-keys 6) ; a single USB frame can only send 6 keycodes plus modifiers
;;; matrix
;;;;;;;;;;;;;;;;;;; matrix
(define (offset-for row col)
(+ col (* row (length columns))))
@ -42,7 +42,7 @@
(car rows-left) columns)))
(scan-matrix keys-pressed key-count (cdr rows-left)))))
;;; debouncing
;;;;;;;;;;;;;;;;;;; debouncing
(define this-scan (vector 0 0 0 0 0 0 0))
(define last-scan (vector 0 0 0 0 0 0 0))
@ -50,29 +50,46 @@
(define debounce-passes 8)
(define (debounce-matrix keys-pressed last-count passes-left)
(vector-copy this-scan last-scan 0 6 0)
;; older versions of microscheme don't have vector-copy!, only vector-copy
;; which does the same thing but takes the arguments in a different order
(vector-copy! last-scan 0 this-scan 0 6)
(if (< 0 passes-left)
(let ((this-count (scan-matrix this-scan 1 rows)))
(if (and (= this-count last-count)
(equal? this-scan last-scan))
(debounce-matrix keys-pressed this-count (- passes-left 1))
(debounce-matrix keys-pressed this-count passes-left)))
(begin (vector-copy this-scan keys-pressed 0 6 0)
(begin (vector-copy! keys-pressed 0 this-scan 0 6)
last-count)))
;;; layout
;;;;;;;;;;;;;;;;;;; layout
(define (lookup keys-pressed which-key)
(let ((layout (or momentary-layer current-layer)))
(vector-ref layout (vector-ref keys-pressed which-key))))
(define (keycode-for keys-pressed which-key keycodes)
(let ((code (vector-ref layout (vector-ref keys-pressed which-key))))
(let ((code (lookup keys-pressed which-key)))
;; (printf "keycode ~s ~s~n" code which-key)
(if (modifier? code)
(begin (vector-set! keycodes 0 (+ (vector-ref keycodes 0)
(unmodify code)))
(uncombo code))
(and (not (procedure? code)) code))))
(define (call-functions keys-pressed key-count)
(if (< 0 key-count)
(let ((code (lookup keys-pressed key-count)))
(if (procedure? code)
(code)
#f)
code)))
(call-functions keys-pressed (- key-count 1)))
#f))
;; translate key numbers into specific USB keycodes
(define (keycodes-for keys-pressed key-count keycodes)
;; this happens before we look up "regular" keycodes because it changes layers
(call-functions keys-pressed key-count)
(if (= 0 key-count)
(vector->list keycodes)
(let ((keycode (keycode-for keys-pressed key-count keycodes)))
@ -81,9 +98,10 @@
#f)
(keycodes-for keys-pressed (- key-count 1) keycodes))))
;;; showtime
;;;;;;;;;;;;;;;;;;; showtime
(define (init)
(set-layer-0)
(for-each-vector output row-pins)
(for-each-vector high row-pins)
(for-each-vector input column-pins)
@ -96,6 +114,7 @@
(call-c-func "usb_send" modifiers key1 key2 key3 key4 key5 key6))
(define (loop)
(set! momentary-layer #f)
(free! (let ((keys-pressed (vector 0 0 0 0 0 0 0)))
;; scanning the matrix tells us only which physical keys were
;; pressed and how many; it doesn't tell us which keycodes to

View file

@ -13,13 +13,8 @@
(define (high pin) (vector-set! pins pin #t))
(define (low pin) (vector-set! pins pin #f))
;; microscheme has this as a separate form but it's just for
(define (for-each-vector f v) (for ([x v]) (f x)))
(define (vector-copy src dest src-start src-finish dest-start)
;; ignore src-start and dest-start
(for ([i (range src-finish)])
(vector-set! dest i (vector-ref src i))))
;; microscheme has this as a separate form
(define for-each-vector vector-map)
(define last-usb-frame #f) ; save this off so we can test it
@ -49,12 +44,31 @@
(define (make-test-data)
;; have to put this in a function so we can internal-define; eww
(include "keycodes.scm")
;; pair of pins/keycodes
`(((1) . (0 ,key-w 0 0 0 0 0))
;; each test case is a pair of inputs->outputs
;; inputs are a list of keys (by offset), outputs are elements of a USB frame
`(;; single key
((3) . (0 ,key-r 0 0 0 0 0))
;; another single key
((2) . (0 ,key-e 0 0 0 0 0))
;; multiple normal keys
((2 3) . (0 ,key-e ,key-r 0 0 0 0))
;; modifier keys (alt)
((27) . (4 0 0 0 0 0 0))
;; two modifiers (shift+alt) get ORed together
((27 36) . (6 0 0 0 0 0 0))
;; modifier (shift) and normal key
((36 4) . (2 ,key-t 0 0 0 0 0))
((36 4 6) . (2 ,key-t ,key-y 0 0 0 0))))
;; modifier and multiple normal keys
((36 4 6) . (2 ,key-t ,key-y 0 0 0 0))
;; fn key alone
((40) . (0 0 0 0 0 0 0))
;; fn key and normal key
((40 1) . (2 ,key-2 0 0 0 0 0))
;; fn key and modifier and normal key
((40 35 2) . (8 ,key-up 0 0 0 0 0))
;; releasing fn should leave the previously-pressed key on the fn layer!!!
;; ((2) . (0 ,key-up 0 0 0 0 0))
))
(define test-data (make-test-data))