class KeymapEditor(BasicEditor): def __init__(self, layout_editor): super().__init__() self.layout_editor = layout_editor self.layout_layers = QHBoxLayout() self.layout_size = QVBoxLayout() layer_label = QLabel(tr("KeymapEditor", "Layer")) layout_labels_container = QHBoxLayout() layout_labels_container.addWidget(layer_label) layout_labels_container.addLayout(self.layout_layers) layout_labels_container.addStretch() layout_labels_container.addLayout(self.layout_size) # contains the actual keyboard self.container = KeyboardWidget(layout_editor) self.container.clicked.connect(self.on_key_clicked) layout = QVBoxLayout() layout.addLayout(layout_labels_container) layout.addWidget(self.container) layout.setAlignment(self.container, Qt.AlignHCenter) self.layer_buttons = [] self.keyboard = None self.current_layer = 0 layout_editor.changed.connect(self.on_layout_changed) self.container.anykey.connect(self.on_any_keycode) self.tabbed_keycodes = TabbedKeycodes() self.tabbed_keycodes.keycode_changed.connect(self.on_keycode_changed) self.tabbed_keycodes.anykey.connect(self.on_any_keycode) self.addLayout(layout) self.addWidget(self.tabbed_keycodes) self.device = None KeycodeDisplay.notify_keymap_override(self) def on_container_clicked(self): """ Called when a mouse click event is bubbled up to the editor's container """ self.container.deselect() self.container.update() def on_keycode_changed(self, code): self.set_key(code) def rebuild_layers(self): # delete old layer labels for label in self.layer_buttons: label.hide() label.deleteLater() self.layer_buttons = [] # create new layer labels for x in range(self.keyboard.layers): btn = SquareButton(str(x)) btn.setFocusPolicy(Qt.NoFocus) btn.setRelSize(1.667) btn.setCheckable(True) btn.clicked.connect(lambda state, idx=x: self.switch_layer(idx)) self.layout_layers.addWidget(btn) self.layer_buttons.append(btn) for x in range(0, 2): btn = SquareButton("-") if x else SquareButton("+") btn.setFocusPolicy(Qt.NoFocus) btn.setCheckable(False) btn.clicked.connect(lambda state, idx=x: self.adjust_size(idx)) self.layout_size.addWidget(btn) self.layer_buttons.append(btn) def adjust_size(self, minus): if minus: self.container.set_scale(self.container.get_scale() - 0.1) else: self.container.set_scale(self.container.get_scale() + 0.1) self.refresh_layer_display() def rebuild(self, device): super().rebuild(device) if self.valid(): self.keyboard = device.keyboard # get number of layers self.rebuild_layers() self.container.set_keys(self.keyboard.keys, self.keyboard.encoders) self.current_layer = 0 self.on_layout_changed() recreate_keyboard_keycodes(self.keyboard) self.tabbed_keycodes.recreate_keycode_buttons() TabbedKeycodes.tray.recreate_keycode_buttons() self.refresh_layer_display() self.container.setEnabled(self.valid()) def valid(self): return isinstance(self.device, VialKeyboard) def save_layout(self): return self.keyboard.save_layout() def restore_layout(self, data): if json.loads( data.decode("utf-8")).get("uid") != self.keyboard.keyboard_id: ret = QMessageBox.question( self.widget(), "", tr( "KeymapEditor", "Saved keymap belongs to a different keyboard," " are you sure you want to continue?"), QMessageBox.Yes | QMessageBox.No) if ret != QMessageBox.Yes: return self.keyboard.restore_layout(data) self.refresh_layer_display() def on_any_keycode(self): if self.container.active_key is None: return current_code = self.code_for_widget(self.container.active_key) if self.container.active_mask: current_code &= 0xFF dlg = AnyKeycodeDialog(current_code) if dlg.exec_() and dlg.value >= 0: self.on_keycode_changed(dlg.value) def code_for_widget(self, widget): if widget.desc.row is not None: return self.keyboard.layout[(self.current_layer, widget.desc.row, widget.desc.col)] else: return self.keyboard.encoder_layout[(self.current_layer, widget.desc.encoder_idx, widget.desc.encoder_dir)] def refresh_layer_display(self): """ Refresh text on key widgets to display data corresponding to current layer """ self.container.update_layout() for idx, btn in enumerate(self.layer_buttons): btn.setEnabled(idx != self.current_layer) btn.setChecked(idx == self.current_layer) for widget in self.container.widgets: code = self.code_for_widget(widget) KeycodeDisplay.display_keycode(widget, code) self.container.update() self.container.updateGeometry() def switch_layer(self, idx): self.container.deselect() self.current_layer = idx self.refresh_layer_display() def set_key(self, keycode): """ Change currently selected key to provided keycode """ if self.container.active_key is None: return if isinstance(self.container.active_key, EncoderWidget): self.set_key_encoder(keycode) else: self.set_key_matrix(keycode) self.container.select_next() def set_key_encoder(self, keycode): l, i, d = self.current_layer, self.container.active_key.desc.encoder_idx,\ self.container.active_key.desc.encoder_dir # if masked, ensure that this is a byte-sized keycode if self.container.active_mask: if keycode > 0xFF: return keycode = (self.keyboard.encoder_layout[(l, i, d)] & 0xFF00) | keycode self.keyboard.set_encoder(l, i, d, keycode) self.refresh_layer_display() def set_key_matrix(self, keycode): l, r, c = self.current_layer, self.container.active_key.desc.row, self.container.active_key.desc.col if r >= 0 and c >= 0: # if masked, ensure that this is a byte-sized keycode if self.container.active_mask: if keycode > 0xFF: return keycode = (self.keyboard.layout[(l, r, c)] & 0xFF00) | keycode self.keyboard.set_key(l, r, c, keycode) self.refresh_layer_display() def on_key_clicked(self): """ Called when a key on the keyboard widget is clicked """ self.refresh_layer_display() def on_layout_changed(self): if self.keyboard is None: return self.refresh_layer_display() self.keyboard.set_layout_options(self.layout_editor.pack()) def on_keymap_override(self): self.refresh_layer_display()
class MatrixTest(BasicEditor): def __init__(self, layout_editor): super().__init__() self.layout_editor = layout_editor self.keyboardWidget = KeyboardWidget(layout_editor) self.keyboardWidget.set_enabled(False) self.unlock_btn = QPushButton("Unlock") self.reset_btn = QPushButton("Reset") layout = QVBoxLayout() layout.addWidget(self.keyboardWidget) layout.setAlignment(self.keyboardWidget, Qt.AlignCenter) self.addLayout(layout) btn_layout = QHBoxLayout() btn_layout.addStretch() self.unlock_lbl = QLabel(tr("MatrixTest", "Unlock the keyboard before testing:")) btn_layout.addWidget(self.unlock_lbl) btn_layout.addWidget(self.unlock_btn) btn_layout.addWidget(self.reset_btn) self.addLayout(btn_layout) self.keyboard = None self.device = None self.polling = False self.timer = QTimer() self.timer.timeout.connect(self.matrix_poller) self.unlock_btn.clicked.connect(self.unlock) self.reset_btn.clicked.connect(self.reset_keyboard_widget) self.grabber = QWidget() def rebuild(self, device): super().rebuild(device) if self.valid(): self.keyboard = device.keyboard self.keyboardWidget.set_keys(self.keyboard.keys, self.keyboard.encoders) self.keyboardWidget.setEnabled(self.valid()) def valid(self): # Check if vial protocol is v3 or later return isinstance(self.device, VialKeyboard) and \ (self.device.keyboard and self.device.keyboard.vial_protocol >= 3) def reset_keyboard_widget(self): # reset keyboard widget for w in self.keyboardWidget.widgets: w.setPressed(False) w.setActive(False) self.keyboardWidget.update_layout() self.keyboardWidget.update() self.keyboardWidget.updateGeometry() def matrix_poller(self): if not self.valid(): self.timer.stop() return try: unlocked = self.keyboard.get_unlock_status(3) except (RuntimeError, ValueError): self.timer.stop() return if not unlocked: self.unlock_btn.show() self.unlock_lbl.show() return # we're unlocked, so hide unlock button and label self.unlock_btn.hide() self.unlock_lbl.hide() # Get size for matrix rows = self.keyboard.rows cols = self.keyboard.cols # Generate 2d array of matrix matrix = [[None] * cols for x in range(rows)] # Get matrix data from keyboard try: data = self.keyboard.matrix_poll() except (RuntimeError, ValueError): self.timer.stop() return # Calculate the amount of bytes belong to 1 row, each bit is 1 key, so per 8 keys in a row, # a byte is needed for the row. row_size = math.ceil(cols / 8) for row in range(rows): # Make slice of bytes for the row (skip first 2 bytes, they're for VIAL) row_data_start = 2 + (row * row_size) row_data_end = row_data_start + row_size row_data = data[row_data_start:row_data_end] # Get each bit representing pressed state for col for col in range(cols): # row_data is array of bytes, calculate in which byte the col is located col_byte = len(row_data) - 1 - math.floor(col / 8) # since we select a single byte as slice of byte, mod 8 to get nth pos of byte col_mod = (col % 8) # write to matrix array matrix[row][col] = (row_data[col_byte] >> col_mod) & 1 # write matrix state to keyboard widget for w in self.keyboardWidget.widgets: if w.desc.row is not None and w.desc.col is not None: row = w.desc.row col = w.desc.col if row < len(matrix) and col < len(matrix[row]): w.setPressed(matrix[row][col]) if matrix[row][col]: w.setActive(True) self.keyboardWidget.update_layout() self.keyboardWidget.update() self.keyboardWidget.updateGeometry() def unlock(self): Unlocker.unlock(self.keyboard) def activate(self): self.grabber.grabKeyboard() self.timer.start(20) def deactivate(self): self.grabber.releaseKeyboard() self.timer.stop()
class MatrixTest(BasicEditor): def __init__(self, layout_editor): super().__init__() self.layout_editor = layout_editor self.keyboardWidget = KeyboardWidget(layout_editor) self.keyboardWidget.set_enabled(False) self.startButtonWidget = QPushButton("Start testing") self.resetButtonWidget = QPushButton("Reset") layout = QVBoxLayout() layout.addWidget(self.keyboardWidget) layout.setAlignment(self.keyboardWidget, Qt.AlignCenter) self.addLayout(layout) self.addWidget(self.resetButtonWidget) self.addWidget(self.startButtonWidget) self.keyboard = None self.device = None self.polling = False self.timer = QTimer() self.timer.timeout.connect(self.matrix_poller) self.startButtonWidget.clicked.connect(self.start_poller) self.resetButtonWidget.clicked.connect(self.reset_keyboard_widget) def rebuild(self, device): super().rebuild(device) if self.valid(): self.keyboard = device.keyboard self.keyboardWidget.set_keys(self.keyboard.keys, self.keyboard.encoders) def valid(self): # Check if vial protocol is v3 or later return isinstance(self.device, VialKeyboard) and (self.device.keyboard and self.device.keyboard.vial_protocol >= 3) def reset_keyboard_widget(self): # reset keyboard widget for w in self.keyboardWidget.widgets: w.setPressed(False) w.setActive(False) self.keyboardWidget.update_layout() self.keyboardWidget.update() self.keyboardWidget.updateGeometry() def matrix_poller(self): # Get size for matrix rows = self.keyboard.rows cols = self.keyboard.cols # Generate 2d array of matrix matrix = [ [None for y in range(cols)] for x in range(rows) ] # Get matrix data from keyboard data = self.keyboard.matrix_poll() # Calculate the amount of bytes belong to 1 row, each bit is 1 key, so per 8 keys in a row, a byte is needed for the row. row_size = math.ceil(cols / 8) for row in range(rows): # Make slice of bytes for the row (skip first 2 bytes, they're for VIAL) row_data_start = 2 + (row * row_size) row_data_end = row_data_start + row_size row_data = data[row_data_start:row_data_end] #Get each bit representing pressed state for col for col in range(cols): # row_data is array of bytes, calculate in which byte the col is located col_byte = len(row_data) - 1 - math.floor(col / 8) # since we select a single byte as slice of byte, mod 8 to get nth pos of byte col_mod = (col % 8) # write to matrix array matrix[row][col] = (row_data[col_byte] >> col_mod) & 1 # write matrix state to keyboard widget for w in self.keyboardWidget.widgets: if w.desc.row is not None and w.desc.col is not None: row = w.desc.row col = w.desc.col if row < len(matrix) and col < len(matrix[row]): w.setPressed(matrix[row][col]) if matrix[row][col]: w.setActive(True) self.keyboardWidget.update_layout() self.keyboardWidget.update() self.keyboardWidget.updateGeometry() 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
class LayoutEditor(BasicEditor): changed = pyqtSignal() def __init__(self, parent=None): super().__init__(parent) self.device = self.keyboard = None self.choices = [] self.widgets = [] self.addStretch() self.keyboard_preview = KeyboardWidget(self) self.keyboard_preview.set_enabled(False) self.keyboard_preview.set_scale(0.7) self.addWidget(self.keyboard_preview) self.setAlignment(self.keyboard_preview, QtCore.Qt.AlignHCenter) w = QWidget() w.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum) self.container = QGridLayout() w.setLayout(self.container) self.addWidget(w) self.setAlignment(w, QtCore.Qt.AlignHCenter) self.addStretch() def update_preview(self): self.keyboard_preview.set_keys(self.keyboard.keys, self.keyboard.encoders) self.keyboard_preview.update_layout() self.keyboard_preview.update() self.keyboard_preview.updateGeometry() def rebuild(self, device): super().rebuild(device) if not self.valid(): return self.keyboard = device.keyboard self.blockSignals(True) for choice in self.choices: choice.delete() self.choices = [] for item in device.keyboard.layout_labels: if isinstance(item, str): choice = BooleanChoice(self.on_changed, self.container, item) else: choice = SelectChoice(self.on_changed, self.container, item[0], item[1:]) self.choices.append(choice) self.unpack(self.device.keyboard.layout_options) self.blockSignals(False) self.update_preview() def valid(self): return isinstance(self.device, VialKeyboard) and self.device.keyboard.layout_labels def pack(self): if not self.choices: return 0 val = "" for choice in self.choices: val += choice.pack() return int(val, 2) def unpack(self, value): # we operate on bit strings value = "0" * 100 + bin(value)[2:] # VIA stores option choices backwards, we need to parse the input in reverse for choice in self.choices[::-1]: sz = len(choice.pack()) choice.unpack(value[-sz:]) value = value[:-sz] def get_choice(self, index): return int(self.choices[index].pack(), 2) def on_changed(self): self.changed.emit() self.update_preview()
class KeyboardContainer(QWidget): def __init__(self, layout_editor): super().__init__() self.layout_editor = layout_editor self.layout_layers = QHBoxLayout() layer_label = QLabel(tr("KeyboardContainer", "Layer")) layout_labels_container = QHBoxLayout() layout_labels_container.addWidget(layer_label) layout_labels_container.addLayout(self.layout_layers) layout_labels_container.addStretch() # contains the actual keyboard self.container = KeyboardWidget(layout_editor) self.container.clicked.connect(self.on_key_clicked) layout = QVBoxLayout() layout.addLayout(layout_labels_container) layout.addWidget(self.container) layout.setAlignment(self.container, Qt.AlignHCenter) self.setLayout(layout) self.layer_buttons = [] self.keyboard = None self.current_layer = 0 layout_editor.changed.connect(self.on_layout_changed) self.keymap_override = KEYMAPS[0][1] def rebuild_layers(self): # delete old layer labels for label in self.layer_buttons: label.hide() label.deleteLater() self.layer_buttons = [] # create new layer labels for x in range(self.keyboard.layers): btn = SquareButton(str(x)) btn.setRelSize(1.667) btn.setCheckable(True) btn.clicked.connect(lambda state, idx=x: self.switch_layer(idx)) self.layout_layers.addWidget(btn) self.layer_buttons.append(btn) def rebuild(self, keyboard): self.keyboard = keyboard # get number of layers self.rebuild_layers() self.container.set_keys(keyboard.keys, keyboard.encoders) self.current_layer = 0 self.on_layout_changed() def code_is_overriden(self, code): """ Check whether a country-specific keymap overrides a code """ key = find_keycode(code) return key is not None and key.qmk_id in self.keymap_override def get_label(self, code): """ Get label for a specific keycode """ if self.code_is_overriden(code): return self.keymap_override[find_keycode(code).qmk_id] return keycode_label(code) def refresh_layer_display(self): """ Refresh text on key widgets to display data corresponding to current layer """ self.container.update_layout() for btn in self.layer_buttons: btn.setEnabled(True) btn.setChecked(False) self.layer_buttons[self.current_layer].setEnabled(False) self.layer_buttons[self.current_layer].setChecked(True) for widget in self.container.widgets: if widget.desc.row is not None: code = self.keyboard.layout[(self.current_layer, widget.desc.row, widget.desc.col)] else: code = self.keyboard.encoder_layout[(self.current_layer, widget.desc.encoder_idx, widget.desc.encoder_dir)] text = self.get_label(code) tooltip = keycode_tooltip(code) mask = keycode_is_mask(code) mask_text = self.get_label(code & 0xFF) if mask: text = text.split("\n")[0] widget.masked = mask widget.setText(text) widget.setMaskText(mask_text) widget.setToolTip(tooltip) if self.code_is_overriden(code): widget.setColor(QApplication.palette().color(QPalette.Link)) else: widget.setColor(None) self.container.update() self.container.updateGeometry() def switch_layer(self, idx): self.container.deselect() self.current_layer = idx self.refresh_layer_display() def set_key(self, keycode): """ Change currently selected key to provided keycode """ if isinstance(self.container.active_key, EncoderWidget): self.set_key_encoder(keycode) else: self.set_key_matrix(keycode) self.container.select_next() def set_key_encoder(self, keycode): l, i, d = self.current_layer, self.container.active_key.desc.encoder_idx,\ self.container.active_key.desc.encoder_dir # if masked, ensure that this is a byte-sized keycode if self.container.active_mask: if keycode > 0xFF: return keycode = (self.keyboard.encoder_layout[(l, i, d)] & 0xFF00) | keycode self.keyboard.set_encoder(l, i, d, keycode) self.refresh_layer_display() def set_key_matrix(self, keycode): l, r, c = self.current_layer, self.container.active_key.desc.row, self.container.active_key.desc.col if r >= 0 and c >= 0: # if masked, ensure that this is a byte-sized keycode if self.container.active_mask: if keycode > 0xFF: return keycode = (self.keyboard.layout[(l, r, c)] & 0xFF00) | keycode self.keyboard.set_key(l, r, c, keycode) self.refresh_layer_display() def on_key_clicked(self): """ Called when a key on the keyboard widget is clicked """ self.refresh_layer_display() def save_layout(self): return self.keyboard.save_layout() def restore_layout(self, data): self.keyboard.restore_layout(data) self.refresh_layer_display() def on_layout_changed(self): if self.keyboard is None: return self.refresh_layer_display() self.keyboard.set_layout_options(self.layout_editor.pack()) def set_keymap_override(self, override): self.keymap_override = override self.refresh_layer_display()
class Unlocker(QDialog): def __init__(self, layout_editor, keyboard): super().__init__() self.keyboard = keyboard layout = QVBoxLayout() self.progress = QProgressBar() layout.addWidget( QLabel( tr( "Unlocker", "In order to proceed, the keyboard must be set into unlocked mode.\n" "You should only perform this operation on computers that you trust." ))) layout.addWidget( QLabel( tr( "Unlocker", "To exit this mode, you will need to replug the keyboard\n" "or select Security->Lock from the menu."))) layout.addWidget( QLabel( tr( "Unlocker", "Press and hold the following keys until the progress bar " "below fills up:"))) self.keyboard_reference = KeyboardWidget(layout_editor) self.keyboard_reference.set_enabled(False) self.keyboard_reference.set_scale(0.5) layout.addWidget(self.keyboard_reference) layout.setAlignment(self.keyboard_reference, Qt.AlignHCenter) layout.addWidget(self.progress) self.setLayout(layout) self.setWindowFlags(Qt.Dialog | Qt.WindowTitleHint | Qt.CustomizeWindowHint) self.update_reference() self.timer = QTimer() self.timer.timeout.connect(self.unlock_poller) self.perform_unlock() def update_reference(self): """ Updates keycap reference image """ self.keyboard_reference.set_keys(self.keyboard.keys, self.keyboard.encoders) # use "active" background to indicate keys to hold lock_keys = self.keyboard.get_unlock_keys() for w in self.keyboard_reference.widgets: if (w.desc.row, w.desc.col) in lock_keys: w.setActive(True) self.keyboard_reference.update_layout() self.keyboard_reference.update() self.keyboard_reference.updateGeometry() def unlock_poller(self): data = self.keyboard.unlock_poll() unlocked = data[0] unlock_counter = data[2] self.progress.setMaximum(max(self.progress.maximum(), unlock_counter)) self.progress.setValue(self.progress.maximum() - unlock_counter) if unlocked == 1: self.accept() def perform_unlock(self): self.progress.setMaximum(1) self.progress.setValue(0) self.keyboard.unlock_start() self.timer.start(200) @classmethod def unlock(cls, keyboard): if keyboard.get_unlock_status() == 1: return True dlg = cls(cls.global_layout_editor, keyboard) return bool(dlg.exec_()) def keyPressEvent(self, ev): """ Ignore all key presses, e.g. Esc should not close the window """ pass
class KeymapEditor(BasicEditor): def __init__(self, layout_editor): super().__init__() self.layout_editor = layout_editor self.layout_layers = QHBoxLayout() layer_label = QLabel(tr("KeymapEditor", "Layer")) layout_labels_container = QHBoxLayout() layout_labels_container.addWidget(layer_label) layout_labels_container.addLayout(self.layout_layers) layout_labels_container.addStretch() # contains the actual keyboard self.container = KeyboardWidget(layout_editor) self.container.clicked.connect(self.on_key_clicked) layout = QVBoxLayout() layout.addLayout(layout_labels_container) layout.addWidget(self.container) layout.setAlignment(self.container, Qt.AlignHCenter) self.layer_buttons = [] self.keyboard = None self.current_layer = 0 layout_editor.changed.connect(self.on_layout_changed) self.keymap_override = KEYMAPS[0][1] self.container.anykey.connect(self.on_any_keycode) self.tabbed_keycodes = TabbedKeycodes() self.tabbed_keycodes.keycode_changed.connect(self.on_keycode_changed) self.tabbed_keycodes.anykey.connect(self.on_any_keycode) self.addLayout(layout) self.addWidget(self.tabbed_keycodes) self.device = None def on_keycode_changed(self, code): self.set_key(code) def rebuild_layers(self): # delete old layer labels for label in self.layer_buttons: label.hide() label.deleteLater() self.layer_buttons = [] # create new layer labels for x in range(self.keyboard.layers): btn = SquareButton(str(x)) btn.setRelSize(1.667) btn.setCheckable(True) btn.clicked.connect(lambda state, idx=x: self.switch_layer(idx)) self.layout_layers.addWidget(btn) self.layer_buttons.append(btn) def rebuild(self, device): super().rebuild(device) if self.valid(): self.keyboard = device.keyboard # get number of layers self.rebuild_layers() self.container.set_keys(self.keyboard.keys, self.keyboard.encoders) self.current_layer = 0 self.on_layout_changed() recreate_keyboard_keycodes(self.keyboard) self.tabbed_keycodes.recreate_keycode_buttons() self.refresh_layer_display() def valid(self): return isinstance(self.device, VialKeyboard) def save_layout(self): return self.keyboard.save_layout() def restore_layout(self, data): if json.loads( data.decode("utf-8")).get("uid") != self.keyboard.keyboard_id: ret = QMessageBox.question( self.widget(), "", tr( "KeymapEditor", "Saved keymap belongs to a different keyboard," " are you sure you want to continue?"), QMessageBox.Yes | QMessageBox.No) if ret != QMessageBox.Yes: return self.keyboard.restore_layout(data) self.refresh_layer_display() def set_keymap_override(self, override): self.keymap_override = override self.refresh_layer_display() self.tabbed_keycodes.set_keymap_override(override) def on_any_keycode(self): if self.container.active_key is None: return current_code = self.code_for_widget(self.container.active_key) dlg = AnyKeycodeDialog(current_code) if dlg.exec_() and dlg.value >= 0: self.on_keycode_changed(dlg.value) def code_is_overriden(self, code): """ Check whether a country-specific keymap overrides a code """ key = Keycode.find_outer_keycode(code) return key is not None and key.qmk_id in self.keymap_override def get_label(self, code): """ Get label for a specific keycode """ if self.code_is_overriden(code): return self.keymap_override[Keycode.find_outer_keycode( code).qmk_id] return Keycode.label(code) def code_for_widget(self, widget): if widget.desc.row is not None: return self.keyboard.layout[(self.current_layer, widget.desc.row, widget.desc.col)] else: return self.keyboard.encoder_layout[(self.current_layer, widget.desc.encoder_idx, widget.desc.encoder_dir)] def refresh_layer_display(self): """ Refresh text on key widgets to display data corresponding to current layer """ self.container.update_layout() for idx, btn in enumerate(self.layer_buttons): btn.setEnabled(idx != self.current_layer) btn.setChecked(idx == self.current_layer) for widget in self.container.widgets: code = self.code_for_widget(widget) text = self.get_label(code) tooltip = Keycode.tooltip(code) mask = Keycode.is_mask(code) mask_text = self.get_label(code & 0xFF) if mask: text = text.split("\n")[0] widget.masked = mask widget.setText(text) widget.setMaskText(mask_text) widget.setToolTip(tooltip) if self.code_is_overriden(code): widget.setColor(QApplication.palette().color(QPalette.Link)) else: widget.setColor(None) self.container.update() self.container.updateGeometry() def switch_layer(self, idx): self.container.deselect() self.current_layer = idx self.refresh_layer_display() def set_key(self, keycode): """ Change currently selected key to provided keycode """ if isinstance(self.container.active_key, EncoderWidget): self.set_key_encoder(keycode) else: self.set_key_matrix(keycode) self.container.select_next() def set_key_encoder(self, keycode): l, i, d = self.current_layer, self.container.active_key.desc.encoder_idx,\ self.container.active_key.desc.encoder_dir # if masked, ensure that this is a byte-sized keycode if self.container.active_mask: if keycode > 0xFF: return keycode = (self.keyboard.encoder_layout[(l, i, d)] & 0xFF00) | keycode self.keyboard.set_encoder(l, i, d, keycode) self.refresh_layer_display() def set_key_matrix(self, keycode): l, r, c = self.current_layer, self.container.active_key.desc.row, self.container.active_key.desc.col if r >= 0 and c >= 0: # if masked, ensure that this is a byte-sized keycode if self.container.active_mask: if keycode > 0xFF: return keycode = (self.keyboard.layout[(l, r, c)] & 0xFF00) | keycode self.keyboard.set_key(l, r, c, keycode) self.refresh_layer_display() def on_key_clicked(self): """ Called when a key on the keyboard widget is clicked """ self.refresh_layer_display() def on_layout_changed(self): if self.keyboard is None: return self.refresh_layer_display() self.keyboard.set_layout_options(self.layout_editor.pack())