built-in keyboard

This commit is contained in:
alfrix 2022-07-18 20:19:39 -03:00 committed by Alfredo Monclus
parent 0d8746d3e3
commit 9c2b52009a
11 changed files with 197 additions and 34 deletions

View File

@ -0,0 +1,110 @@
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, GLib
class Keyboard(Gtk.Box):
def __init__(self, screen, close_cb, entry=None):
super().__init__(orientation=Gtk.Orientation.VERTICAL)
_ = screen.lang.gettext
self._gtk = screen.gtk
self.close_cb = close_cb
self.keyboard = Gtk.Grid()
self.keyboard.set_direction(Gtk.TextDirection.LTR)
self.timeout = self.clear_timeout = None
self.entry = entry
self.keys = [
[["q", "w", "e", "r", "t", "y", "u", "i", "o", "p", ""],
["a", "s", "d", "f", "g", "h", "j", "k", "l", "'"],
["ABC", "z", "x", "c", "v", "b", "n", "m", ",", ".", "?123"],
["", " ", ""]
],
[["Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", ""],
["A", "S", "D", "F", "G", "H", "J", "K", "L", "'"],
["?123", "Z", "X", "C", "V", "B", "N", "M", ",", ".", "abc"],
["", " ", ""]
],
[["1", "2", "3", "4", "5", "6", "7", "8", "9", "0", ""],
["=", "-", "+", "*", "/", "\\", ":", ";", "'", "\""],
["abc", "(", ")", "#", "$", "!", "?", "@", "_", ",", "ABC"],
["", " ", ""]
]
]
self.labels = self.keys.copy()
for p, pallet in enumerate(self.keys):
for r, row in enumerate(pallet):
for k, key in enumerate(row):
self.labels[p][r][k] = self._gtk.Button(key)
self.labels[p][r][k].set_hexpand(True)
self.labels[p][r][k].set_vexpand(True)
self.labels[p][r][k].connect('button-press-event', self.repeat, key)
self.labels[p][r][k].connect('button-release-event', self.release)
self.labels[p][r][k].get_style_context().add_class("keyboard_pad")
self.pallet_nr = 0
self.set_pallet(self.pallet_nr)
self.add(self.keyboard)
def set_pallet(self, p):
pallet = self.keys[p]
span = 2
for r, row in enumerate(pallet[:-1]):
for k, key in enumerate(row):
x = k * 2 + 1 if r == 1 else k * 2
old = self.keyboard.get_child_at(x, r)
if old:
self.keyboard.remove(old)
self.keyboard.attach(self.labels[p][r][k], x, r, span, 1)
if not self.keyboard.get_child_at(0, 4):
self.keyboard.attach(self.labels[p][3][0], 0, 4, 3, 1)
self.keyboard.attach(self.labels[p][3][1], 3, 4, 16, 1)
self.keyboard.attach(self.labels[p][3][2], 19, 4, 3, 1)
self.show_all()
def repeat(self, widget, event, key):
# Button-press
self.update_entry(widget, key)
if self.timeout is None and key == "":
# Hold for repeat, hold longer to clear the field
self.clear_timeout = GLib.timeout_add_seconds(3, self.clear, widget)
# This can be used to repeat all the keys,
# but I don't find it useful on the console
self.timeout = GLib.timeout_add(400, self.repeat, widget, None, key)
return True
def release(self, widget, event):
# Button-release
if self.timeout is not None:
GLib.source_remove(self.timeout)
self.timeout = None
if self.clear_timeout is not None:
GLib.source_remove(self.clear_timeout)
self.clear_timeout = None
def clear(self, widget=None):
self.entry.set_text("")
if self.clear_timeout is not None:
GLib.source_remove(self.clear_timeout)
self.clear_timeout = None
def update_entry(self, widget, key):
if key == "":
Gtk.Entry.do_backspace(self.entry)
elif key == "":
self.close_cb()
return
elif key == "":
self.clear()
self.close_cb()
return
elif key == "abc":
self.set_pallet(0)
elif key == "ABC":
self.set_pallet(1)
elif key == "?123":
self.set_pallet(2)
else:
Gtk.Entry.do_insert_at_cursor(self.entry, key)

