From 99146577d45e494a08a1ffa20be65c519b220d62 Mon Sep 17 00:00:00 2001 From: Thomas Date: Sat, 17 Oct 2026 02:42:09 +0200 Subject: [PATCH] New locale --- AGENTS.md | 78 ++++++++++++++++ README.md | 32 +++++++ po/de.po | 66 ++++++------- po/de.po~ | 102 --------------------- po/en.po | 131 ++++++++++++++++++++++++++ po/es.po | 67 ++++++-------- po/es.po~ | 100 -------------------- po/fr.po | 71 +++++++------- po/fr.po~ | 100 -------------------- po/gkeymapper.pot | 96 ++++++++++++------- src/main.cpp | 229 ++++++++++++++++++++++++++++++++++++++++++++-- 11 files changed, 614 insertions(+), 458 deletions(-) create mode 100644 AGENTS.md delete mode 100644 po/de.po~ create mode 100644 po/en.po delete mode 100644 po/es.po~ delete mode 100644 po/fr.po~ diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..947b734 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,78 @@ +# AGENTS.md + +## What this is +A pure GTK4 C++ GUI for remapping the G1–G9 keys of a Logitech G910. Today it +only edits and persists mappings: there is **no** hardware G-key detection and +**no** command execution yet (a native daemon is the planned next step). The +whole program is one translation unit, `src/main.cpp`. + +## Build / run / verify +- `make` — builds the `gkeymapper` binary **and** the `.mo` catalogs. + Needs `g++` (C++17), `make`, `gettext`, `libgtk-4-dev` (see README for + `apt install` on a fresh machine). +- `make translations` — only runs `msgfmt` on the existing `.po` files. +- `make run` — builds, then runs with `GKEYMAPPER_LOCALEDIR=$PWD/locale` and + `GKEYMAPPER_ASSETS_DIR=$PWD/assets` so the working-tree translations and + assets are used. Plain `./gkeymapper` works too (assets fall back to + `./assets`). +- `make clean` — deletes the binary and the generated `locale/` tree. +- No tests and no CI. Verify changes by building and running the app. + +## i18n — easy to get wrong +- English is the source language (the `msgid`) **and** also has an explicit + identity catalog `po/en.po`. Languages: `de`, `en`, `es`, `fr`. +- `make translations` does **not** regenerate the `.pot`. When you add or change + a UI string, edit `po/gkeymapper.pot` and `po/*.po` by hand, then run + `make translations`; validate with `msgfmt --check -o /dev/null po/.po`. +- Never edit the generated `.mo` files under `locale/` (gitignored). Delete any + `po/*.po~` backups before committing. +- All documentation and source comments are English. German appears only inside + `po/de.po`. + +## Code layout and conventions +- `src/main.cpp` holds everything in an anonymous namespace. The global `rows` + vector keeps one `KeyRow` (widget pointers) per G key. `on_activate` registers + the app actions `app.export-config`, `app.import-config`, `app.about`; + `build_ui` constructs the window. App id: `com.example.gkeymapper`. +- The Type dropdown index is meaningful everywhere: `0=Key`, `1=Command`, + `2=Disabled`. Keep that order — import/export map against it. +- The capture dialog's `CaptureSession` is heap-allocated and freed only by the + window's `"destroy"` handler. Always close the dialog with + `gtk_window_destroy` so the session is released. +- Use GTK4 API only: `gtk_editable_set_text` / `gtk_editable_get_text` (there is + no `gtk_entry_set_text`), `gtk_window_destroy` (no `gtk_dialog_run`), + `G_APPLICATION_FLAGS_NONE`. +- The main window is intentionally **non-resizable** and has **no** + `GtkScrolledWindow` (one collapsed the rows earlier). Keep the fixed widths + (Type dropdown 150 px, target entry 440 px min, action button 180 px) so rows + do not jump when the language changes. +- Because it is pure GTK4 it follows the system theme (Mint-Y ships a + `gtk-4.0` theme). Do **not** add the `suggested-action` CSS class — Mint-Y + tints it green and it clashes with the rest of the layout. + +## Config file format +`Save mappings` writes `~/.config/gKeyMapper/mappings.conf`; Export/Import use +the same format: + +``` +G1=key:ctrl+c,ctrl+v +G2=command:/usr/bin/firefox +G3=disabled: +``` + +`:`, one line per key. `key` is a captured sequence (lowercase +`gdk_keyval_name` output; modifiers joined with `+`, steps joined with `,`), +`command` is a program/file path, `disabled` is inactive. + +## Assets +`find_asset()` resolves in order: `$GKEYMAPPER_ASSETS_DIR` → `./assets` → +compiled-in `ASSETS_DIR` (`/usr/local/share/gkeymapper/assets`). The icon +(`assets/icon.png`) is used in the header bar and the About dialog. + +## Driving the GUI for manual checks +There is no `xdotool`/`wtype` on this machine, and the capture-dialog buttons +(`Clear`/`Cancel`/`Done`) expose an empty AT-SPI accessible name — the text is in +a child `label` node, so target the button by its child label. `pyatspi` +(`queryAction().doAction(0)`) plus `Xlib`'s `xtest.fake_input` can click buttons +and inject keys. Warn the user before synthesizing keystrokes or stealing window +focus. diff --git a/README.md b/README.md index 11ca5fd..6aae0da 100644 --- a/README.md +++ b/README.md @@ -81,6 +81,38 @@ make clean Removes the binary and the generated `locale/` directory. +## Capturing key sequences + +For rows of type **Key**, the action button opens a capture dialog: + +- Press keys one after another; each press becomes one step. +- Modifier keys (Ctrl, Alt, Shift, Super) held during a press are recorded + as part of that step. +- The live preview shows the sequence. `Clear` resets it, `Done` writes it + into the row, `Cancel` discards it. + +The sequence uses the same format as +[g910-gkey-macro-support](https://github.com/JSubelj/g910-gkey-macro-support): +modifiers are joined with `+`, steps are separated with `,` +(e.g. `ctrl+c,ctrl+v` or `shift+f4,super+t`). + +## Configuration format + +`Save mappings` writes `~/.config/gKeyMapper/mappings.conf`: + +``` +# gKeyMapper mappings (G1..G9) +G1=key:ctrl+c,ctrl+v +G2=command:/usr/bin/firefox +G3=disabled: +``` + +The same format is used by Export/Import. `key` holds a captured shortcut +sequence, `command` a program or file path, `disabled` ignores the G key +(similar to the `shortcut` / `run` / `nothing` hotkey types of the +reference project above; a native C++ daemon for G-key detection and +replay is planned next, no Python involved). + ## Project structure ``` diff --git a/po/de.po b/po/de.po index ec32863..33320ae 100644 --- a/po/de.po +++ b/po/de.po @@ -6,8 +6,8 @@ msgid "" msgstr "" "Project-Id-Version: gkeymapper 0.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-10-16 21:53+0200\n" -"PO-Revision-Date: 2026-10-16 21:00+0000\n" +"POT-Creation-Date: 2026-10-16 22:12+0200\n" +"PO-Revision-Date: 2026-10-16 22:12+0200\n" "Last-Translator: \n" "Language-Team: German\n" "Language: de\n" @@ -15,124 +15,116 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: src/main.cpp:53 msgid "Choose file" msgstr "Datei auswählen" -#: src/main.cpp:56 src/main.cpp:224 src/main.cpp:236 msgid "_Cancel" msgstr "_Abbrechen" -#: src/main.cpp:57 src/main.cpp:237 msgid "_Open" msgstr "_Öffnen" -#: src/main.cpp:75 -msgid "" -msgstr "" +msgid "No keys recorded yet" +msgstr "Noch keine Tasten aufgezeichnet" + +msgid "Capture key sequence" +msgstr "Tastensequenz aufnehmen" + +msgid "Clear" +msgstr "Leeren" + +msgid "Cancel" +msgstr "Abbrechen" + +msgid "Done" +msgstr "Fertig" + +msgid "" +"Press keys in order (modifiers like Ctrl, Alt, Shift and Super are recorded " +"too). Click Done to apply or Cancel to discard." +msgstr "" +"Tasten der Reihe nach drücken (Modifikatoren wie Strg, Alt, Shift und Super " +"werden mit aufgezeichnet). Mit Fertig übernehmen oder mit Abbrechen verwerfen." -#: src/main.cpp:87 msgid "Choose file..." msgstr "Datei auswählen..." -#: src/main.cpp:89 src/main.cpp:364 +msgid "e.g. /usr/bin/firefox or custom command" +msgstr "z. B. /usr/bin/firefox oder eigener Befehl" + msgid "Capture" msgstr "Aufnehmen" -#: src/main.cpp:125 +msgid "e.g. ctrl+c, ctrl+v" +msgstr "z. B. Strg+C, Strg+V" + #, c-format msgid "Could not save %s.\n" msgstr "Konnte %s nicht speichern.\n" -#: src/main.cpp:129 msgid "Mappings saved to " msgstr "Mappings gespeichert nach " -#: src/main.cpp:135 #, c-format msgid "Could not open %s.\n" msgstr "Konnte %s nicht öffnen.\n" -#: src/main.cpp:187 msgid "Could not export mappings.\n" msgstr "Mappings konnten nicht exportiert werden.\n" -#: src/main.cpp:210 src/main.cpp:273 msgid "gKeyMapper" msgstr "gKeyMapper" -#: src/main.cpp:213 msgid "G-Key mapper for the Logitech G910 (GTK4)." msgstr "G-Key-Mapper für die Logitech G910 (GTK4)." -#: src/main.cpp:221 msgid "Export configuration" msgstr "Konfiguration exportieren" -#: src/main.cpp:225 msgid "_Save" msgstr "_Speichern" -#: src/main.cpp:233 msgid "Import configuration" msgstr "Konfiguration importieren" -#: src/main.cpp:269 msgid "gKeyMapper – Logitech G910" msgstr "gKeyMapper – Logitech G910" -#: src/main.cpp:277 msgid "Export configuration..." msgstr "Konfiguration exportieren..." -#: src/main.cpp:278 msgid "Import configuration..." msgstr "Konfiguration importieren..." -#: src/main.cpp:281 msgid "About" msgstr "Über" -#: src/main.cpp:305 msgid "G1 to G9 of the Logitech G910 remapped to keys or commands" msgstr "G1 bis G9 der Logitech G910 auf Tasten oder Befehle ummappen" -#: src/main.cpp:327 msgid "G-Key" msgstr "G-Taste" -#: src/main.cpp:327 msgid "Type" msgstr "Typ" -#: src/main.cpp:327 msgid "Target (Key/Command)" msgstr "Ziel (Taste/Befehl)" -#: src/main.cpp:327 msgid "Action" msgstr "Aktion" -#: src/main.cpp:335 msgid "Key" msgstr "Taste" -#: src/main.cpp:335 msgid "Command" msgstr "Befehl" -#: src/main.cpp:335 msgid "Disabled" msgstr "Deaktiviert" -#: src/main.cpp:358 -msgid "e.g. ctrl+c or ls -la" -msgstr "z. B. Strg+C oder ls -la" - -#: src/main.cpp:378 msgid "Save mappings" msgstr "Mappings speichern" -#: src/main.cpp:383 msgid "Saved to ~/.config/gKeyMapper/mappings.conf" msgstr "Gespeichert in ~/.config/gKeyMapper/mappings.conf" diff --git a/po/de.po~ b/po/de.po~ deleted file mode 100644 index 48da094..0000000 --- a/po/de.po~ +++ /dev/null @@ -1,102 +0,0 @@ -# German translation for gkeymapper. -# Copyright (C) 2026 -# This file is distributed under the same license as the gkeymapper package. -# -msgid "" -msgstr "" -"Project-Id-Version: gkeymapper 0.1\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-10-16 21:00+0000\n" -"PO-Revision-Date: 2026-10-16 21:00+0000\n" -"Last-Translator: \n" -"Language-Team: German\n" -"Language: de\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" - -msgid "" -msgstr "" - -#, c-format -msgid "Could not save %s.\n" -msgstr "Konnte %s nicht speichern.\n" - -msgid "Mappings saved to " -msgstr "Mappings gespeichert nach " - -#, c-format -msgid "Could not open %s.\n" -msgstr "Konnte %s nicht öffnen.\n" - -msgid "Could not export mappings.\n" -msgstr "Mappings konnten nicht exportiert werden.\n" - -msgid "gKeyMapper" -msgstr "gKeyMapper" - -msgid "G-Key mapper for the Logitech G910 (GTK4)." -msgstr "G-Key-Mapper für die Logitech G910 (GTK4)." - -msgid "Export configuration" -msgstr "Konfiguration exportieren" - -msgid "_Cancel" -msgstr "_Abbrechen" - -msgid "_Save" -msgstr "_Speichern" - -msgid "Import configuration" -msgstr "Konfiguration importieren" - -msgid "_Open" -msgstr "_Öffnen" - -msgid "gKeyMapper – Logitech G910" -msgstr "gKeyMapper – Logitech G910" - -msgid "Export configuration..." -msgstr "Konfiguration exportieren..." - -msgid "Import configuration..." -msgstr "Konfiguration importieren..." - -msgid "About" -msgstr "Über" - -msgid "G1 to G9 of the Logitech G910 remapped to keys or commands" -msgstr "G1 bis G9 der Logitech G910 auf Tasten oder Befehle ummappen" - -msgid "G-Key" -msgstr "G-Taste" - -msgid "Type" -msgstr "Typ" - -msgid "Target (Key/Command)" -msgstr "Ziel (Taste/Befehl)" - -msgid "Action" -msgstr "Aktion" - -msgid "Key" -msgstr "Taste" - -msgid "Command" -msgstr "Befehl" - -msgid "Disabled" -msgstr "Deaktiviert" - -msgid "e.g. ctrl+c or ls -la" -msgstr "z. B. Strg+C oder ls -la" - -msgid "Capture" -msgstr "Aufnehmen" - -msgid "Save mappings" -msgstr "Mappings speichern" - -msgid "Saved to ~/.config/gKeyMapper/mappings.conf" -msgstr "Gespeichert in ~/.config/gKeyMapper/mappings.conf" diff --git a/po/en.po b/po/en.po new file mode 100644 index 0000000..1131c1c --- /dev/null +++ b/po/en.po @@ -0,0 +1,131 @@ +# English translation for gkeymapper. +# Copyright (C) 2026 +# This file is distributed under the same license as the gkeymapper package. +# English is the source language; this catalog keeps the strings explicit. +# +msgid "" +msgstr "" +"Project-Id-Version: gkeymapper 0.1\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2026-10-16 22:12+0200\n" +"PO-Revision-Date: 2026-10-16 22:12+0200\n" +"Last-Translator: \n" +"Language-Team: English\n" +"Language: en\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +msgid "Choose file" +msgstr "Choose file" + +msgid "_Cancel" +msgstr "_Cancel" + +msgid "_Open" +msgstr "_Open" + +msgid "No keys recorded yet" +msgstr "No keys recorded yet" + +msgid "Capture key sequence" +msgstr "Capture key sequence" + +msgid "Clear" +msgstr "Clear" + +msgid "Cancel" +msgstr "Cancel" + +msgid "Done" +msgstr "Done" + +msgid "" +"Press keys in order (modifiers like Ctrl, Alt, Shift and Super are recorded " +"too). Click Done to apply or Cancel to discard." +msgstr "" +"Press keys in order (modifiers like Ctrl, Alt, Shift and Super are recorded " +"too). Click Done to apply or Cancel to discard." + +msgid "Choose file..." +msgstr "Choose file..." + +msgid "e.g. /usr/bin/firefox or custom command" +msgstr "e.g. /usr/bin/firefox or custom command" + +msgid "Capture" +msgstr "Capture" + +msgid "e.g. ctrl+c, ctrl+v" +msgstr "e.g. ctrl+c, ctrl+v" + +#, c-format +msgid "Could not save %s.\n" +msgstr "Could not save %s.\n" + +msgid "Mappings saved to " +msgstr "Mappings saved to " + +#, c-format +msgid "Could not open %s.\n" +msgstr "Could not open %s.\n" + +msgid "Could not export mappings.\n" +msgstr "Could not export mappings.\n" + +msgid "gKeyMapper" +msgstr "gKeyMapper" + +msgid "G-Key mapper for the Logitech G910 (GTK4)." +msgstr "G-Key mapper for the Logitech G910 (GTK4)." + +msgid "Export configuration" +msgstr "Export configuration" + +msgid "_Save" +msgstr "_Save" + +msgid "Import configuration" +msgstr "Import configuration" + +msgid "gKeyMapper – Logitech G910" +msgstr "gKeyMapper – Logitech G910" + +msgid "Export configuration..." +msgstr "Export configuration..." + +msgid "Import configuration..." +msgstr "Import configuration..." + +msgid "About" +msgstr "About" + +msgid "G1 to G9 of the Logitech G910 remapped to keys or commands" +msgstr "G1 to G9 of the Logitech G910 remapped to keys or commands" + +msgid "G-Key" +msgstr "G-Key" + +msgid "Type" +msgstr "Type" + +msgid "Target (Key/Command)" +msgstr "Target (Key/Command)" + +msgid "Action" +msgstr "Action" + +msgid "Key" +msgstr "Key" + +msgid "Command" +msgstr "Command" + +msgid "Disabled" +msgstr "Disabled" + +msgid "Save mappings" +msgstr "Save mappings" + +msgid "Saved to ~/.config/gKeyMapper/mappings.conf" +msgstr "Saved to ~/.config/gKeyMapper/mappings.conf" diff --git a/po/es.po b/po/es.po index 94cc2a3..b3789b3 100644 --- a/po/es.po +++ b/po/es.po @@ -4,8 +4,8 @@ msgid "" msgstr "" "Project-Id-Version: gkeymapper 0.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-10-16 21:53+0200\n" -"PO-Revision-Date: 2026-10-16 21:00+0000\n" +"POT-Creation-Date: 2026-10-16 22:12+0200\n" +"PO-Revision-Date: 2026-10-16 22:12+0200\n" "Last-Translator: \n" "Language-Team: Spanish\n" "Language: es\n" @@ -13,124 +13,117 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: src/main.cpp:53 msgid "Choose file" msgstr "Elegir archivo" -#: src/main.cpp:56 src/main.cpp:224 src/main.cpp:236 msgid "_Cancel" msgstr "_Cancelar" -#: src/main.cpp:57 src/main.cpp:237 msgid "_Open" msgstr "_Abrir" -#: src/main.cpp:75 -msgid "" -msgstr "" +msgid "No keys recorded yet" +msgstr "Aún no se ha registrado ninguna tecla" + +msgid "Capture key sequence" +msgstr "Capturar secuencia de teclas" + +msgid "Clear" +msgstr "Borrar" + +msgid "Cancel" +msgstr "Cancelar" + +msgid "Done" +msgstr "Aceptar" + +msgid "" +"Press keys in order (modifiers like Ctrl, Alt, Shift and Super are recorded " +"too). Click Done to apply or Cancel to discard." +msgstr "" +"Pulsa las teclas en orden (los modificadores como Ctrl, Alt, Mayús y Super " +"también se registran). Haz clic en Aceptar para aplicar o en Cancelar para " +"descartar." -#: src/main.cpp:87 msgid "Choose file..." msgstr "Elegir archivo..." -#: src/main.cpp:89 src/main.cpp:364 +msgid "e.g. /usr/bin/firefox or custom command" +msgstr "p. ej. /usr/bin/firefox o comando personalizado" + msgid "Capture" msgstr "Capturar" -#: src/main.cpp:125 +msgid "e.g. ctrl+c, ctrl+v" +msgstr "p. ej. ctrl+c, ctrl+v" + #, c-format msgid "Could not save %s.\n" msgstr "No se pudo guardar %s.\n" -#: src/main.cpp:129 msgid "Mappings saved to " msgstr "Asignaciones guardadas en " -#: src/main.cpp:135 #, c-format msgid "Could not open %s.\n" msgstr "No se pudo abrir %s.\n" -#: src/main.cpp:187 msgid "Could not export mappings.\n" msgstr "No se pudieron exportar las asignaciones.\n" -#: src/main.cpp:210 src/main.cpp:273 msgid "gKeyMapper" msgstr "gKeyMapper" -#: src/main.cpp:213 msgid "G-Key mapper for the Logitech G910 (GTK4)." msgstr "Asignador de teclas G para el Logitech G910 (GTK4)." -#: src/main.cpp:221 msgid "Export configuration" msgstr "Exportar configuración" -#: src/main.cpp:225 msgid "_Save" msgstr "_Guardar" -#: src/main.cpp:233 msgid "Import configuration" msgstr "Importar configuración" -#: src/main.cpp:269 msgid "gKeyMapper – Logitech G910" msgstr "gKeyMapper – Logitech G910" -#: src/main.cpp:277 msgid "Export configuration..." msgstr "Exportar configuración..." -#: src/main.cpp:278 msgid "Import configuration..." msgstr "Importar configuración..." -#: src/main.cpp:281 msgid "About" msgstr "Acerca de" -#: src/main.cpp:305 msgid "G1 to G9 of the Logitech G910 remapped to keys or commands" msgstr "Reasigna las G1 a G9 del Logitech G910 a teclas o comandos" -#: src/main.cpp:327 msgid "G-Key" msgstr "Tecla G" -#: src/main.cpp:327 msgid "Type" msgstr "Tipo" -#: src/main.cpp:327 msgid "Target (Key/Command)" msgstr "Destino (Tecla/Comando)" -#: src/main.cpp:327 msgid "Action" msgstr "Acción" -#: src/main.cpp:335 msgid "Key" msgstr "Tecla" -#: src/main.cpp:335 msgid "Command" msgstr "Comando" -#: src/main.cpp:335 msgid "Disabled" msgstr "Desactivado" -#: src/main.cpp:358 -msgid "e.g. ctrl+c or ls -la" -msgstr "p. ej. ctrl+c o ls -la" - -#: src/main.cpp:378 msgid "Save mappings" msgstr "Guardar asignaciones" -#: src/main.cpp:383 msgid "Saved to ~/.config/gKeyMapper/mappings.conf" msgstr "Guardado en ~/.config/gKeyMapper/mappings.conf" diff --git a/po/es.po~ b/po/es.po~ deleted file mode 100644 index 2b4933c..0000000 --- a/po/es.po~ +++ /dev/null @@ -1,100 +0,0 @@ -# Spanish translation for gkeymapper. -# -msgid "" -msgstr "" -"Project-Id-Version: gkeymapper 0.1\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-10-16 21:00+0000\n" -"PO-Revision-Date: 2026-10-16 21:00+0000\n" -"Last-Translator: \n" -"Language-Team: Spanish\n" -"Language: es\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" - -msgid "" -msgstr "" - -#, c-format -msgid "Could not save %s.\n" -msgstr "No se pudo guardar %s.\n" - -msgid "Mappings saved to " -msgstr "Asignaciones guardadas en " - -#, c-format -msgid "Could not open %s.\n" -msgstr "No se pudo abrir %s.\n" - -msgid "Could not export mappings.\n" -msgstr "No se pudieron exportar las asignaciones.\n" - -msgid "gKeyMapper" -msgstr "gKeyMapper" - -msgid "G-Key mapper for the Logitech G910 (GTK4)." -msgstr "Asignador de teclas G para el Logitech G910 (GTK4)." - -msgid "Export configuration" -msgstr "Exportar configuración" - -msgid "_Cancel" -msgstr "_Cancelar" - -msgid "_Save" -msgstr "_Guardar" - -msgid "Import configuration" -msgstr "Importar configuración" - -msgid "_Open" -msgstr "_Abrir" - -msgid "gKeyMapper – Logitech G910" -msgstr "gKeyMapper – Logitech G910" - -msgid "Export configuration..." -msgstr "Exportar configuración..." - -msgid "Import configuration..." -msgstr "Importar configuración..." - -msgid "About" -msgstr "Acerca de" - -msgid "G1 to G9 of the Logitech G910 remapped to keys or commands" -msgstr "Reasigna las G1 a G9 del Logitech G910 a teclas o comandos" - -msgid "G-Key" -msgstr "Tecla G" - -msgid "Type" -msgstr "Tipo" - -msgid "Target (Key/Command)" -msgstr "Destino (Tecla/Comando)" - -msgid "Action" -msgstr "Acción" - -msgid "Key" -msgstr "Tecla" - -msgid "Command" -msgstr "Comando" - -msgid "Disabled" -msgstr "Desactivado" - -msgid "e.g. ctrl+c or ls -la" -msgstr "p. ej. ctrl+c o ls -la" - -msgid "Capture" -msgstr "Capturar" - -msgid "Save mappings" -msgstr "Guardar asignaciones" - -msgid "Saved to ~/.config/gKeyMapper/mappings.conf" -msgstr "Guardado en ~/.config/gKeyMapper/mappings.conf" diff --git a/po/fr.po b/po/fr.po index 55e0b78..bb86874 100644 --- a/po/fr.po +++ b/po/fr.po @@ -4,8 +4,8 @@ msgid "" msgstr "" "Project-Id-Version: gkeymapper 0.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-10-16 21:53+0200\n" -"PO-Revision-Date: 2026-10-16 21:00+0000\n" +"POT-Creation-Date: 2026-10-16 22:12+0200\n" +"PO-Revision-Date: 2026-10-16 22:12+0200\n" "Last-Translator: \n" "Language-Team: French\n" "Language: fr\n" @@ -13,126 +13,117 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: src/main.cpp:53 msgid "Choose file" msgstr "Choisir un fichier" -#: src/main.cpp:56 src/main.cpp:224 src/main.cpp:236 msgid "_Cancel" msgstr "_Annuler" -#: src/main.cpp:57 src/main.cpp:237 msgid "_Open" msgstr "_Ouvrir" -#: src/main.cpp:75 -msgid "" -msgstr "" +msgid "No keys recorded yet" +msgstr "Aucune touche enregistrée pour le moment" + +msgid "Capture key sequence" +msgstr "Capturer une séquence de touches" + +msgid "Clear" +msgstr "Effacer" + +msgid "Cancel" +msgstr "Annuler" + +msgid "Done" +msgstr "Terminer" + +msgid "" +"Press keys in order (modifiers like Ctrl, Alt, Shift and Super are recorded " +"too). Click Done to apply or Cancel to discard." +msgstr "" +"Appuyez sur les touches dans l'ordre (les modificateurs comme Ctrl, Alt, " +"Maj et Super sont également enregistrés). Cliquez sur Terminer pour " +"appliquer ou sur Annuler pour abandonner." -#: src/main.cpp:87 msgid "Choose file..." msgstr "Choisir un fichier..." -#: src/main.cpp:89 src/main.cpp:364 +msgid "e.g. /usr/bin/firefox or custom command" +msgstr "ex. /usr/bin/firefox ou commande personnalisée" + msgid "Capture" msgstr "Capturer" -#: src/main.cpp:125 +msgid "e.g. ctrl+c, ctrl+v" +msgstr "ex. ctrl+c, ctrl+v" + #, c-format msgid "Could not save %s.\n" msgstr "Impossible d'enregistrer %s.\n" -#: src/main.cpp:129 msgid "Mappings saved to " msgstr "Attributions enregistrées dans " -#: src/main.cpp:135 #, c-format msgid "Could not open %s.\n" msgstr "Impossible d'ouvrir %s.\n" -#: src/main.cpp:187 msgid "Could not export mappings.\n" msgstr "Impossible d'exporter les attributions.\n" -#: src/main.cpp:210 src/main.cpp:273 msgid "gKeyMapper" msgstr "gKeyMapper" -#: src/main.cpp:213 msgid "G-Key mapper for the Logitech G910 (GTK4)." msgstr "Assignateur de touches G pour le Logitech G910 (GTK4)." -#: src/main.cpp:221 msgid "Export configuration" msgstr "Exporter la configuration" -#: src/main.cpp:225 msgid "_Save" msgstr "_Enregistrer" -#: src/main.cpp:233 msgid "Import configuration" msgstr "Importer la configuration" -#: src/main.cpp:269 msgid "gKeyMapper – Logitech G910" msgstr "gKeyMapper – Logitech G910" -#: src/main.cpp:277 msgid "Export configuration..." msgstr "Exporter la configuration..." -#: src/main.cpp:278 msgid "Import configuration..." msgstr "Importer la configuration..." -#: src/main.cpp:281 msgid "About" msgstr "À propos" -#: src/main.cpp:305 msgid "G1 to G9 of the Logitech G910 remapped to keys or commands" -msgstr "" -"Réassignation des touches G1 à G9 du Logitech G910 vers des touches ou des " -"commandes" +msgstr "Réassignation des touches G1 à G9 du Logitech G910 vers des touches ou des commandes" -#: src/main.cpp:327 msgid "G-Key" msgstr "Touche G" -#: src/main.cpp:327 msgid "Type" msgstr "Type" -#: src/main.cpp:327 msgid "Target (Key/Command)" msgstr "Cible (Touche/Commande)" -#: src/main.cpp:327 msgid "Action" msgstr "Action" -#: src/main.cpp:335 msgid "Key" msgstr "Touche" -#: src/main.cpp:335 msgid "Command" msgstr "Commande" -#: src/main.cpp:335 msgid "Disabled" msgstr "Désactivé" -#: src/main.cpp:358 -msgid "e.g. ctrl+c or ls -la" -msgstr "ex. ctrl+c ou ls -la" - -#: src/main.cpp:378 msgid "Save mappings" msgstr "Enregistrer les attributions" -#: src/main.cpp:383 msgid "Saved to ~/.config/gKeyMapper/mappings.conf" msgstr "Enregistré dans ~/.config/gKeyMapper/mappings.conf" diff --git a/po/fr.po~ b/po/fr.po~ deleted file mode 100644 index 4d27816..0000000 --- a/po/fr.po~ +++ /dev/null @@ -1,100 +0,0 @@ -# French translation for gkeymapper. -# -msgid "" -msgstr "" -"Project-Id-Version: gkeymapper 0.1\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-10-16 21:00+0000\n" -"PO-Revision-Date: 2026-10-16 21:00+0000\n" -"Last-Translator: \n" -"Language-Team: French\n" -"Language: fr\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" - -msgid "" -msgstr "" - -#, c-format -msgid "Could not save %s.\n" -msgstr "Impossible d'enregistrer %s.\n" - -msgid "Mappings saved to " -msgstr "Attributions enregistrées dans " - -#, c-format -msgid "Could not open %s.\n" -msgstr "Impossible d'ouvrir %s.\n" - -msgid "Could not export mappings.\n" -msgstr "Impossible d'exporter les attributions.\n" - -msgid "gKeyMapper" -msgstr "gKeyMapper" - -msgid "G-Key mapper for the Logitech G910 (GTK4)." -msgstr "Assignateur de touches G pour le Logitech G910 (GTK4)." - -msgid "Export configuration" -msgstr "Exporter la configuration" - -msgid "_Cancel" -msgstr "_Annuler" - -msgid "_Save" -msgstr "_Enregistrer" - -msgid "Import configuration" -msgstr "Importer la configuration" - -msgid "_Open" -msgstr "_Ouvrir" - -msgid "gKeyMapper – Logitech G910" -msgstr "gKeyMapper – Logitech G910" - -msgid "Export configuration..." -msgstr "Exporter la configuration..." - -msgid "Import configuration..." -msgstr "Importer la configuration..." - -msgid "About" -msgstr "À propos" - -msgid "G1 to G9 of the Logitech G910 remapped to keys or commands" -msgstr "Réassignation des touches G1 à G9 du Logitech G910 vers des touches ou des commandes" - -msgid "G-Key" -msgstr "Touche G" - -msgid "Type" -msgstr "Type" - -msgid "Target (Key/Command)" -msgstr "Cible (Touche/Commande)" - -msgid "Action" -msgstr "Action" - -msgid "Key" -msgstr "Touche" - -msgid "Command" -msgstr "Commande" - -msgid "Disabled" -msgstr "Désactivé" - -msgid "e.g. ctrl+c or ls -la" -msgstr "ex. ctrl+c ou ls -la" - -msgid "Capture" -msgstr "Capturer" - -msgid "Save mappings" -msgstr "Enregistrer les attributions" - -msgid "Saved to ~/.config/gKeyMapper/mappings.conf" -msgstr "Enregistré dans ~/.config/gKeyMapper/mappings.conf" diff --git a/po/gkeymapper.pot b/po/gkeymapper.pot index adcf269..2bb0055 100644 --- a/po/gkeymapper.pot +++ b/po/gkeymapper.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-10-16 21:53+0200\n" +"POT-Creation-Date: 2026-10-16 22:12+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,124 +17,150 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: src/main.cpp:53 +#: src/main.cpp:55 msgid "Choose file" msgstr "" -#: src/main.cpp:56 src/main.cpp:224 src/main.cpp:236 +#: src/main.cpp:58 src/main.cpp:419 src/main.cpp:431 msgid "_Cancel" msgstr "" -#: src/main.cpp:57 src/main.cpp:237 +#: src/main.cpp:59 src/main.cpp:432 msgid "_Open" msgstr "" -#: src/main.cpp:75 -msgid "" +#: src/main.cpp:129 src/main.cpp:218 +msgid "No keys recorded yet" msgstr "" -#: src/main.cpp:87 +#: src/main.cpp:187 +msgid "Capture key sequence" +msgstr "" + +#: src/main.cpp:191 +msgid "Clear" +msgstr "" + +#: src/main.cpp:192 +msgid "Cancel" +msgstr "" + +#: src/main.cpp:193 +msgid "Done" +msgstr "" + +#: src/main.cpp:213 +msgid "" +"Press keys in order (modifiers like Ctrl, Alt, Shift and Super are recorded " +"too). Click Done to apply or Cancel to discard." +msgstr "" + +#: src/main.cpp:263 msgid "Choose file..." msgstr "" -#: src/main.cpp:89 src/main.cpp:364 +#: src/main.cpp:265 +msgid "e.g. /usr/bin/firefox or custom command" +msgstr "" + +#: src/main.cpp:267 src/main.cpp:586 msgid "Capture" msgstr "" -#: src/main.cpp:125 +#: src/main.cpp:269 src/main.cpp:579 +msgid "e.g. ctrl+c, ctrl+v" +msgstr "" + +#: src/main.cpp:306 #, c-format msgid "Could not save %s.\n" msgstr "" -#: src/main.cpp:129 +#: src/main.cpp:310 msgid "Mappings saved to " msgstr "" -#: src/main.cpp:135 +#: src/main.cpp:316 #, c-format msgid "Could not open %s.\n" msgstr "" -#: src/main.cpp:187 +#: src/main.cpp:368 msgid "Could not export mappings.\n" msgstr "" -#: src/main.cpp:210 src/main.cpp:273 +#: src/main.cpp:393 src/main.cpp:499 msgid "gKeyMapper" msgstr "" -#: src/main.cpp:213 +#: src/main.cpp:396 msgid "G-Key mapper for the Logitech G910 (GTK4)." msgstr "" -#: src/main.cpp:221 +#: src/main.cpp:416 msgid "Export configuration" msgstr "" -#: src/main.cpp:225 +#: src/main.cpp:420 msgid "_Save" msgstr "" -#: src/main.cpp:233 +#: src/main.cpp:428 msgid "Import configuration" msgstr "" -#: src/main.cpp:269 +#: src/main.cpp:488 msgid "gKeyMapper – Logitech G910" msgstr "" -#: src/main.cpp:277 +#: src/main.cpp:503 msgid "Export configuration..." msgstr "" -#: src/main.cpp:278 +#: src/main.cpp:504 msgid "Import configuration..." msgstr "" -#: src/main.cpp:281 +#: src/main.cpp:507 msgid "About" msgstr "" -#: src/main.cpp:305 +#: src/main.cpp:531 msgid "G1 to G9 of the Logitech G910 remapped to keys or commands" msgstr "" -#: src/main.cpp:327 +#: src/main.cpp:548 msgid "G-Key" msgstr "" -#: src/main.cpp:327 +#: src/main.cpp:548 msgid "Type" msgstr "" -#: src/main.cpp:327 +#: src/main.cpp:548 msgid "Target (Key/Command)" msgstr "" -#: src/main.cpp:327 +#: src/main.cpp:548 msgid "Action" msgstr "" -#: src/main.cpp:335 +#: src/main.cpp:556 msgid "Key" msgstr "" -#: src/main.cpp:335 +#: src/main.cpp:556 msgid "Command" msgstr "" -#: src/main.cpp:335 +#: src/main.cpp:556 msgid "Disabled" msgstr "" -#: src/main.cpp:358 -msgid "e.g. ctrl+c or ls -la" -msgstr "" - -#: src/main.cpp:378 +#: src/main.cpp:603 msgid "Save mappings" msgstr "" -#: src/main.cpp:383 +#: src/main.cpp:608 msgid "Saved to ~/.config/gKeyMapper/mappings.conf" msgstr "" diff --git a/src/main.cpp b/src/main.cpp index 1535bc4..f7c45be 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,10 +4,12 @@ #include #include +#include #include #include #include #include +#include #include #include @@ -60,20 +62,227 @@ static void pick_command_file(KeyRow* row, GtkWindow* parent) { gtk_window_present(GTK_WINDOW(dialog)); } +struct CaptureSession { + KeyRow* row = nullptr; + GtkWidget* displayLabel = nullptr; + std::vector steps; + std::set heldKeys; // non-modifier keyvals currently held (ignores auto-repeat) +}; + +static bool is_modifier_keyval(guint keyval) { + switch (keyval) { + case GDK_KEY_Control_L: + case GDK_KEY_Control_R: + case GDK_KEY_Alt_L: + case GDK_KEY_Alt_R: + case GDK_KEY_Shift_L: + case GDK_KEY_Shift_R: + case GDK_KEY_Super_L: + case GDK_KEY_Super_R: + case GDK_KEY_Meta_L: + case GDK_KEY_Meta_R: + case GDK_KEY_ISO_Level3_Shift: // AltGr + return true; + default: + return false; + } +} + +// Format one step like the reference project: modifiers joined with '+', +// e.g. "ctrl+shift+t". Multiple steps are joined with ',' ("ctrl+c,ctrl+v"). +static std::string format_capture_step(GdkModifierType state, guint keyval) { + std::string step; + if (state & GDK_CONTROL_MASK) { + step += "ctrl+"; + } + if (state & GDK_ALT_MASK) { + step += "alt+"; + } + if (state & GDK_SHIFT_MASK) { + step += "shift+"; + } + if (state & (GDK_SUPER_MASK | GDK_META_MASK)) { + step += "super+"; + } + const char* name = gdk_keyval_name(keyval); + std::string key = name ? name : "?"; + std::transform(key.begin(), key.end(), key.begin(), + [](unsigned char c) { return std::tolower(c); }); + step += key; + return step; +} + +static std::string join_capture_steps(const std::vector& steps) { + std::string out; + for (size_t i = 0; i < steps.size(); ++i) { + if (i > 0) { + out += ","; + } + out += steps[i]; + } + return out; +} + +static void update_capture_display(CaptureSession* session) { + std::string text = join_capture_steps(session->steps); + if (text.empty()) { + text = _("No keys recorded yet"); + } + gtk_label_set_text(GTK_LABEL(session->displayLabel), text.c_str()); +} + +static gboolean on_capture_key_pressed(GtkEventControllerKey* /*controller*/, + guint keyval, guint /*keycode*/, + GdkModifierType state, gpointer userData) { + auto* session = static_cast(userData); + if (is_modifier_keyval(keyval)) { + return TRUE; // modifiers are recorded as part of the next real key + } + if (session->heldKeys.count(keyval)) { + return TRUE; // ignore auto-repeat while the key is held down + } + session->heldKeys.insert(keyval); + constexpr GdkModifierType kModMask = static_cast( + GDK_SHIFT_MASK | GDK_CONTROL_MASK | GDK_ALT_MASK | + GDK_SUPER_MASK | GDK_META_MASK); + session->steps.push_back(format_capture_step( + static_cast(state & kModMask), keyval)); + update_capture_display(session); + return TRUE; +} + +static gboolean on_capture_key_released(GtkEventControllerKey* /*controller*/, + guint keyval, guint /*keycode*/, + GdkModifierType /*state*/, gpointer userData) { + auto* session = static_cast(userData); + session->heldKeys.erase(keyval); + return TRUE; +} + +static void on_capture_session_destroy(GtkWidget* /*widget*/, gpointer userData) { + delete static_cast(userData); +} + +static void on_capture_done_clicked(GtkButton* btn, gpointer userData) { + auto* session = static_cast(userData); + if (!session->steps.empty()) { + gtk_editable_set_text(GTK_EDITABLE(session->row->targetEntry), + join_capture_steps(session->steps).c_str()); + } + GtkWindow* window = GTK_WINDOW(gtk_widget_get_root(GTK_WIDGET(btn))); + gtk_window_destroy(window); // triggers session cleanup via "destroy" +} + +static void on_capture_cancel_clicked(GtkButton* btn, gpointer /*userData*/) { + GtkWindow* window = GTK_WINDOW(gtk_widget_get_root(GTK_WIDGET(btn))); + gtk_window_destroy(window); // triggers session cleanup via "destroy" +} + +static void on_capture_clear_clicked(GtkButton* /*btn*/, gpointer userData) { + auto* session = static_cast(userData); + session->steps.clear(); + session->heldKeys.clear(); + update_capture_display(session); +} + +static void open_key_capture_dialog(KeyRow* row, GtkWindow* parent) { + auto* session = new CaptureSession(); + session->row = row; + + GtkWidget* dialog = gtk_window_new(); + gtk_window_set_title(GTK_WINDOW(dialog), _("Capture key sequence")); + gtk_window_set_transient_for(GTK_WINDOW(dialog), parent); + gtk_window_set_modal(GTK_WINDOW(dialog), TRUE); + gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE); + gtk_window_set_default_size(GTK_WINDOW(dialog), 540, 300); + g_signal_connect(dialog, "destroy", G_CALLBACK(on_capture_session_destroy), session); + + GtkWidget* outer = gtk_box_new(GTK_ORIENTATION_VERTICAL, 16); + gtk_widget_set_margin_top(outer, 20); + gtk_widget_set_margin_bottom(outer, 20); + gtk_widget_set_margin_start(outer, 20); + gtk_widget_set_margin_end(outer, 20); + gtk_window_set_child(GTK_WINDOW(dialog), outer); + + GtkWidget* title = gtk_label_new(nullptr); + gtk_label_set_markup(GTK_LABEL(title), + g_strdup_printf("%s", + _("Capture key sequence"))); + gtk_label_set_xalign(GTK_LABEL(title), 0.0f); + gtk_box_append(GTK_BOX(outer), title); + + GtkWidget* info = gtk_label_new(_("Press keys in order (modifiers like Ctrl, Alt, Shift and Super are recorded too). Click Done to apply or Cancel to discard.")); + gtk_label_set_wrap(GTK_LABEL(info), TRUE); + gtk_label_set_xalign(GTK_LABEL(info), 0.0f); + gtk_widget_add_css_class(info, "dim-label"); + gtk_box_append(GTK_BOX(outer), info); + + session->displayLabel = gtk_label_new(_("No keys recorded yet")); + gtk_label_set_xalign(GTK_LABEL(session->displayLabel), 0.0f); + gtk_label_set_ellipsize(GTK_LABEL(session->displayLabel), PANGO_ELLIPSIZE_MIDDLE); + gtk_widget_add_css_class(session->displayLabel, "monospace"); + gtk_widget_set_margin_top(session->displayLabel, 12); + gtk_widget_set_margin_bottom(session->displayLabel, 12); + gtk_widget_set_margin_start(session->displayLabel, 12); + gtk_widget_set_margin_end(session->displayLabel, 12); + GtkWidget* frame = gtk_frame_new(nullptr); + gtk_frame_set_child(GTK_FRAME(frame), session->displayLabel); + gtk_widget_set_size_request(frame, -1, 64); + gtk_widget_set_vexpand(frame, TRUE); + gtk_box_append(GTK_BOX(outer), frame); + + gtk_box_append(GTK_BOX(outer), gtk_separator_new(GTK_ORIENTATION_HORIZONTAL)); + + // Buttons: Clear on the left, Cancel/Done grouped on the right. + GtkWidget* buttonRow = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); + gtk_box_append(GTK_BOX(outer), buttonRow); + + GtkWidget* clearBtn = gtk_button_new_with_label(_("Clear")); + gtk_widget_set_size_request(clearBtn, 110, -1); + g_signal_connect(clearBtn, "clicked", G_CALLBACK(on_capture_clear_clicked), session); + gtk_box_append(GTK_BOX(buttonRow), clearBtn); + + GtkWidget* spacer = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); + gtk_widget_set_hexpand(spacer, TRUE); + gtk_box_append(GTK_BOX(buttonRow), spacer); + + GtkWidget* endBox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8); + gtk_box_append(GTK_BOX(buttonRow), endBox); + + GtkWidget* cancelBtn = gtk_button_new_with_label(_("Cancel")); + gtk_widget_set_size_request(cancelBtn, 110, -1); + g_signal_connect(cancelBtn, "clicked", G_CALLBACK(on_capture_cancel_clicked), nullptr); + gtk_box_append(GTK_BOX(endBox), cancelBtn); + + GtkWidget* doneBtn = gtk_button_new_with_label(_("Done")); + gtk_widget_set_size_request(doneBtn, 110, -1); + g_signal_connect(doneBtn, "clicked", G_CALLBACK(on_capture_done_clicked), session); + gtk_box_append(GTK_BOX(endBox), doneBtn); + + // Key events go to the dialog; buttons must not steal Space/Return. + GtkEventController* keyCtrl = gtk_event_controller_key_new(); + g_signal_connect(keyCtrl, "key-pressed", G_CALLBACK(on_capture_key_pressed), session); + g_signal_connect(keyCtrl, "key-released", G_CALLBACK(on_capture_key_released), session); + gtk_widget_add_controller(dialog, keyCtrl); + gtk_widget_set_focusable(clearBtn, FALSE); + gtk_widget_set_focusable(cancelBtn, FALSE); + gtk_widget_set_focusable(doneBtn, FALSE); + + gtk_window_present(GTK_WINDOW(dialog)); +} + void on_capture_clicked(GtkButton* btn, gpointer userData) { auto* row = static_cast(userData); guint sel = gtk_drop_down_get_selected(GTK_DROP_DOWN(row->typeDrop)); + GtkWindow* window = GTK_WINDOW(gtk_widget_get_root(GTK_WIDGET(btn))); if (sel == 1) { - GtkWindow* window = GTK_WINDOW(gtk_widget_get_root(GTK_WIDGET(btn))); pick_command_file(row, window); return; } if (sel == 0) { - // Placeholder: real key capture will be added in a later version. - gtk_editable_set_text(GTK_EDITABLE(row->targetEntry), _("")); - std::cout << "G" << (row->index + 1) << ": waiting for key...\n"; + open_key_capture_dialog(row, window); } } @@ -85,8 +294,12 @@ static void update_row_state(KeyRow* row) { if (sel == 1) { gtk_button_set_label(GTK_BUTTON(row->captureButton), _("Choose file...")); + gtk_entry_set_placeholder_text(GTK_ENTRY(row->targetEntry), + _("e.g. /usr/bin/firefox or custom command")); } else { gtk_button_set_label(GTK_BUTTON(row->captureButton), _("Capture")); + gtk_entry_set_placeholder_text(GTK_ENTRY(row->targetEntry), + _("e.g. ctrl+c, ctrl+v")); } gtk_widget_set_size_request(row->captureButton, 180, -1); } @@ -215,7 +428,7 @@ static void show_about_dialog(GtkWindow* parent) { gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(dialog), _("G-Key mapper for the Logitech G910 (GTK4).")); gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(dialog), "https://rager.dev"); - gtk_about_dialog_set_website_label(GTK_ABOUT_DIALOG(dialog), "rager.dev"); + gtk_about_dialog_set_website_label(GTK_ABOUT_DIALOG(dialog), "Thomas Rager - rager.dev"); std::string iconPath = find_asset("icon.png"); GError* error = nullptr; @@ -396,7 +609,7 @@ void build_ui(GtkApplication* app) { // Target input (wide: commands and file paths need room) GtkWidget* entry = gtk_entry_new(); - gtk_entry_set_placeholder_text(GTK_ENTRY(entry), _("e.g. ctrl+c or ls -la")); + gtk_entry_set_placeholder_text(GTK_ENTRY(entry), _("e.g. ctrl+c, ctrl+v")); gtk_widget_set_size_request(entry, 440, -1); gtk_widget_set_hexpand(entry, TRUE); gtk_grid_attach(GTK_GRID(grid), entry, 2, i + 1, 1, 1); @@ -421,7 +634,9 @@ void build_ui(GtkApplication* app) { gtk_box_append(GTK_BOX(outer), footer); GtkWidget* saveBtn = gtk_button_new_with_label(_("Save mappings")); - gtk_widget_add_css_class(saveBtn, "suggested-action"); + // No "suggested-action" class on purpose: it gets a strong accent color + // (e.g. Mint-Y green) that clashes with the rest of the layout. The plain + // button follows the system theme like everything else. g_signal_connect(saveBtn, "clicked", G_CALLBACK(on_save_clicked), nullptr); gtk_box_append(GTK_BOX(footer), saveBtn);