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 test: ; racket test.rkt
clean: clean: ; -rm -f $(TARGET){,.hex} *.o *.elf *.s
-rm -f $(TARGET){,.hex} *.o *.elf *.s
count: ; cloc *.scm
$(TARGET).hex: $(TARGET).elf $(TARGET).hex: $(TARGET).elf
avr-size $(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 \ avr-gcc -std=gnu99 -S -D F_CPU=$(F_CPU)UL -mmcu=$(MCU) -c \
-o usb_keyboard.s usb_keyboard.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-x 27)
(define key-y 28) (define key-y 28)
(define key-z 29) (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-comma 54)
(define key-period 55) (define key-period 55)
(define key-slash 56) (define key-slash 56)
(define key-dash 45) (define key-dash 45)
(define key-quote 52) (define key-quote 52)
(define key-equal 46)
(define key-left-bracket 47)
(define key-right-bracket 48)
(define key-space 44) (define key-space 44)
(define key-backspace 42) (define key-backspace 42)
@ -43,12 +68,18 @@
(define key-backslash 49) (define key-backslash 49)
(define key-backtick 53) (define key-backtick 53)
(define key-vol-up 128)
(define key-vol-down 129)
(define (modifier? keycode) (list? keycode)) (define (modifier? keycode) (list? keycode))
(define (modify keycode) (list keycode)) (define (modify keycode) (list keycode))
(define (unmodify keycode) (car 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-ctrl (modify #x01))
(define mod-shift (modify #x02)) (define mod-shift (modify #x02))
(define mod-alt (modify #x04)) (define mod-alt (modify #x04))
(define mod-gui (modify #x08)) (define mod-super (modify #x08))
(define mod-fn (modify #x16))

View file

@ -1,12 +1,50 @@
(define layout ;;; this is the multidvorak layout
(vector key-q key-w key-e key-r key-t key-backslash
key-y key-u key-i key-o key-p
key-a key-s key-d key-f key-g key-backtick ;; we have to declare this up front and set it later because of circularity
key-h key-j key-k key-l key-semicolon (define layers (vector #f #f #f))
(define current-layer #f)
(define momentary-layer #f)
key-z key-x key-c key-v key-b mod-alt (define (fn)
key-n key-m key-comma key-period key-slash (set! momentary-layer (vector-ref layers 1)))
key-esc key-tab mod-gui mod-shift key-backspace mod-ctrl (define (set-layer-2)
key-space mod-fn key-dash key-quote key-enter)) (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
key-a key-s key-d key-f key-g key-backtick
key-h key-j key-k key-l key-semicolon
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-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 (define max-keys 6) ; a single USB frame can only send 6 keycodes plus modifiers
;;; matrix ;;;;;;;;;;;;;;;;;;; matrix
(define (offset-for row col) (define (offset-for row col)
(+ col (* row (length columns)))) (+ col (* row (length columns))))
@ -42,7 +42,7 @@
(car rows-left) columns))) (car rows-left) columns)))
(scan-matrix keys-pressed key-count (cdr rows-left))))) (scan-matrix keys-pressed key-count (cdr rows-left)))))
;;; debouncing ;;;;;;;;;;;;;;;;;;; debouncing
(define this-scan (vector 0 0 0 0 0 0 0)) (define this-scan (vector 0 0 0 0 0 0 0))
(define last-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-passes 8)
(define (debounce-matrix keys-pressed last-count passes-left) (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) (if (< 0 passes-left)
(let ((this-count (scan-matrix this-scan 1 rows))) (let ((this-count (scan-matrix this-scan 1 rows)))
(if (and (= this-count last-count) (if (and (= this-count last-count)
(equal? this-scan last-scan)) (equal? this-scan last-scan))
(debounce-matrix keys-pressed this-count (- passes-left 1)) (debounce-matrix keys-pressed this-count (- passes-left 1))
(debounce-matrix keys-pressed this-count passes-left))) (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))) 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) (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) ;; (printf "keycode ~s ~s~n" code which-key)
(if (modifier? code) (if (modifier? code)
(begin (vector-set! keycodes 0 (+ (vector-ref keycodes 0) (begin (vector-set! keycodes 0 (+ (vector-ref keycodes 0)
(unmodify code))) (unmodify code)))
#f) (uncombo code))
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)
(call-functions keys-pressed (- key-count 1)))
#f))
;; translate key numbers into specific USB keycodes ;; translate key numbers into specific USB keycodes
(define (keycodes-for keys-pressed key-count 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) (if (= 0 key-count)
(vector->list keycodes) (vector->list keycodes)
(let ((keycode (keycode-for keys-pressed key-count keycodes))) (let ((keycode (keycode-for keys-pressed key-count keycodes)))
@ -81,9 +98,10 @@
#f) #f)
(keycodes-for keys-pressed (- key-count 1) keycodes)))) (keycodes-for keys-pressed (- key-count 1) keycodes))))
;;; showtime ;;;;;;;;;;;;;;;;;;; showtime
(define (init) (define (init)
(set-layer-0)
(for-each-vector output row-pins) (for-each-vector output row-pins)
(for-each-vector high row-pins) (for-each-vector high row-pins)
(for-each-vector input column-pins) (for-each-vector input column-pins)
@ -96,6 +114,7 @@
(call-c-func "usb_send" modifiers key1 key2 key3 key4 key5 key6)) (call-c-func "usb_send" modifiers key1 key2 key3 key4 key5 key6))
(define (loop) (define (loop)
(set! momentary-layer #f)
(free! (let ((keys-pressed (vector 0 0 0 0 0 0 0))) (free! (let ((keys-pressed (vector 0 0 0 0 0 0 0)))
;; scanning the matrix tells us only which physical keys were ;; scanning the matrix tells us only which physical keys were
;; pressed and how many; it doesn't tell us which keycodes to ;; 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 (high pin) (vector-set! pins pin #t))
(define (low pin) (vector-set! pins pin #f)) (define (low pin) (vector-set! pins pin #f))
;; microscheme has this as a separate form but it's just for ;; microscheme has this as a separate form
(define (for-each-vector f v) (for ([x v]) (f x))) (define for-each-vector vector-map)
(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))))
(define last-usb-frame #f) ; save this off so we can test it (define last-usb-frame #f) ; save this off so we can test it
@ -49,12 +44,31 @@
(define (make-test-data) (define (make-test-data)
;; have to put this in a function so we can internal-define; eww ;; have to put this in a function so we can internal-define; eww
(include "keycodes.scm") (include "keycodes.scm")
;; pair of pins/keycodes ;; each test case is a pair of inputs->outputs
`(((1) . (0 ,key-w 0 0 0 0 0)) ;; 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)) ((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)) ((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) . (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)) (define test-data (make-test-data))