mirror of
https://github.com/yusufipk/dikte.git
synced 2026-09-11 19:06:11 +00:00
Add a Mac as the third system, beside Wayland and X11
Dikte already chose its clipboard programs once instead of in every function; macOS joins that table rather than adding a branch to each one. A Mac copies through pbcopy and presses Cmd+V straight into CoreGraphics, records through AVFoundation, and asks Carbon for its global shortcuts. The three tables are paste.Desktop, audio.Sound, and the pair of predicates in hotkey.py. Each reads sys.platform inside the chooser, so a test can stand somewhere else: 697 of the 737 tests now run on any machine, the Wayland and X11 halves included, and the suite passes whole whichever system it is run on. Two things a Mac does not have needed saying rather than pretending: there is no shortcut registry to install into, so Settings offers no Install button and the listener is the mechanism instead of a fallback; and nothing is offered as the sound the speakers are playing, so a meeting needs BlackHole or Loopback and says so. The KDE-only labels around them were already wrong on GNOME, and now name whichever desktop is there. Co-authored-by: firat <[email protected]>
This commit is contained in:
+82
-32
@@ -20,6 +20,7 @@ import config as cfg
|
||||
import filetranscribe
|
||||
import hotkey
|
||||
import meeting
|
||||
import paste
|
||||
from filetranscribe import FileTranscriber
|
||||
from i18n import t
|
||||
|
||||
@@ -89,7 +90,6 @@ REASONING_LEVELS = [
|
||||
("Low", "low"), ("Medium", "medium"), ("High", "high"),
|
||||
("Very high", "xhigh"), ("Maximum", "max"),
|
||||
]
|
||||
PASTE_SHORTCUTS = ["ctrl+v", "ctrl+shift+v", "shift+insert"]
|
||||
# Offered for all three global shortcuts, which keeps them one kind of field
|
||||
# rather than three. The boxes stay editable: this is a shortlist of
|
||||
# combinations that are usually free, not the set of ones that work.
|
||||
@@ -99,6 +99,13 @@ SHORTCUTS = [
|
||||
"Meta+A", "Meta+D", "Meta+M",
|
||||
"Ctrl+Alt+F1", "Ctrl+Alt+F2", "Ctrl+Alt+F3",
|
||||
]
|
||||
# Cmd+Space is Spotlight and Ctrl+Space switches input sources, so a Mac gets
|
||||
# its own shortlist. Option is what Alt is called on that keyboard.
|
||||
MAC_SHORTCUTS = [
|
||||
"Ctrl+Option+Space", "Cmd+Shift+Space", "Ctrl+Shift+Space",
|
||||
"Ctrl+Option+A", "Ctrl+Option+D", "Ctrl+Option+M",
|
||||
"Cmd+Option+A", "Cmd+Option+D", "Cmd+Option+M",
|
||||
]
|
||||
AUDIO_FILTER = ("*.mp3 *.wav *.m4a *.ogg *.opus *.flac *.aac *.wma "
|
||||
"*.mp4 *.mkv *.webm *.mov *.avi")
|
||||
|
||||
@@ -191,10 +198,16 @@ class SettingsWindow(QDialog):
|
||||
form.addRow("", self.auto_paste)
|
||||
|
||||
self.paste_shortcut = QComboBox()
|
||||
self.paste_shortcut.addItems(PASTE_SHORTCUTS)
|
||||
self.paste_shortcut.setToolTip(
|
||||
t("Terminals usually want ctrl+shift+v. Change this if pasting does nothing.")
|
||||
)
|
||||
# A shortlist of the combinations that usually paste, not the set of
|
||||
# them: a stored one this desktop does not offer is kept as it is
|
||||
# rather than quietly replaced by the first item on the list.
|
||||
self.paste_shortcut.setEditable(True)
|
||||
self.paste_shortcut.addItems(paste.desktop().shortcuts)
|
||||
self.paste_shortcut.setToolTip(t(
|
||||
"macOS asks for Accessibility permission the first time this is sent."
|
||||
if paste.desktop() is paste.MACOS else
|
||||
"Terminals usually want ctrl+shift+v. Change this if pasting does nothing."
|
||||
))
|
||||
form.addRow(t("Paste key"), self.paste_shortcut)
|
||||
|
||||
self.restore_clipboard = QCheckBox(t("Restore the previous clipboard after pasting"))
|
||||
@@ -232,7 +245,9 @@ class SettingsWindow(QDialog):
|
||||
)
|
||||
form.addRow("", self.filter_hallucinations)
|
||||
|
||||
self.keep_audio = QCheckBox(t("Keep audio files (~/.local/share/dikte/recordings)"))
|
||||
self.keep_audio = QCheckBox(
|
||||
t("Keep audio files ({path})", path=str(cfg.RECORDINGS_DIR))
|
||||
)
|
||||
form.addRow("", self.keep_audio)
|
||||
return page
|
||||
|
||||
@@ -368,12 +383,11 @@ class SettingsWindow(QDialog):
|
||||
how = QGroupBox(t("How it runs"))
|
||||
how_form = QFormLayout(how)
|
||||
self.assistant_shortcut = self._shortcut_box(t("none"))
|
||||
install = QPushButton(t("Install as a KDE shortcut"))
|
||||
install.clicked.connect(self._install_ask_shortcut)
|
||||
remove = QPushButton(t("Remove"))
|
||||
remove.clicked.connect(self._remove_ask_shortcut)
|
||||
how_form.addRow(t("Shortcut"),
|
||||
self._row(self.assistant_shortcut, install, remove))
|
||||
how_form.addRow(t("Shortcut"), self._row(
|
||||
self.assistant_shortcut,
|
||||
*self._install_buttons(self._install_ask_shortcut,
|
||||
self._remove_ask_shortcut),
|
||||
))
|
||||
self.assistant_shortcut_status = QLabel("")
|
||||
self.assistant_shortcut_status.setWordWrap(True)
|
||||
how_form.addRow(self.assistant_shortcut_status)
|
||||
@@ -555,6 +569,15 @@ class SettingsWindow(QDialog):
|
||||
self.meeting_system.addItem(desc, name)
|
||||
sources_form.addRow(t("The other participants"), self.meeting_system)
|
||||
|
||||
if audio.sound() is audio.COREAUDIO:
|
||||
mac_note = QLabel(t(
|
||||
"macOS does not offer what the speakers are playing as something "
|
||||
"to record. Install BlackHole or Loopback, send the meeting's "
|
||||
"sound through it, and pick it above."
|
||||
))
|
||||
mac_note.setWordWrap(True)
|
||||
sources_form.addRow(mac_note)
|
||||
|
||||
note = QLabel(t(
|
||||
"Wear headphones if you can. Through speakers your microphone hears "
|
||||
"the other side as well, and although a line that lands on both "
|
||||
@@ -630,12 +653,11 @@ class SettingsWindow(QDialog):
|
||||
recording_form.addRow("", self.meeting_keep_audio)
|
||||
|
||||
self.meeting_shortcut = self._shortcut_box(t("none"))
|
||||
install = QPushButton(t("Install as a KDE shortcut"))
|
||||
install.clicked.connect(self._install_meeting_shortcut)
|
||||
remove = QPushButton(t("Remove"))
|
||||
remove.clicked.connect(self._remove_meeting_shortcut)
|
||||
recording_form.addRow(t("Shortcut"),
|
||||
self._row(self.meeting_shortcut, install, remove))
|
||||
recording_form.addRow(t("Shortcut"), self._row(
|
||||
self.meeting_shortcut,
|
||||
*self._install_buttons(self._install_meeting_shortcut,
|
||||
self._remove_meeting_shortcut),
|
||||
))
|
||||
self.meeting_shortcut_status = QLabel("")
|
||||
self.meeting_shortcut_status.setWordWrap(True)
|
||||
recording_form.addRow(self.meeting_shortcut_status)
|
||||
@@ -784,13 +806,10 @@ class SettingsWindow(QDialog):
|
||||
form.addRow(t("Shortcut"), self.shortcut)
|
||||
layout.addLayout(form)
|
||||
|
||||
install = QPushButton(t("Install as a KDE shortcut"))
|
||||
install.clicked.connect(self._install_shortcut)
|
||||
remove = QPushButton(t("Remove"))
|
||||
remove.clicked.connect(self._remove_shortcut)
|
||||
row = QHBoxLayout()
|
||||
row.addWidget(install)
|
||||
row.addWidget(remove)
|
||||
for button in self._install_buttons(self._install_shortcut,
|
||||
self._remove_shortcut):
|
||||
row.addWidget(button)
|
||||
row.addStretch(1)
|
||||
layout.addLayout(row)
|
||||
|
||||
@@ -799,20 +818,34 @@ class SettingsWindow(QDialog):
|
||||
layout.addWidget(self.shortcut_status)
|
||||
|
||||
self.evdev_enabled = QCheckBox(t(
|
||||
"Use the built-in listener (/dev/input), for when the KDE shortcut is "
|
||||
"not active yet"
|
||||
"Use the built-in listener (/dev/input), for when the {desktop} "
|
||||
"shortcut is not active yet", desktop=hotkey.desktop_name()
|
||||
))
|
||||
self.evdev_enabled.setToolTip(t(
|
||||
"Works immediately, no session restart. The only difference: the key "
|
||||
"combination also reaches the focused application."
|
||||
))
|
||||
layout.addWidget(self.evdev_enabled)
|
||||
# Nothing to wait for where nothing is installed: there the listener is
|
||||
# the mechanism, always on, and not a choice to offer.
|
||||
self.evdev_enabled.setVisible(hotkey.installs_shortcuts())
|
||||
|
||||
note = QLabel(t(
|
||||
"KWin only reads shortcut settings at startup. After 'Install' the "
|
||||
"shortcut shows up under System Settings → Shortcuts, but it will not "
|
||||
"fire until you log out and back in. Until then, use the built-in listener."
|
||||
))
|
||||
if hotkey.shortcut_needs_restart():
|
||||
explanation = t(
|
||||
"KWin only reads shortcut settings at startup. After 'Install' the "
|
||||
"shortcut shows up under System Settings → Shortcuts, but it will "
|
||||
"not fire until you log out and back in. Until then, use the "
|
||||
"built-in listener."
|
||||
)
|
||||
elif hotkey.installs_shortcuts():
|
||||
explanation = t("The shortcut starts working as soon as it is installed.")
|
||||
else:
|
||||
explanation = t(
|
||||
"Dikte asks macOS for these combinations itself, while it is "
|
||||
"running. Nothing is installed, and no other application receives "
|
||||
"them in the meantime."
|
||||
)
|
||||
note = QLabel(explanation)
|
||||
note.setWordWrap(True)
|
||||
layout.addWidget(note)
|
||||
layout.addStretch(1)
|
||||
@@ -885,12 +918,29 @@ class SettingsWindow(QDialog):
|
||||
"""The field a global shortcut is typed or picked in."""
|
||||
box = QComboBox()
|
||||
box.setEditable(True)
|
||||
box.addItems(SHORTCUTS)
|
||||
box.addItems(MAC_SHORTCUTS if hotkey.desktop_name() == "macOS"
|
||||
else SHORTCUTS)
|
||||
box.setCurrentText("")
|
||||
if placeholder:
|
||||
box.lineEdit().setPlaceholderText(placeholder)
|
||||
return box
|
||||
|
||||
@staticmethod
|
||||
def _install_buttons(install_handler, remove_handler):
|
||||
"""Install and Remove, where this system has somewhere to install into.
|
||||
|
||||
macOS has not: Dikte asks for the combination itself while it runs, so
|
||||
there is nothing to write down and nothing to take back out.
|
||||
"""
|
||||
if not hotkey.installs_shortcuts():
|
||||
return []
|
||||
install = QPushButton(t("Install as a {desktop} shortcut",
|
||||
desktop=hotkey.desktop_name()))
|
||||
install.clicked.connect(install_handler)
|
||||
remove = QPushButton(t("Remove"))
|
||||
remove.clicked.connect(remove_handler)
|
||||
return [install, remove]
|
||||
|
||||
@staticmethod
|
||||
def _row(*widgets):
|
||||
"""Widgets side by side in one form row; the first one takes the space."""
|
||||
|
||||
Reference in New Issue
Block a user