Skip to content

feat(plugins): add Keymoji offline emoji keyboard - #206

Open
eduardoaugustolb wants to merge 12 commits into
Ryoku-dev:mainfrom
eduardoaugustolb:feat/keymoji
Open

eduardoaugustolb wants to merge 12 commits into
Ryoku-dev:mainfrom
eduardoaugustolb:feat/keymoji

Conversation

@eduardoaugustolb

@eduardoaugustolb eduardoaugustolb commented Nov 9, 2026 •

Copy link
Copy Markdown
Contributor

Keymoji 0.4.0

Adds a community QS Bar emoji keyboard with offline search across 3,944 Emoji 17.0 sequences in Portuguese, English, Spanish and French. Includes localized CLDR dictionaries, Unicode attribution, Tabler icons and their licences, a Qt-rendered preview, and a catalogue entry.

The menu supports insertion into the original target, copy-only selection, and choosing the last-used emoji without copying or typing. Its header identifies the active mode. Search receives focus on opening; arrows, paging, Home/End and Enter navigate/select. Dismissal immediately releases input and unmaps the surface; compositor animations own opening/closing. Theme, language and internal motion follow Ryoku settings, including reduced-motion and low-power preferences.

A resident windowless service pastes the latest recent emoji and serializes a bounded repeat queue. It uses wl-copy and the fixed, manifest-declared keymoji-paste command. The bundled portable implementation sends Ctrl+V with wtype; a desktop integration may provide the same declared command through normal PATH resolution. No environment variable selects an executable path, and no compositor-specific IPC is included in the plugin. Desktop shortcuts are configured locally by the contributor; the plugin installs none automatically.

Runtime requires Quickshell, wtype, wl-copy and the declared shell utilities. Bun is development-only. State writes are confined to the plugin state directory. Palette/language references to shell.json are read-only and documented for static-screen review. No network access, privileged commands, automatic keybind edits or security-policy changes are added.

Validation

  • 29 Bun tests passed, including search, complete emoji sequences, insertion/history guards, localization, navigation, palette and motion.
  • Catalogue validation passed; product file hashes and the registry hash are refreshed.
  • Native isolated-state checks verified copy-only/selection-only side effects and normal-mode reset, using a failing/logging insertion stub.
  • Native checks verified that the removed executable-selection environment variable is ignored and that the declared portable paste command sends fixed Ctrl+V arguments.
  • Earlier live Wayland checks verified focus/navigation/dismissal, theme/motion, locale switching/persistence, and complete emoji pastes into a disposable Obsidian input. The user confirmed the physical last-emoji shortcut after the local desktop integration was configured.
  • Client interoperability limits and the distinction between backend process success and actual text delivery remain documented in plugins/keymoji/docs/validation.md.

Maintained by Eduardo Augusto; this is community content, not an official Ryoku product. Ongoing maintenance remains the contributor's responsibility.

@neur0map neur0map left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 mika reviewed this change; details in the walkthrough comment.

🧹 Nitpicks (5) — optional, not blocking
  1. plugins/keymoji/app/i18n/Locale.mjs:3-7 — Bug — The desktop language is documented as accepting Auto, but normalize("auto") returns auto as a supported locale. Treat it as unset so resolve falls through to the process locale instead of selecting a nonexistent…

    Suggested change

export function normalize(value) {
    const name=String(value||'').trim().toLowerCase().replace(/_/g,'-').split(/[.@]/)[0];
    if(name==='c'||name==='posix')return 'en';
    const base=name.split('-')[0];return languages.indexOf(base)>0?base:null;
}
  1. plugins/keymoji/app/Search.mjs:39-44 — Performance — Every query splits the searchable text and can run fuzzy matching against every word in all 3,944 entries on the QML thread. Short queries with few matches can therefore block keyboard interaction repeatedly after each d…

  2. plugins/keymoji/app/shell.qml:151-160 — Possible Bug — If wtype cannot start, for example because it is missing, onExited is not sufficient to clear busy and report the failure. The keyboard can then remain stuck in its inserting state. Handle process start errors and…

  3. plugins/keymoji/app/Search.mjs:41-45 — Suggestion: bug — Match emoji within longer sequences

    Suggested change

if(r.e.includes(query.trim()))score+=80;
else if(words.indexOf(t)>=0) score+=80;
else if(words.some(w=>w.indexOf(t)===0))score+=40;
else if(r.search.indexOf(t)>=0)score+=15;
else if(words.some(w=>near(t,w)))score+=5;
else return null;
  1. plugins/keymoji/app/i18n/Locale.mjs:3-7 — Suggestion: bug — Treat auto as an unset locale

    Suggested change

export function normalize(value) {
    const name=String(value||'').trim().toLowerCase().replace(/_/g,'-').split(/[.@]/)[0];
    if(name==='c'||name==='posix')return 'en';
    const base=name.split('-')[0];return languages.indexOf(base)>0?base:null;
}

@neur0map

neur0map commented Nov 10, 2026 •

Copy link
Copy Markdown
Member

🦊 mika's review

Incremental review: new commits since the last checkpoint.

Summary

  • Add Keymoji, an offline emoji keyboard for the QS Bar.
  • Search localized emoji names and keywords in four languages.
  • Insert selections with focus guards and support repeatable last-emoji paste.
  • Follow Ryoku theme and motion preferences; keep history locally.

Estimated review effort: 2/5 · risk: high

📁 Walkthrough details

