diff --git a/qml/BarToggle.qml b/qml/BarToggle.qml index d2a2a60..de732cb 100644 --- a/qml/BarToggle.qml +++ b/qml/BarToggle.qml @@ -1,7 +1,7 @@ import QtQuick -// A small on/off button in the grab bar; lit while on. The icon goes inside -// and should draw in `foreground`. +// On/off button in the grab bar, highlighted while on. +// Child items form the icon and should use `foreground` as their color. Item { id: toggle diff --git a/qml/DragHandle.qml b/qml/DragHandle.qml index b1409e9..db07805 100644 --- a/qml/DragHandle.qml +++ b/qml/DragHandle.qml @@ -1,11 +1,11 @@ import QtQuick -// The grab bar under the floating keyboard. Moving the window is up to the -// owner (the window manager's move, so it works for mouse and touch alike). +// Grab bar below the keyboard. Only emits dragStarted(); the parent starts +// the window manager's move (works for mouse and touch). Item { id: handle - // Narrower when the bar's buttons leave less room in the middle. + // Set smaller when the bar's buttons take up more width. property real pillWidth: 120 signal dragStarted() diff --git a/qml/FloatingButton.qml b/qml/FloatingButton.qml index a44373c..2f216c1 100644 --- a/qml/FloatingButton.qml +++ b/qml/FloatingButton.qml @@ -1,8 +1,8 @@ import QtQuick -// The dismiss key left floating while the keyboard is shrunk; see-through so -// it hides less. Tap to bring the keyboard back; dragging is up to the owner -// (the window manager's move). +// Button shown in place of the keyboard while it is collapsed. Semi-transparent +// so it covers less. Tap emits tapped() (expand); drag emits dragStarted() and +// the parent starts the window manager's move. Item { id: button @@ -28,7 +28,7 @@ Item { TapHandler { id: tap - // The move ends with a release that would otherwise count as a tap. + // Set during a drag, so the release that ends the drag isn't treated as a tap. property bool moved: false onPressedChanged: if (pressed) moved = false onTapped: if (!moved) button.tapped() diff --git a/qml/Key.qml b/qml/Key.qml index 22436c1..9f70710 100644 --- a/qml/Key.qml +++ b/qml/Key.qml @@ -30,9 +30,9 @@ Item { return modifierModes[modifier] ?? KeyboardController.Off return KeyboardController.Off } - // Shift shows locking with its glyph; the others turn accent-coloured. + // Accent color for locked modifiers. Shift is excluded: its glyph shows the lock. readonly property bool locked: latch === KeyboardController.Locked && keyType !== "shift" - // Character keys darken when pressed; function keys lighten (as on iPad). + // Light background: character keys at rest, function keys while pressed or latched (as on iPad). readonly property bool lit: (isCharacter !== pressed) || latch !== KeyboardController.Off readonly property var defaultGlyphs: ({ @@ -46,7 +46,7 @@ Item { return ["⇧", "⬆", "⇪"][shiftMode] return label !== "" ? label : (defaultGlyphs[keyType] ?? "") } - // Count code points, not UTF-16 units, so emoji glyphs aren't treated as words. + // Multi-character label (e.g. "return"). Counts code points, not UTF-16 units, so an emoji counts as one. readonly property bool isWord: [...displayLabel].length > 1 && !isCharacter x: keyX diff --git a/qml/Main.qml b/qml/Main.qml index 4e01631..940d824 100644 --- a/qml/Main.qml +++ b/qml/Main.qml @@ -12,36 +12,36 @@ Window { property var collapse: null // CollapseController, set from C++ readonly property bool collapsed: collapse?.collapsed ?? false property bool settingsOpen: false - // Height of the key area, for C++ keeping key sizes when rows change. + // Read by C++ to keep key size constant when rows are added or removed. readonly property real keysHeight: keyboard.height - // Transparent room above the keyboard for long-press popups on the top row. + // Transparent space above the keyboard for the top row's long-press popups. readonly property real popupMargin: 90 - // Outside this, input passes through to whatever is below the window. + // Input outside this rect goes to the window underneath. readonly property rect inputRegion: collapsed ? Qt.rect(floatingButton.x, floatingButton.y, floatingButton.width, floatingButton.height) : keyboard.alternates.open ? Qt.rect(0, 0, width, height) : Qt.rect(panel.x, panel.y, panel.width, panel.height) - // Empty when nothing shows through, so the compositor skips the blur. + // Empty (no blur) when collapsed, blur is off, or the background is opaque. readonly property rect blurRegion: !collapsed && settings.blurBackground && settings.backgroundOpacity < 1 ? Qt.rect(panel.x, panel.y, panel.width, panel.height) : Qt.rect(0, 0, 0, 0) width: 1000 height: 340 + popupMargin - // None while shrunk to the floating button. + // No minimum while collapsed, so the window can shrink to the button. minimumWidth: collapsed ? 0 : 480 minimumHeight: collapsed ? 0 : 180 + popupMargin visible: false color: "transparent" - // Alt+F4 or the task manager would hide it behind the visibility - // controller's back; the dismiss key and the tray toggle hide it instead. + // Ignore close requests (Alt+F4, task manager): they would hide the window + // without VisibilityController knowing. Hiding goes through the dismiss key or tray toggle. onClosing: close => close.accepted = false onInputRegionChanged: placement?.setInputRegion(inputRegion) onBlurRegionChanged: placement?.setBlurRegion(blurRegion, Theme.windowRadius) - // For CollapseController. + // Called by CollapseController. function dismissKeyRect() { return keyboard.keyRect("dismiss"); } @@ -107,7 +107,7 @@ Window { FloatingButton { id: floatingButton readonly property rect keyRect: root.collapse?.keyRect ?? Qt.rect(0, 0, 0, 0) - // Over the key while the window is full size, then in the shrunk window. + // keyRect is in full-window coordinates; the clamp keeps the button inside the window once it has shrunk. x: Math.max(0, Math.min(keyRect.x, root.width - width)) y: Math.max(0, Math.min(keyRect.y, root.height - height)) width: keyRect.width diff --git a/qml/QuickToggles.qml b/qml/QuickToggles.qml index 6843831..c52caac 100644 --- a/qml/QuickToggles.qml +++ b/qml/QuickToggles.qml @@ -1,8 +1,8 @@ import QtQuick import Sloposk -// One-tap switches for the most changed key options, beside the gear. -// Icons are drawn from boxes so they don't depend on the fonts installed. +// Toggle buttons for frequently changed key options, next to the settings button. +// Icons are built from Rectangles, so they don't depend on installed fonts. Row { id: toggles @@ -13,8 +13,8 @@ Row { return layoutModel.sections.some(s => s.id === id); } - // Shows or hides one of the template's optional sections; absent from - // layouts without it. + // Shows or hides an optional template section. Not displayed if the + // layout has no such section. component SectionToggle: BarToggle { required property string section @@ -23,7 +23,7 @@ Row { onToggled: checked => toggles.settings.setSectionVisible(section, checked) } - // A grid of tiny keys, optionally in a keyboard outline. + // Icon: grid of small keys, optionally inside a keyboard outline. component KeyGrid: Item { id: keyGrid required property color color @@ -58,7 +58,7 @@ Row { } } - // A key outline with a label on it. + // Icon: key outline with a text label. component LabelledKey: Rectangle { property alias label: caption.text property alias textColor: caption.color @@ -90,7 +90,7 @@ Row { label: qsTr("Hold Keys") checked: toggles.settings.holdKeys onToggled: checked => toggles.settings.holdKeys = checked - // A fingertip resting on a key, holding it down. + // Icon: finger pressing a key (hold-keys mode). Rectangle { anchors { horizontalCenter: parent.horizontalCenter; bottom: parent.bottom } width: 18 @@ -119,7 +119,7 @@ Row { id: navigation section: "navigation" label: qsTr("Navigation Keys") - // The inverted T of the arrow keys. + // Icon: arrow keys in an inverted T. Repeater { model: [[1, 0], [0, 1], [1, 1], [2, 1]] Rectangle { diff --git a/qml/ResizeHandle.qml b/qml/ResizeHandle.qml index 34b4e32..a65fb20 100644 --- a/qml/ResizeHandle.qml +++ b/qml/ResizeHandle.qml @@ -1,6 +1,6 @@ import QtQuick -// Corner grip. Resizing is up to the owner (the window manager's resize). +// Corner grip. Only emits dragStarted(); the parent starts the window manager's resize. Item { id: grip @@ -28,7 +28,7 @@ Item { DragHandler { target: null - // The grab bar lies underneath and would take the drag over. + // Prevent the grab bar underneath from taking over the drag. grabPermissions: PointerHandler.TakeOverForbidden cursorShape: Qt.SizeFDiagCursor onActiveChanged: if (active) grip.dragStarted() diff --git a/qml/SettingsButton.qml b/qml/SettingsButton.qml index ece49d4..0396ac9 100644 --- a/qml/SettingsButton.qml +++ b/qml/SettingsButton.qml @@ -5,7 +5,7 @@ Item { id: button property bool checked: false - // Something doesn't work (see Diagnostics): a dot invites a look in settings. + // Shows a dot when Diagnostics reports a problem. property bool alert: false signal clicked() diff --git a/qml/SettingsPanel.qml b/qml/SettingsPanel.qml index f34d658..cc171ac 100644 --- a/qml/SettingsPanel.qml +++ b/qml/SettingsPanel.qml @@ -1,8 +1,8 @@ import QtQuick import Sloposk -// Replaces the keys while open, over the window's own background so -// opacity changes show live. Binds straight to Settings, which persists. +// Shown instead of the keys while open. Drawn on the window background, so +// opacity changes are visible immediately. Bound directly to Settings, which saves to disk. Flickable { id: panel @@ -113,7 +113,7 @@ Flickable { } Repeater { - // "main" is the typing keys; the rest come from the template. + // "main" = the typing keys; other ids are template sections. model: [{ id: "main", name: qsTr("Typing keys") }].concat(panel.layoutModel.sections) ToggleRow { diff --git a/qml/SliderRow.qml b/qml/SliderRow.qml index c66360b..9ac760e 100644 --- a/qml/SliderRow.qml +++ b/qml/SliderRow.qml @@ -1,6 +1,6 @@ import QtQuick -// A labelled slider in the iOS style; value runs from `from` to 1. +// iOS-style labelled slider; value range is `from`..1. Item { id: row diff --git a/src/app/Checks.cpp b/src/app/Checks.cpp index c8fcbd6..44d962d 100644 --- a/src/app/Checks.cpp +++ b/src/app/Checks.cpp @@ -28,8 +28,8 @@ QString fakeInputProblem(const KWinFakeInput &fakeInput) void watchInputMethod(Diagnostics &diagnostics, const KWinInputMethod &backend, bool launchedByKWin) { - // Qt binds globals KWin already announced on construction, so the first - // check is final unless KWin restarts. + // Qt binds the globals KWin has already announced during construction, so + // this result only changes if KWin restarts. const auto checkInputMethod = [&] { diagnostics.check(QStringLiteral("input-method"), launchedByKWin && backend.isAvailable(), tr("Not running as KWin's virtual keyboard, so it can't type into text fields: " diff --git a/src/app/Checks.h b/src/app/Checks.h index 50619a2..636e684 100644 --- a/src/app/Checks.h +++ b/src/app/Checks.h @@ -4,11 +4,10 @@ class Diagnostics; class KWinInputMethod; class SystemLayouts; -// Reports to `diagnostics` what this session doesn't allow, and keeps the -// reports current as protocols and services come and go. -// KWin offers the input-method global to every client but only activates -// the process it launched, which it hands a connection: `launchedByKWin` is -// whether WAYLAND_SOCKET was set at startup. +// Reports missing protocols and D-Bus services to `diagnostics`, and updates +// the reports when they appear or disappear. +// `launchedByKWin`: WAYLAND_SOCKET was set at startup. KWin advertises the +// input-method global to every client, but only activates the process it launched. void watchInputMethod(Diagnostics &diagnostics, const KWinInputMethod &backend, bool launchedByKWin); void watchSystemLayouts(Diagnostics &diagnostics, const SystemLayouts &layouts); void reportDBusControl(Diagnostics &diagnostics, bool registered); diff --git a/src/app/KWinVirtualKeyboard.h b/src/app/KWinVirtualKeyboard.h index e670406..2704f39 100644 --- a/src/app/KWinVirtualKeyboard.h +++ b/src/app/KWinVirtualKeyboard.h @@ -4,10 +4,10 @@ #include -// KWin's virtual keyboard policy (the tray toggle, System Settings → -// Virtual Keyboard): KWin activates the input method for every text field -// and the policy only gates its input panel, which sloposk doesn't use, so -// sloposk asks it over org.kde.KWin /VirtualKeyboard instead. +// Queries KWin's virtual keyboard policy (tray toggle, System Settings → +// Virtual Keyboard) over org.kde.KWin /VirtualKeyboard. +// Needed because KWin activates the input method for every text field and +// applies the policy only to the input panel surface, which sloposk doesn't use. class KWinVirtualKeyboard : public QObject { Q_OBJECT @@ -15,9 +15,11 @@ class KWinVirtualKeyboard : public QObject public: explicit KWinVirtualKeyboard(QObject *parent = nullptr); - // Calls `answer` with whether a field focused now should show the - // keyboard: never when it's off, only after touch or a pen in the - // default mode. True if KWin can't be asked. + // Asynchronously asks KWin whether to show the keyboard for the currently + // focused field and calls `answer` with the result: + // - false if the virtual keyboard is disabled + // - in the default (touch-only) mode, true only if the last input was touch or pen + // - true if KWin can't be reached void askShowOnActive(QObject *context, std::function answer); Q_SIGNALS: diff --git a/src/app/SystemLayouts.cpp b/src/app/SystemLayouts.cpp index 44f1f44..9b3e018 100644 --- a/src/app/SystemLayouts.cpp +++ b/src/app/SystemLayouts.cpp @@ -23,7 +23,7 @@ SystemLayouts::SystemLayouts(QObject *parent) : QObject(parent) { QDBusConnection bus = QDBusConnection::sessionBus(); - // Follows the service's owner, so it survives KWin restarting. + // Watches the service owner, so it reconnects after KWin restarts. bus.connect(Service, Path, Interface, QStringLiteral("layoutChanged"), this, SLOT(setCurrent(uint))); auto *watcher = new QDBusServiceWatcher(Service, bus, QDBusServiceWatcher::WatchForOwnerChange, this); connect(watcher, &QDBusServiceWatcher::serviceRegistered, this, &SystemLayouts::fetchCurrent); diff --git a/src/app/SystemLayouts.h b/src/app/SystemLayouts.h index 89176bd..54478a4 100644 --- a/src/app/SystemLayouts.h +++ b/src/app/SystemLayouts.h @@ -2,10 +2,10 @@ #include -// Which of the system's keyboard layouts is active, followed and switched -// over KWin's org.kde.keyboard D-Bus interface, so the on-screen and the -// physical keyboard always agree. Without that service it switches locally, -// until the service appears (KWin starting late or restarting). +// Tracks and switches the active system keyboard layout via KWin's +// org.kde.keyboard D-Bus interface, so the on-screen and physical keyboards +// use the same layout. While the service is missing (KWin not started yet or +// restarting), switching only changes the local index. class SystemLayouts : public QObject { Q_OBJECT @@ -19,7 +19,7 @@ public: Q_SIGNALS: void currentChanged(); - // After each attempt to reach the service, and when it goes away. + // Emitted after each attempt to reach the service, and when it disappears. void serviceChecked(bool available); private Q_SLOTS: diff --git a/src/backend/KWinFakeInput.h b/src/backend/KWinFakeInput.h index d402ee4..7c699ac 100644 --- a/src/backend/KWinFakeInput.h +++ b/src/backend/KWinFakeInput.h @@ -5,8 +5,8 @@ #include "qwayland-fake-input.h" -// Key events for whatever window has focus, as from a hardware keyboard: -// KWin's fake-input protocol, which it offers to the input-method process. +// Sends key events to the focused window, as a hardware keyboard would, via +// KWin's fake-input protocol (offered to the input-method process). // Used when no text field is focused, so shortcuts, terminals and games work. class KWinFakeInput : public QWaylandClientExtensionTemplate, public QtWayland::org_kde_kwin_fake_input { @@ -26,7 +26,7 @@ public: void typeText(const QString &text); // KWin offers the protocol only to clients whose desktop file lists it // (see the .desktop.in); isActive() says whether it did. - // keyboard_keysym, which everything here uses, needs this version. + // Minimum version: required for keyboard_keysym, which all requests here use. static constexpr uint32_t RequiredVersion = 6; bool canSendKeysyms() const; // The version KWin bound, which may be older than the one asked for: diff --git a/src/backend/KWinInputMethod.cpp b/src/backend/KWinInputMethod.cpp index 89bb3e4..f2c9744 100644 --- a/src/backend/KWinInputMethod.cpp +++ b/src/backend/KWinInputMethod.cpp @@ -58,7 +58,7 @@ void KWinInputMethod::replaceBeforeCursor(const QString &before, const QString & m_context->replaceBeforeCursor(before, text); return; } - // Key events are one ordered stream, so plain Backspaces are safe here. + // Key events are delivered in order, so sending Backspace keys is safe here. for (qsizetype i = 0; i < before.toUcs4().size(); ++i) m_fakeInput.sendKeysym(XKB_KEY_BackSpace); m_fakeInput.typeText(text); diff --git a/src/backend/KWinInputMethod.h b/src/backend/KWinInputMethod.h index 1cc2eb5..72b2194 100644 --- a/src/backend/KWinInputMethod.h +++ b/src/backend/KWinInputMethod.h @@ -42,7 +42,7 @@ public: // False when the compositor didn't hand us the input-method global. bool isAvailable() const; - // Key events outside text fields, held keys and modifier combos. + // Used for key events outside text fields, held keys and modifier combos. const KWinFakeInput &fakeInput() const { return m_fakeInput; } bool isActive() const override; @@ -64,6 +64,7 @@ private: KWinInputMethodGlobal m_global; KWinFakeInput m_fakeInput; std::unique_ptr m_context; - // Replaced by an activate before KWin deactivated it; kept until it does. + // Context replaced by a new activate before KWin deactivated it. Kept + // until KWin sends its deactivate, then destroyed. std::unique_ptr m_previous; }; diff --git a/src/backend/TextBackend.h b/src/backend/TextBackend.h index 8d90bcf..aa755a6 100644 --- a/src/backend/TextBackend.h +++ b/src/backend/TextBackend.h @@ -34,7 +34,7 @@ public: virtual void setKeyPressed(quint32 keysym, bool pressed) = 0; Q_SIGNALS: - // Also when focus moves straight from one field to another. + // Also emitted when focus moves directly from one field to another. void activeChanged(); void contextChanged(); }; diff --git a/src/backend/TextContext.h b/src/backend/TextContext.h index 6bdfc5c..77797f5 100644 --- a/src/backend/TextContext.h +++ b/src/backend/TextContext.h @@ -29,7 +29,8 @@ struct TextContext { Purpose purpose = Purpose::Normal; quint32 hints = 0; - // Prose fields get iOS conveniences; codes, addresses and secrets don't. + // Whether typing aids (auto-capitalization, double-space period) apply: + // yes for normal text and names, no for passwords, URLs, emails, numbers etc. bool isProse() const { const bool prosePurpose = purpose == Purpose::Normal || purpose == Purpose::Alpha @@ -37,8 +38,8 @@ struct TextContext { return field && prosePurpose && !(hints & (HiddenText | SensitiveData)); } - // Fields that state any text preference must ask for capitals; most that - // state none (hints 0) still want them. + // Fields that set any text hint get auto-capitalization only if they set + // AutoCapitalization. Fields with no hints get it by default. bool allowsAutoCapitalization() const { constexpr quint32 Preferences = AutoCompletion | AutoCorrection | AutoCapitalization | Lowercase diff --git a/src/input/AlternatesPicker.h b/src/input/AlternatesPicker.h index 5adcc88..78f1873 100644 --- a/src/input/AlternatesPicker.h +++ b/src/input/AlternatesPicker.h @@ -26,10 +26,11 @@ public: int selected() const { return m_selected; } QString selectedText() const { return m_choices.value(m_selected); } - // Places one key-sized cell per choice just above the key, starting over it - // and extending right (shifted left near the edge to stay within - // [0, boundsWidth]; lowered, over the key, to stay below minTop). The cell - // above the finger starts selected. + // Lays out one key-sized cell per choice in a row above the key, starting + // at the key's x and extending right. + // - shifted left if needed to stay within [0, boundsWidth] + // - moved down (overlapping the key) if needed to stay below minTop + // Selects the cell above the finger. void open(const QRectF &keyRect, const QStringList &choices, qreal boundsWidth, qreal minTop, qreal gap); void selectAt(qreal x); void close(); diff --git a/src/input/DeadKeys.cpp b/src/input/DeadKeys.cpp index 270bf4c..32e6675 100644 --- a/src/input/DeadKeys.cpp +++ b/src/input/DeadKeys.cpp @@ -51,7 +51,8 @@ QString DeadKeys::press(quint32 deadKeysym) return composed; } case XKB_COMPOSE_CANCELLED: { - // No sequence goes on like this: type the old accents, start anew. + // No compose sequence continues with this key: flush the pending accents + // and start a new sequence. const QString accents = m_pending; cancel(); return accents + press(deadKeysym); diff --git a/src/input/DeadKeys.h b/src/input/DeadKeys.h index 5709cf0..6cf2906 100644 --- a/src/input/DeadKeys.h +++ b/src/input/DeadKeys.h @@ -17,12 +17,13 @@ public: ~DeadKeys(); bool isPending() const { return !m_pending.isEmpty(); } - // A dead key was typed: starts or extends the sequence. Returns text to - // type now: what two dead keys composed (´´ → ´), or the accents of a - // sequence the new one can't continue; empty while still pending. + // Dead key pressed: starts or extends the sequence. Returns text to type now: + // - the result if the dead keys composed (´´ → ´) + // - the pending accents if this key can't continue the sequence + // - empty while the sequence is still pending QString press(quint32 deadKeysym); - // `text` typed while pending: the composed character, or the accents - // followed by `text` when nothing composes. Ends the sequence. + // Text key pressed while a sequence is pending. Returns the composed + // character, or the pending accents + `text` if nothing composes. Ends the sequence. QString compose(const QString &text); void cancel(); diff --git a/src/input/HardwareKeys.h b/src/input/HardwareKeys.h index a0eba9d..5a51b57 100644 --- a/src/input/HardwareKeys.h +++ b/src/input/HardwareKeys.h @@ -7,11 +7,12 @@ class InputEngine; -// The "hold keys" mode: the keyboard acts like a hardware one. A key is down -// while the finger is, so apps see held keys (games, Shift+click, the -// system's key repeat). Shift, Ctrl, Alt, Super and AltGr are plain keys, caps lock -// is the system's, and dead keys compose in the app; none of the touch -// conveniences (sticky shift, auto-capitalization, accents) apply. +// "Hold keys" mode: behaves like a hardware keyboard. +// - a key is pressed while touched and released on lift, so apps see held +// keys (games, Shift+click, system key repeat) +// - Shift, Ctrl, Alt, Super and AltGr are normal keys; caps lock is the system's +// - dead keys are sent as-is and composed by the app +// - no sticky modifiers, auto-capitalization or long-press accents class HardwareKeys { public: @@ -25,7 +26,7 @@ public: // Lets go of everything still down, e.g. when the mode is turned off. void releaseAll(); - // For the view: shift and AltGr shown while held, caps lock while on. + // For the view: shift/AltGr are on while held, caps lock while active. KeyLevel keyLevel() const; bool isShiftHeld() const; bool isCapsLockOn() const { return m_capsLock; } diff --git a/src/input/KeyboardController.cpp b/src/input/KeyboardController.cpp index 6dba600..23adf27 100644 --- a/src/input/KeyboardController.cpp +++ b/src/input/KeyboardController.cpp @@ -14,10 +14,10 @@ static_assert(int(KeyboardController::ShiftMode::Locked) == int(ShiftState::Mode namespace { // Enough history for the text rules; fields may report megabytes. constexpr qsizetype MaxTextBefore = 256; -// Stands for text we can't see: neither a sentence start nor a word, so no -// rule fires on it. For fields that don't report text, after cursor moves. +// Placeholder for unknown text before the cursor (field doesn't report text, +// or the cursor moved). Neither a sentence start nor a word, so no text rule triggers. constexpr QChar UnknownText = u'\uFFFC'; -// Like a hardware key: no word mode, a faster rate than Backspace. +// Same as a hardware key repeat: no word mode, faster than Backspace. constexpr KeyRepeater::Timing KeysymRepeat{.intervalMs = 50, .wordModeAfterMs = std::numeric_limits::max()}; } @@ -72,7 +72,7 @@ void KeyboardController::keyDown(const KeyDef &key, qint64 timeMs) break; case KeyType::Backspace: if (m_deadKeys.isPending()) { - m_deadKeys.cancel(); // backspace takes back the accent + m_deadKeys.cancel(); // backspace discards the pending accent } else if (m_modifiers.active()) { sendKey(XKB_KEY_BackSpace); } else { @@ -156,7 +156,7 @@ void KeyboardController::keyCancelled(const KeyDef &key) void KeyboardController::slideReleased(const KeyDef &target, qint64 timeMs) { - holdKey(target, true); // only in hold-keys mode: the slide never pressed it + holdKey(target, true); // hold-keys mode only: the slide target was never pressed, press it now keyUp(target, KeyOutput::Primary, {}, timeMs); m_model.setLayer(m_layerBeforeSwitch); } @@ -190,7 +190,7 @@ void KeyboardController::setContext(const TextContext &context) if (context.hasSurroundingText) { m_textBefore = context.textBeforeCursor.right(MaxTextBefore); } else if (m_context.hasSurroundingText) { - // The field stopped reporting (an input-method reset): what we knew is stale. + // The field stopped reporting text (input-method reset): drop the tracked text. m_deadKeys.cancel(); m_textBefore.clear(); } @@ -220,8 +220,8 @@ void KeyboardController::typeCharacter(const KeyDef &key, KeyOutput output, cons { const QString base = key.type == KeyType::Space ? QStringLiteral(" ") : key.label; if (m_modifiers.active()) { - // A shortcut such as Ctrl+C: the key's unshifted symbol, with modifiers; - // for a dead key its dead keysym, as the physical key sends. + // Shortcut such as Ctrl+C: send the key's unshifted keysym with modifiers + // (for a dead key, its dead keysym, same as the physical key). m_deadKeys.cancel(); sendKey(key.dead ? key.dead : xkb_utf32_to_keysym(base.toLower().toUcs4().value(0))); return; @@ -229,7 +229,7 @@ void KeyboardController::typeCharacter(const KeyDef &key, KeyOutput output, cons const KeyLevel level = keyLevel(); if (level.altGr) { - // Used up by this key, like a one-shot shift. + // Clear one-shot modifiers, like a one-shot shift. m_modifiers.keyTyped(); modifiersUpdated(); } @@ -295,7 +295,7 @@ void KeyboardController::deleteBackward(bool wholeWord) autoCapitalize(); } -// Only the key that started the repeat stops it; another finger's key doesn't. +// Only releasing the key that started the repeat stops it, not another finger's key. void KeyboardController::stopRepeating(const KeyDef &key) { if (key.keysym == m_repeatingKeysym) diff --git a/src/input/KeyboardController.h b/src/input/KeyboardController.h index d12f529..aa71cbb 100644 --- a/src/input/KeyboardController.h +++ b/src/input/KeyboardController.h @@ -19,15 +19,15 @@ class LayoutModel; // Which of a key's outputs the gesture selected. enum class KeyOutput { Primary, Flick, Alternate }; -// Keyboard rules: what each key does, shift and the other modifiers, dead -// keys, layers and the iOS conveniences (auto-capitalization, double-space -// period, backspace repeat). Knows nothing about touch or Wayland: it -// receives key presses and text-field context, and talks to an InputEngine. +// Keyboard logic: key actions, shift and other modifiers, dead keys, layers +// and iOS-style typing aids (auto-capitalization, double-space period, +// backspace repeat). Independent of touch and Wayland: input is key presses +// and text-field context, output goes to an InputEngine. // -// With Ctrl, Alt or Super active, keys become shortcuts (keysyms with those -// modifiers) instead of text; AltGr instead types a key's AltGr symbol. Shift joins shortcuts and non-text keys -// (Shift+F5, Shift+Tab, Shift+arrows) only when the user turned it on, not -// when auto-capitalization did. +// With Ctrl, Alt or Super active, keys send shortcuts (keysym + modifiers) +// instead of text. AltGr types the key's AltGr symbol. +// Shift is added to shortcuts and non-text keys (Shift+F5, Shift+Tab, +// Shift+arrows) only if the user enabled it, not if auto-capitalization did. class KeyboardController : public QObject { Q_OBJECT @@ -45,19 +45,19 @@ public: ShiftMode shiftMode() const; QVariantMap modifierModes() const; - // Hold-keys mode: no long-press, flick or trackpad gestures, no rollover. + // Hold-keys mode disables long-press, flick and trackpad gestures, and rollover. bool holdsKeys() const { return m_options.holdKeys; } void keyDown(const KeyDef &key, qint64 timeMs); void keyUp(const KeyDef &key, KeyOutput output, const QString &alternate, qint64 timeMs); void keyCancelled(const KeyDef &key); - // Finger slid from a layer key onto `target`: type it, then switch back. + // Finger slid from a layer key onto `target` and lifted: type it, then switch back to the previous layer. void slideReleased(const KeyDef &target, qint64 timeMs); // Space-bar trackpad: move the text cursor by whole steps. void moveCursor(QPoint steps); - // A field was focused (context.field) or unfocused: forget what we knew - // about the text and start over from what it reported. + // Field focused (context.field) or unfocused: discard tracked text and + // start from `context`. void resetContext(const TextContext &context); // The focused field reported new text/content type. void setContext(const TextContext &context); @@ -67,22 +67,22 @@ Q_SIGNALS: void shiftChanged(); void modifiersChanged(); void dismissRequested(); - void nextLayoutRequested(); // the globe key: switching is the system's job - // Hold-keys mode is about to flip: keys still down must be cancelled now, - // under the rules they were pressed with. + void nextLayoutRequested(); // globe key; SystemLayouts does the switch + // Hold-keys mode is about to change: release keys still down now, using + // the mode they were pressed in. void holdKeysAboutToChange(); private: void typeCharacter(const KeyDef &key, KeyOutput output, const QString &alternate); void typeText(const QString &text); - // Sends a non-text key or shortcut with the active modifiers, then uses them up. + // Sends a non-text key or shortcut with the active modifiers, then clears one-shot modifiers. void sendKey(quint32 keysym); Qt::KeyboardModifiers shortcutModifiers() const; KeyLevel keyLevel() const; - // Hold-keys mode: forwards the key to m_hardware; false if it isn't one it presses. + // Hold-keys mode: forwards the key to m_hardware. Returns false if m_hardware doesn't handle it. bool holdKey(const KeyDef &key, bool pressed); void useModifiers(); - // The modifiers changed: refreshes the labels and tells the view. + // Call after modifiers change: updates key labels and notifies the view. void modifiersUpdated(); void deleteBackward(bool wholeWord); void sendRepeatedKeysym(); @@ -105,7 +105,7 @@ private: QString m_layerBeforeSwitch; TextContext m_context; - // Best guess of the text before the cursor: the field's last report plus - // what we typed since. Fields that don't report text rely on the latter. + // Estimated text before the cursor: the field's last report plus what we + // typed since. For fields that don't report text, only what we typed. QString m_textBefore; }; diff --git a/src/input/KeyboardSurface.cpp b/src/input/KeyboardSurface.cpp index 3c4cb00..792a732 100644 --- a/src/input/KeyboardSurface.cpp +++ b/src/input/KeyboardSurface.cpp @@ -104,13 +104,13 @@ void KeyboardSurface::pointerDown(int id, QPointF pos, qint64 timeMs) m_lastEventMs = timeMs; if (!m_model || !m_controller) return; - // A press for an id still down means its release was lost. + // A press for an id that is already down means its release was lost. if (const auto stale = m_pointers.constFind(id); stale != m_pointers.cend()) { const Pointer pointer = *stale; m_pointers.erase(stale); cancel(pointer); } - // Rollover would let go of keys still held, which hold-keys mode must not. + // No rollover in hold-keys mode: it would release keys that are still held. if (!m_controller->holdsKeys()) commitPendingTaps(timeMs); @@ -179,7 +179,7 @@ void KeyboardSurface::longPressElapsed(int id, quint64 serial) if (it->tracker.gesture() == Gesture::Trackpad) setTrackpadActive(true); else if (it->tracker.gesture() == Gesture::LongPress) - openAlternates(Pointer(*it), m_lastEventMs); // a copy: opening may erase from m_pointers + openAlternates(Pointer(*it), m_lastEventMs); // copy: openAlternates() may erase from m_pointers } // --- Gesture outcomes @@ -198,7 +198,7 @@ void KeyboardSurface::finish(const Pointer &pointer, qint64 timeMs) m_controller->keyUp(key, tracker.flickCommitted() ? KeyOutput::Flick : KeyOutput::Primary, {}, timeMs); break; case Gesture::LongPress: { - // Without the popup (it never opened), the key types its primary output. + // Popup never opened: type the key's primary output. const QString alternate = ownsAlternates(pointer) ? m_alternates.selectedText() : QString(); if (ownsAlternates(pointer)) closeAlternates(); @@ -230,7 +230,7 @@ void KeyboardSurface::cancel(const Pointer &pointer) m_controller->keyCancelled(pointer.tracker.key()); } -// Clears the visual state a pointer left on the model. +// Clears the pointer's pressed/hover state in the model. void KeyboardSurface::release(const Pointer &pointer) { m_model->setPressed(pointer.index, false); @@ -261,12 +261,12 @@ void KeyboardSurface::updateSlideHover(Pointer &pointer) pointer.hoverIndex = hover; } -// One popup: a second long-press first finishes the one showing it, as a new -// press commits pending taps. +// Only one popup at a time: a second long-press first commits the open popup, +// the same way a new press commits pending taps. void KeyboardSurface::openAlternates(const Pointer &pointer, qint64 timeMs) { if (pointer.index < 0) - return; // the layout changed under the finger: no key to place it over + return; // layer changed during the press: the key is gone for (auto it = m_pointers.begin(); it != m_pointers.end(); ++it) { if (it->serial != pointer.serial && ownsAlternates(*it)) { const Pointer owner = *it; diff --git a/src/input/KeyboardSurface.h b/src/input/KeyboardSurface.h index 5d5c5e2..c0e8083 100644 --- a/src/input/KeyboardSurface.h +++ b/src/input/KeyboardSurface.h @@ -10,10 +10,9 @@ #include #include -// Receives all touch points (and the mouse) over the keyboard, runs one -// PointerTracker per finger, and turns finished gestures into controller -// calls. Several fingers can type at once: a new press commits pending taps -// (rollover), as on iOS. +// Handles touch points and the mouse over the keyboard. Runs one +// PointerTracker per finger and turns finished gestures into controller calls. +// Rollover (as on iOS): a new press commits the other fingers' pending taps. class KeyboardSurface : public QQuickItem { Q_OBJECT @@ -22,8 +21,8 @@ class KeyboardSurface : public QQuickItem Q_PROPERTY(KeyboardController *controller READ controller WRITE setController NOTIFY controllerChanged) Q_PROPERTY(AlternatesPicker *alternates READ alternates CONSTANT) Q_PROPERTY(bool trackpadActive READ isTrackpadActive NOTIFY trackpadActiveChanged) - // Room above the surface that long-press popups may use; taller keys put - // top-row popups lower, over their key, instead of cutting them off. + // Space above the surface available to long-press popups. If a popup + // doesn't fit, it is moved down over its key instead of being clipped. Q_PROPERTY(qreal popupHeadroom MEMBER m_popupHeadroom NOTIFY popupHeadroomChanged) public: @@ -53,10 +52,10 @@ protected: private: struct Pointer { - PointerTracker tracker; // holds a copy of the key: layers may change mid-press + PointerTracker tracker; // has its own copy of the key: the layer may change mid-press int index = -1; // pressed key in the model, -1 once the layer changed int hoverIndex = -1; // key under the finger while sliding - quint64 serial = 0; // tells a reused touch id from the original + quint64 serial = 0; // distinguishes a reused touch id from the original }; void pointerDown(int id, QPointF pos, qint64 timeMs); @@ -82,7 +81,7 @@ private: quint64 m_alternatesSerial = 0; // the pointer the popup belongs to QHash m_pointers; quint64 m_nextSerial = 1; - qint64 m_lastEventMs = 0; // timers have no event time; they use this + qint64 m_lastEventMs = 0; // timestamp of the last event; used as "now" in timer callbacks bool m_trackpadActive = false; qreal m_popupHeadroom = std::numeric_limits::max(); }; diff --git a/src/input/Modifiers.h b/src/input/Modifiers.h index 841d6bd..bd831e5 100644 --- a/src/input/Modifiers.h +++ b/src/input/Modifiers.h @@ -9,19 +9,19 @@ #include // Ctrl, Alt, Super and AltGr, each sticky like shift (see ShiftState): tap -// for the next key, double-tap to lock, hold while typing with another finger. -// The first three turn keys into shortcuts; AltGr picks their AltGr symbols. +// for the next key, double-tap to lock, or hold while typing with another finger. +// Ctrl/Alt/Super make keys send shortcuts; AltGr selects their AltGr symbols. class Modifiers { public: // Names as used in layouts: "ctrl", "alt", "super", "altgr". void press(const QString &name, qint64 timeMs); void release(const QString &name); - // A key was typed: one-shot modifiers are used up. + // Call after a key is typed: clears one-shot modifiers. void keyTyped(); void clear(); - // Ctrl, Alt and Super: what makes a key a shortcut. + // Active Ctrl/Alt/Super, i.e. the ones that make a key a shortcut. Qt::KeyboardModifiers active() const; bool isAltGrActive() const; // name → ShiftState::Mode as int, for the view. diff --git a/src/input/PointerTracker.cpp b/src/input/PointerTracker.cpp index 25f16f4..a96bf97 100644 --- a/src/input/PointerTracker.cpp +++ b/src/input/PointerTracker.cpp @@ -29,7 +29,7 @@ void PointerTracker::moveTo(QPointF pos) if (m_key.type == KeyType::LayerSwitch) { m_gesture = Gesture::Slide; } else if (m_config.gestures && m_key.type == KeyType::Space && qAbs(delta.x()) > qAbs(delta.y())) { - // From the press point: the slop counts towards the first step. + // Measured from the press point, so the slop distance counts towards the first step. m_gesture = Gesture::Trackpad; m_trackpadOrigin = m_start; m_trackpadLines = false; @@ -68,7 +68,7 @@ QPoint PointerTracker::takeTrackpadSteps() return {}; const QPointF travel = m_position - m_trackpadOrigin; - // Truncate towards zero so jitter around the origin doesn't step. + // Truncate towards zero so jitter around the origin doesn't produce steps. const int rows = m_trackpadLines ? int(travel.y() / m_config.trackpadRowStep) : 0; const QPoint total(int(travel.x() / m_config.trackpadStep), rows); const QPoint steps = total - m_trackpadStepsTaken; diff --git a/src/input/PointerTracker.h b/src/input/PointerTracker.h index 8e5f9a6..20bcd5f 100644 --- a/src/input/PointerTracker.h +++ b/src/input/PointerTracker.h @@ -8,7 +8,7 @@ // Gesture recognition for one finger on one key. Pure logic: the caller feeds // positions and tells it when the long-press delay has elapsed. // -// Tap pressed, not (yet) anything else +// Tap pressed, no other gesture recognized (yet) // Flick moved down on a key with a flick symbol // LongPress held still on a key with alternates // Trackpad held still on space; movement moves the text cursor. Sliding diff --git a/src/input/ShiftState.cpp b/src/input/ShiftState.cpp index d76f616..d354b62 100644 --- a/src/input/ShiftState.cpp +++ b/src/input/ShiftState.cpp @@ -2,8 +2,8 @@ void ShiftState::press(qint64 timeMs) { - // Locks whatever the first tap did: at a sentence start that tap turns - // auto-shift off, and the second must still lock. + // A double tap always locks, even when the first tap turned auto-shift off + // (at a sentence start). const bool doubleTap = timeMs - m_lastPress <= DoubleTapMs && !m_lastPressUnlocked; m_lastPress = timeMs; m_lastPressUnlocked = m_mode == Mode::Locked; @@ -28,7 +28,7 @@ void ShiftState::release() void ShiftState::characterTyped() { - m_lastPress = NoPress; // shift, type, shift is not a double tap + m_lastPress = NoPress; // shift, type, shift must not count as a double tap m_userChoice = false; if (m_held) m_typedWhileHeld = true; diff --git a/src/input/ShiftState.h b/src/input/ShiftState.h index ce2142c..fd2af48 100644 --- a/src/input/ShiftState.h +++ b/src/input/ShiftState.h @@ -18,20 +18,19 @@ public: Mode mode() const { return m_mode; } bool isActive() const { return m_mode != Mode::Off; } - // Whether shift joins shortcuts and non-text keys (Shift+F5): only when - // tapped or held by the user. Neither auto-capitalization nor caps lock - // does, as on a PC. + // Whether shift is added to shortcuts and non-text keys (Shift+F5): only + // if the user tapped or held it, not for auto-capitalization or caps lock (as on a PC). bool appliesToShortcuts() const { return m_held || (m_mode == Mode::Once && !m_automatic); } void press(qint64 timeMs); void release(); void characterTyped(); - // Auto-capitalization hint; ignored while shift is held or locked. A shift - // the user tapped stays until a character is typed or the hint changes, - // so a field re-reporting the same context doesn't undo it. + // Auto-capitalization hint; ignored while shift is held or locked. A + // user-tapped shift is kept until a character is typed or the hint value + // changes, so the field re-sending the same context doesn't reset it. void setAutomatic(bool capitalize); - // A new field: the user's shift choice no longer applies. + // New field focused: discard the user's manual shift. void forgetUserChoice() { m_userChoice = false; } // Caps lock key: locks, or unlocks if locked. void toggleLock(); @@ -43,7 +42,7 @@ private: bool m_userChoice = false; // the user set the mode since the last character bool m_held = false; bool m_typedWhileHeld = false; - bool m_lastPressUnlocked = false; // a tap leaving caps lock doesn't start a double tap + bool m_lastPressUnlocked = false; // the tap that unlocks caps lock must not start a double tap static constexpr qint64 NoPress = std::numeric_limits::min() / 2; qint64 m_lastPress = NoPress; }; diff --git a/src/input/TextRules.h b/src/input/TextRules.h index 229db19..a6b5e47 100644 --- a/src/input/TextRules.h +++ b/src/input/TextRules.h @@ -2,7 +2,7 @@ #include -// Pure text heuristics behind the iOS conveniences. +// Text heuristics for the iOS-style typing aids. No state. namespace TextRules { // True at the start of a sentence: empty text, after a newline, or after diff --git a/src/layout/KeyGeometry.cpp b/src/layout/KeyGeometry.cpp index 077b063..4e36e1f 100644 --- a/src/layout/KeyGeometry.cpp +++ b/src/layout/KeyGeometry.cpp @@ -13,7 +13,7 @@ qreal blockUnits(const Block &block) return units; } -// Key widths in units once stretch keys take up the row's slack. +// Key widths in units, after stretch keys are widened to fill the row. QList stretchedWidths(const Row &row, qreal targetUnits) { const auto stretchy = std::ranges::count_if(row, &KeyDef::stretch); @@ -44,7 +44,7 @@ qreal totalUnits(const QList &blocks) qsizetype totalRows(const QList &blocks) { - // Filling blocks only count when nothing else is shown. + // fillHeight blocks are ignored, unless all blocks are fillHeight. const bool allFill = std::ranges::all_of(blocks, &Block::fillHeight); qsizetype rows = 0; for (const Block &block : blocks) { @@ -78,7 +78,7 @@ QList computeKeyRects(const QList &blocks, QSizeF size, KeyboardM const auto rows = block.rows.size(); const qreal span = block.fillHeight ? innerHeight : spanOf(std::max(rows, block.minRows)); const qsizetype fixed = std::min(block.fixedRows, rows); - // Rows after the fixed ones share what's left; with none, the block sits at the bottom. + // Rows after fixedRows split the remaining height; if there are none, the block is bottom-aligned. const qreal flexHeight = rows > fixed ? (span - qreal(fixed) * (sharedRowHeight + metrics.gap) - qreal(rows - fixed - 1) * metrics.gap) / qreal(rows - fixed) diff --git a/src/layout/KeyGeometry.h b/src/layout/KeyGeometry.h index c122131..ef9cdd4 100644 --- a/src/layout/KeyGeometry.h +++ b/src/layout/KeyGeometry.h @@ -12,8 +12,8 @@ struct KeyboardMetrics { }; // The keys on screen: blocks of rows, side by side. -// A block can reserve room (minUnits, minRows) so that swapping its rows, e.g. -// switching layers, moves nothing else; its keys stretch into the room. +// A block can reserve space (minUnits, minRows), so swapping its rows (e.g. +// switching layers) doesn't move other blocks. Its keys stretch to fill it. struct Block { QList rows; bool fillHeight = false; // spans the full height instead of max(rows, minRows) shared rows diff --git a/src/layout/KeymapKeys.h b/src/layout/KeymapKeys.h index 45090f1..f247cfe 100644 --- a/src/layout/KeymapKeys.h +++ b/src/layout/KeymapKeys.h @@ -34,5 +34,5 @@ struct KeymapKeys { KeymapKeys readKeymapKeys(xkb_keymap *keymap, quint32 layoutIndex); -// What a dead key shows and types when nothing composes: ´ for dead_acute. +// Spacing accent for a dead keysym, used as its label and when nothing composes: ´ for dead_acute. QString deadKeyText(quint32 keysym); diff --git a/src/layout/LayoutBuilder.cpp b/src/layout/LayoutBuilder.cpp index 531accb..f4d3960 100644 --- a/src/layout/LayoutBuilder.cpp +++ b/src/layout/LayoutBuilder.cpp @@ -19,7 +19,7 @@ const QHash &baseOverrides() return bases; } -// "š" → "s": the letter an accented letter is a variant of. +// Base letter of an accented letter: "š" → "s". QString baseLetter(const QString &letter) { if (const auto it = baseOverrides().constFind(letter); it != baseOverrides().cend()) @@ -41,7 +41,7 @@ KeyDef characterKey(const KeymapKey &source) return key; } -// The compact letter rows: letters only, and not the keys some keyboards lack. +// Compact-mode letter rows: letters only, without keys missing on some keyboards (BKSL, LSGT). QList letterKeys(const KeymapKeys &keymap, int row, const QStringList &flicks) { QList keys; @@ -49,7 +49,7 @@ QList letterKeys(const KeymapKeys &keymap, int row, const QStringList &f if (!source.isLetter() || source.position != KeymapKey::Position::Regular) continue; KeyDef key = characterKey(source); - // iPad letters always uppercase; the keymap may shift some to a symbol (sk: ô → "). + // Shifted letters are always uppercased (as on iPad), even where the keymap's shift level is a symbol (sk: ô → "). key.shifted = source.lower.toUpper(); key.deadShifted = 0; key.flick = flicks.value(keys.size()); @@ -58,13 +58,13 @@ QList letterKeys(const KeymapKeys &keymap, int row, const QStringList &f return keys; } -// A full row: every typing key, the shifted symbol shown (and flickable) above; -// for letters, whose shift only capitalizes, the AltGr symbol (sk: ' on j). -// `withLessGreater` tells whether the ISO key left of Z is among them. +// Full-mode row: every typing key. The secondary (flick) symbol is the shifted +// symbol, or for letters (where shift only capitalizes) the AltGr symbol (sk: ' on j). +// `withLessGreater` is set if the row contains the ISO key left of Z. QList rowKeys(const KeymapKeys &keymap, int row, bool *withLessGreater) { *withLessGreater = false; - QSet elsewhere; // LSGT often repeats a pair that exists elsewhere (US: < >) + QSet elsewhere; // LSGT often duplicates symbols on other keys (US: < >) for (const auto &keys : keymap.rows) { for (const KeymapKey &key : keys) { if (key.position != KeymapKey::Position::LessGreater) @@ -78,7 +78,7 @@ QList rowKeys(const KeymapKeys &keymap, int row, bool *withLessGreater) continue; *withLessGreater |= source.position == KeymapKey::Position::LessGreater; KeyDef key = characterKey(source); - // Show (and flick for) a shifted level that isn't just the capital letter: ! on 1, " on sk ô. + // Use the shifted level as the flick symbol unless it's just the capital letter: ! on 1, " on sk ô. if (!source.deadUpper && source.upper != source.lower && source.upper != source.lower.toUpper()) key.flick = source.upper; else if (!source.deadAltGr && source.altGr != source.lower) @@ -97,7 +97,7 @@ Row expandPlaceholders(const Row &row, const KeymapKeys &keymap) else if (key.type == KeyType::Keys) { bool withLessGreater = false; const QList keys = rowKeys(keymap, key.lettersRow, &withLessGreater); - // As on ISO keyboards, that key takes its room from the one before it (left shift). + // As on ISO keyboards, LSGT's width is taken from the key before it (left shift). if (withLessGreater && !result.isEmpty()) result.back().width = std::max(1.0, result.back().width - 1); result += keys; @@ -108,9 +108,9 @@ Row expandPlaceholders(const Row &row, const KeymapKeys &keymap) return result; } -// Long-press choices per letter: the keymap's letters that have no letter key -// first (they're what this language types), then the template's. Letters on the -// number row (sk: ť) stay choices in full mode too: they're out of the way there. +// Long-press choices per letter: first the keymap's letters that have no key of +// their own in the letter rows (the language's own letters), then the template's. +// Number-row letters (sk: ť) are kept as choices in full mode too, since the number row is hard to reach. void addAlternates(Layer &layer, const Layout &tmpl, const KeymapKeys &keymap) { QSet onKeys; diff --git a/src/layout/LayoutBuilder.h b/src/layout/LayoutBuilder.h index 1ef7372..f4aef38 100644 --- a/src/layout/LayoutBuilder.h +++ b/src/layout/LayoutBuilder.h @@ -8,7 +8,7 @@ enum class KeyboardMode { Full, // iPad Pro / PC: number row, punctuation, tab, modifiers }; -// Turns the template into the layout shown: picks each layer's rows for the -// mode, fills the keymap placeholders, and gives letters their long-press -// choices (letters of the keymap without a key of their own come first). +// Builds the displayed layout from the template: picks each layer's rows for +// the mode, fills the keymap placeholders, and assigns long-press choices to +// letters (keymap letters without their own key first). Layout buildLayout(const Layout &tmpl, const KeymapKeys &keymap, KeyboardMode mode = KeyboardMode::Compact); diff --git a/src/layout/LayoutModel.cpp b/src/layout/LayoutModel.cpp index 58fe978..c08ca48 100644 --- a/src/layout/LayoutModel.cpp +++ b/src/layout/LayoutModel.cpp @@ -49,7 +49,7 @@ QVariant LayoutModel::data(const QModelIndex &index, int role) const const QRectF rect = m_rects.value(index.row()); switch (role) { case LabelRole: return key.text(m_keyLevel); - // A shifted or AltGr key may already show its flick symbol (! on 1): don't repeat it. + // Hide the flick symbol if the main label already shows it (shifted or AltGr: ! on 1). case FlickLabelRole: return key.flick == key.text(m_keyLevel) ? QString() : key.flick; case ModifierRole: return key.modifier; case KeyTypeRole: return keyTypeName(key.type); @@ -185,7 +185,7 @@ QList LayoutModel::composeBlocks() const main.rows += section.rows; } if (layer && shown(MainSectionId)) { - // Room for the biggest layer, so switching layers keeps the other blocks still. + // Reserve space for the largest layer, so switching layers doesn't move other blocks. main.fixedRows = main.rows.size(); for (const Layer &other : m_layout.layers) { main.minRows = std::max(main.minRows, main.fixedRows + other.rows.size()); @@ -202,7 +202,7 @@ QList LayoutModel::composeBlocks() const if (section.placement == Section::Placement::Right && shown(section.id)) blocks.append({section.rows, section.fillHeight}); } - // Never show nothing. + // If no block is shown, fall back to the current layer. if (blocks.isEmpty() && layer) blocks.append({layer->rows}); return blocks; diff --git a/src/main.cpp b/src/main.cpp index 2d4cb59..faab350 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -46,8 +46,8 @@ std::optional loadTemplate() return std::nullopt; } -// The shown layout is the template filled with the active system layout's -// keys. Returns the rebuild, for settings that change the result. +// Builds the displayed layout from the template and the active system layout. +// Returns the rebuild function, for settings that affect the result. std::function connectLayouts(const Layout &tmpl, WaylandKeymap &keymap, SystemLayouts &systemLayouts, const Settings &settings, KeyboardController &controller, LayoutModel &model) { @@ -63,7 +63,7 @@ std::function connectLayouts(const Layout &tmpl, WaylandKeymap &keymap, return rebuild; } -// Settings that add or remove keys resize the window so keys keep their size. +// Settings that add or remove keys resize the window, so key size stays the same. void connectKeySettings(Settings &settings, LayoutModel &model, FloatingWindow &placement, const QQuickWindow &window, const std::function &rebuild) { @@ -83,7 +83,7 @@ void connectKeySettings(Settings &settings, LayoutModel &model, FloatingWindow & [keepingKeySize, rebuild] { keepingKeySize(rebuild); }); } -// The shrunk button's geometry isn't the keyboard's: not saved. +// Geometry isn't saved while collapsed (it's the button's, not the keyboard's). void restoreAndPersistGeometry(FloatingWindow &placement, WindowSettings &settings, const CollapseController &collapse) { if (const auto geometry = settings.load(placement.screenName())) @@ -94,8 +94,8 @@ void restoreAndPersistGeometry(FloatingWindow &placement, WindowSettings &settin }); } -// A focused field shows the keyboard only if KWin's policy wants one now; -// asked before showing, so a "no" doesn't flash the keyboard. +// On field focus, ask KWin's policy first and show the keyboard only if it +// agrees. Asking before showing avoids a brief flash when the answer is no. void connectFieldFocus(VisibilityController &visibility, KWinInputMethod &backend, KWinVirtualKeyboard &policy) { QObject::connect(&backend, &TextBackend::activeChanged, &visibility, [&] { @@ -105,7 +105,7 @@ void connectFieldFocus(VisibilityController &visibility, KWinInputMethod &backen } policy.askShowOnActive(&visibility, [&](bool show) { if (!backend.isActive()) - return; // left the field before KWin answered + return; // field lost focus before KWin answered visibility.setShowOnField(show); visibility.setFieldActive(true); }); @@ -118,14 +118,14 @@ void connectFieldFocus(VisibilityController &visibility, KWinInputMethod &backen void connectVisibility(VisibilityController &visibility, KWinInputMethod &backend, const Settings &settings, FloatingWindow &placement) { - // First, so the initial state below reaches the window too. + // Connect first, so the initial state set below is applied to the window. QObject::connect(&visibility, &VisibilityController::visibleChanged, &placement, [&](bool visible) { visible ? placement.show() : placement.hide(); }); visibility.setAlwaysVisible(settings.alwaysVisible()); QObject::connect(&settings, &Settings::alwaysVisibleChanged, &visibility, [&] { visibility.setAlwaysVisible(settings.alwaysVisible()); }); - // Without the input-method global (run outside KWin's control, e.g. for UI - // work) there is no focus signal: stay visible so it can be tried out. + // Without the input-method global (not launched by KWin, e.g. during UI + // development) there are no focus events: stay visible. const auto updateStandalone = [&] { visibility.setStandalone(!backend.isAvailable()); }; QObject::connect(&backend, &KWinInputMethod::availableChanged, &visibility, updateStandalone); updateStandalone(); @@ -154,10 +154,10 @@ void connectTextContext(KWinInputMethod &backend, KeyboardController &controller int main(int argc, char *argv[]) { blockQuitSignals(); - // libwayland unsets it once connected. + // Read before connecting: libwayland unsets it. const bool launchedByKWin = qEnvironmentVariableIsSet("WAYLAND_SOCKET"); QGuiApplication app(argc, argv); - // KWin relaunches it only after a crash: a closed window mustn't quit it. + // Don't quit when the window closes: KWin only restarts the input method after a crash. QGuiApplication::setQuitOnLastWindowClosed(false); quitOnSignal(); QGuiApplication::setApplicationName(QStringLiteral("sloposk")); diff --git a/src/settings/DebouncedStore.h b/src/settings/DebouncedStore.h index d0b4a37..196ec8b 100644 --- a/src/settings/DebouncedStore.h +++ b/src/settings/DebouncedStore.h @@ -4,8 +4,8 @@ #include #include -// QSettings writes that arrive in bursts (dragging a slider or the window), -// saved once the burst ends instead of on every step. Flushes on destruction. +// Debounced QSettings writes: values that change rapidly (slider or window +// drag) are saved once changes stop. Flushes on destruction. class DebouncedStore : public QObject { Q_OBJECT diff --git a/src/settings/Settings.h b/src/settings/Settings.h index 4d7ba51..dfa6ea8 100644 --- a/src/settings/Settings.h +++ b/src/settings/Settings.h @@ -44,7 +44,7 @@ public: void setHoldKeys(bool enabled); QStringList visibleSections() const { return m_visibleSections; } - // Hiding the last visible section is refused: something must stay on screen. + // Refuses to hide the last visible section. Q_INVOKABLE void setSectionVisible(const QString &id, bool visible); bool fullKeyboard() const { return m_fullKeyboard; } diff --git a/src/window/CollapseController.cpp b/src/window/CollapseController.cpp index 0bf6cb8..37bbf46 100644 --- a/src/window/CollapseController.cpp +++ b/src/window/CollapseController.cpp @@ -37,7 +37,7 @@ bool CollapseController::collapse() m_expandedSize = m_window.size(); m_collapsed = true; Q_EMIT collapsedChanged(); - // After the next frame, once the compositor knows the lower minimum size. + // Wait one frame, so the compositor has the new (lower) minimum size before the resize. connect(&m_window, &QQuickWindow::frameSwapped, this, [this] { if (m_collapsed) m_placement.moveResize(m_keyRect, false); @@ -50,10 +50,10 @@ void CollapseController::expand() if (!m_collapsed || m_expanding.isActive()) return; if (roughlyEqual(m_window.size(), m_expandedSize)) { - finishExpanding(); // never shrank: nothing to move + finishExpanding(); // window never shrank: nothing to resize return; } - // Stays collapsed until the window has grown, so the keys don't flash squeezed. + // Stay collapsed until the window has grown, so the keys aren't drawn squeezed. m_placement.moveResize(QRectF(-m_keyRect.topLeft(), m_expandedSize), true); m_expanding.start(); } @@ -68,7 +68,7 @@ void CollapseController::finishExpanding() { m_expanding.stop(); if (!roughlyEqual(m_window.size(), m_expandedSize)) - m_window.resize(m_expandedSize); // no KWin to do it + m_window.resize(m_expandedSize); // KWin didn't resize (timeout): resize directly m_collapsed = false; Q_EMIT collapsedChanged(); } diff --git a/src/window/CollapseController.h b/src/window/CollapseController.h index 59f941c..61f5785 100644 --- a/src/window/CollapseController.h +++ b/src/window/CollapseController.h @@ -8,15 +8,16 @@ class FloatingWindow; class QQuickWindow; -// Shrinks the keyboard window to just its dismiss key, floating on its own, -// and grows it back with the key under the button again (kept on screen). -// The window itself shrinks, so it can be dragged anywhere and covers -// nothing else. QML draws from `collapsed` and `keyRect`. +// Collapses the keyboard window to the size of its dismiss key (a floating +// button) and expands it back, positioned so the dismiss key is where the +// button was (clamped to the screen). The window itself is resized, so the +// button can be dragged anywhere and covers nothing else. +// QML uses `collapsed` and `keyRect`. class CollapseController : public QObject { Q_OBJECT Q_PROPERTY(bool collapsed READ isCollapsed NOTIFY collapsedChanged) - // The key in the full window; the button stays there until the window shrinks. + // Dismiss key rect in the full window. The button is drawn there until the window has shrunk. Q_PROPERTY(QRectF keyRect READ keyRect NOTIFY collapsedChanged) public: @@ -41,5 +42,5 @@ private: bool m_collapsed = false; QRectF m_keyRect; QSize m_expandedSize; - QTimer m_expanding; // waits for KWin; runs out without it + QTimer m_expanding; // timeout for KWin's resize; fires if KWin never resizes }; diff --git a/src/window/FloatingWindow.cpp b/src/window/FloatingWindow.cpp index 8664357..ea922a3 100644 --- a/src/window/FloatingWindow.cpp +++ b/src/window/FloatingWindow.cpp @@ -22,7 +22,7 @@ FloatingWindow::FloatingWindow(QWindow *window, QObject *parent) bool FloatingWindow::eventFilter(QObject *watched, QEvent *event) { - // Exposed means mapped, so KWin knows the window by now. + // Exposed implies mapped, so KWin knows the window at this point. if (watched == m_window && event->type() == QEvent::Expose) { if (m_window->isExposed() && !m_exposed) moveResize(QRectF(QPointF(), m_window->size()), true); @@ -107,8 +107,8 @@ void FloatingWindow::startResize(Qt::Edges edges) releaseMouse(); } -// The window manager keeps the button's release: without one, the pressed -// item holds on to the mouse and eats the next press. +// After a system move/resize the window never gets the mouse release. Send +// one, otherwise the pressed item keeps the mouse grab and swallows the next press. void FloatingWindow::releaseMouse() { if (!(QGuiApplication::mouseButtons() & Qt::LeftButton)) diff --git a/src/window/FloatingWindow.h b/src/window/FloatingWindow.h index 00e8816..d549802 100644 --- a/src/window/FloatingWindow.h +++ b/src/window/FloatingWindow.h @@ -6,12 +6,12 @@ class QWindow; -// Makes a keyboard window a frameless, always-on-top window that never takes -// focus. The window manager places it and moves it (Super+drag included); -// on KWin Wayland that relies on the rule from installKWinRule(). -// Each time it appears, it's moved back on screen: KWin remembers where it -// was, which may be somewhere it was smaller. Geometry is relative to the -// window's screen. +// Makes the keyboard window frameless, always on top and never focused. +// The window manager places and moves it (including Super+drag); on KWin +// Wayland this needs the rule from installKWinRule(). +// On each show, the window is moved back onto the screen: KWin restores the +// last position, which may be off-screen at the current size. +// Geometry is relative to the window's screen. class FloatingWindow : public QObject { Q_OBJECT @@ -27,9 +27,9 @@ public: // Grows from the top-left corner; respects the window's minimum size. Q_INVOKABLE void resizeBy(qreal dw, qreal dh); - // Moves the window by `relative`'s offset and resizes it to its size, - // optionally clamped to the screen's free area. Done by KWin (Wayland - // clients can't place themselves), so it applies later. + // Moves the window by `relative`'s offset and resizes it to `relative`'s + // size, optionally clamped to the screen's available area. Done by KWin + // (Wayland clients can't position themselves), so it's asynchronous. void moveResize(const QRectF &relative, bool keepOnScreen); // Only this part of the window takes input; the rest passes through. Q_INVOKABLE void setInputRegion(const QRectF ®ion); diff --git a/src/window/KWinScript.cpp b/src/window/KWinScript.cpp index c1cd8cb..6944504 100644 --- a/src/window/KWinScript.cpp +++ b/src/window/KWinScript.cpp @@ -31,7 +31,7 @@ void runKWinScript(const QString &source) { static int count = 0; const QString plugin = QStringLiteral("sloposk-%1").arg(++count); - // Unloading from within: `stop` right after `run` could beat the script. + // The script unloads itself: calling `stop` right after `run` could unload it before it runs. const QString unload = QStringLiteral("\ncallDBus(\"%1\", \"%2\", \"%3\", \"unloadScript\", \"%4\");\n") .arg(Service, ScriptingPath, ScriptingInterface, plugin); diff --git a/src/window/VisibilityController.h b/src/window/VisibilityController.h index d72862b..7135884 100644 --- a/src/window/VisibilityController.h +++ b/src/window/VisibilityController.h @@ -3,13 +3,12 @@ #include #include -// Decides whether the keyboard is shown: -// - while a text field is focused, if the system wants a keyboard for it -// - always, if the user wants it (to type into any window) or when running -// standalone (no input-method connection) -// - show()/hide()/toggle() override that until the focus changes, also -// from one field straight to another -// - never while the system's virtual keyboard toggle is off +// Decides whether the keyboard is visible: +// - hidden while the system virtual keyboard toggle is off (overrides everything) +// - show()/hide()/toggle() override the rules below until the next focus change +// (including focus moving directly from one field to another) +// - shown if "always visible" is set, or when standalone (no input-method connection) +// - shown while a text field is focused, if KWin's policy allows it class VisibilityController : public QObject { Q_OBJECT @@ -19,13 +18,14 @@ public: bool isVisible() const { return m_visible; } - // Called on every focus change, even when a field follows a field. + // Call on every focus change, including field-to-field. void setFieldActive(bool active); - // KWin's policy (off, or touch only) for fields focused from now on. + // Whether KWin's policy (disabled / touch only) allows showing for the focused field. void setShowOnField(bool show); void setStandalone(bool standalone); void setAlwaysVisible(bool always); - // The system toggle (KWin's tray icon); off hides it whatever else says. + // System virtual keyboard toggle (KWin tray icon). When false, the keyboard + // is always hidden, regardless of the other settings. Clears show()/hide() overrides. void setEnabled(bool enabled); void show(); diff --git a/src/window/WindowSettings.h b/src/window/WindowSettings.h index a26a8b3..ccb09b2 100644 --- a/src/window/WindowSettings.h +++ b/src/window/WindowSettings.h @@ -6,8 +6,8 @@ #include #include -// Remembers the keyboard's geometry per screen (~/.config/sloposk.conf). -// Saving is debounced so dragging doesn't hammer the disk. +// Stores the keyboard's geometry per screen (~/.config/sloposk/sloposk.conf). +// Saving is debounced, so dragging doesn't write on every step. class WindowSettings : public QObject { Q_OBJECT diff --git a/tests/tst_controller.cpp b/tests/tst_controller.cpp index f6ea324..dd452bb 100644 --- a/tests/tst_controller.cpp +++ b/tests/tst_controller.cpp @@ -443,7 +443,7 @@ private Q_SLOTS: QCOMPARE(controller->modifierModes().value(u"ctrl"_s).toInt(), 1); controller->setOptions({}); // turned off while held QVERIFY(engine.held.isEmpty()); - controller->keyUp(ctrl, KeyOutput::Primary, {}, 10); // back to sticky rules: harmless + controller->keyUp(ctrl, KeyOutput::Primary, {}, 10); // released under sticky rules: no effect QVERIFY(engine.held.isEmpty()); } diff --git a/tests/tst_keyboardsurface.cpp b/tests/tst_keyboardsurface.cpp index b2d26a6..1037211 100644 --- a/tests/tst_keyboardsurface.cpp +++ b/tests/tst_keyboardsurface.cpp @@ -131,11 +131,11 @@ private Q_SLOTS: QTest::touchEvent(&window, touchscreen).press(0, e); QTest::qWait(LongPressWaitMs); QTest::touchEvent(&window, touchscreen).stationary(0).press(1, u); - QTest::qWait(LongPressWaitMs); // u's popup replaces e's, which types its choice + QTest::qWait(LongPressWaitMs); // u's popup opens; e's popup closes and types its selection QCOMPARE(engine.output, u"é"); QVERIFY(surface->alternates()->isOpen()); QTest::touchEvent(&window, touchscreen).release(0, e).stationary(1); - QCOMPARE(engine.output, u"é"); // the first finger's lift does nothing more + QCOMPARE(engine.output, u"é"); // lifting the first finger types nothing more QVERIFY(surface->alternates()->isOpen()); QTest::touchEvent(&window, touchscreen).release(1, u); QCOMPARE(engine.output.size(), 2); diff --git a/tests/tst_visibility.cpp b/tests/tst_visibility.cpp index 693e84d..4961f6f 100644 --- a/tests/tst_visibility.cpp +++ b/tests/tst_visibility.cpp @@ -79,7 +79,7 @@ private Q_SLOTS: v.show(); QVERIFY(!v.isVisible()); v.hide(); - v.setEnabled(true); // turning it back on forgets the dismiss + v.setEnabled(true); // re-enabling clears the earlier hide() QVERIFY(v.isVisible()); }