def restore_layout(self, data): """ Restores saved layout """ data = json.loads(data.decode("utf-8")) # restore keymap for l, layer in enumerate(data["layout"]): for r, row in enumerate(layer): for c, code in enumerate(row): if (l, r, c) in self.layout: self.set_key(l, r, c, Keycode.deserialize(code)) # restore encoders for l, layer in enumerate(data["encoder_layout"]): for e, encoder in enumerate(layer): self.set_encoder(l, e, 0, Keycode.deserialize(encoder[0])) self.set_encoder(l, e, 1, Keycode.deserialize(encoder[1])) self.set_layout_options(data["layout_options"]) # we need to unlock the keyboard before we can restore the macros, lock it afterwards # only do that if it's different from current macros macro = base64.b64decode(data["macro"]) if macro != self.macro: Unlocker.unlock(self) self.set_macro(macro) self.lock()
def restore_macros(self, macros): if not isinstance(macros, list): return tag_to_action = { "down": ActionDown, "up": ActionUp, "tap": ActionTap, "text": ActionText, "delay": ActionDelay, } full_macro = [] for macro in macros: actions = [] for act in macro: if act[0] in tag_to_action: obj = tag_to_action[act[0]]() obj.restore(act) actions.append(obj) full_macro.append(actions) if len(full_macro) < self.macro_count: full_macro += [[] for x in range(self.macro_count - len(full_macro))] full_macro = full_macro[:self.macro_count] # TODO: log a warning if macro is cutoff data = self.macros_serialize(full_macro)[0:self.macro_memory] if data != self.macro: Unlocker.unlock(self) self.set_macro(data) self.lock()
def set_key(self, layer, row, col, code): if code < 0: return key = (layer, row, col) if self.layout[key] != code: if code == RESET_KEYCODE: Unlocker.unlock(self) self.usb_send(self.dev, struct.pack(">BBBBH", CMD_VIA_SET_KEYCODE, layer, row, col, code), retries=20) self.layout[key] = code
def start_poller(self): if not self.polling: Unlocker.unlock(self.keyboard) self.startButtonWidget.setText("Stop testing") self.timer.start(20) self.polling = True else: self.timer.stop() self.keyboard.lock() self.startButtonWidget.setText("Start testing") self.polling = False
def rebuild(self): # don't show "Security" menu for bootloader mode, as the bootloader is inherently insecure self.security_menu.menuAction().setVisible(isinstance(self.current_device, VialKeyboard)) # if unlock process was interrupted, we must finish it first if isinstance(self.current_device, VialKeyboard) and self.current_device.keyboard.get_unlock_in_progress(): Unlocker.unlock(self.current_device.keyboard) self.current_device.keyboard.reload() for e in [self.layout_editor, self.keymap_editor, self.firmware_flasher, self.macro_recorder]: e.rebuild(self.current_device)
def set_encoder(self, layer, index, direction, code): if code < 0: return key = (layer, index, direction) if self.encoder_layout[key] != code: if code == RESET_KEYCODE: Unlocker.unlock(self) self.usb_send(self.dev, struct.pack(">BBBBBH", CMD_VIA_VIAL_PREFIX, CMD_VIAL_SET_ENCODER, layer, index, direction, code), retries=20) self.encoder_layout[key] = code
def on_click_flash(self): if not self.selected_firmware_path: self.log("Error: Please select a firmware update package") return with open(self.selected_firmware_path, "rb") as inf: firmware = inf.read() if len(firmware) > 10 * 1024 * 1024: self.log("Error: Firmware is too large. Check you've selected the correct file") return self.log("Preparing to flash...") self.lock_ui() self.layout_restore = self.uid_restore = None if isinstance(self.device, VialKeyboard): # back up current layout if self.chk_restore_keymap.isChecked(): self.log("Backing up current layout...") self.layout_restore = self.device.keyboard.save_layout() # keep track of which keyboard we should restore saved layout to self.uid_restore = self.device.keyboard.get_uid() firmware_uid = firmware[8:16] if self.uid_restore != firmware_uid: self.log("Error: Firmware UID does not match keyboard UID. Check that you have the correct file") self.unlock_ui(False) return Unlocker.unlock(self.device.keyboard) self.log("Restarting in bootloader mode...") self.device.keyboard.reset() # watch for bootloaders to appear and ask them for their UID, return one that matches the keyboard found = None while found is None: self.log("Looking for devices...") QCoreApplication.processEvents() time.sleep(1) found = self.find_device_with_uid(VialBootloader, self.uid_restore) self.log("Found Vial Bootloader device at {}".format(found.desc["path"].decode("utf-8"))) found.open() self.device = found threading.Thread(target=lambda: cmd_flash( self.device, firmware, self.layout_restore is not None, self.on_log, self.on_progress, self.on_complete, self.on_error)).start()
def reboot_to_bootloader(self): if isinstance(self.current_device, VialKeyboard): Unlocker.unlock(self.current_device.keyboard) self.current_device.keyboard.reset()
def unlock_keyboard(self): if isinstance(self.current_device, VialKeyboard): Unlocker.unlock(self.current_device.keyboard)
def unlock(self): Unlocker.unlock(self.keyboard)
def on_save(self): Unlocker.unlock(self.device.keyboard) self.keyboard.set_macro(self.serialize()) self.on_change()