Report unavailable protocols and services; send combos as real keys

Diagnostics collects what this session doesn't allow, logs it, and lists
it in the settings panel (with a dot on the gear): KWin not launching
sloposk as its keyboard (detected by WAYLAND_SOCKET, since KWin offers the
input-method global to every client), fake input missing or too old,
org.kde.keyboard unreachable, and the D-Bus control name taken.

Modifier combos go through fake input even in text fields: KWin drops
the input method's modifier mask for most clients, so Ctrl+A typed "a".

The desktop file is generated with an absolute Exec, which KWin needs to
match it: one for the installed binary, one for the build's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-15 11:36:56 +02:00
co-authored by Claude Opus 5.5
parent 6164839886
commit 499e5ee76e
21 changed files with 362 additions and 104 deletions
+3
View File
@@ -7,6 +7,7 @@ Window {
required property LayoutModel layoutModel
required property KeyboardController controller
required property Settings settings
required property Diagnostics diagnostics
property var placement: null // FloatingWindow, set from C++
property bool settingsOpen: false
// Height of the key area, for C++ keeping key sizes when rows change.
@@ -58,6 +59,7 @@ Window {
visible: root.settingsOpen
settings: root.settings
layoutModel: root.layoutModel
diagnostics: root.diagnostics
}
DragHandle {
@@ -69,6 +71,7 @@ Window {
SettingsButton {
anchors { left: parent.left; leftMargin: 8; bottom: parent.bottom }
checked: root.settingsOpen
alert: root.diagnostics.problems.length > 0
onClicked: root.settingsOpen = !root.settingsOpen
}
+26
View File
@@ -0,0 +1,26 @@
import QtQuick
// What doesn't work in this session and why (see Diagnostics); hidden when all is well.
Column {
id: list
property list<string> problems
visible: problems.length > 0
spacing: 4
SectionHeader { text: qsTr("Not Available"); color: Theme.warning }
Repeater {
model: list.problems
Text {
required property string modelData
width: list.width
text: "⚠ " + modelData
color: Theme.text
font.pixelSize: 13
wrapMode: Text.Wrap
}
}
}
+12
View File
@@ -5,6 +5,8 @@ Item {
id: button
property bool checked: false
// Something doesn't work (see Diagnostics): a dot invites a look in settings.
property bool alert: false
signal clicked()
implicitWidth: 36
@@ -17,6 +19,16 @@ Item {
color: tap.pressed ? Theme.text : Theme.handle
}
Rectangle {
visible: button.alert && !button.checked
width: 6
height: 6
radius: 3
color: Theme.warning
x: parent.width / 2 + 6
y: 3
}
TapHandler {
id: tap
onTapped: button.clicked()
+91 -79
View File
@@ -8,101 +8,113 @@ Flickable {
required property Settings settings
required property LayoutModel layoutModel
required property Diagnostics diagnostics
clip: true
contentHeight: columns.height + 2 * columns.y
contentHeight: content.height + 2 * content.y
boundsBehavior: Flickable.StopAtBounds
Row {
id: columns
readonly property real columnWidth: (width - spacing) / 2
Column {
id: content
x: 16
y: 16
width: panel.width - 2 * x
spacing: 32
spacing: 16
Column {
width: columns.columnWidth
spacing: 4
SectionHeader { text: qsTr("Typing") }
ToggleRow {
width: parent.width
text: qsTr("Auto-Capitalization")
detail: qsTr("Shift at the start of a sentence")
checked: panel.settings.autoCapitalize
onToggled: checked => panel.settings.autoCapitalize = checked
}
ToggleRow {
width: parent.width
text: qsTr("Hold Keys")
detail: qsTr("Keys stay down while touched, like a hardware keyboard; no accents or flicks")
checked: panel.settings.holdKeys
onToggled: checked => panel.settings.holdKeys = checked
}
ToggleRow {
width: parent.width
text: qsTr("Always Show")
detail: qsTr("Type into any window, not just text fields")
checked: panel.settings.alwaysVisible
onToggled: checked => panel.settings.alwaysVisible = checked
}
ToggleRow {
width: parent.width
text: qsTr("“.” Shortcut")
detail: qsTr("Double-tap space for a period and a space")
checked: panel.settings.doubleSpacePeriod
onToggled: checked => panel.settings.doubleSpacePeriod = checked
}
SectionHeader { text: qsTr("Appearance"); topPadding: 12 }
SliderRow {
width: parent.width
text: qsTr("Background")
from: panel.settings.minBackgroundOpacity
value: panel.settings.backgroundOpacity
onMoved: value => panel.settings.backgroundOpacity = value
}
ToggleRow {
width: parent.width
text: qsTr("Blur Behind")
detail: qsTr("Frosted glass under a see-through background, if the desktop supports it")
checked: panel.settings.blurBackground
onToggled: checked => panel.settings.blurBackground = checked
}
ProblemList {
width: parent.width
problems: panel.diagnostics.problems
}
Column {
width: columns.columnWidth
spacing: 4
Row {
id: columns
readonly property real columnWidth: (width - spacing) / 2
SectionHeader { text: qsTr("Keys") }
width: parent.width
spacing: 32
ToggleRow {
width: parent.width
text: qsTr("Full Keyboard")
detail: qsTr("Number row, tab, ctrl, alt — like iPad Pro")
checked: panel.settings.fullKeyboard
onToggled: checked => panel.settings.fullKeyboard = checked
}
Column {
width: columns.columnWidth
spacing: 4
Repeater {
// "main" is the typing keys; the rest come from the template.
model: [{ id: "main", name: qsTr("Typing keys") }].concat(panel.layoutModel.sections)
SectionHeader { text: qsTr("Typing") }
ToggleRow {
required property var modelData
width: parent.width
text: modelData.name
checked: panel.settings.visibleSections.includes(modelData.id)
onToggled: checked => panel.settings.setSectionVisible(modelData.id, checked)
text: qsTr("Auto-Capitalization")
detail: qsTr("Shift at the start of a sentence")
checked: panel.settings.autoCapitalize
onToggled: checked => panel.settings.autoCapitalize = checked
}
ToggleRow {
width: parent.width
text: qsTr("Hold Keys")
detail: qsTr("Keys stay down while touched, like a hardware keyboard; no accents or flicks")
checked: panel.settings.holdKeys
onToggled: checked => panel.settings.holdKeys = checked
}
ToggleRow {
width: parent.width
text: qsTr("Always Show")
detail: qsTr("Type into any window, not just text fields")
checked: panel.settings.alwaysVisible
onToggled: checked => panel.settings.alwaysVisible = checked
}
ToggleRow {
width: parent.width
text: qsTr("“.” Shortcut")
detail: qsTr("Double-tap space for a period and a space")
checked: panel.settings.doubleSpacePeriod
onToggled: checked => panel.settings.doubleSpacePeriod = checked
}
SectionHeader { text: qsTr("Appearance"); topPadding: 12 }
SliderRow {
width: parent.width
text: qsTr("Background")
from: panel.settings.minBackgroundOpacity
value: panel.settings.backgroundOpacity
onMoved: value => panel.settings.backgroundOpacity = value
}
ToggleRow {
width: parent.width
text: qsTr("Blur Behind")
detail: qsTr("Frosted glass under a see-through background, if the desktop supports it")
checked: panel.settings.blurBackground
onToggled: checked => panel.settings.blurBackground = checked
}
}
Column {
width: columns.columnWidth
spacing: 4
SectionHeader { text: qsTr("Keys") }
ToggleRow {
width: parent.width
text: qsTr("Full Keyboard")
detail: qsTr("Number row, tab, ctrl, alt — like iPad Pro")
checked: panel.settings.fullKeyboard
onToggled: checked => panel.settings.fullKeyboard = checked
}
Repeater {
// "main" is the typing keys; the rest come from the template.
model: [{ id: "main", name: qsTr("Typing keys") }].concat(panel.layoutModel.sections)
ToggleRow {
required property var modelData
width: parent.width
text: modelData.name
checked: panel.settings.visibleSections.includes(modelData.id)
onToggled: checked => panel.settings.setSectionVisible(modelData.id, checked)
}
}
}
}
+1
View File
@@ -16,6 +16,7 @@ QtObject {
readonly property color accent: dark ? "#0a84ff" : "#007aff"
readonly property color accentText: "#ffffff"
readonly property color toggleOn: dark ? "#30d158" : "#34c759"
readonly property color warning: dark ? "#ff9f0a" : "#ff9500"
readonly property real windowRadius: 14
readonly property real keyRadius: 6