~technomancy/menelaus

dcc363073b3fa5a19455416f9992749715e4dba0 — Phil Hagelberg 9 months ago 66f01f2
Fix a bug in releasing fn-layer shifted keys.
6 files changed, 64 insertions(+), 28 deletions(-)

M Makefile
M README.md
M layout.scm
M menelaus.scm
M test.rkt
M usb_keyboard.c
M Makefile => Makefile +1 -1
@@ 16,7 16,7 @@ test: ; racket test.rkt

clean: ; -rm -f $(TARGET){,.hex} *.o *.elf *.s

count: ; cloc menelaus.scm keycodes.scm
count: ; cloc menelaus.scm keycodes.scm layout.scm

$(TARGET).hex: $(TARGET).elf
	avr-size $(TARGET).elf

M README.md => README.md +3 -0
@@ 49,6 49,9 @@ into Racket and simulates the GPIO functions with a test harness:
If you hold down two keys which contain a modifier (for instance,
shift and !) and release one of them, it will count as if both are released.

The reset function has no effect; hard-reset must be used to reflash
the firmware.

## License

Copyright © 2014-2019 Phil Hagelberg and contributors

M layout.scm => layout.scm +20 -11
@@ 1,5 1,7 @@
;;; this is the multidvorak layout

;; it will work for the 44-key Atreus 2 or the 42-key Atreus 1.