View File

@ -227,7 +227,7 @@ class BedMeshPanel(ScreenPanel):
self.labels['profile_name'].set_text('')
self.labels['profile_name'].set_hexpand(True)
self.labels['profile_name'].connect("activate", self.create_profile)
self.labels['profile_name'].connect("focus-in-event", self._screen.show_keyboard)
self.labels['profile_name'].connect("focus-in-event", self._show_keyboard)
self.labels['profile_name'].grab_focus_without_selecting()
save = self._gtk.ButtonImage("complete", _("Save"), "color3")
@ -246,9 +246,12 @@ class BedMeshPanel(ScreenPanel):
self.labels['create_profile'].pack_start(box, True, True, 5)
self.content.add(self.labels['create_profile'])
self._screen.show_keyboard()
self._show_keyboard()
self.show_create = True
def _show_keyboard(self, widget=None, event=None):
self._screen.show_keyboard(entry=self.labels['profile_name'])
def show_mesh(self, widget, profile):
bm = self._printer.get_config_section(f"bed_mesh {profile}")

View File

@ -80,7 +80,7 @@ class ConsolePanel(ScreenPanel):
entry = Gtk.Entry()
entry.set_hexpand(True)
entry.set_vexpand(False)
entry.connect("button-press-event", self._screen.show_keyboard)
entry.connect("button-press-event", self._show_keyboard)
entry.connect("focus-in-event", self._screen.show_keyboard)
entry.connect("activate", self._send_command)
entry.grab_focus_without_selecting()
@ -105,6 +105,9 @@ class ConsolePanel(ScreenPanel):
content_box.pack_end(ebox, False, False, 0)
self.content.add(content_box)
def _show_keyboard(self, widget=None, event=None):
self._screen.show_keyboard(entry=self.labels['entry'])
def clear(self, widget):
self.labels['tb'].set_text("")

View File

@ -351,7 +351,7 @@ class NetworkPanel(ScreenPanel):
self.labels['network_psk'].set_text('')
self.labels['network_psk'].set_hexpand(True)
self.labels['network_psk'].connect("activate", self.add_new_network, ssid, True)
self.labels['network_psk'].connect("focus-in-event", self._screen.show_keyboard)
self.labels['network_psk'].connect("focus-in-event", self._show_keyboard)
self.labels['network_psk'].grab_focus_without_selecting()
save = self._gtk.ButtonImage("sd", _("Save"), "color3")
@ -374,6 +374,9 @@ class NetworkPanel(ScreenPanel):
self.content.show_all()
self.show_add = True
def _show_keyboard(self, widget=None, event=None):
self._screen.show_keyboard(entry=self.labels['network_psk'])
def update_all_networks(self):
for network in list(self.networks):
self.update_network_info(network)

View File

