1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-08-01 19:18:28 -04:00

clipboard: implement virtual-keyboard-unstable-v1 to replace wtype for

pasting entries
This commit is contained in:
bbedward
2026-07-04 16:23:50 -04:00
parent 81a4d3b4e0
commit fd99558ce5
24 changed files with 1383 additions and 715 deletions
@@ -396,7 +396,7 @@ Item {
}
sourceComponent: ClipboardKeyboardHints {
wtypeAvailable: modal.wtypeAvailable
pasteAvailable: modal.pasteAvailable
enterToPaste: SettingsData.clipboardEnterToPaste
}
}
@@ -496,7 +496,7 @@ Item {
implicitHeight: saveMenuPasteRow.implicitHeight + Theme.spacingS * 2
radius: Theme.cornerRadius
color: saveMenuPasteArea.containsMouse ? Theme.surfaceVariant : Theme.withAlpha(Theme.surfaceVariant, 0)
opacity: modal.wtypeAvailable ? 1 : 0.5
opacity: modal.pasteAvailable ? 1 : 0.5
Row {
id: saveMenuPasteRow
@@ -522,7 +522,7 @@ Item {
id: saveMenuPasteArea
anchors.fill: parent
hoverEnabled: true
enabled: modal.wtypeAvailable
enabled: modal.pasteAvailable
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
onClicked: {
saveMenu.close();
@@ -21,7 +21,7 @@ FocusScope {
property string activeFilter: SettingsData.clipboardRememberTypeFilter ? SettingsData.clipboardTypeFilter : "all"
readonly property bool clipboardAvailable: ClipboardService.clipboardAvailable
readonly property bool wtypeAvailable: ClipboardService.wtypeAvailable
readonly property bool pasteAvailable: ClipboardService.pasteAvailable
readonly property int totalCount: ClipboardService.totalCount
readonly property var clipboardEntries: ClipboardService.clipboardEntries
readonly property var pinnedEntries: ClipboardService.pinnedEntries
@@ -5,10 +5,10 @@ import qs.Widgets
Rectangle {
id: keyboardHints
property bool wtypeAvailable: false
property bool pasteAvailable: false
property bool enterToPaste: false
readonly property string hintsText: {
if (!wtypeAvailable)
if (!pasteAvailable)
return I18n.tr("Ctrl+Tab: Switch Tab • Ctrl+S: Pin/Unpin • Shift+Del: Clear All • Esc: Close");
return enterToPaste ? I18n.tr("Ctrl+Tab: Switch Tabs • Ctrl+S: Pin/Unpin • Shift+Enter: Copy • Shift+Del: Clear All • F10: Help • Esc: Close", "Keyboard hints when enter-to-paste is enabled") : I18n.tr("Ctrl+Tab: Switch Tabs • Ctrl+S: Pin/Unpin • Shift+Enter: Paste • Shift+Del: Clear All • F10: Help • Esc: Close");
}
@@ -145,12 +145,6 @@ Item {
}
}
Process {
id: wtypeProcess
command: ["wtype", "-M", "ctrl", "-P", "v", "-p", "v", "-m", "ctrl"]
running: false
}
Process {
id: copyProcess
running: false
@@ -161,7 +155,7 @@ Item {
id: pasteTimer
interval: 200
repeat: false
onTriggered: wtypeProcess.running = true
onTriggered: ClipboardService.sendPasteKeystroke()
}
function pasteSelected() {
@@ -179,10 +173,6 @@ Item {
}
return;
}
if (!SessionService.wtypeAvailable) {
ToastService.showError(I18n.tr("wtype not available - install wtype for paste support"));
return;
}
const pluginId = selectedItem.pluginId;
if (!pluginId)
+50 -25
View File
@@ -3,7 +3,7 @@ pragma ComponentBehavior: Bound
import QtQuick
import Quickshell
import Quickshell.Io
import Quickshell.Wayland
import qs.Common
import qs.Services
@@ -14,7 +14,10 @@ Singleton {
readonly property int longTextThreshold: 200
readonly property bool clipboardAvailable: DMSService.isConnected && (DMSService.capabilities.length === 0 || DMSService.capabilities.includes("clipboard"))
readonly property bool wtypeAvailable: SessionService.wtypeAvailable
property bool pasteSupported: false
readonly property bool pasteAvailable: clipboardAvailable && pasteSupported
readonly property var terminalAppIds: ["kitty", "foot", "footclient", "alacritty", "st", "org.wezfurlong.wezterm", "com.mitchellh.ghostty", "ghostty", "org.kde.konsole", "konsole", "org.gnome.terminal", "gnome-terminal-server", "org.gnome.console", "kgx", "com.gexperts.tilix", "tilix", "terminator", "xfce4-terminal", "lxterminal", "deepin-terminal", "io.elementary.terminal", "rio", "contour", "wayst", "urxvt", "rxvt"]
property var internalEntries: []
property var clipboardEntries: []
@@ -37,38 +40,62 @@ Singleton {
signal historyCleared
signal launcherSearchReady(string query)
Process {
id: wtypeProcess
// TODO: This is only a paste shortcut fallback. It assumes the target
// application accepts Ctrl+V, which is false for many terminals.
// Replace with a more reliable target-aware paste strategy.
command: ["wtype", "-M", "ctrl", "-P", "v", "-p", "v", "-m", "ctrl"]
running: false
}
Timer {
id: pasteTimer
interval: 200
repeat: false
onTriggered: wtypeProcess.running = true
onTriggered: root.sendPasteKeystroke()
}
Connections {
target: DMSService
function onIsConnectedChanged() {
root.refreshPasteSupport();
}
}
Component.onCompleted: refreshPasteSupport()
function refreshPasteSupport() {
if (!DMSService.isConnected) {
pasteSupported = false;
return;
}
DMSService.sendRequest("clipboard.pasteSupported", null, function (response) {
root.pasteSupported = !response.error && response.result && response.result.supported === true;
});
}
function isTerminalFocused() {
const appId = (ToplevelManager.activeToplevel?.appId ?? "").toLowerCase();
if (!appId) {
return false;
}
return terminalAppIds.includes(appId) || appId.endsWith("term") || appId.includes("terminal");
}
function sendPasteKeystroke() {
DMSService.sendRequest("clipboard.sendPaste", {
"shift": isTerminalFocused()
}, function (response) {
if (response.error) {
ToastService.showError(I18n.tr("Paste failed: %1").arg(response.error));
}
});
}
function updateFilteredModel() {
let filtered = internalEntries;
if (activeFilter !== "all") {
filtered = filtered.filter(entry =>
getEntryType(entry) === activeFilter
);
filtered = filtered.filter(entry => getEntryType(entry) === activeFilter);
}
const query = searchText.trim();
if (query.length > 0) {
const lowerQuery = query.toLowerCase();
filtered = filtered.filter(entry =>
entry.preview.toLowerCase().includes(lowerQuery)
);
filtered = filtered.filter(entry => entry.preview.toLowerCase().includes(lowerQuery));
}
filtered.sort((a, b) => {
@@ -256,19 +283,17 @@ Singleton {
}
function pasteClipboard(closeCallback) {
if (!wtypeAvailable) {
ToastService.showError(I18n.tr("wtype not available - install wtype for paste support"));
return;
}
if (closeCallback) {
closeCallback();
}
pasteTimer.start();
if (pasteAvailable) {
pasteTimer.start();
}
}
function pasteEntry(entry, closeCallback) {
if (!wtypeAvailable) {
ToastService.showError(I18n.tr("wtype not available - install wtype for paste support"));
if (!pasteAvailable) {
copyEntry(entry, closeCallback);
return;
}
DMSService.sendRequest("clipboard.copyEntry", {
-11
View File
@@ -21,7 +21,6 @@ Singleton {
property string nvidiaCommand: ""
property bool loginctlAvailable: false
property bool wtypeAvailable: false
property string sessionId: ""
property string sessionPath: ""
property bool locked: false
@@ -55,7 +54,6 @@ Singleton {
detectElogindProcess.running = true;
detectHibernateProcess.running = true;
detectPrimeRunProcess.running = true;
detectWtypeProcess.running = true;
if (!SettingsData.loginctlLockIntegration) {
log.debug("loginctl lock integration disabled by user");
return;
@@ -120,15 +118,6 @@ Singleton {
}
}
Process {
id: detectWtypeProcess
running: false
command: ["sh", "-c", "command -v wtype"]
onExited: exitCode => {
wtypeAvailable = (exitCode === 0);
}
}
Process {
id: detectPrimeRunProcess
running: false
File diff suppressed because it is too large Load Diff
+39 -25
View File
@@ -916,13 +916,6 @@
"reference": "",
"comment": ""
},
{
"term": "Active Lock Screen Monitor",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "Active VPN",
"translation": "",
@@ -1196,13 +1189,6 @@
"reference": "",
"comment": ""
},
{
"term": "All Monitors",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "All checks passed",
"translation": "",
@@ -2484,6 +2470,13 @@
"reference": "",
"comment": ""
},
{
"term": "Battery Alerts",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "Battery Charge Limit",
"translation": "",
@@ -2506,7 +2499,7 @@
"comment": ""
},
{
"term": "Battery Protection & Charging",
"term": "Battery Protection",
"translation": "",
"context": "",
"reference": "",
@@ -3367,7 +3360,21 @@
"comment": ""
},
{
"term": "Choose how to be notified about battery alerts.",
"term": "Choose how to be notified about critical battery alerts.",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "Choose how to be notified about low battery alerts.",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "Choose how to be notified when charge limit is reached.",
"translation": "",
"context": "",
"reference": "",
@@ -3458,7 +3465,7 @@
"comment": ""
},
{
"term": "Choose which monitor shows the lock screen interface. Other monitors will display a solid color for OLED burn-in protection.",
"term": "Choose which monitors show the lock screen interface. Other monitors will display a solid color for OLED burn-in protection.",
"translation": "",
"context": "",
"reference": "",
@@ -13663,6 +13670,13 @@
"reference": "",
"comment": ""
},
{
"term": "Paste failed: %1",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "Path copied to clipboard",
"translation": "",
@@ -14266,7 +14280,7 @@
"comment": ""
},
{
"term": "Power Profiles Auto-Switching",
"term": "Power Profiles & Saving",
"translation": "",
"context": "",
"reference": "",
@@ -19403,6 +19417,13 @@
"reference": "",
"comment": ""
},
{
"term": "Unknown Model",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "Unknown Monitor",
"translation": "",
@@ -21461,13 +21482,6 @@
"reference": "",
"comment": ""
},
{
"term": "wtype not available - install wtype for paste support",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "• Install only from trusted sources",
"translation": "",