;; we have to declare this up front and set it later because of circularity
(define layers #f)
(define current-layer #f)


@@ 10,15 12,22 @@
(define (set-layer n)
  (lambda (_) (set! current-layer (vector-ref layers n))))

(define (reset _) (call-c-func "reset"))
(define (reset _) (call-c-func "reset")) ; broken

;; on the Atreus 1, we need to expose backtick on the fn layer, but on
;; the Atreus 2 it has its own key, so we put percent there instead
(define backtick-or-percent
  key-backtick
  ;; (sft key-5)
  )

;;;; layers

(define base-layer
 (vector key-q key-w key-e key-r key-t key-backslash
 (vector key-q key-w key-e key-r key-t key-backtick
         key-y key-u key-i key-o key-p

         key-a key-s key-d key-f key-g key-backtick
         key-a key-s key-d key-f key-g key-backslash
         key-h key-j key-k key-l key-semicolon

         key-z key-x key-c key-v key-b mod-ctrl


@@ 28,14 37,14 @@
         key-space fn key-quote key-left-bracket key-enter))

(define fn-layer
 (vector (sft key-1) (sft key-2) key-up (sft key-dash) (sft key-equal) 0
         key-page-up key-7 key-8 key-9 (sft key-8)
 (vector (sft key-1) (sft key-2) key-up (sft key-4) backtick-or-percent (sft key-6)
         key-page-up key-7 key-8 key-9 key-backspace

         (sft key-3) key-left key-down key-right (sft key-4) 0
         key-page-down key-4 key-5 key-6 (sft key-right-bracket)
         (sft key-9) key-left key-down key-right (sft key-0) (sft key-7)
         key-page-down key-4 key-5 key-6 key-backslash

         key-dash key-equal (sft key-9) (sft key-0) (sft key-7) mod-ctrl
         key-backtick key-1 key-2 key-3 key-backslash
         key-dash key-equal (sft key-3) (sft key-dash) (sft key-equal) mod-ctrl
         (sft key-8) key-1 key-2 key-3 (sft key-right-bracket)

         (set-layer 2) key-insert mod-super mod-shift key-backspace mod-alt
         key-space fn key-e key-0 key-right-bracket))


@@ 67,8 76,8 @@
         key-space fn key-quote key-left-bracket key-enter))

(define hard-dvorak-fn-layer
 (vector (sft key-1) (sft key-2) key-up (sft key-left-bracket) (sft key-right-bracket) 0
         key-page-up key-7 key-8 key-9 (sft key-8)
 (vector (sft key-1) (sft key-2) key-up (sft key-4) (sft key-5) (sft key-6)
         key-page-up key-7 key-8 key-9 (sft key-backspace)

         (sft key-3) key-left key-down key-right (sft key-4) 0
         key-page-down key-4 key-5 key-6 (sft key-equal)

M menelaus.scm => menelaus.scm +22 -14
@@ 1,5 1,4 @@
(include "keycodes.scm")
(include "layout.scm")

(define rows (list 0 1 2 3))
(define row-pins (vector 3 2 1 0))


@@ 8,6 7,13 @@

(define max-keys 10) ; single USB frame can only send 6 keycodes plus modifiers

;; pcbdown flip, comment out for normal
;; (begin (set! mod-alt (modify 1))
;;        (set! mod-ctrl (modify 3))
;;        (set! column-pins (vector 11 12 18 19 10 4 7 8 9 5 6)))

(include "layout.scm")

;;;;;;;;;;;;;;;;;;; utils

(define (member v lst)


@@ 59,7 65,7 @@

;;;;;;;;;;;;;;;;;;; debouncing

(define debounce-passes 4)
(define debounce-passes 3)

(define (debounce-matrix-aux last-scan passes-left)
  (if (< 0 passes-left)


@@ 74,10 80,10 @@

;;;;;;;;;;;;;;;;;;; press and release tracking

(define last-keys-down (vector 0 0 0 0 0 0 0 0 0 0))
(define last-keys-down (vector #f #f #f #f #f #f #f #f #f #f))

(define (add-last-down-aux key n)
  (if (= 0 (vector-ref last-keys-down n))
  (if (not (vector-ref last-keys-down n))
      (vector-set! last-keys-down n key)
      (if (< n 9)
          (add-last-down-aux key (+ n 1))


@@ 87,8 93,8 @@

(define (remove-last-down-aux key n)
  (if (< n 9)
      (if (= key (vector-ref last-keys-down n))
          (vector-set! last-keys-down n 0)
      (if (= key (or (vector-ref last-keys-down n) -1))
          (vector-set! last-keys-down n #f)
          (remove-last-down-aux key (+ n 1)))
      #f))



@@ 98,7 104,7 @@
(define (remove-aux v lst checked all?)
  (if (null? lst)
      (reverse checked)
      (if (= v (car lst))
      (if (equal? v (car lst))
          (if all?
              (remove-aux v (cdr lst) checked all?)
              (reverse (append (cdr lst) checked)))


@@ 117,7 123,7 @@

(define (press/release-for keys-scanned)
  (let ((p/r (press/release-aux (list)
                                (remove-all 0 (vector->list last-keys-down))
                                (remove-all #f (vector->list last-keys-down))
                                keys-scanned)))
    ;; save off press/release into last-keys-down for next cycle
    (for-each add-last-down (car p/r))


@@ 139,8 145,6 @@

(define (press-modifier keycode key)
  (vector-set! modifiers (- keycode 1) 1)
  ;; TODO: there is one bug here: if multiple keys have caused a modifier to be
  ;; active, then releasing only one of the keys will release the modifier.
  (vector-set! keys-for-modifiers (- keycode 1) key))

(define (release-modifier keycode key n)


@@ 169,17 173,21 @@
            (press-normal-key keycode key)))))

(define (release-key key)
  ;; lookup here looks it up in the current layer, even if it was pressed in
  ;; the momentary layer. these need to be consistent across layers or tracked
  ;; in a similar manner as keys-for-frame.
  (let ((keycode (lookup key)))
    (if (procedure? keycode)
        (keycode #f)
        (let ((slot (find keys-for-frame key)))
        (let ((slot (find keys-for-frame key))
              (modifier-slot (find keys-for-modifiers key)))
          (if slot
              (begin
                (vector-set! keycodes-down slot 0)
                (vector-set! keys-for-frame slot 0))
              #f)
          (if (modifier? keycode)
              (release-modifier (unmodify keycode) key 0)
          (if modifier-slot
              (release-modifier modifier-slot key 0)
              #f)))))

;;;;;;;;;;;;;;;;;;; showtime


@@ 203,7 211,7 @@

(define (usb-send m k0 k1 k2 k3 k4 k5)
  ;; call-c-func is a special form and cannot be applied
  (let ((mods (+ (vector-ref m 0) (* (vector-ref m 1) 2)))) ; plus isn't variadic
  (let ((mods (+ (vector-ref m 0) (* (vector-ref m 1) 2)))) ; + isn't variadic
    (let ((mods (+ mods (+ (* (vector-ref m 2) 4) (* (vector-ref m 3) 8)))))
      (call-c-func "usb_send" mods k0 k1 k2 k3 k4 k5))))


M test.rkt => test.rkt +15 -1
@@ 59,8 59,10 @@
    ((3) . (() ,key-r))
    ;; another single key
    ((2) . (() ,key-e))
    ;; the first key in the whole layout
    ((0) . (() ,key-q))
    ;; multiple normal keys
    ((2 3) . (() ,key-r ,key-e))
    ((2 3) . (() ,key-e ,key-r))
    ;; modifier keys (ctrl)
    ((27) . ((ctrl)))
    ;; two modifiers (shift+ctrl) get ORed together


@@ 77,6 79,18 @@
    ((40 35 2) . ((super) ,key-up))
    ;; releasing fn should leave the previously-pressed key on the fn layer!!!
    ((2) . (() ,key-up))

    ;; fn key alone
    ((40) . (()))
    ;; fn key and *
    ((40 28) . ((shift) ,key-8))
    ;; fn is released
    ((28) . ((shift) ,key-8))
    ;; * is released
    (() . (()))
    ;; normal key doesn't leave shift down
    ((0) . (() ,key-q))

    ;; changing to L2 (fn+esc)
    ((40) . (()))
    ((40 33) . (()))

M usb_keyboard.c => usb_keyboard.c +3 -1
@@ 26,6 26,7 @@

#define USB_SERIAL_PRIVATE_INCLUDE
#include "usb_keyboard.h"
#include <util/delay.h>

/**************************************************************************
 *


@@ 603,9 604,10 @@ ISR(USB_COM_vect)
  UECONX = (1<<STALLRQ) | (1<<EPEN);  // stall
}

// this fails to enter the bootloader
void reset(void) {
  UDCON = 1; USBCON = (1<<FRZCLK); UCSR1B = 0;
  // _delay_ms(5);
  _delay_ms(5);
  EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0; ADCSRA = 0;
  TIMSK0 = 0; TIMSK1 = 0; TIMSK3 = 0; TIMSK4 = 0; UCSR1B = 0; TWCR = 0;
  DDRB = 0; DDRC = 0; DDRD = 0; DDRE = 0; DDRF = 0; TWCR = 0;