Commit Graph
10 Commits
Author SHA1 Message Date
jatinkrmalikandSbenazar 3e4089a45c fix(ibus): handle engine instance destruction on layout switch (fixes #388, closes #389)
Override do_destroy() to clear _active_instance when IBus destroys the
engine on keyboard layout switch (Super+Space). Add retry logic in
inject_text() — on NO_ENGINE, re-activates via switch_engine() and
retries once to recover cleanly.

Co-authored-by: Sbenazar <127324689+Sbenazar@users.noreply.github.com>
2026-05-02 17:33:42 -07:00
Jatin K MalikandGitHub 45a69d5946 test(ibus): cover socket-readiness timeout warning branch (#384)
Add a test for the for/else warning path in _setup_engine() introduced
in PR #361: when all 15 socket-readiness poll attempts exhaust without
SOCKET_PATH appearing, a WARNING is logged and activation is attempted
anyway. The new test mocks time.sleep to avoid real delays and asserts
the exact retry count (15) and log message.

Fixes Codecov patch-coverage gap reported on #361.
2026-04-05 17:37:47 -07:00
SbenazarandGitHub c4f5b797ce fix(ibus): start engine process before checking registration (fixes #360) (#361)
* fix(ibus): start engine process before checking registration

_setup_engine() gated on is_engine_registered() which queries
`ibus list-engine`. On systems where the IBus daemon doesn't scan
user-level component directories (~/.local/share/ibus/component/),
the engine never appeared in the list, blocking start_engine_process()
from ever being called — even though its register_component() D-Bus
call is the correct registration path for standalone-launched engines.

Reorder _setup_engine() to start the engine process first, relying on
register_component() for runtime registration. Remove the XML
install step from the setup path since install_ibus_component()
triggers `ibus restart` which kills the engine process.

Follow-up to PR #304 which added register_component() support.

* fix(ibus): remove dead code and add engine readiness check

Address review feedback:
- Remove install_ibus_component(), is_engine_registered(),
  is_component_up_to_date(), _get_expected_component_xml()
  and their tests — no longer called after setup order fix
- Add SOCKET_PATH poll after start_engine_process() to verify
  engine is fully initialized before activation
- Rebase onto current main
2026-04-05 17:31:35 -07:00
Jatin K MalikandGitHub 93032471c3 fix(ibus): detect IBus on Wayland without env vars and fix text injection (#381)
Fix two related IBus issues on KDE Plasma Wayland (and similar DEs):

1. IBus not detected without legacy environment variables:
   On Wayland, IBus is configured via the DE's Virtual Keyboard setting
   and IBus itself recommends unsetting GTK_IM_MODULE / QT_IM_MODULE.
   The detection logic only checked these env vars, so it never found
   IBus on a properly configured Wayland session.

   Fix: When no IM env vars are set, check if ibus-daemon is running
   and has an active engine. If another IM (e.g. Fcitx) is explicitly
   configured via env vars, respect that and don't override.

2. IBus text injection silently fails on Wayland:
   After switching to the Vocalinux IBus engine, the code called
   setxkbmap to capture/restore the keyboard layout. On Wayland,
   setxkbmap does not reflect the compositor's state and returns
   incorrect results (e.g. 'us' when the user has 'de'). Calling
   setxkbmap to restore this wrong layout interfered with IBus's
   ability to commit text, causing silent injection failures.

   Fix: Skip setxkbmap-based XKB layout management entirely on
   Wayland sessions. The Wayland compositor manages keyboard layouts
   natively, and setxkbmap can only cause harm there.

Fixes #380
2026-04-03 15:47:55 -07:00
Jatin K MalikandGitHub 9ba63484c2 fix(keyboard): preserve XKB layout when activating Vocalinux IBus engine (fixes #292) (#343)
* fix(keyboard): preserve XKB layout when activating Vocalinux IBus engine

When Vocalinux starts, it may start or restart the IBus daemon, which
can override the user's system-level keyboard layout with IBus's
configured layout (often defaulting to US).

This fix captures the current XKB layout before activating the
Vocalinux IBus engine and restores it after activation, ensuring
users with non-US keyboard layouts don't lose their settings.

Fixes #292

* fix(keyboard): restore XKB layout after engine activation, not just on shutdown (#292)

The draft PR only restored the user's XKB layout when Vocalinux shut
down. The French AZERTY reporter confirmed the real problem: switching
to the Vocalinux IBus engine overrides the system keyboard layout
immediately, so typing 'a' produces 'q' (AZERTY mapped through US
QWERTY). The same applies to Spanish and other non-US layouts.

Changes:
- Restore XKB layout immediately after IBus engine activation in
  _setup_engine(), not just in stop(). This preserves the user's
  keyboard layout while Vocalinux is actively running.
- Remove the 'layout != us' guard in stop() -- always restore
  whatever layout was captured, including US with custom options.
- Fix 4 broken tests: wrong expected options values, missing
  TimeoutExpired argument, incorrect call count assertion.
- Add test cases for Spanish and French AZERTY layouts.

* test(keyboard): add coverage for XKB layout capture/restore in IBusTextInjector

Addresses Codecov report on PR #343 - adds tests covering:
- stop() restores captured XKB layout (Spanish with variant/options)
- stop() skips restore when no layout was captured
- _setup_engine() captures XKB layout and restores it after engine activation (French AZERTY)

* fix(test): mock start_engine_process in setup_engine XKB test

The test was missing a mock for start_engine_process, causing it to
fail on CI where the IBus engine PID file path doesn't exist.
2026-03-27 14:31:00 -07:00
Jatin K MalikandGitHub bcd6d94eea fix(text-injection): detect if IBus is the active input method before using it (#277)
* fix(text-injection): detect if IBus is the active input method before using it

This commit fixes issue #249 where Vocalinux incorrectly tries to use
IBus for text injection when IBus is installed but not configured as
the active input method (e.g., user uses ydotool on Arch + KDE Plasma 6).

Changes:
- Add is_ibus_active_input_method() function that checks GTK_IM_MODULE,
  QT_IM_MODULE, and XMODIFIERS environment variables to determine if
  IBus is the active input method
- Update _check_dependencies() to skip IBus when it's not the active
  input method, falling back to ydotool/wtype/xdotool instead
- Add comprehensive unit tests for the new functionality

The fix ensures Vocalinux will use the appropriate text injection
method based on the user's actual input method configuration,
rather than just checking if IBus is installed.

Fixes #249

* test: fix existing tests to mock is_ibus_active_input_method

* test: add comprehensive test coverage for is_ibus_active_input_method

Add additional tests to ensure complete coverage of the new functionality:

- Edge cases for empty string env vars
- Case-insensitive detection for all three env vars
- Priority ordering (GTK > Qt > XMODIFIERS)
- X11 fallback when IBus is not active input method
- Exception handling during IBus setup falls back correctly

Total tests: 62 (was 54), all passing.
2026-02-28 17:08:47 -08:00
59455098d3 fix(ibus): raise exception on setup failure to enable fallback (#240)
* fix(ibus): raise exception on setup failure to enable fallback

- Add IBusSetupError exception class for detailed error context
- Modify _setup_engine() to raise exception instead of silent return
- Ensures text_injector.py fallback mechanism works when IBus fails
- Add unit tests for IBusSetupError and setup failure scenarios

Fixes silent IBus text injection failures on Wayland/Fedora reported in #34

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* test(text-injector): add tests for IBus setup failure fallback

- Test that TextInjector falls back to xdotool when IBus fails
- Test fallback on both X11 and Wayland environments
- Test that text injection still works after IBus failure

Related to #34

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

---------

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-02-21 00:39:19 -08:00
Jatin K MalikandGitHub 79c3ca7f88 feat(text-injection): extend IBus support to X11 for non-US keyboard layouts (#227)
IBus sends Unicode directly via commit_text(), bypassing keyboard layout
issues entirely. This provides the same reliable text injection on X11
that we already have on Wayland.

Changes:
- Add X11_IBUS desktop environment enum
- Prefer IBus on both X11 and Wayland (before falling back to xdotool)
- Add tests for X11 IBus preference and fallback behavior

This supersedes the layout-switching approach in PR #206, which only
worked on X11 and had overhead from layout switching.

Closes #199
2026-02-17 22:40:20 -08:00
Jatin K MalikandGitHub 0da4e74005 fix(test): add missing mocks for IBus engine test (#226)
* fix(test): add missing mocks for IBus engine test

The test_init_auto_activate test was missing mocks for:
- install_ibus_component
- start_engine_process

Without these mocks, the test would fail in CI where IBus is not
installed, as _setup_engine() would fail early and never reach
switch_engine().

* style: fix black formatting in test_ibus_engine.py
2026-02-17 22:26:38 -08:00
a1725f7cfc feat(text-injection): add IBus engine for Wayland text injection (#211)
* feat(text-injection): add IBus engine for Wayland text injection

Add a custom IBus input method engine for reliable text injection on
Wayland, solving keyboard layout issues with xdotool/wtype.

Key features:
- IBus proxy engine that passes through normal keyboard input
- Text injection via Unix socket IPC
- User-level component installation (no sudo required)
- Auto-reactivation when user switches keyboard layouts
- Graceful fallback when IBus is unavailable

Changes:
- New ibus_engine.py with VocalinuxEngine and IBusTextInjector
- TextInjector now prefers IBus on Wayland for best compatibility
- Add IBus GObject bindings to system dependencies in install.sh
- Add comprehensive tests for IBus engine

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* security: secure IBus socket with permissions and peer verification

- Set directory to 0o700 (owner-only access)
- Set socket to 0o600 (owner-only read/write)
- Add SO_PEERCRED verification to reject connections from other users

This provides defense-in-depth: even if directory permissions are
bypassed, the socket server verifies the connecting process UID.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: address PR review feedback for IBus text injection

- Fix infinite loop in socket server by adding _server_running flag
- Use sys.executable instead of hardcoded python3 for venv compatibility
  - Also inherit environment (env=os.environ.copy()) for venv deps
  - Fix component XML to use sys.executable in <exec> tag
- Replace unsafe pgrep with PID file tracking and /proc verification
- Integrate TextInjector.stop() in TrayIndicator._quit() for cleanup
- Remove unused is_engine_registered import
- Fix redundant hasattr check to use proper None comparison
- Auto-detect and update stale IBus component XML on startup

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: AntoineMontane <monnet.antoine@gmail.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-17 22:15:06 -08:00