add keyboard rendering
parent
cbe3a2dd9e
commit
8f1123ee77
|
|
@ -0,0 +1,130 @@
|
|||
{
|
||||
"name": "g60",
|
||||
"vendorId": "0xFEED",
|
||||
"productId": "0x6464",
|
||||
"lighting": "none",
|
||||
"matrix": {
|
||||
"rows": 5,
|
||||
"cols": 15
|
||||
},
|
||||
"layouts": {
|
||||
"keymap": [
|
||||
[
|
||||
"0,0",
|
||||
"0,1",
|
||||
"0,2",
|
||||
"0,3",
|
||||
"0,4",
|
||||
"0,5",
|
||||
"0,6",
|
||||
"0,7",
|
||||
"0,8",
|
||||
"0,9",
|
||||
"0,10",
|
||||
"0,11",
|
||||
"0,12",
|
||||
"0,13",
|
||||
"0,14"
|
||||
],
|
||||
[
|
||||
{
|
||||
"w": 1.5
|
||||
},
|
||||
"1,0",
|
||||
"1,2",
|
||||
"1,3",
|
||||
"1,4",
|
||||
"1,5",
|
||||
"1,6",
|
||||
"1,7",
|
||||
"1,8",
|
||||
"1,9",
|
||||
"1,10",
|
||||
"1,11",
|
||||
"1,12",
|
||||
"1,13",
|
||||
{
|
||||
"w": 1.5
|
||||
},
|
||||
"1,14"
|
||||
],
|
||||
[
|
||||
{
|
||||
"w": 1.75
|
||||
},
|
||||
"2,0",
|
||||
"2,2",
|
||||
"2,3",
|
||||
"2,4",
|
||||
"2,5",
|
||||
"2,6",
|
||||
"2,7",
|
||||
"2,8",
|
||||
"2,9",
|
||||
"2,10",
|
||||
"2,11",
|
||||
"2,12",
|
||||
{
|
||||
"w": 2.25
|
||||
},
|
||||
"2,13"
|
||||
],
|
||||
[
|
||||
{
|
||||
"w": 1.25
|
||||
},
|
||||
"3,0",
|
||||
"3,1",
|
||||
"3,2",
|
||||
"3,3",
|
||||
"3,4",
|
||||
"3,5",
|
||||
"3,6",
|
||||
"3,7",
|
||||
"3,8",
|
||||
"3,9",
|
||||
"3,10",
|
||||
"3,11",
|
||||
{
|
||||
"w": 1.75
|
||||
},
|
||||
"3,13",
|
||||
"3,14"
|
||||
],
|
||||
[
|
||||
{
|
||||
"w": 1.25
|
||||
},
|
||||
"4,0",
|
||||
{
|
||||
"w": 1.25
|
||||
},
|
||||
"4,1",
|
||||
{
|
||||
"w": 1.25
|
||||
},
|
||||
"4,3",
|
||||
{
|
||||
"w": 6.25
|
||||
},
|
||||
"4,6",
|
||||
{
|
||||
"w": 1.25
|
||||
},
|
||||
"4,10",
|
||||
{
|
||||
"w": 1.25
|
||||
},
|
||||
"4,11",
|
||||
{
|
||||
"w": 1.25
|
||||
},
|
||||
"4,13",
|
||||
{
|
||||
"w": 1.25
|
||||
},
|
||||
"4,14"
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,301 @@
|
|||
{
|
||||
"name": "plain60",
|
||||
"vendorId": "0x4705",
|
||||
"productId": "0x0160",
|
||||
"lighting": "none",
|
||||
"matrix": {
|
||||
"rows": 5,
|
||||
"cols": 15
|
||||
},
|
||||
"layouts": {
|
||||
"labels": [
|
||||
[
|
||||
"Enter Key",
|
||||
"ANSI",
|
||||
"ISO"
|
||||
],
|
||||
"Split Left Shift",
|
||||
"Split Right Shift",
|
||||
"Split Backspace",
|
||||
[
|
||||
"Bottom row",
|
||||
"Default",
|
||||
"Tsangan",
|
||||
"WKL",
|
||||
"HHKB"
|
||||
]
|
||||
],
|
||||
"keymap": [
|
||||
[
|
||||
{
|
||||
"x": 2.75,
|
||||
"c": "#777777"
|
||||
},
|
||||
"0,0",
|
||||
{
|
||||
"c": "#cccccc"
|
||||
},
|
||||
"0,1",
|
||||
"0,2",
|
||||
"0,3",
|
||||
"0,4",
|
||||
"0,5",
|
||||
"0,6",
|
||||
"0,7",
|
||||
"0,8",
|
||||
"0,9",
|
||||
"0,10",
|
||||
"0,11",
|
||||
"0,12",
|
||||
{
|
||||
"c": "#aaaaaa",
|
||||
"w": 2
|
||||
},
|
||||
"0,14\n\n\n3,0",
|
||||
{
|
||||
"x": 0.5,
|
||||
"c": "#cccccc"
|
||||
},
|
||||
"0,13\n\n\n3,1",
|
||||
"0,14\n\n\n3,1"
|
||||
],
|
||||
[
|
||||
{
|
||||
"x": 2.75,
|
||||
"c": "#aaaaaa",
|
||||
"w": 1.5
|
||||
},
|
||||
"1,0",
|
||||
{
|
||||
"c": "#cccccc"
|
||||
},
|
||||
"1,1",
|
||||
"1,2",
|
||||
"1,3",
|
||||
"1,4",
|
||||
"1,5",
|
||||
"1,6",
|
||||
"1,7",
|
||||
"1,8",
|
||||
"1,9",
|
||||
"1,10",
|
||||
"1,11",
|
||||
"1,12",
|
||||
{
|
||||
"w": 1.5
|
||||
},
|
||||
"1,13\n\n\n0,0",
|
||||
{
|
||||
"x": 1.5,
|
||||
"c": "#777777",
|
||||
"w": 1.25,
|
||||
"h": 2,
|
||||
"w2": 1.5,
|
||||
"h2": 1,
|
||||
"x2": -0.25
|
||||
},
|
||||
"2,13\n\n\n0,1"
|
||||
],
|
||||
[
|
||||
{
|
||||
"x": 2.75,
|
||||
"c": "#aaaaaa",
|
||||
"w": 1.75
|
||||
},
|
||||
"2,0",
|
||||
{
|
||||
"c": "#cccccc"
|
||||
},
|
||||
"2,1",
|
||||
"2,2",
|
||||
"2,3",
|
||||
"2,4",
|
||||
"2,5",
|
||||
"2,6",
|
||||
"2,7",
|
||||
"2,8",
|
||||
"2,09",
|
||||
"2,10",
|
||||
"2,11",
|
||||
{
|
||||
"c": "#777777",
|
||||
"w": 2.25
|
||||
},
|
||||
"2,13\n\n\n0,0",
|
||||
{
|
||||
"x": 0.5,
|
||||
"c": "#cccccc"
|
||||
},
|
||||
"2,12\n\n\n0,1"
|
||||
],
|
||||
[
|
||||
{
|
||||
"c": "#aaaaaa",
|
||||
"w": 1.25
|
||||
},
|
||||
"3,0\n\n\n1,1",
|
||||
{
|
||||
"c": "#cccccc"
|
||||
},
|
||||
"3,1\n\n\n1,1",
|
||||
{
|
||||
"x": 0.5,
|
||||
"c": "#aaaaaa",
|
||||
"w": 2.25
|
||||
},
|
||||
"3,0\n\n\n1,0",
|
||||
{
|
||||
"c": "#cccccc"
|
||||
},
|
||||
"3,2",
|
||||
"3,3",
|
||||
"3,4",
|
||||
"3,5",
|
||||
"3,6",
|
||||
"3,7",
|
||||
"3,8",
|
||||
"3,9",
|
||||
"3,10",
|
||||
"3,11",
|
||||
{
|
||||
"c": "#aaaaaa",
|
||||
"w": 2.75
|
||||
},
|
||||
"3,12\n\n\n2,0",
|
||||
{
|
||||
"x": 0.5,
|
||||
"w": 1.75
|
||||
},
|
||||
"3,12\n\n\n2,1",
|
||||
"3,13\n\n\n2,1"
|
||||
],
|
||||
[
|
||||
{
|
||||
"x": 2.75,
|
||||
"w": 1.25
|
||||
},
|
||||
"4,0\n\n\n4,0",
|
||||
{
|
||||
"w": 1.25
|
||||
},
|
||||
"4,1\n\n\n4,0",
|
||||
{
|
||||
"w": 1.25
|
||||
},
|
||||
"4,2\n\n\n4,0",
|
||||
{
|
||||
"c": "#cccccc",
|
||||
"w": 6.25
|
||||
},
|
||||
"4,6\n\n\n4,0",
|
||||
{
|
||||
"c": "#aaaaaa",
|
||||
"w": 1.25
|
||||
},
|
||||
"4,10\n\n\n4,0",
|
||||
{
|
||||
"w": 1.25
|
||||
},
|
||||
"4,11\n\n\n4,0",
|
||||
{
|
||||
"w": 1.25
|
||||
},
|
||||
"4,12\n\n\n4,0",
|
||||
{
|
||||
"w": 1.25
|
||||
},
|
||||
"4,13\n\n\n4,0"
|
||||
],
|
||||
[
|
||||
{
|
||||
"y": 0.25,
|
||||
"x": 2.75,
|
||||
"w": 1.5
|
||||
},
|
||||
"4,0\n\n\n4,1",
|
||||
"4,1\n\n\n4,1",
|
||||
{
|
||||
"w": 1.5
|
||||
},
|
||||
"4,2\n\n\n4,1",
|
||||
{
|
||||
"c": "#cccccc",
|
||||
"w": 7
|
||||
},
|
||||
"4,6\n\n\n4,1",
|
||||
{
|
||||
"c": "#aaaaaa",
|
||||
"w": 1.5
|
||||
},
|
||||
"4,11\n\n\n4,1",
|
||||
"4,12\n\n\n4,1",
|
||||
{
|
||||
"w": 1.5
|
||||
},
|
||||
"4,13\n\n\n4,1"
|
||||
],
|
||||
[
|
||||
{
|
||||
"x": 2.75,
|
||||
"w": 1.5
|
||||
},
|
||||
"4,0\n\n\n4,2",
|
||||
{
|
||||
"d": true
|
||||
},
|
||||
"\n\n\n4,2",
|
||||
{
|
||||
"w": 1.5
|
||||
},
|
||||
"4,2\n\n\n4,2",
|
||||
{
|
||||
"c": "#cccccc",
|
||||
"w": 7
|
||||
},
|
||||
"4,6\n\n\n4,2",
|
||||
{
|
||||
"c": "#aaaaaa",
|
||||
"w": 1.5
|
||||
},
|
||||
"4,11\n\n\n4,2",
|
||||
{
|
||||
"d": true
|
||||
},
|
||||
"\n\n\n4,2",
|
||||
{
|
||||
"w": 1.5
|
||||
},
|
||||
"4,13\n\n\n4,2"
|
||||
],
|
||||
[
|
||||
{
|
||||
"x": 2.75,
|
||||
"w": 1.5,
|
||||
"d": true
|
||||
},
|
||||
"\n\n\n4,3",
|
||||
"4,1\n\n\n4,3",
|
||||
{
|
||||
"w": 1.5
|
||||
},
|
||||
"4,2\n\n\n4,3",
|
||||
{
|
||||
"c": "#cccccc",
|
||||
"w": 7
|
||||
},
|
||||
"4,6\n\n\n4,3",
|
||||
{
|
||||
"c": "#aaaaaa",
|
||||
"w": 1.5
|
||||
},
|
||||
"4,11\n\n\n4,3",
|
||||
"4,12\n\n\n4,3",
|
||||
{
|
||||
"w": 1.5,
|
||||
"d": true
|
||||
},
|
||||
"\n\n\n4,3"
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
import hid
|
||||
|
||||
VIAL_SERIAL_NUMBER_MAGIC = "vial:f64c2b3c"
|
||||
|
||||
def find_vial_keyboards():
|
||||
for dev in hid.enumerate():
|
||||
print(dev)
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
REPORT_LEN = 32
|
||||
|
||||
def hid_send(dev, msg):
|
||||
if len(report) > REPORT_LEN:
|
||||
raise RuntimeError("report must be less than 64 bytes")
|
||||
msg += b"\x00" * (REPORT_LEN - len(msg))
|
||||
|
||||
# add 00 at start for hidapi report id
|
||||
dev.write(b"\x00" + report)
|
||||
|
||||
return dev.read(REPORT_LEN)
|
||||
|
|
@ -0,0 +1,202 @@
|
|||
# Based on https://github.com/ijprest/kle-serial
|
||||
import json
|
||||
from copy import copy
|
||||
|
||||
|
||||
class KeyDefaults:
|
||||
|
||||
def __init__(self):
|
||||
self.textColor = "#000000"
|
||||
self.textSize = 3
|
||||
|
||||
|
||||
class Key:
|
||||
|
||||
def __init__(self):
|
||||
self.color = "#cccccc"
|
||||
self.labels = []
|
||||
self.textColor = [None] * 12
|
||||
self.textSize = []
|
||||
self.default = KeyDefaults()
|
||||
self.x = 0
|
||||
self.y = 0
|
||||
self.width = 1
|
||||
self.height = 1
|
||||
self.x2 = 0
|
||||
self.y2 = 0
|
||||
self.width2 = 1
|
||||
self.height2 = 1
|
||||
self.rotation_x = 0
|
||||
self.rotation_y = 0
|
||||
self.rotation_angle = 0
|
||||
self.decal = False
|
||||
self.ghost = False
|
||||
self.stepped = False
|
||||
self.nub = False
|
||||
self.profile = ""
|
||||
self.sm = ""
|
||||
self.sb = ""
|
||||
self.st = ""
|
||||
|
||||
|
||||
class KeyboardMetadata:
|
||||
|
||||
def __init__(self):
|
||||
self.author = ""
|
||||
self.backcolor = "#eeeeee"
|
||||
self.background = None
|
||||
self.name = ""
|
||||
self.notes = ""
|
||||
self.radii = ""
|
||||
self.switchBrand = ""
|
||||
self.switchMount = ""
|
||||
self.switchType = ""
|
||||
|
||||
|
||||
class Keyboard:
|
||||
|
||||
def __init__(self):
|
||||
self.meta = KeyboardMetadata()
|
||||
self.keys = []
|
||||
|
||||
|
||||
class Serial:
|
||||
|
||||
labelMap = [
|
||||
# 0 1 2 3 4 5 6 7 8 9 10 11 # align flags
|
||||
[ 0, 6, 2, 8, 9,11, 3, 5, 1, 4, 7,10], # 0 = no centering
|
||||
[ 1, 7,-1,-1, 9,11, 4,-1,-1,-1,-1,10], # 1 = center x
|
||||
[ 3,-1, 5,-1, 9,11,-1,-1, 4,-1,-1,10], # 2 = center y
|
||||
[ 4,-1,-1,-1, 9,11,-1,-1,-1,-1,-1,10], # 3 = center x & y
|
||||
[ 0, 6, 2, 8,10,-1, 3, 5, 1, 4, 7,-1], # 4 = center front (default)
|
||||
[ 1, 7,-1,-1,10,-1, 4,-1,-1,-1,-1,-1], # 5 = center front & x
|
||||
[ 3,-1, 5,-1,10,-1,-1,-1, 4,-1,-1,-1], # 6 = center front & y
|
||||
[ 4,-1,-1,-1,10,-1,-1,-1,-1,-1,-1,-1], # 7 = center front & x & y
|
||||
]
|
||||
|
||||
def reorderLabelsIn(self, labels, align):
|
||||
ret = [None] * 12
|
||||
for i in range(len(labels)):
|
||||
if labels[i]:
|
||||
ret[self.labelMap[align][i]] = labels[i]
|
||||
return ret
|
||||
|
||||
def deserializeError(self, msg, data):
|
||||
raise RuntimeError("Error: {} {}".format(msg, data))
|
||||
|
||||
def deserialize(self, rows):
|
||||
current = Key()
|
||||
kbd = Keyboard()
|
||||
align = 4
|
||||
|
||||
for r in range(len(rows)):
|
||||
if isinstance(rows[r], list):
|
||||
for k in range(len(rows[r])):
|
||||
item = rows[r][k]
|
||||
if isinstance(item, str):
|
||||
newKey = copy(current)
|
||||
|
||||
# Calculate some generated values
|
||||
newKey.width2 = current.width if newKey.width2 == 0 else current.width2
|
||||
newKey.height2 = current.height if newKey.height2 == 0 else current.height2
|
||||
newKey.labels = self.reorderLabelsIn(item.split("\n"), align)
|
||||
newKey.textSize = self.reorderLabelsIn(newKey.textSize, align)
|
||||
|
||||
# Clean up the data
|
||||
for i in range(12):
|
||||
if newKey.labels[i] is None:
|
||||
newKey.textSize[i] = newKey.textColor[i] = None
|
||||
if newKey.textSize[i] == newKey.default.textSize:
|
||||
newKey.textSize[i] = None
|
||||
if newKey.textColor[i] == newKey.default.textColor:
|
||||
newKey.textColor[i] = None
|
||||
|
||||
# Add the key!
|
||||
kbd.keys.append(newKey)
|
||||
|
||||
# Set up for the next key
|
||||
current.x += current.width
|
||||
current.width = current.height = 1
|
||||
current.x2 = current.y2 = current.width2 = current.height2 = 0
|
||||
current.nub = current.stepped = current.decal = False
|
||||
else:
|
||||
if k != 0 and ("r" in item or "rx" in item or "ry" in item):
|
||||
self.deserializeError("rotation can only be specified on the first key in a row", item)
|
||||
if "r" in item:
|
||||
current.rotation_angle = item["r"]
|
||||
if "rx" in item:
|
||||
current.rotation_x = item["rx"]
|
||||
if "ry" in item:
|
||||
current.rotation_y = item["ry"]
|
||||
if "a" in item:
|
||||
align = item["a"]
|
||||
if "f" in item:
|
||||
current.default.textSize = item["f"]
|
||||
current.textSize = []
|
||||
if "f2" in item:
|
||||
for i in range(1, 12):
|
||||
current.textSize[i] = item["f2"]
|
||||
if "fa" in item:
|
||||
current.textSize = item["fa"]
|
||||
if "p" in item:
|
||||
current.profile = item["p"]
|
||||
if "c" in item:
|
||||
current.color = item["c"]
|
||||
if "t" in item:
|
||||
split = item["t"].split("\n")
|
||||
if split[0] != "":
|
||||
current.default.textColor = split[0]
|
||||
current.textColor = self.reorderLabelsIn(split, align)
|
||||
if "x" in item:
|
||||
current.x += item["x"]
|
||||
if "y" in item:
|
||||
current.y += item["y"]
|
||||
if "w" in item:
|
||||
current.width = current.width2 = item["w"]
|
||||
if "h" in item:
|
||||
current.height = current.height2 = item["h"]
|
||||
if "x2" in item:
|
||||
current.x2 = item["x2"]
|
||||
if "y2" in item:
|
||||
current.y2 = item["y2"]
|
||||
if "w2" in item:
|
||||
current.width2 = item["w2"]
|
||||
if "h2" in item:
|
||||
current.height2 = item["h2"]
|
||||
if "n" in item:
|
||||
current.nub = item["n"]
|
||||
if "l" in item:
|
||||
current.stepped = item["l"]
|
||||
if "d" in item:
|
||||
current.decal = item["d"]
|
||||
if "g" in item and item["g"]:
|
||||
current.ghost = item.g
|
||||
if "sm" in item:
|
||||
current.sm = item["sm"]
|
||||
if "sb" in item:
|
||||
current.sb = item["sb"]
|
||||
if "st" in item:
|
||||
current.st = item["st"]
|
||||
|
||||
# End of the row
|
||||
current.y += 1
|
||||
current.x = current.rotation_x
|
||||
elif isinstance(item, dict):
|
||||
if r != 0:
|
||||
self.deserializeError("keyboard metadata must the be first element", rows[r])
|
||||
# TODO: parse prop
|
||||
else:
|
||||
self.deserializeError("unexpected", rows[r])
|
||||
return kbd
|
||||
|
||||
|
||||
# TODO: add tests
|
||||
|
||||
|
||||
# serial = Serial()
|
||||
# data = open("plain60.json", "r").read()
|
||||
# data = json.loads(data)
|
||||
# kb = serial.deserialize(data["layouts"]["keymap"])
|
||||
|
||||
# for key in kb.keys:
|
||||
# print("{} {}x{}+{}x{}".format(key.labels, key.x, key.y, key.width, key.height))
|
||||
|
|
@ -3,8 +3,11 @@ from PyQt5.QtCore import Qt
|
|||
from PyQt5.QtWidgets import QWidget, QTabWidget, QVBoxLayout, QPushButton, QLabel
|
||||
|
||||
import sys
|
||||
import json
|
||||
|
||||
from flowlayout import FlowLayout
|
||||
from util import tr
|
||||
from kle_serial import Serial as KleSerial
|
||||
|
||||
class TabbedKeycodes(QTabWidget):
|
||||
|
||||
|
|
@ -13,7 +16,7 @@ class TabbedKeycodes(QTabWidget):
|
|||
self.tab_basic = QWidget()
|
||||
layout = FlowLayout()
|
||||
|
||||
for lbl in ["", "TODO", "Esc", "A", "B", "C", "D", "E", "F"]:
|
||||
for lbl in ["", "hello", "Esc", "A", "B", "C", "D", "E", "F"]:
|
||||
btn = QPushButton(lbl)
|
||||
btn.setFixedSize(50, 50)
|
||||
layout.addWidget(btn)
|
||||
|
|
@ -22,14 +25,14 @@ class TabbedKeycodes(QTabWidget):
|
|||
self.tab_media = QWidget()
|
||||
self.tab_macro = QWidget()
|
||||
|
||||
self.addTab(self.tab_basic, "Basic")
|
||||
self.addTab(self.tab_media, "Media")
|
||||
self.addTab(self.tab_macro, "Macro")
|
||||
self.addTab(self.tab_basic, tr("TabbedKeycodes", "Basic"))
|
||||
self.addTab(self.tab_media, tr("TabbedKeycodes", "Media"))
|
||||
self.addTab(self.tab_macro, tr("TabbedKeycodes", "Macro"))
|
||||
|
||||
|
||||
KEY_WIDTH = 40
|
||||
KEY_HEIGHT = KEY_WIDTH
|
||||
KEY_SPACING = 10
|
||||
KEY_SPACING = 4
|
||||
|
||||
|
||||
class KeyboardContainer(QWidget):
|
||||
|
|
@ -37,23 +40,32 @@ class KeyboardContainer(QWidget):
|
|||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
|
||||
self.setFixedSize(300, 300)
|
||||
serial = KleSerial()
|
||||
data = open("g60.json", "r").read()
|
||||
data = json.loads(data)
|
||||
kb = serial.deserialize(data["layouts"]["keymap"])
|
||||
|
||||
for x, btn in enumerate(["Q", "W", "E", "R"]):
|
||||
widget = QLabel(btn)
|
||||
max_w = max_h = 0
|
||||
|
||||
for key in kb.keys:
|
||||
widget = QLabel(str(key.labels[0]))
|
||||
widget.setParent(self)
|
||||
widget.setStyleSheet('background-color:red;')
|
||||
widget.setStyleSheet('background-color:white; border: 1px solid black')
|
||||
widget.setAlignment(Qt.AlignCenter)
|
||||
widget.setFixedSize(KEY_WIDTH, KEY_HEIGHT)
|
||||
widget.move((KEY_WIDTH + KEY_SPACING) * x, 0)
|
||||
|
||||
x = (KEY_WIDTH + KEY_SPACING) * key.x
|
||||
y = (KEY_HEIGHT + KEY_SPACING) * key.y
|
||||
w = (KEY_WIDTH + KEY_SPACING) * key.width - KEY_SPACING
|
||||
h = (KEY_HEIGHT + KEY_SPACING) * key.height - KEY_SPACING
|
||||
|
||||
widget.setFixedSize(w, h)
|
||||
widget.move(x, y)
|
||||
print("{} {}x{}+{}x{}".format(key.labels, key.x, key.y, key.width, key.height))
|
||||
|
||||
max_w = max(max_w, x + w)
|
||||
max_h = max(max_h, y + h)
|
||||
|
||||
for x, btn in enumerate(["A", "S", "D", "F"]):
|
||||
widget = QLabel(btn)
|
||||
widget.setParent(self)
|
||||
widget.setStyleSheet('background-color:red;')
|
||||
widget.setAlignment(Qt.AlignCenter)
|
||||
widget.setFixedSize(KEY_WIDTH, KEY_HEIGHT)
|
||||
widget.move((KEY_WIDTH + KEY_SPACING) * (x + 0.25), KEY_HEIGHT + KEY_SPACING)
|
||||
self.setFixedSize(max_w, max_h)
|
||||
|
||||
|
||||
class MainWindow(QWidget):
|
||||
|
|
@ -67,6 +79,7 @@ class MainWindow(QWidget):
|
|||
|
||||
layout = QVBoxLayout()
|
||||
layout.addWidget(self.keyboard_container)
|
||||
layout.setAlignment(self.keyboard_container, Qt.AlignHCenter)
|
||||
layout.addWidget(self.tabbed_keycodes)
|
||||
self.setLayout(layout)
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
from PyQt5.QtCore import QCoreApplication
|
||||
|
||||
tr = QCoreApplication.translate
|
||||
Loading…
Reference in New Issue