Skip to content

Commit

Permalink
Add implementation for Mod-Tap and Modifier Keys (#61)
Browse files Browse the repository at this point in the history
  • Loading branch information
sago35 authored Dec 18, 2024
1 parent 9d02bba commit 75c716b
Show file tree
Hide file tree
Showing 3 changed files with 213 additions and 6 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ The following are supported.
* [Layers](https://get.vial.today/manual/layers.html) (MO(x), TO(x))
* Matrix testers
* [Macros](https://get.vial.today/manual/macros.html)
* [Mod-Tap](https://docs.qmk.fm/mod_tap)
* [Modifier Keys](https://docs.qmk.fm/feature_advanced_keycodes#modifier-keys)
* [Combos](https://get.vial.today/manual/combos.html)

## Microcontrollers
Expand Down
191 changes: 187 additions & 4 deletions keyboard.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ type Device struct {
combosKey uint32
combosFounds []Keycode

tapOrHold map[uint32]time.Time

pressToReleaseBuf []uint32
noneToPressBuf []uint32
}
Expand Down Expand Up @@ -87,6 +89,8 @@ func New() *Device {
combosKey: 0xFFFFFFFF,
combosFounds: make([]Keycode, 10),

tapOrHold: map[uint32]time.Time{},

pressToReleaseBuf: make([]uint32, 0, 20),
noneToPressBuf: make([]uint32, 0, 20),
}
Expand Down Expand Up @@ -344,6 +348,104 @@ func (d *Device) Tick() error {
}
}

for _, xx := range noneToPress {
kbidx, layer, index := decKey(xx)
x := d.kb[kbidx].Key(layer, index)
switch x & keycodes.QuantumMask {
case keycodes.TypeLxxxT, keycodes.TypeRxxxT:
d.tapOrHold[xx] = time.Now().Add(200 * time.Millisecond)
}
}

for xx, tt := range d.tapOrHold {
if tt.IsZero() {
// hold release
for _, yy := range pressToRelease {
if xx == yy {
kbidx, layer, index := decKey(xx)
x := d.kb[kbidx].Key(layer, index)
switch x & keycodes.QuantumMask {
case keycodes.TypeLxxxT:
if x&keycodes.TypeXCtl > 0 {
pressToRelease = append(pressToRelease, uint32(0xFF000000)|uint32(keycodes.KeyLeftCtrl))
}
if x&keycodes.TypeXSft > 0 {
pressToRelease = append(pressToRelease, uint32(0xFF000000)|uint32(keycodes.KeyLeftShift))
}
if x&keycodes.TypeXAlt > 0 {
pressToRelease = append(pressToRelease, uint32(0xFF000000)|uint32(keycodes.KeyLeftAlt))
}
if x&keycodes.TypeXGui > 0 {
pressToRelease = append(pressToRelease, uint32(0xFF000000)|uint32(keycodes.KeyWindows))
}
case keycodes.TypeRxxxT:
if x&keycodes.TypeXCtl > 0 {
pressToRelease = append(pressToRelease, uint32(0xFF000000)|uint32(keycodes.KeyRightCtrl))
}
if x&keycodes.TypeXSft > 0 {
pressToRelease = append(pressToRelease, uint32(0xFF000000)|uint32(keycodes.KeyRightShift))
}
if x&keycodes.TypeXAlt > 0 {
pressToRelease = append(pressToRelease, uint32(0xFF000000)|uint32(keycodes.KeyLeftAlt))
}
if x&keycodes.TypeXGui > 0 {
pressToRelease = append(pressToRelease, uint32(0xFF000000)|uint32(keycodes.KeyWindows))
}
}
delete(d.tapOrHold, xx)
}
}
} else if time.Now().Before(tt) {
// tap
for _, yy := range pressToRelease {
if xx == yy {
kbidx, layer, index := decKey(xx)
x := d.kb[kbidx].Key(layer, index)
switch x & keycodes.QuantumMask {
case keycodes.TypeLxxxT, keycodes.TypeRxxxT:
kc := uint32(0xFF000000) | uint32(keycodeViaToTGK(x&0x00FF))
noneToPress = append(noneToPress, kc)
pressToRelease = append(pressToRelease, kc)
}
delete(d.tapOrHold, xx)
}
}
} else {
// hold
kbidx, layer, index := decKey(xx)
x := d.kb[kbidx].Key(layer, index)
switch x & keycodes.QuantumMask {
case keycodes.TypeLxxxT:
if x&keycodes.TypeXCtl > 0 {
noneToPress = append(noneToPress, uint32(0xFF000000)|uint32(keycodes.KeyLeftCtrl))
}
if x&keycodes.TypeXSft > 0 {
noneToPress = append(noneToPress, uint32(0xFF000000)|uint32(keycodes.KeyLeftShift))
}
if x&keycodes.TypeXAlt > 0 {
noneToPress = append(noneToPress, uint32(0xFF000000)|uint32(keycodes.KeyLeftAlt))
}
if x&keycodes.TypeXGui > 0 {
noneToPress = append(noneToPress, uint32(0xFF000000)|uint32(keycodes.KeyWindows))
}
case keycodes.TypeRxxxT:
if x&keycodes.TypeXCtl > 0 {
noneToPress = append(noneToPress, uint32(0xFF000000)|uint32(keycodes.KeyRightCtrl))
}
if x&keycodes.TypeXSft > 0 {
noneToPress = append(noneToPress, uint32(0xFF000000)|uint32(keycodes.KeyRightShift))
}
if x&keycodes.TypeXAlt > 0 {
noneToPress = append(noneToPress, uint32(0xFF000000)|uint32(keycodes.KeyLeftAlt))
}
if x&keycodes.TypeXGui > 0 {
noneToPress = append(noneToPress, uint32(0xFF000000)|uint32(keycodes.KeyWindows))
}
}
d.tapOrHold[xx] = time.Time{}
}
}

for _, xx := range noneToPress {
kbidx, layer, index := decKey(xx)
var x Keycode
Expand All @@ -362,6 +464,36 @@ func (d *Device) Tick() error {
} else {
d.layerStack = append(d.layerStack, d.layer)
}
} else if x&keycodes.QuantumMask == keycodes.TypeLxxx && x&keycodes.QuantumTypeMask != 0 {
// TypeLxxx
if x&keycodes.TypeXCtl > 0 {
d.Keyboard.Down(keycodes.KeyLeftCtrl)
}
if x&keycodes.TypeXSft > 0 {
d.Keyboard.Down(keycodes.KeyLeftShift)
}
if x&keycodes.TypeXAlt > 0 {
d.Keyboard.Down(keycodes.KeyLeftAlt)
}
if x&keycodes.TypeXGui > 0 {
d.Keyboard.Down(keycodes.KeyWindows)
}
d.Keyboard.Down(k.Keycode(x&0x00FF | keycodes.TypeNormal))
} else if x&keycodes.QuantumMask == keycodes.TypeRxxx && x&keycodes.QuantumTypeMask != 0 {
// TypeRxxx
if x&keycodes.TypeXCtl > 0 {
d.Keyboard.Down(keycodes.KeyRightCtrl)
}
if x&keycodes.TypeXSft > 0 {
d.Keyboard.Down(keycodes.KeyRightShift)
}
if x&keycodes.TypeXAlt > 0 {
d.Keyboard.Down(keycodes.KeyLeftAlt)
}
if x&keycodes.TypeXGui > 0 {
d.Keyboard.Down(keycodes.KeyWindows)
}
d.Keyboard.Down(k.Keycode(x&0x00FF | keycodes.TypeNormal))
} else if x == keycodes.KeyRestoreDefaultKeymap {
// restore default keymap for QMK
machine.Flash.EraseBlocks(0, 1)
Expand Down Expand Up @@ -438,6 +570,36 @@ func (d *Device) Tick() error {
d.layer = d.layerStack[len(d.layerStack)-1]
}
}
} else if x&keycodes.QuantumMask == keycodes.TypeLxxx && x&keycodes.QuantumTypeMask != 0 {
// TypeLxxx
if x&keycodes.TypeXCtl > 0 {
d.Keyboard.Up(keycodes.KeyLeftCtrl)
}
if x&keycodes.TypeXSft > 0 {
d.Keyboard.Up(keycodes.KeyLeftShift)
}
if x&keycodes.TypeXAlt > 0 {
d.Keyboard.Up(keycodes.KeyLeftAlt)
}
if x&keycodes.TypeXGui > 0 {
d.Keyboard.Up(keycodes.KeyWindows)
}
d.Keyboard.Up(k.Keycode(x&0x00FF | keycodes.TypeNormal))
} else if x&keycodes.QuantumMask == keycodes.TypeRxxx && x&keycodes.QuantumTypeMask != 0 {
// TypeRxxx
if x&keycodes.TypeXCtl > 0 {
d.Keyboard.Up(keycodes.KeyRightCtrl)
}
if x&keycodes.TypeXSft > 0 {
d.Keyboard.Up(keycodes.KeyRightShift)
}
if x&keycodes.TypeXAlt > 0 {
d.Keyboard.Up(keycodes.KeyLeftAlt)
}
if x&keycodes.TypeXGui > 0 {
d.Keyboard.Up(keycodes.KeyWindows)
}
d.Keyboard.Up(k.Keycode(x&0x00FF | keycodes.TypeNormal))
} else if x&0xF000 == 0xD000 {
switch x & 0x00FF {
case 0x01, 0x02, 0x04, 0x08, 0x10:
Expand Down Expand Up @@ -613,10 +775,20 @@ func (d *Device) KeyVia(layer, kbIndex, index int) Keycode {
// restore default keymap for QMK
kc = keycodes.KeyRestoreDefaultKeymap
default:
if kc&0xFF00 == keycodes.TypeMacroKey {
switch kc & keycodes.QuantumMask {
case keycodes.TypeRxxx, keycodes.TypeLxxxT, keycodes.TypeRxxxT:
// skip
} else {
kc = kc & 0x0FFF
default:
if kc&keycodes.QuantumMask == 0 && kc&keycodes.QuantumTypeMask != 0 {
// skip (keycodes.TpeLxxx)
} else {
switch kc & keycodes.ModKeyMask {
case keycodes.TypeMacroKey:
// skip
default:
kc = kc & 0x0FFF
}
}
}
}
return kc
Expand Down Expand Up @@ -680,8 +852,19 @@ func keycodeViaToTGK(key Keycode) Keycode {
case keycodes.KeyRestoreDefaultKeymap:
kc = keycodes.KeyRestoreDefaultKeymap
default:
if key&0xFF00 == keycodes.TypeMacroKey {
switch key & keycodes.QuantumMask {
case keycodes.TypeRxxx, keycodes.TypeLxxxT, keycodes.TypeRxxxT:
kc = key
default:
if key&keycodes.QuantumMask == 0 && key&keycodes.QuantumTypeMask != 0 {
// keycodes.TpeLxxx
kc = key
} else {
switch key & 0xFF00 {
case keycodes.TypeMacroKey:
kc = key
}
}
}
}
return kc
Expand Down
26 changes: 24 additions & 2 deletions keycodes/keycodes.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import (
)

const (
ModKeyMask = 0xFF00
ToKeyMask = 0x0010
ModKeyMask = 0xFF00
QuantumMask = 0xF000
QuantumTypeMask = 0x0F00
ToKeyMask = 0x0010
)

const (
Expand All @@ -16,6 +18,26 @@ const (
TypeModKey = 0xFF00
TypeToKey = 0xFF10
TypeMacroKey = 0x7700
TypeLxxx = 0x0000
TypeRxxx = 0x1000
TypeLxxxT = 0x2000
TypeRxxxT = 0x3000
)

const (
TypeXCtl = 0x0100
TypeXSft = 0x0200
TypeXAlt = 0x0400
TypeXGui = 0x0800

TypeLCtlT = TypeLxxxT | TypeXCtl
TypeLSftT = TypeLxxxT | TypeXSft
TypeLAltT = TypeLxxxT | TypeXAlt
TypeLGuiT = TypeLxxxT | TypeXGui
TypeRCtlT = TypeRxxxT | TypeXCtl
TypeRSftT = TypeRxxxT | TypeXSft
TypeRAltT = TypeRxxxT | TypeXAlt
TypeRGuiT = TypeRxxxT | TypeXGui
)

const (
Expand Down

0 comments on commit 75c716b

Please sign in to comment.