import unittest from kmk.keys import KC from kmk.modules.layers import Layers from kmk.modules.modtap import ModTap from kmk.modules.oneshot import OneShot from tests.keyboard_test import KeyboardTest class TestHoldTap(unittest.TestCase): def test_holdtap(self): keyboard = KeyboardTest( [Layers(), ModTap(), OneShot()], [ [KC.MT(KC.A, KC.LCTL), KC.LT(1, KC.B), KC.C, KC.D, KC.OS(KC.E)], [KC.N1, KC.N2, KC.N3, KC.N4, KC.N5], ], debug_enabled=False, ) keyboard.test('MT tap behaviour', [(0, True), 100, (0, False)], [{KC.A}, {}]) keyboard.test( 'MT hold behaviour', [(0, True), 350, (0, False)], [{KC.LCTL}, {}] ) # TODO test multiple mods being held # MT keyboard.test( 'MT within tap time sequential -> tap behavior', [(0, True), 100, (0, False), (3, True), (3, False)], [{KC.A}, {}, {KC.D}, {}], ) keyboard.test( 'MT within tap time rolling -> hold behavior', [(0, True), 100, (3, True), 250, (0, False), (3, False)], [{KC.LCTL}, {KC.LCTL, KC.D}, {KC.D}, {}], ) keyboard.test( 'MT within tap time nested -> hold behavior', [(0, True), 100, (3, True), (3, False), 250, (0, False)], [{KC.LCTL}, {KC.LCTL, KC.D}, {KC.LCTL}, {}], ) keyboard.test( 'MT after tap time sequential -> hold behavior', [(0, True), 350, (0, False), (3, True), (3, False)], [{KC.LCTL}, {}, {KC.D}, {}], ) keyboard.test( 'MT after tap time rolling -> hold behavior', [(0, True), 350, (3, True), (0, False), (3, False)], [{KC.LCTL}, {KC.LCTL, KC.D}, {KC.D}, {}], ) keyboard.test( 'MT after tap time nested -> hold behavior', [(0, True), 350, (3, True), (3, False), (0, False)], [{KC.LCTL}, {KC.LCTL, KC.D}, {KC.LCTL}, {}], ) # LT keyboard.test( 'LT within tap time sequential -> tap behavior', [(1, True), 100, (1, False), (3, True), (3, False)], [{KC.B}, {}, {KC.D}, {}], ) keyboard.test( 'LT within tap time rolling -> tap behavior', [(1, True), 100, (3, True), 250, (1, False), (3, False)], [{KC.B}, {KC.B, KC.D}, {KC.D}, {}], ) keyboard.test( 'LT within tap time nested -> tap behavior', [(1, True), 100, (3, True), (3, False), 250, (1, False)], [{KC.B}, {KC.B, KC.D}, {KC.B}, {}], ) keyboard.test( 'LT after tap time sequential -> hold behavior', [(1, True), 350, (1, False), (3, True), (3, False)], [{KC.D}, {}], ) keyboard.test( 'LT after tap time rolling -> hold behavior', [(1, True), 350, (3, True), (1, False), (3, False)], [{KC.N4}, {}], ) keyboard.test( 'LT after tap time nested -> hold behavior', [(1, True), 350, (3, True), (3, False), (1, False)], [{KC.N4}, {}], ) keyboard.test( 'LT after tap time nested -> hold behavior', [ (0, True), 350, (1, True), 350, (3, True), (3, False), (1, False), (0, False), ], [{KC.LCTL}, {KC.LCTL, KC.N4}, {KC.LCTL}, {}], ) def test_holdtap_chain(self): keyboard = KeyboardTest( [ModTap()], [ [ KC.N0, KC.MT(KC.N1, KC.LCTL, tap_time=50), KC.MT(KC.N2, KC.LSFT, tap_interrupted=True, tap_time=50), KC.MT( KC.N3, KC.LALT, prefer_hold=False, tap_interrupted=True, tap_time=50, ), ], ], debug_enabled=False, ) # t_within = 40 t_after = 60 keyboard.test( 'chained 0', [(1, True), (2, True), (0, True), (0, False), (2, False), (1, False)], [ {KC.LCTL}, {KC.LCTL, KC.LSFT}, {KC.LCTL, KC.LSFT, KC.N0}, {KC.LCTL, KC.LSFT}, {KC.LCTL}, {}, ], ) keyboard.test( 'chained 1', [(2, True), (1, True), (0, True), (0, False), (1, False), (2, False)], [ {KC.LCTL}, {KC.LCTL, KC.LSFT}, {KC.LCTL, KC.LSFT, KC.N0}, {KC.LCTL, KC.LSFT}, {KC.LSFT}, {}, ], ) keyboard.test( 'chained 2', [(1, True), (2, True), (0, True), (1, False), (2, False), (0, False)], [ {KC.LCTL}, {KC.LCTL, KC.LSFT}, {KC.LCTL, KC.LSFT, KC.N0}, {KC.LSFT, KC.N0}, {KC.N0}, {}, ], ) keyboard.test( 'chained 3', [(1, True), (3, True), (0, True), (0, False), (1, False), (3, False)], [ {KC.LCTL}, {KC.LCTL, KC.N3}, {KC.LCTL, KC.N3, KC.N0}, {KC.LCTL, KC.N3}, {KC.N3}, {}, ], ) keyboard.test( 'chained 4', [(1, True), (3, True), (0, True), (3, False), (1, False), (0, False)], [{KC.LCTL}, {KC.LCTL, KC.N3, KC.N0}, {KC.LCTL, KC.N0}, {KC.N0}, {}], ) keyboard.test( 'chained 5', [(3, True), (1, True), (0, True), (0, False), (1, False), (3, False)], [ {KC.LCTL}, {KC.LCTL, KC.N3}, {KC.LCTL, KC.N3, KC.N0}, {KC.LCTL, KC.N3}, {KC.N3}, {}, ], ) keyboard.test( 'chained 6', [ (3, True), (1, True), t_after, (0, True), (0, False), (1, False), (3, False), ], [ {KC.LALT}, {KC.LCTL, KC.LALT}, {KC.LCTL, KC.LALT, KC.N0}, {KC.LCTL, KC.LALT}, {KC.LALT}, {}, ], ) keyboard.test( 'chained 7', [ (1, True), (3, True), t_after, (0, True), (0, False), (1, False), (3, False), ], [ {KC.LCTL}, {KC.LCTL, KC.LALT}, {KC.LCTL, KC.LALT, KC.N0}, {KC.LCTL, KC.LALT}, {KC.LALT}, {}, ], ) keyboard.test( 'chained 8', [(2, True), (3, True), (0, True), (0, False), (2, False), (3, False)], [ {KC.LSFT}, {KC.LSFT, KC.N3}, {KC.LSFT, KC.N3, KC.N0}, {KC.LSFT, KC.N3}, {KC.N3}, {}, ], ) # TODO test TT def test_oneshot(self): keyboard = KeyboardTest( [Layers(), ModTap(), OneShot()], [ [ KC.MT(KC.A, KC.LCTL), KC.LT(1, KC.B), KC.C, KC.D, KC.OS(KC.E, tap_time=50), ], [KC.N1, KC.N2, KC.N3, KC.N4, KC.N5], ], debug_enabled=False, ) t_within = 40 t_after = 60 # OS keyboard.test( 'OS timed out', [(4, True), (4, False), t_after], [{KC.E}, {}], ) keyboard.test( 'OS interrupt within tap time', [(4, True), (4, False), t_within, (3, True), (3, False)], [{KC.E}, {KC.D, KC.E}, {}], ) keyboard.test( 'OS interrupt, multiple within tap time', [(4, True), (4, False), (3, True), (3, False), (2, True), (2, False)], [{KC.E}, {KC.D, KC.E}, {}, {KC.C}, {}], ) keyboard.test( 'OS interrupt, multiple interleaved', [(4, True), (4, False), (3, True), (2, True), (2, False), (3, False)], [{KC.E}, {KC.D, KC.E}, {KC.C, KC.D}, {KC.D}, {}], ) keyboard.test( 'OS interrupt, multiple interleaved', [(4, True), (4, False), (3, True), (2, True), (3, False), (2, False)], [{KC.E}, {KC.D, KC.E}, {KC.C, KC.D}, {KC.C}, {}], ) keyboard.test( 'OS interrupt within tap time, hold', [(4, True), (3, True), (4, False), t_after, (3, False)], [{KC.E}, {KC.D, KC.E}, {KC.D}, {}], ) keyboard.test( 'OS hold with multiple interrupt keys', [ (4, True), t_within, (3, True), (3, False), (2, True), (2, False), (4, False), ], [{KC.E}, {KC.D, KC.E}, {KC.E}, {KC.C, KC.E}, {KC.E}, {}], ) if __name__ == '__main__': unittest.main()