A small keyboard based on Python/Tkinter for inserting special characters. Dependencies: xclip, xdotool for clipboard handling and auto-insertion.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

342 lines
7.6 KiB

from tkinter import Tk, Canvas, font
from PIL import Image, ImageTk
import json
import subprocess
import pyperclip
# Загрузка данных
with open("rectangles.json", "r") as f:
rectangles = json.load(f)
# Загрузка изображения
pil_image = Image.open("background_image.png")
# Создаём интерфейс Tkinter
root = Tk()
root.title("SFG Special Symbols Keyboard")
# Запретить изменение размера окна
root.resizable(False, False)
# Создаём Canvas и устанавливаем фон
canvas = Canvas(root, width=pil_image.width, height=pil_image.height)
canvas.pack()
tk_image = ImageTk.PhotoImage(pil_image)
canvas.create_image(0, 0, anchor="nw", image=tk_image)
key_map = {
0: "Esc",
1: "F1",
2: "F2",
3: "F3",
4: "F4",
5: "F5",
6: "F6",
7: "F7",
8: "F8",
9: "F9",
10: "F10",
11: "F11",
12: "F12",
13: "PrtSc",
14: "ScrL",
15: "Pause",
16: "`",
17: "1",
18: "2",
19: "3",
20: "4",
21: "5",
22: "6",
23: "7",
24: "8",
25: "9",
26: "0",
27: "-",
28: "=",
29: "Backspace",
30: "Ins",
31: "Home",
32: "PgUp",
33: "NumL",
34: "/.",
35: "*.",
36: "-.",
37: "Tab",
38: "q",
39: "w",
40: "e",
41: "r",
42: "t",
43: "y",
44: "u",
45: "i",
46: "o",
47: "p",
48: "[",
49: "]",
50: "\\",
51: "Del",
52: "End",
53: "PgDn",
54: "7.",
55: "8.",
56: "9.",
57: "+.",
58: "Caps",
59: "a",
60: "s",
61: "d",
62: "f",
63: "g",
64: "h",
65: "j",
66: "k",
67: "l",
68: ";",
69: "'",
70: "Enter",
71: "4.",
72: "5.",
73: "6.",
74: "ShiftL",
75: "z",
76: "x",
77: "c",
78: "v",
79: "b",
80: "n",
81: "m",
82: ",",
83: ".",
84: "/",
85: "ShiftR",
86: "",
87: "1.",
88: "2.",
89: "3.",
90: "Ret.",
91: "CtrlL",
92: "Win",
93: "Alt",
94: "Space",
95: "AltGr",
96: "Fn",
97: "Menu",
98: "CtrlR",
99: "",
100: "",
101: "",
102: "Ins.",
103: "Del.",
}
keycode_map = {
9: "Esc",
67: "F1",
68: "F2",
69: "F3",
70: "F4",
71: "F5",
72: "F6",
73: "F7",
74: "F8",
75: "F9",
76: "F10",
95: "F11",
96: "F12",
107: "PrtSc",
78: "ScrL",
127: "Pause",
49: "`",
10: "1",
11: "2",
12: "3",
13: "4",
14: "5",
15: "6",
16: "7",
17: "8",
18: "9",
19: "0",
20: "-",
21: "=",
22: "Backspace",
118: "Ins",
110: "Home",
112: "PgUp",
77: "NumL",
106: "/.",
63: "*.",
82: "-.",
23: "Tab",
24: "q",
25: "w",
26: "e",
27: "r",
28: "t",
29: "y",
30: "u",
31: "i",
32: "o",
33: "p",
34: "[",
35: "]",
51: "\\",
119: "Del",
115: "End",
117: "PgDn",
79: "7.",
80: "8.",
81: "9.",
86: "+.",
66: "Caps",
38: "a",
39: "s",
40: "d",
41: "f",
42: "g",
43: "h",
44: "j",
45: "k",
46: "l",
47: ";",
48: "'",
36: "Enter",
83: "4.",
84: "5.",
85: "6.",
50: "ShiftL",
52: "z",
53: "x",
54: "c",
55: "v",
56: "b",
57: "n",
58: "m",
59: ",",
60: ".",
61: "/",
62: "ShiftR",
111: "",
87: "1.",
88: "2.",
89: "3.",
104: "Ret.",
37: "CtrlL",
133: "Win",
64: "Alt",
65: "Space",
108: "AltGr",
105: "CtrlR",
113: "",
116: "",
114: "",
118: "Ins",
119: "Del",
90: "Ins.",
91: "Del.",
135: "Menu",
}
# Словарь специальных символов для физики и математики
special_symbols = {
"q": "", # Бесконечность
"w": "", # Сумма
"e": "", # Интеграл
"r": "", # Корень
"t": "", # Частная производная
"y": "", # Приблизительно равно
"u": "", # Больше или равно
"i": "", # Меньше или равно
"o": "", # Прямое суммирование
"p": "±", # Плюс-минус
"[": "", # Стрелка вправо
"]": "", # Стрелка влево
"a": "", # Тензорное произведение
"s": "", # Пропорционально
"d": "", # Не равно
"f": "", # Существует
"g": "", # Для всех
"h": "", # Принадлежит
"j": "", # Не принадлежит
"k": "", # Подмножество
"l": "", # Надмножество
";": "", # Пересечение
"'": "", # Объединение
"z": "", # Логическое И
"x": "×",
"c": "¬", # Логическое НЕ
"v": "", # Следовательно
"b": "", # Угол
"n": "°", # Градусы
"m": "", # Параллельность
",": "", # Конгруэнтность
".": "", # Частная производная (дублируем для удобства)
"/": "÷", # Деление
}
# Словарь для отслеживания подсветки
highlighted_rects = {}
# Создаём текстовые подписи для клавиш
padding = 8
sym_font = font.Font(family="Arial", size=12, weight="bold", slant="roman")
spec_font = font.Font(family="Arial", size=18, weight="bold", slant="roman")
for i, (x, y, w, h) in enumerate(rectangles):
key_label = key_map.get(i, f"Key {i}")
special_symbol = special_symbols.get(key_label, "")
rect_id = canvas.create_rectangle(x, y, x + w, y + h, outline="black", width=0)
spec_id = canvas.create_text(
x + padding + (w - 2 * padding) // 2,
y + padding + (h - 2 * padding) // 2,
text=special_symbol,
font=spec_font,
fill="white",
)
text_id = canvas.create_text(
x + padding, # Смещение на 5 пикселей от левого края
y + padding, # Смещение на 5 пикселей от верхнего края
text=key_label,
font=sym_font,
fill="#777777",
anchor="nw", # Выравнивание текста по верхнему левому углу
)
highlighted_rects[key_label] = rect_id
# Обработчик нажатия клавиши
def on_key_press(event):
if event.keysym == "Escape":
root.destroy() # Немедленно закрываем программу при нажатии Escape
return
key = keycode_map.get(event.keycode)
if key in highlighted_rects:
# Подсветка клавиши
canvas.itemconfig(highlighted_rects[key], outline="red", width=4)
# Обработчик отпускания клавиши
def on_key_release(event):
print(event.keycode)
key = keycode_map.get(event.keycode)
special_symbol = special_symbols.get(key)
if key in highlighted_rects:
# Убираем подсветку клавиши
canvas.itemconfig(highlighted_rects[key], outline="white", width=2)
if special_symbol:
pyperclip.copy(special_symbol) # Копируем в буфер
root.after(100, root.destroy) # Закрываемся через 100 мс
subprocess.Popen(["bash", "-c", "sleep 0.12 ; xdotool key Ctrl+v"])
root.bind("<KeyPress>", on_key_press)
root.bind("<KeyRelease>", on_key_release)
root.mainloop()