2022-08-27 03:50:01 -05:00
|
|
|
# Python imports
|
|
|
|
|
|
|
|
|
|
# Lib imports
|
|
|
|
|
import gi
|
|
|
|
|
gi.require_version('Gtk', '3.0')
|
|
|
|
|
from gi.repository import Gtk
|
2025-12-06 02:14:04 -06:00
|
|
|
from gi.repository import GLib
|
2022-08-27 03:50:01 -05:00
|
|
|
|
|
|
|
|
# Application imports
|
|
|
|
|
|
|
|
|
|
|
2022-08-30 17:17:35 -05:00
|
|
|
class Key(Gtk.Button or Gtk.ToggleButton):
|
2025-12-06 03:38:41 -06:00
|
|
|
def __init__(self, primary = "NULL", secondary = "NULL", iscontrol = False):
|
2022-08-27 03:50:01 -05:00
|
|
|
super(Key, self).__init__()
|
|
|
|
|
|
2025-12-06 02:14:04 -06:00
|
|
|
self.timer_id = None
|
2022-10-06 16:57:08 -05:00
|
|
|
self.iscontrol = iscontrol
|
2022-08-27 03:50:01 -05:00
|
|
|
self._primary_symbol = primary
|
|
|
|
|
self._secondary_symbol = secondary
|
2025-12-06 03:38:41 -06:00
|
|
|
self._alt_symbol = ''
|
2022-08-27 03:50:01 -05:00
|
|
|
self._is_upper = False
|
2022-08-27 23:24:12 -05:00
|
|
|
self._is_symbol = False
|
2022-09-16 20:53:04 -05:00
|
|
|
self._is_emoji = False
|
2025-12-06 03:38:41 -06:00
|
|
|
self.isShiftOn = False
|
2022-08-27 03:50:01 -05:00
|
|
|
|
2025-12-06 03:38:41 -06:00
|
|
|
self._setup_styling()
|
|
|
|
|
self._setup_signals()
|
|
|
|
|
self._subscribe_to_events()
|
|
|
|
|
self._setup_if_keycombo(secondary)
|
2022-08-27 03:50:01 -05:00
|
|
|
|
|
|
|
|
|
2025-12-06 03:38:41 -06:00
|
|
|
def _setup_styling(self):
|
|
|
|
|
self.set_label(self._primary_symbol)
|
|
|
|
|
|
|
|
|
|
def _setup_signals(self):
|
2025-12-06 02:14:04 -06:00
|
|
|
self.connect("button-press-event", self._do_press)
|
|
|
|
|
self.connect("button-release-event", self._do_release)
|
2022-09-16 20:53:04 -05:00
|
|
|
self.connect("toggle-emoji-keys", self.toggle_emoji_keys)
|
2022-08-27 03:50:01 -05:00
|
|
|
|
2025-12-06 03:38:41 -06:00
|
|
|
def _subscribe_to_events(self):
|
|
|
|
|
event_system.subscribe("toggle_caps", self.toggle_caps)
|
|
|
|
|
event_system.subscribe("toggle_symbol_keys", self.toggle_symbol_keys)
|
|
|
|
|
|
|
|
|
|
def _setup_if_keycombo(self, secondary: str):
|
|
|
|
|
if not self.iscontrol and (len(secondary) > 1 and '|' in secondary):
|
|
|
|
|
self._secondary_symbol = secondary[0]
|
|
|
|
|
|
|
|
|
|
parts = secondary.split("|")[1].split("+")
|
|
|
|
|
for part in parts:
|
|
|
|
|
if "shift" == part.lower():
|
|
|
|
|
self.isShiftOn = True
|
|
|
|
|
|
|
|
|
|
self._alt_symbol = parts[-1]
|
|
|
|
|
|
2025-12-06 02:14:04 -06:00
|
|
|
def _do_press(self, widget = None, eve = None):
|
|
|
|
|
if self.timer_id:
|
|
|
|
|
GLib.source_remove(self.timer_id)
|
|
|
|
|
self.timer_id = None
|
|
|
|
|
|
|
|
|
|
self._do_type()
|
|
|
|
|
self.timer_id = GLib.timeout_add(200, self._do_type)
|
|
|
|
|
|
|
|
|
|
def _do_type(self, widget = None, eve = None):
|
2022-08-27 03:50:01 -05:00
|
|
|
key = self.get_label().strip()
|
2025-12-06 03:38:41 -06:00
|
|
|
if self._is_emoji:
|
2023-03-03 21:19:39 -06:00
|
|
|
typwriter.set_clipboard_data(key, "utf-16")
|
|
|
|
|
typwriter.isCtrlOn = True
|
|
|
|
|
typwriter.type('v')
|
|
|
|
|
typwriter.isCtrlOn = False
|
2022-08-27 23:24:12 -05:00
|
|
|
|
2025-12-06 03:38:41 -06:00
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
typwriter.isShiftOn = self.isShiftOn
|
|
|
|
|
typwriter.type(
|
|
|
|
|
self._alt_symbol if self._alt_symbol and self._is_symbol else key
|
|
|
|
|
)
|
|
|
|
|
typwriter.isShiftOn = False
|
|
|
|
|
|
2025-12-06 02:14:04 -06:00
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def _do_release(self, widget = None, eve = None):
|
|
|
|
|
if not self.timer_id: return
|
|
|
|
|
GLib.source_remove(self.timer_id)
|
|
|
|
|
self.timer_id = None
|
|
|
|
|
|
2022-08-28 18:47:15 -05:00
|
|
|
def _do_press_special_key(self, widget = None):
|
2025-12-06 02:14:04 -06:00
|
|
|
self._do_type_special_key(widget)
|
|
|
|
|
|
|
|
|
|
def _do_press_special_key_repeater(self, widget = None, eve = None):
|
|
|
|
|
if self.timer_id:
|
|
|
|
|
GLib.source_remove(self.timer_id)
|
|
|
|
|
self.timer_id = None
|
|
|
|
|
|
|
|
|
|
self._do_type_special_key()
|
|
|
|
|
self.timer_id = GLib.timeout_add(200, self._do_type_special_key)
|
|
|
|
|
|
|
|
|
|
def _do_type_special_key(self, widget = None):
|
2022-08-30 17:17:35 -05:00
|
|
|
key = self.get_label()
|
|
|
|
|
if key in ["Ctrl", "Shift", "Alt"]:
|
|
|
|
|
ctx = widget.get_style_context()
|
|
|
|
|
ctx.remove_class("toggled_bttn") if ctx.has_class("toggled_bttn") else ctx.add_class("toggled_bttn")
|
|
|
|
|
|
|
|
|
|
typwriter.press_special_keys(key)
|
2025-12-06 02:14:04 -06:00
|
|
|
return True
|
2022-08-28 18:47:15 -05:00
|
|
|
|
2022-08-27 23:24:12 -05:00
|
|
|
def toggle_symbol_keys(self, widget = None, eve = None):
|
2022-10-06 16:57:08 -05:00
|
|
|
if not self.iscontrol:
|
|
|
|
|
self._is_symbol = not self._is_symbol
|
|
|
|
|
if self._is_symbol:
|
|
|
|
|
self.set_label(self._secondary_symbol)
|
|
|
|
|
else:
|
|
|
|
|
self.set_label(self._primary_symbol.upper()) if self._is_upper else self.set_label(self._primary_symbol.lower())
|
2022-09-16 20:53:04 -05:00
|
|
|
|
|
|
|
|
# NOTE: Might use name attrib on widgets and de-duplicate this and the above logic.
|
|
|
|
|
def toggle_emoji_keys(self, widget = None, eve = None):
|
2022-10-06 16:57:08 -05:00
|
|
|
if not self.iscontrol:
|
2023-03-03 21:19:39 -06:00
|
|
|
if self._is_symbol:
|
2022-10-06 16:57:08 -05:00
|
|
|
self.set_label(self._secondary_symbol)
|
|
|
|
|
else:
|
|
|
|
|
self.set_label(self._primary_symbol.upper()) if self._is_upper else self.set_label(self._primary_symbol.lower())
|
2022-08-27 23:24:12 -05:00
|
|
|
|
|
|
|
|
def toggle_caps(self, widget = None, eve = None):
|
2022-10-06 16:57:08 -05:00
|
|
|
if not self.iscontrol:
|
|
|
|
|
self._is_upper = not self._is_upper
|
|
|
|
|
if not self._is_symbol:
|
2025-12-06 03:38:41 -06:00
|
|
|
self.set_label(self._primary_symbol.upper()) if self._is_upper else self.set_label(self._primary_symbol.lower())
|