PredatorSense replacement for the Acer Predator Helios 16 (PH16-71) on Linux: - predatord: root service for profiles, fans (incl. temperature curves), keyboard RGB, lightbar and battery health; restores settings at boot and after resume, switches profiles on AC/battery changes - Qt desktop app with dashboard, fan curve editor and per-key RGB studio - Plasma 6 panel widget with quick controls - predatorctl command line tool - predator_wmi kernel module (DKMS) as a minimal WMI method bridge Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
116 lines
4.6 KiB
Python
116 lines
4.6 KiB
Python
"""Physical keyboard layouts of the PH16-71 mapped to the 128 LED cells of the keyboard MCU.
|
||
|
||
cell = column * 6 + row (row 0 = bottom row). The mapping is based on the keymap
|
||
recorded by the Venator project (GPL-2.0). Corrections can be placed in
|
||
~/.config/predator-control/layout.json as {"<label>": <cell>}.
|
||
|
||
Each key: (label, cell, x, y, width, height) in key units.
|
||
"""
|
||
|
||
import json
|
||
import locale
|
||
import os
|
||
|
||
|
||
def _row(y, keys, x0=0.0, h=1.0):
|
||
out, x = [], x0
|
||
for label, cell, w in keys:
|
||
if label is not None:
|
||
out.append((label, cell, x, y, w, h))
|
||
x += w
|
||
return out
|
||
|
||
|
||
def _build(variant):
|
||
iso = variant == "iso-de"
|
||
keys = []
|
||
fw = 15.0 / 16
|
||
keys += _row(0, [("Esc", 5, fw)] + [("F%d" % i, 5 + 6 * i, fw) for i in range(1, 13)] +
|
||
[("PrtSc", 83, fw), ("Ins", 89, fw), ("Del", 95, fw)], h=0.8)
|
||
y = 0.9
|
||
nums = [str((i + 1) % 10) for i in range(10)]
|
||
keys += _row(y, [("^" if iso else "`", 4, 1)] + [(n, 10 + 6 * i, 1) for i, n in enumerate(nums)] +
|
||
[("ß" if iso else "-", 70, 1), ("´" if iso else "=", 76, 1), ("⌫", 82, 2)])
|
||
y += 1
|
||
top = "QWERTZUIOP" if iso else "QWERTYUIOP"
|
||
if iso:
|
||
keys += _row(y, [("Tab", 3, 1.5)] + [(c, 15 + 6 * i, 1) for i, c in enumerate(top)] +
|
||
[("Ü", 75, 1), ("+", 81, 1), ("↵", 86, 1.5)])
|
||
else:
|
||
keys += _row(y, [("Tab", 3, 1.5)] + [(c, 15 + 6 * i, 1) for i, c in enumerate(top)] +
|
||
[("[", 75, 1), ("]", 81, 1), ("\\", 87, 1.5)])
|
||
y += 1
|
||
if iso:
|
||
keys += _row(y, [("Caps", 2, 1.75)] + [(c, 20 + 6 * i, 1) for i, c in enumerate("ASDFGHJKL")] +
|
||
[("Ö", 74, 1), ("Ä", 80, 1), ("#", 87, 1), ("↵", 86, 1.25)])
|
||
else:
|
||
keys += _row(y, [("Caps", 2, 1.75)] + [(c, 20 + 6 * i, 1) for i, c in enumerate("ASDFGHJKL")] +
|
||
[(";", 74, 1), ("'", 80, 1), ("Enter", 86, 2.25)])
|
||
y += 1
|
||
if iso:
|
||
keys += _row(y, [("⇧", 1, 1.25), ("<", 13, 1)] + [(c, 19 + 6 * i, 1) for i, c in enumerate("YXCVBNM")] +
|
||
[(",", 61, 1), (".", 67, 1), ("-", 73, 1), ("⇧", 85, 2.75)])
|
||
else:
|
||
keys += _row(y, [("⇧", 1, 2.25)] + [(c, 19 + 6 * i, 1) for i, c in enumerate("ZXCVBNM")] +
|
||
[(",", 61, 1), (".", 67, 1), ("/", 73, 1), ("⇧", 85, 2.75)])
|
||
y += 1
|
||
keys += _row(y, [("Ctrl", 0, 1.25), ("Fn", 6, 1), ("⊞", 12, 1), ("Alt", 18, 1),
|
||
("", 24, 5), ("AltGr" if iso else "Alt", 60, 1), ("☰", 72, 1), ("Ctrl", 78, 1),
|
||
("←", 84, 1)])
|
||
keys.append(("↑", 90, 13.25, y, 1, 0.5))
|
||
keys.append(("↓", 96, 13.25, y + 0.5, 1, 0.5))
|
||
keys.append(("→", 102, 14.25, y, 1, 1))
|
||
|
||
# column of special keys between the main block and the numpad
|
||
sx = 15.6
|
||
for i, (lbl, cell) in enumerate([("⏻", 107), ("P", 106), ("⏯", 105), ("⏮", 104), ("⏭", 103)]):
|
||
keys.append((lbl, cell, sx, 0 if i == 0 else 0.9 + (i - 1), 1, 0.8 if i == 0 else 1))
|
||
|
||
# numpad
|
||
nx = 16.85
|
||
y = 0.9
|
||
keys += _row(y, [("Num", 112, 1), ("/", 118, 1), ("*", 124, 1), ("−", 123, 1)], x0=nx)
|
||
keys += _row(y + 1, [("7", 99, 1), ("8", 111, 1), ("9", 117, 1)], x0=nx)
|
||
keys.append(("+", 122, nx + 3, y + 1, 1, 2))
|
||
keys += _row(y + 2, [("4", 101, 1), ("5", 110, 1), ("6", 116, 1)], x0=nx)
|
||
keys += _row(y + 3, [("1", 100, 1), ("2", 109, 1), ("3", 115, 1)], x0=nx)
|
||
keys.append(("↵", 120, nx + 3, y + 3, 1, 2))
|
||
keys += _row(y + 4, [("0", 108, 2), ("," if iso else ".", 114, 1)], x0=nx)
|
||
return keys
|
||
|
||
|
||
VARIANTS = {"iso-de": "German (ISO)", "ansi-us": "US (ANSI)"}
|
||
|
||
|
||
def default_variant():
|
||
lang = (os.environ.get("LANG") or locale.getlocale()[0] or "").lower()
|
||
return "iso-de" if lang.startswith(("de", "at", "ch")) else "ansi-us"
|
||
|
||
|
||
def keys(variant=None):
|
||
ks = _build(variant or default_variant())
|
||
path = os.path.expanduser("~/.config/predator-control/layout.json")
|
||
try:
|
||
with open(path) as f:
|
||
over = json.load(f)
|
||
ks = [(l, over.get(l, c), x, y, w, h) for (l, c, x, y, w, h) in ks]
|
||
except (OSError, ValueError):
|
||
pass
|
||
return ks
|
||
|
||
|
||
def size(ks):
|
||
return max(k[2] + k[4] for k in ks), max(k[3] + k[5] for k in ks)
|
||
|
||
|
||
# cell groups for quick selection in the RGB studio
|
||
GROUPS = {
|
||
"WASD": [21, 20, 26, 32],
|
||
"Arrows": [84, 90, 96, 102],
|
||
"F-row": [5 + 6 * i for i in range(13)] + [83, 89, 95],
|
||
"Number row": [4] + [10 + 6 * i for i in range(10)] + [70, 76, 82],
|
||
"Numpad": [112, 118, 124, 123, 99, 111, 117, 122, 101, 110, 116, 100, 109, 115, 120, 108, 114],
|
||
"Special keys": [107, 106, 105, 104, 103],
|
||
"Modifiers": [0, 6, 12, 18, 60, 72, 78, 1, 85, 2, 3],
|
||
}
|