encoders: initial support
parent
ffd2d3746f
commit
3fe4dad968
|
|
@ -17,6 +17,8 @@ CMD_VIA_VIAL_PREFIX = 0xFE
|
|||
CMD_VIAL_GET_KEYBOARD_ID = 0x00
|
||||
CMD_VIAL_GET_SIZE = 0x01
|
||||
CMD_VIAL_GET_DEFINITION = 0x02
|
||||
CMD_VIAL_GET_ENCODER = 0x03
|
||||
CMD_VIAL_SET_ENCODER = 0x04
|
||||
|
||||
|
||||
class Keyboard:
|
||||
|
|
@ -28,9 +30,12 @@ class Keyboard:
|
|||
|
||||
# n.b. using OrderedDict here to make order of layout requests consistent for tests
|
||||
self.rowcol = OrderedDict()
|
||||
self.encoderpos = OrderedDict()
|
||||
self.layout = dict()
|
||||
self.encoder_layout = dict()
|
||||
self.rows = self.cols = self.layers = 0
|
||||
self.keys = []
|
||||
self.encoders = []
|
||||
|
||||
self.vial_protocol = self.keyboard_id = -1
|
||||
|
||||
|
|
@ -38,7 +43,9 @@ class Keyboard:
|
|||
""" Load information about the keyboard: number of layers, physical key layout """
|
||||
|
||||
self.rowcol = OrderedDict()
|
||||
self.encoderpos = OrderedDict()
|
||||
self.layout = dict()
|
||||
self.encoder_layout = dict()
|
||||
|
||||
self.reload_layout(sideload_json)
|
||||
self.reload_layers()
|
||||
|
|
@ -82,16 +89,26 @@ class Keyboard:
|
|||
serial = KleSerial()
|
||||
kb = serial.deserialize(payload["layouts"]["keymap"])
|
||||
|
||||
self.keys = kb.keys
|
||||
self.keys = []
|
||||
self.encoders = []
|
||||
|
||||
for key in self.keys:
|
||||
for key in kb.keys:
|
||||
key.row = key.col = None
|
||||
if key.labels[0] and "," in key.labels[0]:
|
||||
key.encoder_idx = key.encoder_dir = None
|
||||
if key.labels[4] == "e":
|
||||
idx, direction = key.labels[0].split(",")
|
||||
idx, direction = int(idx), int(direction)
|
||||
key.encoder_idx = idx
|
||||
key.encoder_dir = direction
|
||||
self.encoderpos[idx] = True
|
||||
self.encoders.append(key)
|
||||
elif key.labels[0] and "," in key.labels[0]:
|
||||
row, col = key.labels[0].split(",")
|
||||
row, col = int(row), int(col)
|
||||
key.row = row
|
||||
key.col = col
|
||||
self.rowcol[(row, col)] = True
|
||||
self.keys.append(key)
|
||||
|
||||
def reload_keymap(self):
|
||||
""" Load current key mapping from the keyboard """
|
||||
|
|
@ -101,6 +118,10 @@ class Keyboard:
|
|||
data = self.usb_send(self.dev, struct.pack("BBBB", CMD_VIA_GET_KEYCODE, layer, row, col))
|
||||
keycode = struct.unpack(">H", data[4:6])[0]
|
||||
self.layout[(layer, row, col)] = keycode
|
||||
for idx in self.encoderpos:
|
||||
data = self.usb_send(self.dev, struct.pack("BBBB", CMD_VIA_VIAL_PREFIX, CMD_VIAL_GET_ENCODER, layer, idx))
|
||||
self.encoder_layout[(layer, idx, 0)] = struct.unpack(">H", data[0:2])[0]
|
||||
self.encoder_layout[(layer, idx, 1)] = struct.unpack(">H", data[2:4])[0]
|
||||
|
||||
def set_key(self, layer, row, col, code):
|
||||
key = (layer, row, col)
|
||||
|
|
@ -108,6 +129,13 @@ class Keyboard:
|
|||
self.usb_send(self.dev, struct.pack(">BBBBH", CMD_VIA_SET_KEYCODE, layer, row, col, code))
|
||||
self.layout[key] = code
|
||||
|
||||
def set_encoder(self, layer, index, direction, code):
|
||||
key = (layer, index, direction)
|
||||
if self.encoder_layout[key] != code:
|
||||
self.usb_send(self.dev, struct.pack(">BBBBBH", CMD_VIA_VIAL_PREFIX, CMD_VIAL_SET_ENCODER,
|
||||
layer, index, direction, code))
|
||||
self.encoder_layout[key] = code
|
||||
|
||||
def save_layout(self):
|
||||
""" Serializes current layout to a binary """
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ from PyQt5.QtCore import pyqtSignal, Qt
|
|||
from PyQt5.QtWidgets import QWidget, QHBoxLayout, QLabel, QVBoxLayout
|
||||
|
||||
from clickable_label import ClickableLabel
|
||||
from keyboard_widget import KeyboardWidget
|
||||
from keyboard_widget import KeyboardWidget, EncoderWidget
|
||||
from keycodes import keycode_label, keycode_tooltip, keycode_is_mask
|
||||
from constants import LAYER_BTN_STYLE, ACTIVE_LAYER_BTN_STYLE
|
||||
from util import tr
|
||||
|
|
@ -39,9 +39,8 @@ class KeyboardContainer(QWidget):
|
|||
|
||||
self.keys = []
|
||||
self.layer_labels = []
|
||||
self.rowcol = defaultdict(list)
|
||||
self.selected_row = -1
|
||||
self.selected_col = -1
|
||||
self.widgets = []
|
||||
self.selected_widget = None
|
||||
self.selected_mask = False
|
||||
self.keyboard = None
|
||||
self.current_layer = 0
|
||||
|
|
@ -74,12 +73,12 @@ class KeyboardContainer(QWidget):
|
|||
self.rebuild_layers()
|
||||
|
||||
# prepare for fetching keymap
|
||||
self.rowcol = defaultdict(list)
|
||||
self.widgets = []
|
||||
|
||||
self.container.set_keys(keyboard.keys)
|
||||
self.container.set_keys(keyboard.keys, keyboard.encoders)
|
||||
for key in self.container.keys:
|
||||
if key.desc.row is not None:
|
||||
self.rowcol[(key.desc.row, key.desc.col)].append(key)
|
||||
if key.desc.row is not None or key.desc.encoder_idx is not None:
|
||||
self.widgets.append(key)
|
||||
|
||||
self.current_layer = 0
|
||||
self.refresh_layer_display()
|
||||
|
|
@ -91,33 +90,54 @@ class KeyboardContainer(QWidget):
|
|||
label.setStyleSheet(LAYER_BTN_STYLE)
|
||||
self.layer_labels[self.current_layer].setStyleSheet(ACTIVE_LAYER_BTN_STYLE)
|
||||
|
||||
for (row, col), widgets in self.rowcol.items():
|
||||
code = self.keyboard.layout[(self.current_layer, row, col)]
|
||||
for widget in self.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 = keycode_label(code)
|
||||
tooltip = keycode_tooltip(code)
|
||||
mask = keycode_is_mask(code)
|
||||
mask_text = keycode_label(code & 0xFF)
|
||||
if mask:
|
||||
text = text.split("\n")[0]
|
||||
for widget in widgets:
|
||||
widget.masked = mask
|
||||
widget.setText(text)
|
||||
widget.setMaskText(mask_text)
|
||||
widget.setToolTip(tooltip)
|
||||
widget.masked = mask
|
||||
widget.setText(text)
|
||||
widget.setMaskText(mask_text)
|
||||
widget.setToolTip(tooltip)
|
||||
self.container.update()
|
||||
self.container.updateGeometry()
|
||||
|
||||
def switch_layer(self, idx):
|
||||
self.container.deselect()
|
||||
self.current_layer = idx
|
||||
self.selected_row = -1
|
||||
self.selected_col = -1
|
||||
self.selected_widget = None
|
||||
self.refresh_layer_display()
|
||||
|
||||
def set_key(self, keycode):
|
||||
""" Change currently selected key to provided keycode """
|
||||
|
||||
l, r, c = self.current_layer, self.selected_row, self.selected_col
|
||||
if isinstance(self.selected_widget, EncoderWidget):
|
||||
self.set_key_encoder(keycode)
|
||||
else:
|
||||
self.set_key_matrix(keycode)
|
||||
|
||||
def set_key_encoder(self, keycode):
|
||||
l, i, d = self.current_layer, self.selected_widget.desc.encoder_idx,\
|
||||
self.selected_widget.desc.encoder_dir
|
||||
|
||||
# if masked, ensure that this is a byte-sized keycode
|
||||
if self.selected_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.selected_widget.desc.row, self.selected_widget.desc.col
|
||||
|
||||
if r >= 0 and c >= 0:
|
||||
# if masked, ensure that this is a byte-sized keycode
|
||||
|
|
@ -133,12 +153,8 @@ class KeyboardContainer(QWidget):
|
|||
""" Change which key is currently selected """
|
||||
|
||||
self.selected_mask = is_mask
|
||||
self.selected_widget = widget
|
||||
|
||||
for (row, col), widgets in self.rowcol.items():
|
||||
if widget in widgets:
|
||||
self.selected_row = row
|
||||
self.selected_col = col
|
||||
break
|
||||
self.refresh_layer_display()
|
||||
|
||||
def save_layout(self):
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ class KeyWidget:
|
|||
self.bbox = self.calculate_bbox(QRectF(self.x, self.y, self.w, self.h))
|
||||
self.polygon = QPolygonF(self.bbox + [self.bbox[0]])
|
||||
self.draw_path = self.calculate_draw_path()
|
||||
self.draw_path2 = self.calculate_draw_path2()
|
||||
|
||||
# calculate areas where the inner keycode will be located
|
||||
# nonmask = outer (e.g. Rsft_T)
|
||||
|
|
@ -73,6 +74,9 @@ class KeyWidget:
|
|||
|
||||
return path
|
||||
|
||||
def calculate_draw_path2(self):
|
||||
return QPainterPath()
|
||||
|
||||
def setText(self, text):
|
||||
self.text = text
|
||||
|
||||
|
|
@ -83,6 +87,28 @@ class KeyWidget:
|
|||
self.tooltip = tooltip
|
||||
|
||||
|
||||
class EncoderWidget(KeyWidget):
|
||||
|
||||
def calculate_draw_path(self):
|
||||
path = QPainterPath()
|
||||
path.addEllipse(int(self.x), int(self.y), int(self.w), int(self.h))
|
||||
return path
|
||||
|
||||
def calculate_draw_path2(self):
|
||||
path = QPainterPath()
|
||||
if self.desc.encoder_dir == 0:
|
||||
path.moveTo(int(self.x), int(self.y + self.h / 2))
|
||||
path.lineTo(int(self.x - self.w / 5), int(self.y + self.h / 3))
|
||||
path.moveTo(int(self.x), int(self.y + self.h / 2))
|
||||
path.lineTo(int(self.x + self.w / 5), int(self.y + self.h / 3))
|
||||
else:
|
||||
path.moveTo(int(self.x), int(self.y + self.h / 2))
|
||||
path.lineTo(int(self.x - self.w / 5), int(self.y + self.h - self.h / 3))
|
||||
path.moveTo(int(self.x), int(self.y + self.h / 2))
|
||||
path.lineTo(int(self.x + self.w / 5), int(self.y + self.h - self.h / 3))
|
||||
return path
|
||||
|
||||
|
||||
class KeyboardWidget(QWidget):
|
||||
|
||||
clicked = pyqtSignal(KeyWidget, bool)
|
||||
|
|
@ -96,10 +122,12 @@ class KeyboardWidget(QWidget):
|
|||
self.active_key = None
|
||||
self.active_mask = False
|
||||
|
||||
def set_keys(self, keys):
|
||||
def set_keys(self, keys, encoders):
|
||||
self.keys = []
|
||||
for key in keys:
|
||||
self.keys.append(KeyWidget(key))
|
||||
for key in encoders:
|
||||
self.keys.append(EncoderWidget(key))
|
||||
self.calculate_size()
|
||||
self.update()
|
||||
|
||||
|
|
@ -155,6 +183,7 @@ class KeyboardWidget(QWidget):
|
|||
|
||||
# draw the keycap
|
||||
qp.drawPath(key.draw_path)
|
||||
qp.strokePath(key.draw_path2, regular_pen)
|
||||
|
||||
# if this is a mask key, draw the inner key
|
||||
if key.masked:
|
||||
|
|
|
|||
Loading…
Reference in New Issue