Compare commits
8 Commits
c3c85a3040
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 9d30b6ac3b | |||
| 8596d5cb69 | |||
| 328dfaa594 | |||
| ae1131c2d7 | |||
| c969c6056b | |||
| b10d69c238 | |||
| 305cae4210 | |||
| e688416244 |
@@ -5,11 +5,11 @@ An onscreen keyboard for the mouse.
|
|||||||
* PyGObject
|
* PyGObject
|
||||||
* python-xlib
|
* python-xlib
|
||||||
* pyautogui
|
* pyautogui
|
||||||
|
* setproctitle
|
||||||
# TODO
|
* fast-autocomplete[levenshtein]
|
||||||
<li>Get save and execute of custom commands working.</li>
|
|
||||||
|
|
||||||
# Images
|
# Images
|
||||||

|

|
||||||

|

|
||||||

|

|
||||||
|

|
||||||
BIN
images/pic3.png
BIN
images/pic3.png
Binary file not shown.
|
Before Width: | Height: | Size: 123 KiB After Width: | Height: | Size: 152 KiB |
BIN
images/pic4.png
Normal file
BIN
images/pic4.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 123 KiB |
@@ -1,4 +1,5 @@
|
|||||||
PyGObject
|
PyGObject
|
||||||
pyautogui
|
|
||||||
python-xlib
|
python-xlib
|
||||||
|
pyautogui
|
||||||
setproctitle
|
setproctitle
|
||||||
|
fast-autocomplete[levenshtein]
|
||||||
@@ -34,9 +34,9 @@ class MissingConfigError(Exception):
|
|||||||
|
|
||||||
class Pyautogui_Controller(ControlMixin):
|
class Pyautogui_Controller(ControlMixin):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.isCtrlOn = False
|
self.isCtrlOn = False
|
||||||
self.isShiftOn = False
|
self.isShiftOn = False
|
||||||
self.isAltOn = False
|
self.isAltOn = False
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -57,7 +57,7 @@ keys_json = {
|
|||||||
},
|
},
|
||||||
"row4": {
|
"row4": {
|
||||||
"pKeys": ['z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '?'],
|
"pKeys": ['z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '?'],
|
||||||
"sKeys": ['', '', '<', '>', '[', ']', '(', ')', '{', '}']
|
"sKeys": ['', '', '<|shift+,', '>', '[', ']', '(', ')', '{', '}']
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -85,8 +85,9 @@ _USR_PATH = f"/usr/share/{app_name.lower()}"
|
|||||||
_CONFIG_PATH = f"{_USER_HOME}/.config/{app_name.lower()}"
|
_CONFIG_PATH = f"{_USER_HOME}/.config/{app_name.lower()}"
|
||||||
_ICON_FILE = f"{_CONFIG_PATH}/icons/{app_name.lower()}.png"
|
_ICON_FILE = f"{_CONFIG_PATH}/icons/{app_name.lower()}.png"
|
||||||
_CSS_FILE = f"{_CONFIG_PATH}/stylesheet.css"
|
_CSS_FILE = f"{_CONFIG_PATH}/stylesheet.css"
|
||||||
|
_DICT_FILE = f"{_CONFIG_PATH}/edmt_dictionary.json"
|
||||||
_EMOJI_FILE = f"{_CONFIG_PATH}/emoji.json"
|
_EMOJI_FILE = f"{_CONFIG_PATH}/emoji.json"
|
||||||
_LOG_FILE = f"{_CONFIG_PATH}/application.log"
|
_LOG_PATH = f"{_CONFIG_PATH}"
|
||||||
ch_log_lvl: int = 10
|
ch_log_lvl: int = 10
|
||||||
fh_log_lvl: int = 20
|
fh_log_lvl: int = 20
|
||||||
|
|
||||||
@@ -110,10 +111,11 @@ if not os.path.exists(_EMOJI_FILE):
|
|||||||
builtins.CONFIG_PATH = _CONFIG_PATH
|
builtins.CONFIG_PATH = _CONFIG_PATH
|
||||||
builtins.ICON_FILE = _ICON_FILE
|
builtins.ICON_FILE = _ICON_FILE
|
||||||
builtins.CSS_FILE = _CSS_FILE
|
builtins.CSS_FILE = _CSS_FILE
|
||||||
|
builtins.DICT_FILE = _DICT_FILE
|
||||||
builtins.EMOJI_FILE = _EMOJI_FILE
|
builtins.EMOJI_FILE = _EMOJI_FILE
|
||||||
|
|
||||||
|
|
||||||
builtins.logger = Logger(_LOG_FILE, ch_log_lvl, fh_log_lvl).get_logger()
|
builtins.logger = Logger(_LOG_PATH, ch_log_lvl, fh_log_lvl).get_logger()
|
||||||
builtins.endpoint_registry = EndpointRegistry()
|
builtins.endpoint_registry = EndpointRegistry()
|
||||||
builtins.event_system = EventSystem()
|
builtins.event_system = EventSystem()
|
||||||
builtins.typwriter = Pyautogui_Controller()
|
builtins.typwriter = Pyautogui_Controller()
|
||||||
@@ -54,9 +54,9 @@ class Keys_Column(Gtk.Box):
|
|||||||
row_box = self.add_row()
|
row_box = self.add_row()
|
||||||
if len(pKeys) == len(sKeys):
|
if len(pKeys) == len(sKeys):
|
||||||
for i in range(10):
|
for i in range(10):
|
||||||
pkey = pKeys[i]
|
pKey = pKeys[i]
|
||||||
sKey = sKeys[i]
|
sKey = sKeys[i]
|
||||||
row_box.add(Key(pkey, sKey))
|
row_box.add(Key(pKey, sKey))
|
||||||
else:
|
else:
|
||||||
raise KeyboardRowMatchError("A row in keys_json has missmatched pKeys to sKeys lengths.")
|
raise KeyboardRowMatchError("A row in keys_json has missmatched pKeys to sKeys lengths.")
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,19 @@
|
|||||||
# Python imports
|
# Python imports
|
||||||
|
import json
|
||||||
|
import time
|
||||||
|
|
||||||
# Lib imports
|
# Lib imports
|
||||||
import gi
|
import gi
|
||||||
gi.require_version('Gtk', '3.0')
|
gi.require_version('Gtk', '3.0')
|
||||||
from gi.repository import Gtk
|
from gi.repository import Gtk
|
||||||
|
|
||||||
|
try:
|
||||||
|
from fast_autocomplete import AutoComplete
|
||||||
|
auto_completion = True
|
||||||
|
except Exception as e:
|
||||||
|
print( repr(e) )
|
||||||
|
auto_completion = False
|
||||||
|
|
||||||
# Application imports
|
# Application imports
|
||||||
from .columns import Left_Column
|
from .columns import Left_Column
|
||||||
from .columns import Keys_Column
|
from .columns import Keys_Column
|
||||||
@@ -20,10 +29,12 @@ class Auto_Type(Gtk.Box):
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(Auto_Type, self).__init__()
|
super(Auto_Type, self).__init__()
|
||||||
|
|
||||||
pad1 = Gtk.Label()
|
self._processing_dictionary = False
|
||||||
pad2 = Gtk.Label()
|
pad1 = Gtk.Label()
|
||||||
self._auto_typer = Gtk.SearchEntry()
|
pad2 = Gtk.Label()
|
||||||
self._type_btn = Gtk.Button(label = "Type")
|
self._res_popover = Gtk.Popover()
|
||||||
|
self._auto_typer = Gtk.SearchEntry()
|
||||||
|
self._type_btn = Gtk.Button(label = "Type")
|
||||||
|
|
||||||
self._auto_typer.set_placeholder_text("Autotype Field...")
|
self._auto_typer.set_placeholder_text("Autotype Field...")
|
||||||
self._auto_typer.set_icon_from_stock(0, "gtk-go-forward") # PRIMARY = 0, SECONDARY = 1
|
self._auto_typer.set_icon_from_stock(0, "gtk-go-forward") # PRIMARY = 0, SECONDARY = 1
|
||||||
@@ -38,15 +49,67 @@ class Auto_Type(Gtk.Box):
|
|||||||
self.add(self._type_btn)
|
self.add(self._type_btn)
|
||||||
self.add(pad2)
|
self.add(pad2)
|
||||||
|
|
||||||
|
self.setup_auto_completion()
|
||||||
self.setup_styling()
|
self.setup_styling()
|
||||||
|
|
||||||
self.setup_signals()
|
self.setup_signals()
|
||||||
self.show_all()
|
self.show_all()
|
||||||
|
|
||||||
|
def setup_auto_completion(self):
|
||||||
|
if auto_completion:
|
||||||
|
self._word_list = Gtk.Box()
|
||||||
|
scrolled_win = Gtk.ScrolledWindow()
|
||||||
|
viewport = Gtk.Viewport()
|
||||||
|
|
||||||
|
viewport.add(self._word_list)
|
||||||
|
scrolled_win.add(viewport)
|
||||||
|
scrolled_win.show_all()
|
||||||
|
|
||||||
|
self._res_popover.set_size_request(200, 400)
|
||||||
|
self._res_popover.set_relative_to(self._auto_typer)
|
||||||
|
self._res_popover.set_modal(False)
|
||||||
|
self._res_popover.add(scrolled_win)
|
||||||
|
self._res_popover.set_default_widget(scrolled_win)
|
||||||
|
|
||||||
|
self._word_list.set_orientation(Gtk.Orientation.VERTICAL)
|
||||||
|
|
||||||
|
self.setup_dictionary()
|
||||||
|
|
||||||
|
@daemon_threaded
|
||||||
|
def setup_dictionary(self):
|
||||||
|
self._processing_dictionary = True
|
||||||
|
|
||||||
|
_words = set()
|
||||||
|
words = {}
|
||||||
|
with open(DICT_FILE, 'r') as f:
|
||||||
|
dict_data = json.load(f)
|
||||||
|
self._auto_typer.set_progress_fraction(0.25)
|
||||||
|
|
||||||
|
for field in dict_data:
|
||||||
|
_words.add( field["word"] )
|
||||||
|
_words.add( field["word"].lower() )
|
||||||
|
|
||||||
|
self._auto_typer.set_progress_fraction(0.5)
|
||||||
|
del dict_data
|
||||||
|
for word in _words:
|
||||||
|
words[word] = {}
|
||||||
|
|
||||||
|
self._auto_typer.set_progress_fraction(0.75)
|
||||||
|
self.autocomplete = AutoComplete(words=words)
|
||||||
|
del _words
|
||||||
|
del words
|
||||||
|
|
||||||
|
self._auto_typer.set_progress_fraction(1.0)
|
||||||
|
time.sleep(1)
|
||||||
|
self._auto_typer.set_progress_fraction(0.0)
|
||||||
|
self._processing_dictionary = False
|
||||||
|
|
||||||
def setup_styling(self):
|
def setup_styling(self):
|
||||||
self.set_margin_bottom(5)
|
self.set_margin_bottom(5)
|
||||||
|
|
||||||
def setup_signals(self):
|
def setup_signals(self):
|
||||||
|
if auto_completion:
|
||||||
|
self._auto_typer.connect("search-changed", self.search_changed)
|
||||||
|
|
||||||
self._auto_typer.connect("enter-notify-event", self.focus_entry)
|
self._auto_typer.connect("enter-notify-event", self.focus_entry)
|
||||||
self._auto_typer.connect("leave-notify-event", self.unfocus_entry)
|
self._auto_typer.connect("leave-notify-event", self.unfocus_entry)
|
||||||
self._type_btn.connect("released", self.type_out)
|
self._type_btn.connect("released", self.type_out)
|
||||||
@@ -61,8 +124,39 @@ class Auto_Type(Gtk.Box):
|
|||||||
widget.grab_remove()
|
widget.grab_remove()
|
||||||
event_system.emit("unset_focusable")
|
event_system.emit("unset_focusable")
|
||||||
|
|
||||||
|
def search_changed(self, widget = None, eve = None):
|
||||||
|
if self._processing_dictionary: return
|
||||||
|
|
||||||
|
text = widget.get_text()
|
||||||
|
if not text:
|
||||||
|
self._res_popover.hide()
|
||||||
|
return
|
||||||
|
|
||||||
|
words = self.autocomplete.search(word=text, max_cost=3, size=100)
|
||||||
|
if not words:
|
||||||
|
self._res_popover.hide()
|
||||||
|
return
|
||||||
|
|
||||||
|
self._clear_children(self._word_list)
|
||||||
|
for word in words:
|
||||||
|
button = Gtk.Button(label=word[0])
|
||||||
|
button.connect("clicked", self.type_out)
|
||||||
|
self._word_list.add(button)
|
||||||
|
|
||||||
|
self._word_list.show_all()
|
||||||
|
self._res_popover.show()
|
||||||
|
|
||||||
|
def _clear_children(self, widget):
|
||||||
|
for child in widget.get_children():
|
||||||
|
widget.remove(child)
|
||||||
|
|
||||||
def type_out(self, widget = None, eve = None):
|
def type_out(self, widget = None, eve = None):
|
||||||
text = self._auto_typer.get_text()
|
text = self._auto_typer.get_text()
|
||||||
|
|
||||||
|
if isinstance(widget, Gtk.Button):
|
||||||
|
if not widget.get_label().lower() == "type":
|
||||||
|
text = widget.get_label()
|
||||||
|
|
||||||
typwriter.type_string(text)
|
typwriter.type_string(text)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -17,20 +17,21 @@ class Esc_Key(Key):
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(Esc_Key, self).__init__("Esc", "Esc", iscontrol = True)
|
super(Esc_Key, self).__init__("Esc", "Esc", iscontrol = True)
|
||||||
|
|
||||||
def setup_signals(self):
|
def _setup_signals(self):
|
||||||
self.connect("released", self._do_press_special_key)
|
self.connect("button-press-event", self._do_press_special_key)
|
||||||
|
self.connect("button-release-event", self._do_release_special_key)
|
||||||
|
|
||||||
class CAPS_Key(Key):
|
class CAPS_Key(Key):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(CAPS_Key, self).__init__("Caps", "Caps", iscontrol = True)
|
super(CAPS_Key, self).__init__("Caps", "Caps", iscontrol = True)
|
||||||
|
|
||||||
self.setup_styling()
|
self._setup_styling()
|
||||||
self.show_all()
|
|
||||||
|
|
||||||
def setup_styling(self):
|
def _setup_styling(self):
|
||||||
self.set_vexpand(True)
|
self.set_vexpand(True)
|
||||||
|
super()._setup_styling()
|
||||||
|
|
||||||
def setup_signals(self):
|
def _setup_signals(self):
|
||||||
self.connect("released", self._clicked)
|
self.connect("released", self._clicked)
|
||||||
|
|
||||||
def _clicked(self, widget = None):
|
def _clicked(self, widget = None):
|
||||||
@@ -45,11 +46,9 @@ class Backspace_Key(Key):
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(Backspace_Key, self).__init__("Backspace", "Backspace", iscontrol=True)
|
super(Backspace_Key, self).__init__("Backspace", "Backspace", iscontrol=True)
|
||||||
|
|
||||||
def setup_signals(self):
|
def _setup_signals(self):
|
||||||
self.connect("released", self._clicked)
|
self.connect("button-press-event", self._do_press_special_key)
|
||||||
|
self.connect("button-release-event", self._do_release_special_key)
|
||||||
def _clicked(self, widget = None):
|
|
||||||
typwriter.press_special_keys(self.get_label())
|
|
||||||
|
|
||||||
class Emoji_Key(Key):
|
class Emoji_Key(Key):
|
||||||
def __init__(self, emoji_popover):
|
def __init__(self, emoji_popover):
|
||||||
@@ -58,7 +57,7 @@ class Emoji_Key(Key):
|
|||||||
self._ctx = self.get_style_context()
|
self._ctx = self.get_style_context()
|
||||||
self._emoji_popover = emoji_popover
|
self._emoji_popover = emoji_popover
|
||||||
|
|
||||||
def setup_signals(self):
|
def _setup_signals(self):
|
||||||
self.connect("released", self._clicked)
|
self.connect("released", self._clicked)
|
||||||
|
|
||||||
def _clicked(self, widget = None):
|
def _clicked(self, widget = None):
|
||||||
@@ -73,7 +72,7 @@ class Symbols_Key(Key):
|
|||||||
super(Symbols_Key, self).__init__("Symbols", "Symbols", iscontrol = True)
|
super(Symbols_Key, self).__init__("Symbols", "Symbols", iscontrol = True)
|
||||||
self.setup_custom_signals()
|
self.setup_custom_signals()
|
||||||
|
|
||||||
def setup_signals(self):
|
def _setup_signals(self):
|
||||||
self.connect("released", self._clicked)
|
self.connect("released", self._clicked)
|
||||||
|
|
||||||
def setup_custom_signals(self):
|
def setup_custom_signals(self):
|
||||||
@@ -92,30 +91,26 @@ class Symbols_Key(Key):
|
|||||||
class Enter_Key(Key):
|
class Enter_Key(Key):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(Enter_Key, self).__init__("Enter", "Enter", iscontrol=True)
|
super(Enter_Key, self).__init__("Enter", "Enter", iscontrol=True)
|
||||||
self.setup_styling()
|
self._setup_styling()
|
||||||
|
|
||||||
def setup_styling(self):
|
def _setup_styling(self):
|
||||||
self.set_vexpand(True)
|
self.set_vexpand(True)
|
||||||
|
super()._setup_styling()
|
||||||
|
|
||||||
def setup_signals(self):
|
def _setup_signals(self):
|
||||||
self.connect("released", self._do_press_special_key)
|
self.connect("button-press-event", self._do_press_special_key)
|
||||||
|
self.connect("button-release-event", self._do_release_special_key)
|
||||||
|
|
||||||
|
|
||||||
############################# Bottom_Key_Row Keys #############################
|
############################# Bottom_Key_Row Keys #############################
|
||||||
|
|
||||||
class Esc_Key(Key):
|
|
||||||
def __init__(self):
|
|
||||||
super(Esc_Key, self).__init__("Esc", "Esc", iscontrol=True)
|
|
||||||
|
|
||||||
def setup_signals(self):
|
|
||||||
self.connect("released", self._do_press_special_key)
|
|
||||||
|
|
||||||
class Space_Key(Key):
|
class Space_Key(Key):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(Space_Key, self).__init__("Space", "Space", iscontrol=True)
|
super(Space_Key, self).__init__("Space", "Space", iscontrol=True)
|
||||||
|
|
||||||
def setup_signals(self):
|
def _setup_signals(self):
|
||||||
self.connect("released", self._do_press_special_key)
|
self.connect("button-press-event", self._do_press_special_key)
|
||||||
|
self.connect("button-release-event", self._do_release_special_key)
|
||||||
|
|
||||||
class AT_Key(Key):
|
class AT_Key(Key):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@@ -132,68 +127,78 @@ class Tab_Key(Key):
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(Tab_Key, self).__init__("Tab", "Tab", iscontrol=True)
|
super(Tab_Key, self).__init__("Tab", "Tab", iscontrol=True)
|
||||||
|
|
||||||
def setup_signals(self):
|
def _setup_signals(self):
|
||||||
self.connect("released", self._do_press_special_key)
|
self.connect("button-press-event", self._do_press_special_key)
|
||||||
|
self.connect("button-release-event", self._do_release_special_key)
|
||||||
|
|
||||||
class Del_Key(Key):
|
class Del_Key(Key):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(Del_Key, self).__init__("Del", "Del", iscontrol=True)
|
super(Del_Key, self).__init__("Del", "Del", iscontrol=True)
|
||||||
|
|
||||||
def setup_signals(self):
|
def _setup_signals(self):
|
||||||
self.connect("released", self._do_press_special_key)
|
self.connect("button-press-event", self._do_press_special_key)
|
||||||
|
self.connect("button-release-event", self._do_release_special_key)
|
||||||
|
|
||||||
class Ctrl_Key(Key):
|
class Ctrl_Key(Key):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(Ctrl_Key, self).__init__("Ctrl", "Ctrl", iscontrol=True)
|
super(Ctrl_Key, self).__init__("Ctrl", "Ctrl", iscontrol=True)
|
||||||
|
|
||||||
def setup_signals(self):
|
def _setup_signals(self):
|
||||||
self.connect("released", self._do_press_special_key)
|
self.connect("button-press-event", self._do_press_special_key)
|
||||||
|
self.connect("button-release-event", self._do_release_special_key)
|
||||||
|
|
||||||
class Shift_Key(Key):
|
class Shift_Key(Key):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(Shift_Key, self).__init__("Shift", "Shift", iscontrol=True)
|
super(Shift_Key, self).__init__("Shift", "Shift", iscontrol=True)
|
||||||
|
|
||||||
def setup_signals(self):
|
def _setup_signals(self):
|
||||||
self.connect("released", self._do_press_special_key)
|
self.connect("button-press-event", self._do_press_special_key)
|
||||||
|
self.connect("button-release-event", self._do_release_special_key)
|
||||||
|
|
||||||
class Alt_Key(Key):
|
class Alt_Key(Key):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(Alt_Key, self).__init__("Alt", "Alt", iscontrol=True)
|
super(Alt_Key, self).__init__("Alt", "Alt", iscontrol=True)
|
||||||
|
|
||||||
def setup_signals(self):
|
def _setup_signals(self):
|
||||||
self.connect("released", self._do_press_special_key)
|
self.connect("button-press-event", self._do_press_special_key)
|
||||||
|
self.connect("button-release-event", self._do_release_special_key)
|
||||||
|
|
||||||
class PrtSc_Key(Key):
|
class PrtSc_Key(Key):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(PrtSc_Key, self).__init__("PrtSc", "PrtSc", iscontrol=True)
|
super(PrtSc_Key, self).__init__("PrtSc", "PrtSc", iscontrol=True)
|
||||||
|
|
||||||
def setup_signals(self):
|
def _setup_signals(self):
|
||||||
self.connect("released", self._do_press_special_key)
|
self.connect("button-press-event", self._do_press_special_key)
|
||||||
|
self.connect("button-release-event", self._do_release_special_key)
|
||||||
|
|
||||||
class Up_Key(Key):
|
class Up_Key(Key):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(Up_Key, self).__init__("Up", "Up", iscontrol=True)
|
super(Up_Key, self).__init__("Up", "Up", iscontrol=True)
|
||||||
|
|
||||||
def setup_signals(self):
|
def _setup_signals(self):
|
||||||
self.connect("released", self._do_press_special_key)
|
self.connect("button-press-event", self._do_press_special_key)
|
||||||
|
self.connect("button-release-event", self._do_release_special_key)
|
||||||
|
|
||||||
class Down_Key(Key):
|
class Down_Key(Key):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(Down_Key, self).__init__("Down", "Down", iscontrol=True)
|
super(Down_Key, self).__init__("Down", "Down", iscontrol=True)
|
||||||
|
|
||||||
def setup_signals(self):
|
def _setup_signals(self):
|
||||||
self.connect("released", self._do_press_special_key)
|
self.connect("button-press-event", self._do_press_special_key)
|
||||||
|
self.connect("button-release-event", self._do_release_special_key)
|
||||||
|
|
||||||
class Left_Key(Key):
|
class Left_Key(Key):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(Left_Key, self).__init__("Left", "Left", iscontrol=True)
|
super(Left_Key, self).__init__("Left", "Left", iscontrol=True)
|
||||||
|
|
||||||
def setup_signals(self):
|
def _setup_signals(self):
|
||||||
self.connect("released", self._do_press_special_key)
|
self.connect("button-press-event", self._do_press_special_key)
|
||||||
|
self.connect("button-release-event", self._do_release_special_key)
|
||||||
|
|
||||||
class Right_Key(Key):
|
class Right_Key(Key):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(Right_Key, self).__init__("Right", "Right", iscontrol=True)
|
super(Right_Key, self).__init__("Right", "Right", iscontrol=True)
|
||||||
|
|
||||||
def setup_signals(self):
|
def _setup_signals(self):
|
||||||
self.connect("released", self._do_press_special_key)
|
self.connect("button-press-event", self._do_press_special_key)
|
||||||
|
self.connect("button-release-event", self._do_release_special_key)
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
# Python imports
|
# Python imports
|
||||||
from collections import defaultdict
|
|
||||||
import json
|
import json
|
||||||
|
import asyncio
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
# Lib imports
|
# Lib imports
|
||||||
import gi
|
import gi
|
||||||
gi.require_version('Gtk', '3.0')
|
gi.require_version('Gtk', '3.0')
|
||||||
from gi.repository import Gtk
|
from gi.repository import Gtk
|
||||||
|
from gi.repository import GLib
|
||||||
|
|
||||||
# Application imports
|
# Application imports
|
||||||
from .key import Key
|
from .key import Key
|
||||||
@@ -19,7 +21,7 @@ class Emoji_Notebook(Gtk.Notebook):
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(Emoji_Notebook, self).__init__()
|
super(Emoji_Notebook, self).__init__()
|
||||||
|
|
||||||
self.load_ui( self.get_data(EMOJI_FILE) )
|
self.load_ui()
|
||||||
|
|
||||||
self.setup_styling()
|
self.setup_styling()
|
||||||
self.show_all()
|
self.show_all()
|
||||||
@@ -29,26 +31,51 @@ class Emoji_Notebook(Gtk.Notebook):
|
|||||||
self.set_current_page(0)
|
self.set_current_page(0)
|
||||||
self.set_scrollable(True)
|
self.set_scrollable(True)
|
||||||
|
|
||||||
def get_data(self, file):
|
def load_ui(self):
|
||||||
emoji_grouping = defaultdict(list)
|
emoji_data = None
|
||||||
|
with open(EMOJI_FILE, 'r') as f:
|
||||||
with open(file, 'r') as f:
|
|
||||||
emoji_data = json.load(f)
|
emoji_data = json.load(f)
|
||||||
for emoji in emoji_data:
|
|
||||||
category = emoji['category']
|
if not emoji_data:
|
||||||
del emoji['category']
|
print("No emoji data found in file...")
|
||||||
del emoji['unicode_version']
|
return
|
||||||
del emoji['ios_version']
|
|
||||||
emoji_grouping[category].append(emoji)
|
try:
|
||||||
|
loop = asyncio.get_running_loop()
|
||||||
|
except RuntimeError:
|
||||||
|
loop = None
|
||||||
|
|
||||||
|
if loop and loop.is_running():
|
||||||
|
loop = asyncio.get_event_loop()
|
||||||
|
loop.create_task( self._async_load_ui(emoji_data) )
|
||||||
|
else:
|
||||||
|
asyncio.run( self._async_load_ui(emoji_data) )
|
||||||
|
|
||||||
|
async def _async_load_ui(self, emoji_data):
|
||||||
|
emoji_grouping = await self._get_emoji_grouping(emoji_data)
|
||||||
|
GLib.idle_add(self._populate_ui, emoji_grouping)
|
||||||
|
|
||||||
|
async def _get_emoji_grouping(self, emoji_data):
|
||||||
|
emoji_grouping = defaultdict(list)
|
||||||
|
async def add_to_group(emoji):
|
||||||
|
category = emoji['category']
|
||||||
|
key = Key( emoji["emoji"], emoji["emoji"] )
|
||||||
|
key._is_emoji = True
|
||||||
|
|
||||||
|
emoji_grouping[category].append(key)
|
||||||
|
|
||||||
|
tasks = [ add_to_group(emoji) for emoji in emoji_data]
|
||||||
|
await asyncio.gather(*tasks)
|
||||||
|
|
||||||
return emoji_grouping
|
return emoji_grouping
|
||||||
|
|
||||||
def load_ui(self, emoji_grouping):
|
def _populate_ui(self, emoji_grouping):
|
||||||
width = 1
|
width = 1
|
||||||
height = 1
|
height = 1
|
||||||
for group in emoji_grouping:
|
for group in emoji_grouping:
|
||||||
tab_widget = Gtk.Label(label=group)
|
tab_widget = Gtk.Label(label=group)
|
||||||
scroll, grid = self.create_scroll_and_grid()
|
scroll, grid = self.create_scroll_and_grid()
|
||||||
|
|
||||||
self.append_page(scroll, tab_widget)
|
self.append_page(scroll, tab_widget)
|
||||||
self.set_tab_reorderable(scroll, False)
|
self.set_tab_reorderable(scroll, False)
|
||||||
self.set_tab_detachable(scroll, False)
|
self.set_tab_detachable(scroll, False)
|
||||||
@@ -56,16 +83,15 @@ class Emoji_Notebook(Gtk.Notebook):
|
|||||||
top = 0
|
top = 0
|
||||||
left = 0
|
left = 0
|
||||||
for emoji in emoji_grouping[group]:
|
for emoji in emoji_grouping[group]:
|
||||||
key = Key(emoji["emoji"], emoji["emoji"])
|
grid.attach(emoji, left, top, width, height)
|
||||||
key._is_emoji = True
|
|
||||||
key.show()
|
|
||||||
grid.attach(key, left, top, width, height)
|
|
||||||
|
|
||||||
left += 1
|
left += 1
|
||||||
if left > 8:
|
if left > 8:
|
||||||
left = 0
|
left = 0
|
||||||
top += 1
|
top += 1
|
||||||
|
|
||||||
|
self.show_all()
|
||||||
|
del emoji_grouping
|
||||||
|
|
||||||
def create_scroll_and_grid(self):
|
def create_scroll_and_grid(self):
|
||||||
scroll = Gtk.ScrolledWindow()
|
scroll = Gtk.ScrolledWindow()
|
||||||
|
|||||||
@@ -4,50 +4,134 @@
|
|||||||
import gi
|
import gi
|
||||||
gi.require_version('Gtk', '3.0')
|
gi.require_version('Gtk', '3.0')
|
||||||
from gi.repository import Gtk
|
from gi.repository import Gtk
|
||||||
|
from gi.repository import GLib
|
||||||
|
|
||||||
# Application imports
|
# Application imports
|
||||||
|
|
||||||
|
|
||||||
class Key(Gtk.Button or Gtk.ToggleButton):
|
class Key(Gtk.Button or Gtk.ToggleButton):
|
||||||
def __init__(self, primary = "NULL", secondary = "NULL", iscontrol=False):
|
def __init__(self, primary = "NULL", secondary = "NULL", iscontrol = False):
|
||||||
super(Key, self).__init__()
|
super(Key, self).__init__()
|
||||||
|
|
||||||
|
self.timer_id = None
|
||||||
self.iscontrol = iscontrol
|
self.iscontrol = iscontrol
|
||||||
self._primary_symbol = primary
|
self._primary_symbol = primary
|
||||||
self._secondary_symbol = secondary
|
self._secondary_symbol = secondary
|
||||||
|
self._alt_symbol = ''
|
||||||
self._is_upper = False
|
self._is_upper = False
|
||||||
self._is_symbol = False
|
self._is_symbol = False
|
||||||
self._is_emoji = False
|
self._is_emoji = False
|
||||||
|
self.isShiftOn = False
|
||||||
|
|
||||||
|
self._setup_styling()
|
||||||
|
self._setup_signals()
|
||||||
|
self._subscribe_to_events()
|
||||||
|
self._setup_if_keycombo(secondary)
|
||||||
|
|
||||||
|
|
||||||
|
def _setup_styling(self):
|
||||||
self.set_label(self._primary_symbol)
|
self.set_label(self._primary_symbol)
|
||||||
self.setup_custom_signals()
|
|
||||||
self.setup_signals()
|
|
||||||
|
|
||||||
def setup_custom_signals(self):
|
def _setup_signals(self):
|
||||||
|
self.connect("button-press-event", self._do_press)
|
||||||
|
self.connect("button-release-event", self._do_release)
|
||||||
|
self.connect("toggle-emoji-keys", self.toggle_emoji_keys)
|
||||||
|
|
||||||
|
def _subscribe_to_events(self):
|
||||||
event_system.subscribe("toggle_caps", self.toggle_caps)
|
event_system.subscribe("toggle_caps", self.toggle_caps)
|
||||||
event_system.subscribe("toggle_symbol_keys", self.toggle_symbol_keys)
|
event_system.subscribe("toggle_symbol_keys", self.toggle_symbol_keys)
|
||||||
|
|
||||||
def setup_signals(self):
|
def _setup_if_keycombo(self, secondary: str):
|
||||||
self.connect("released", self._do_type)
|
if not self.iscontrol and (len(secondary) > 1 and '|' in secondary):
|
||||||
self.connect("toggle-emoji-keys", self.toggle_emoji_keys)
|
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]
|
||||||
|
|
||||||
|
|
||||||
|
def _do_press(self, widget = None, eve = None):
|
||||||
|
if not self.timer_id:
|
||||||
|
self.did_loop_type = False
|
||||||
|
self.timer_id = GLib.timeout_add(500, self._do_wait_loop_type)
|
||||||
|
|
||||||
|
|
||||||
|
def _do_release(self, widget = None, eve = None):
|
||||||
|
if self.did_loop_type:
|
||||||
|
GLib.source_remove(self.timer_id)
|
||||||
|
self.timer_id = None
|
||||||
|
self.did_loop_type = False
|
||||||
|
return
|
||||||
|
|
||||||
|
self._do_type()
|
||||||
|
GLib.source_remove(self.timer_id)
|
||||||
|
self.timer_id = None
|
||||||
|
|
||||||
|
def _do_wait_loop_type(self):
|
||||||
|
if not self.timer_id: return False
|
||||||
|
self.did_loop_type = True
|
||||||
|
self.timer_id = GLib.timeout_add(200, self._do_type)
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _do_type(self):
|
||||||
|
if not self.timer_id: return False
|
||||||
|
|
||||||
def _do_type(self, widget = None):
|
|
||||||
key = self.get_label().strip()
|
key = self.get_label().strip()
|
||||||
if not self._is_emoji:
|
if self._is_emoji:
|
||||||
typwriter.type(key)
|
|
||||||
else:
|
|
||||||
typwriter.set_clipboard_data(key, "utf-16")
|
typwriter.set_clipboard_data(key, "utf-16")
|
||||||
typwriter.isCtrlOn = True
|
typwriter.isCtrlOn = True
|
||||||
typwriter.type('v')
|
typwriter.type('v')
|
||||||
typwriter.isCtrlOn = False
|
typwriter.isCtrlOn = False
|
||||||
|
|
||||||
def _do_press_special_key(self, widget = None):
|
return True
|
||||||
|
|
||||||
|
if self._alt_symbol and self._is_symbol:
|
||||||
|
typwriter.isShiftOn = self.isShiftOn
|
||||||
|
typwriter.type(self._alt_symbol)
|
||||||
|
typwriter.isShiftOn = False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
typwriter.type(key)
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def _do_press_special_key(self, widget = None, eve = None):
|
||||||
|
if not self.timer_id:
|
||||||
|
self.did_loop_type = False
|
||||||
|
self.timer_id = GLib.timeout_add(500, self._do_wait_loop_special_type)
|
||||||
|
|
||||||
|
def _do_release_special_key(self, widget = None, eve = None):
|
||||||
|
if self.did_loop_type:
|
||||||
|
GLib.source_remove(self.timer_id)
|
||||||
|
self.timer_id = None
|
||||||
|
self.did_loop_type = False
|
||||||
|
return
|
||||||
|
|
||||||
|
self._do_type_special_key()
|
||||||
|
GLib.source_remove(self.timer_id)
|
||||||
|
self.timer_id = None
|
||||||
|
|
||||||
|
def _do_wait_loop_special_type(self):
|
||||||
|
if not self.timer_id: return False
|
||||||
|
self.did_loop_type = True
|
||||||
|
self.timer_id = GLib.timeout_add(200, self._do_type_special_key)
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _do_type_special_key(self):
|
||||||
|
if not self.timer_id: return False
|
||||||
|
|
||||||
key = self.get_label()
|
key = self.get_label()
|
||||||
if key in ["Ctrl", "Shift", "Alt"]:
|
if key in ["Ctrl", "Shift", "Alt"]:
|
||||||
ctx = widget.get_style_context()
|
ctx = self.get_style_context()
|
||||||
ctx.remove_class("toggled_bttn") if ctx.has_class("toggled_bttn") else ctx.add_class("toggled_bttn")
|
ctx.remove_class("toggled_bttn") if ctx.has_class("toggled_bttn") else ctx.add_class("toggled_bttn")
|
||||||
|
|
||||||
typwriter.press_special_keys(key)
|
typwriter.press_special_keys(key)
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
def toggle_symbol_keys(self, widget = None, eve = None):
|
def toggle_symbol_keys(self, widget = None, eve = None):
|
||||||
if not self.iscontrol:
|
if not self.iscontrol:
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user