def test_save(self): down = ActionDown([KC_A, KC_B]) self.assertEqual(down.save(), ["down", "KC_A", "KC_B"]) tap = ActionTap([KC_B, KC_A]) self.assertEqual(tap.save(), ["tap", "KC_B", "KC_A"]) text = ActionText("Hello world") self.assertEqual(text.save(), ["text", "Hello world"]) delay = ActionDelay(123) self.assertEqual(delay.save(), ["delay", 123])
def test_deserialize_v1(self): kb = DummyKeyboard(None) kb.vial_protocol = 1 macro = kb.macro_deserialize( b"Hello\x01\x04\x01\x05\x01\x06World\x02\x06\x02\x05\x02\x04") self.assertEqual(macro, [ ActionText("Hello"), ActionTap([KC_A, KC_B, KC_C]), ActionText("World"), ActionDown([KC_C, KC_B, KC_A]) ])
def test_restore(self): down = ActionDown() down.restore(["down", "KC_A", "KC_B"]) self.assertEqual(down, ActionDown([KC_A, KC_B])) tap = ActionTap() tap.restore(["tap", "KC_B", "KC_A"]) self.assertEqual(tap, ActionTap([KC_B, KC_A])) text = ActionText() text.restore(["text", "Hello world"]) self.assertEqual(text, ActionText("Hello world")) delay = ActionDelay() delay.restore(["delay", 123]) self.assertEqual(delay, ActionDelay(123))
def on_stop(self): for x in range(self.keyboard.macro_count): self.tabs.tabBar().setTabEnabled(x, True) if not self.recording_append: self.recording_tab.clear() self.recording_tab.post_record() self.keystrokes = macro_optimize(self.keystrokes) actions = [] for k in self.keystrokes: if isinstance(k, KeyString): actions.append(ActionText(k.string)) else: cls = { KeyDown: ActionDown, KeyUp: ActionUp, KeyTap: ActionTap }[type(k)] actions.append(cls([k.keycode])) # merge: i.e. replace multiple instances of KeyDown with a single multi-key ActionDown, etc actions = self.keyboard.macro_deserialize( self.keyboard.macro_serialize(actions)) self.recording_tab.clear() for act in actions: self.recording_tab.add_action(ui_action[type(act)]( self.recording_tab.container, act))
def macro_deserialize_v2(data): """ Deserialize a single macro, protocol version 2 """ out = [] sequence = [] data = bytearray(data) while len(data) > 0: if data[0] == SS_QMK_PREFIX: if data[1] in [SS_TAP_CODE, SS_DOWN_CODE, SS_UP_CODE]: # append to previous *_CODE if it's the same type, otherwise create a new entry if len(sequence) > 0 and isinstance( sequence[-1], list) and sequence[-1][0] == data[1]: sequence[-1][1].append(data[2]) else: sequence.append([data[1], [data[2]]]) for x in range(3): data.pop(0) elif data[1] == SS_DELAY_CODE: # decode the delay delay = (data[2] - 1) + (data[3] - 1) * 255 sequence.append([SS_DELAY_CODE, delay]) for x in range(4): data.pop(0) else: # append to previous string if it is a string, otherwise create a new entry ch = chr(data[0]) if len(sequence) > 0 and isinstance(sequence[-1], str): sequence[-1] += ch else: sequence.append(ch) data.pop(0) for s in sequence: if isinstance(s, str): out.append(ActionText(s)) else: args = None if s[0] in [SS_TAP_CODE, SS_DOWN_CODE, SS_UP_CODE]: # map integer values to qmk keycodes args = [] for code in s[1]: keycode = Keycode.find_outer_keycode(code) if keycode: args.append(keycode) elif s[0] == SS_DELAY_CODE: args = s[1] if args is not None: cls = { SS_TAP_CODE: ActionTap, SS_DOWN_CODE: ActionDown, SS_UP_CODE: ActionUp, SS_DELAY_CODE: ActionDelay }[s[0]] out.append(cls(args)) return out
def test_serialize_v2(self): kb = DummyKeyboard(None) kb.vial_protocol = 2 data = kb.macro_serialize([ ActionText("Hello"), ActionTap([KC_A, KC_B, KC_C]), ActionText("World"), ActionDown([KC_C, KC_B, KC_A]), ActionDelay(1000) ]) self.assertEqual( data, b"Hello\x01\x01\x04\x01\x01\x05\x01\x01\x06World\x01\x02\x06\x01\x02\x05\x01\x02\x04" b"\x01\x04\xEC\x04") data = kb.macro_serialize([ ActionText("Hello"), ActionTap([KC_A, KC_B, KC_C]), ActionText("World"), ActionDown([KC_C, KC_B, KC_A]), ActionDelay(0) ]) self.assertEqual( data, b"Hello\x01\x01\x04\x01\x01\x05\x01\x01\x06World\x01\x02\x06\x01\x02\x05\x01\x02\x04" b"\x01\x04\x01\x01") data = kb.macro_serialize([ ActionText("Hello"), ActionTap([KC_A, KC_B, KC_C]), ActionText("World"), ActionDown([KC_C, KC_B, KC_A]), ActionDelay(1) ]) self.assertEqual( data, b"Hello\x01\x01\x04\x01\x01\x05\x01\x01\x06World\x01\x02\x06\x01\x02\x05\x01\x02\x04" b"\x01\x04\x02\x01") data = kb.macro_serialize([ ActionText("Hello"), ActionTap([KC_A, KC_B, KC_C]), ActionText("World"), ActionDown([KC_C, KC_B, KC_A]), ActionDelay(256) ]) self.assertEqual( data, b"Hello\x01\x01\x04\x01\x01\x05\x01\x01\x06World\x01\x02\x06\x01\x02\x05\x01\x02\x04" b"\x01\x04\x02\x02")
def macro_deserialize_v1(data): """ Deserialize a single macro, protocol version 1 """ out = [] sequence = [] data = bytearray(data) while len(data) > 0: if data[0] in [SS_TAP_CODE, SS_DOWN_CODE, SS_UP_CODE]: if len(data) < 2: break # append to previous *_CODE if it's the same type, otherwise create a new entry if len(sequence) > 0 and isinstance( sequence[-1], list) and sequence[-1][0] == data[0]: sequence[-1][1].append(data[1]) else: sequence.append([data[0], [data[1]]]) data.pop(0) data.pop(0) else: # append to previous string if it is a string, otherwise create a new entry ch = chr(data[0]) if len(sequence) > 0 and isinstance(sequence[-1], str): sequence[-1] += ch else: sequence.append(ch) data.pop(0) for s in sequence: if isinstance(s, str): out.append(ActionText(s)) else: # map integer values to qmk keycodes keycodes = [] for code in s[1]: keycode = Keycode.find_outer_keycode(code) if keycode: keycodes.append(keycode) cls = { SS_TAP_CODE: ActionTap, SS_DOWN_CODE: ActionDown, SS_UP_CODE: ActionUp }[s[0]] out.append(cls(keycodes)) return out
def deserialize(self, data): self.clear() sequence = [] data = bytearray(data) while len(data) > 0: if data[0] in [SS_TAP_CODE, SS_DOWN_CODE, SS_UP_CODE]: # append to previous *_CODE if it's the same type, otherwise create a new entry if len(sequence) > 0 and isinstance( sequence[-1], list) and sequence[-1][0] == data[0]: sequence[-1][1].append(data[1]) else: sequence.append([data[0], [data[1]]]) data.pop(0) data.pop(0) else: # append to previous string if it is a string, otherwise create a new entry ch = chr(data[0]) if len(sequence) > 0 and isinstance(sequence[-1], str): sequence[-1] += ch else: sequence.append(ch) data.pop(0) for s in sequence: if isinstance(s, str): self.add_action(ActionText(self.container, s)) else: # map integer values to qmk keycodes keycodes = [] for code in s[1]: keycode = find_keycode(code) if keycode: keycodes.append(keycode) cls = { SS_TAP_CODE: ActionTap, SS_DOWN_CODE: ActionDown, SS_UP_CODE: ActionUp }[s[0]] self.add_action(cls(self.container, keycodes))
def on_add(self): self.add_action(ActionText(self.container))