@ -23,7 +23,7 @@ from ks_includes.KlippyRest import KlippyRest
from ks_includes.files import KlippyFiles
from ks_includes.KlippyGtk import KlippyGtk
from ks_includes.printer import Printer
from ks_includes.widgets.keyboard import Keyboard
from ks_includes.config import KlipperScreenConfig
from panels.base_panel import BasePanel
@ -1020,47 +1020,59 @@ class KlipperScreen(Gtk.Window):
self.show_panel('job_status', "job_status", "Print Status", 2)
self.base_panel.show_heaters(True)
def show_keyboard(self, widget=None, event=None):
def show_keyboard(self, widget=None, event=None, entry=None):
if self.keyboard is not None:
return
env = os.environ.copy()
usrkbd = "/home/pi/.matchbox/keyboard.xml"
if os.path.isfile(usrkbd):
env["MB_KBD_CONFIG"] = usrkbd
else:
env["MB_KBD_CONFIG"] = "ks_includes/locales/keyboard.xml"
p = subprocess.Popen(["matchbox-keyboard", "--xid"], stdout=subprocess.PIPE,
stderr=subprocess.PIPE, env=env)
xid = int(p.stdout.readline())
logging.debug(f"XID {xid}")
logging.debug(f"PID {p.pid}")
keyboard = Gtk.Socket()
box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
box.set_size_request(self.gtk.get_content_width(), self.gtk.get_keyboard_height())
if self._config.get_main_config().getboolean("use-matchbox-keyboard", False):
env = os.environ.copy()
usrkbd = os.path.expanduser("~/.matchbox/keyboard.xml")
if os.path.isfile(usrkbd):
env["MB_KBD_CONFIG"] = usrkbd
else:
env["MB_KBD_CONFIG"] = "ks_includes/locales/keyboard.xml"
p = subprocess.Popen(["matchbox-keyboard", "--xid"], stdout=subprocess.PIPE,
stderr=subprocess.PIPE, env=env)
xid = int(p.stdout.readline())
logging.debug(f"XID {xid}")
logging.debug(f"PID {p.pid}")
keyboard = Gtk.Socket()
box.get_style_context().add_class("keyboard_matchbox")
box.pack_start(keyboard, True, True, 0)
self.base_panel.get_content().pack_end(box, False, False, 0)
self.show_all()
keyboard.add_id(xid)
self.keyboard = {
"box": box,
"process": p,
"socket": keyboard
}
return
if entry is None:
logging.debug("Error: no entry provided for keyboard")
return
box.get_style_context().add_class("keyboard_box")
box.pack_start(keyboard, True, True, 0)
self.base_panel.get_content().pack_end(box, False, False, 0)
self.show_all()
keyboard.add_id(xid)
box.add(Keyboard(self, self.remove_keyboard, entry=entry))
self.keyboard = {
"box": box,
# "panel": cur_panel.get(),
"process": p,
"socket": keyboard
"entry": entry,
"box": box
}
self.base_panel.get_content().pack_end(box, False, False, 0)
self.base_panel.get_content().show_all()
def remove_keyboard(self, widget=None, event=None):
if self.keyboard is None:
return
if 'process' in self.keyboard:
os.kill(self.keyboard['process'].pid, signal.SIGTERM)
self.base_panel.get_content().remove(self.keyboard['box'])
os.kill(self.keyboard['process'].pid, signal.SIGTERM)
self.keyboard = None
def change_cursor(self, cursortype=None):

View File

@ -267,9 +267,19 @@ trough {
}
.keyboard_box {
margin-top: 35px;
}
.keyboard_matchbox {
margin-top: 42px;
}
.keyboard_pad {
margin: 0.05em;
padding: 0.0em;
border-radius: 0.7em;
}
.message_popup {
border-bottom: .1em solid white;
}

View File

@ -235,3 +235,7 @@ textview .time {
.error {
background-color: #dc322f; /*solarized-red*/
}
.keyboard_pad {
background-color: #073642; /*base02*/
}

View File

@ -19,8 +19,8 @@ button:active {
.button_active {
background-color: #000000;
border-color: #d81549;
border-width: .15em;
border-style: dashed;
border-width: .25em;
border-radius: 1em;
}
@ -227,3 +227,7 @@ textview .time {
.error {
background-color: #B71C1C;
}
.keyboard_pad {
background-color: #090909; /*base02*/
}

View File

@ -24,6 +24,7 @@ button:active {
.button_active {
border-color: #282828;
border-style: solid;
border-width: .25em;
background-color: #282828;
border-radius: 1em;
}
@ -209,3 +210,7 @@ textview .time {
.error {
background-color: #CF6679;
}
.keyboard_pad {
background-color: #090909; /*base02*/
}

View File

@ -23,8 +23,9 @@ button:active {
.button_active {
border-color: #BDBDBD;
border-style: solid;
border-width: .25em;
background-color: white;
box-shadow: .15em .15em #BDBDBD;
box-shadow: .1em .1em #BDBDBD;
border-radius: 1em;
}
@ -257,3 +258,7 @@ textview .time {
.error {
background-color: #EF9A9A;
}
.keyboard_pad {
background-color: #BDBDBD;
}

View File

@ -206,3 +206,7 @@ textview .time {
.error {
background-color: rgba(204, 30, 30, 0.7);
}
.keyboard_pad {
background-color: #13181C;
}