plugins/keymoji/app/shell.qml

  • Adds the layer-shell picker, localized search grid, keyboard navigation, favorites, and recents.
  • Releases input on dismissal and checks the remembered target before insertion.
    • Loads the catalogue and active locale; persists history in plugin state.
    • Inserts selections through wtype without changing the clipboard.

plugins/keymoji/app/insert-last.qml

  • Adds a windowless service for pasting the most recent emoji without opening the picker.
    • Serializes a bounded request queue and cancels on target changes or backend failure.
    • Copies with wl-copy and pastes using wtype or an optional helper.

plugins/keymoji/bin/keymoji

  • Adds the launcher and IPC commands for toggling, opening, closing, and last-emoji insertion.
    • Creates and passes the plugin state directory to Quickshell.

plugins/keymoji/app/Search.mjs

  • Indexes localized catalogue entries and ranks searches by names, keywords, emoji, and code points.
    • Supports accent folding, simple typos, categories, favorites, and recents.

plugins/keymoji/app/Input.mjs

  • Validates insertion sequences and rejects missing or changed targets.
    • Extracts the first recent sequence for last-emoji paste.

plugins/keymoji/app/Navigation.mjs

  • Adds column-aware grid navigation, boundary handling, and paging.
    • Keeps selection within the available results.

plugins/keymoji/app/Localization.qml

  • Resolves and persists the plugin language while watching Ryoku's desktop language.
    • Stores the preference in the plugin state directory.

plugins/keymoji/app/i18n/Locale.mjs

  • Resolves language precedence from plugin preference, desktop language, and process locale.
    • Normalizes supported locales and falls back to English.

plugins/keymoji/app/i18n/Messages.mjs

  • Adds interface and category translations for Portuguese, English, Spanish, and French.
    • Provides localized labels, status messages, and insertion errors.

plugins/keymoji/app/LanguagePicker.qml

  • Adds a themed language selector with an automatic environment-based option.
    • Applies the selected language through the shared localization component.

plugins/keymoji/app/Theme.qml

  • Watches Ryoku theme, shell palette, and wallpaper colors for the picker.
    • Exposes adaptive color roles with fallback colors.

plugins/keymoji/app/Motion.qml

  • Reads desktop and performance settings and refreshes effective motion defaults through ryoku-hub.
    • Exposes resolved timings and curves for internal transitions.

plugins/keymoji/app/MotionConfig.mjs

  • Resolves inherited animation settings, curves, and separate layer fade channels.
    • Honors animation, motion-speed, reduced-motion, and low-power settings.

plugins/keymoji/service/Main.qml

  • Connects the PluginKit panel to the launcher with the host-provided state directory.
    • Closes the bar panel when launching the picker.

plugins/keymoji/content/Widget.qml

  • Adds the QS Bar keyboard glyph and panel toggle.
    • Uses the PluginKit accent color.

plugins/keymoji/content/Panel.qml

  • Adds a localized bar panel with a button to open Keymoji.
    • Reads the same language preference as the picker.

plugins/keymoji/manifest.json

  • Declares the community plugin, QS Bar entry points, dependencies, and packaged files.
    • Declares no network or privileged capabilities.

plugins/keymoji/product-manifest.json

  • Records package file hashes, permissions, sizes, and installation flags.
    • Excludes development tests, package metadata, and preview from installation.

plugins/keymoji/docs/validation.md

  • Documents reported unit and Wayland checks alongside remaining client interoperability coverage.
    • Describes focus, motion, localization, and last-emoji paste validation.

plugins/registry.json

  • Adds Keymoji 0.4.0 to the community plugin catalogue.
    • Links the preview, upstream source, and product manifest hash.

No actionable findings. Mika looked for bugs, security issues, and risks in the diff and came up empty on clear defects.

⚠️ Security concerns: The paste helper allows execution of an undeclared environment-selected program.

🚦 Merge recommendation: changes_required


🦊 Generated by Mika — the Ryoku org's self-hosted AI code reviewer. Machine findings: verify before merging.

@neur0map

Copy link
Copy Markdown
Member

I've reviewed 5 pushes on this PR automatically, so I'll stop doing full passes here and only check whether open threads get fixed. Add the mika:review label or comment @ryoku-mika review for another full review.

@eduardoaugustolb

eduardoaugustolb commented Nov 10, 2026 •

Copy link
Copy Markdown
Contributor Author

Addressed the remaining security concern in the latest walkthrough:

  • Removed KEYMOJI_PASTE_HELPER executable-path selection.
  • The service now invokes only the fixed keymoji-paste command, explicitly declared in the manifest's dependencies and commands.
  • Included bin/keymoji-paste with the portable wtype implementation. The launcher adds the bundled bin directory as a PATH fallback; a user-installed desktop integration may supply the same declared command through normal PATH resolution.
  • Native isolated-state checks verified that an executable supplied through the removed environment variable is never invoked, and that the bundled fallback passes only the fixed Ctrl+V arguments.

The original review's Auto-locale items (duplicates), repeated search tokenization/fuzzy work, process-start failure handling, and matching emoji within longer sequences are also addressed. There are no GitHub review threads to mark resolved; these findings were posted in review/walkthrough summaries.

Validation: 29 Bun tests passed, catalogue validation passed, and the local plugin validator has no blocking findings after reviewing the two existing read-only shell.json references. Evidence and remaining interoperability limits are in plugins/keymoji/docs/validation.md.

@ryoku-mika review
@neur0map

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants