This commit is contained in:
2025-12-21 06:55:49 +01:00
parent 8b80ad87c6
commit 896173815c
21 changed files with 4767 additions and 1 deletions

255
CHANGELOG.md Normal file
View File

@@ -0,0 +1,255 @@
# CHANGELOG - Extension GNOME Shell ASUS RGB Keyboard
Ce fichier documente l'évolution du développement de l'extension pour faciliter la reprise du travail.
## [Non publié] - En cours de développement
### 📅 2025-12-21
#### 🆕 Nouvelles Améliorations (Session 4)
**Amélioration 4: Presets GNOME et restauration thème**
- **Demande**: Remplacer les 6 presets personnalisés par les 9 couleurs d'accentuation GNOME
- **Solution implémentée**:
- Modification du schéma GSettings : ajout de `preset-7`, `preset-8`, `preset-9`
- Mise à jour de tous les presets avec les couleurs GNOME officielles :
1. Bleu (53, 132, 228) - couleur par défaut GNOME
2. Turquoise (51, 209, 122)
3. Vert (87, 227, 137)
4. Jaune (246, 211, 45)
5. Orange (255, 120, 0)
6. Rouge (237, 51, 59)
7. Rose (246, 97, 81)
8. Violet (145, 65, 172)
9. Gris ardoise (119, 118, 123)
- Adaptation UI : boucle de 6 → 9 presets, ajustement taille boutons (32px → 28px)
- Restauration thème : désactiver la synchronisation remet GNOME sur "blue" (défaut)
- **Résultat**: Cohérence totale entre presets clavier et couleurs d'accentuation GNOME
**Amélioration 5: Style presets ronds et surbrillance**
- **Demande**: Presets en forme de ronds avec cercle blanc autour du preset actif
- **Solution implémentée**:
- Modification style : `border-radius: 50%` pour rendre les presets circulaires
- Taille ajustée : 26×26px pour des cercles parfaits
- Fonction `_updatePresetSelection()` : cercle blanc épais (3px) + box-shadow sur le preset actif
- Stockage des boutons dans `this._presetButtons[]` avec propriétés `_preset` et `_baseStyle`
- Comparaison RGB avec tolérance de ±10
- Appel à chaque changement de couleur pour mise à jour en temps réel
- **Résultat**: Feedback visuel clair du preset actuellement sélectionné
**Amélioration 6: Synchronisation thème universelle**
- **Problème**: Synchronisation thème GNOME fonctionnait uniquement depuis la roue chromatique
- **Cause**: `_onPresetClicked()` appelait directement `Backend.writeRGB()` au lieu de `_onRGBChanged()`
- **Solution**: Refactorisation de `_onPresetClicked()` pour utiliser `_onRGBChanged()`
- **Déclenchement synchronisation maintenant actif**:
- ✅ Depuis la roue chromatique
- ✅ Depuis les sliders RGB
- ✅ Depuis les presets
- ✅ Depuis le slider Master
- **Résultat**: La couleur GNOME se synchronise peu importe le mode de sélection utilisé
#### 🆕 Nouvelles Améliorations (Session 2 et 3)
**Amélioration 1: Surbrillance des boutons d'intensité**
- **Problème**: Les boutons OFF/1/2/3 n'affichaient pas de surbrillance du niveau sélectionné
- **Cause**: Classe CSS incorrecte (`'button'` au lieu de `'brightness-button'`)
- **Solution**: Correction de `style_class` dans `_buildBrightnessButtons()`
- **Résultat**: Bouton actif affiché avec fond bleu et texte blanc gras
**Amélioration 2: Surbrillance de la couleur sélectionnée dans la roue**
- **Problème**: Pas de feedback visuel sur la couleur active dans la roue chromatique
- **Solution implémentée**:
- Stockage des 113 boutons dans `this._wheelButtons[]`
- Ajout de propriétés `_rgb` et `_baseStyle` sur chaque bouton
- Nouvelle fonction `_updateWheelSelection()` pour mettre à jour la bordure
- Bordure blanche épaisse (3px) + box-shadow sur la couleur sélectionnée
- Comparaison RGB avec tolérance de ±10 pour gérer les approximations HSL
- **Appels**:
- ✅ À la construction de la roue (affichage initial)
- ✅ Sur clic dans la roue
- ✅ Sur clic preset
- ✅ Sur changement de couleur
- **Résultat**: Indication claire de quelle couleur est actuellement appliquée dès l'ouverture du menu
**Amélioration 3: Synchronisation avec le thème GNOME**
- **Demande**: Appliquer automatiquement la couleur du clavier comme couleur d'accentuation GNOME
- **Solution implémentée**:
- Ajout clé GSettings `sync-gnome-theme` (booléen, défaut: false)
- Fonction `_rgbToGnomeAccent()` : mapping RGB → 9 couleurs GNOME (blue, teal, green, yellow, orange, red, pink, purple, slate)
- Algorithme: distance euclidienne dans l'espace RGB pour trouver la couleur la plus proche
- Fonction `_syncGnomeTheme()` : applique via `org.gnome.desktop.interface accent-color`
- UI: `PopupSwitchMenuItem` "Synchroniser thème GNOME" après les presets
- **Déclenchement**:
- ✅ Activation de la case à cocher (application immédiate)
- ✅ Lors de chaque changement de couleur clavier (si activé)
- **Résultat**: La couleur d'accentuation GNOME (affichée dans Paramètres → Apparence) change automatiquement pour correspondre au clavier RGB
#### 🔍 Analyse des Problèmes Identifiés (Session 1)
**Problème 1: Roue chromatique non fonctionnelle**
- **Symptôme**: Impossible de sélectionner une couleur en cliquant sur la roue
- **Cause identifiée**:
- Première tentative avec `St.DrawingArea` non interactive sous GNOME Shell 48
- Deuxième tentative avec grille 16×16 de boutons (cellSize: 12px) potentiellement trop petits
- Les boutons sont créés mais les clics ne sont pas détectés
- **Hypothèse**: Boutons trop petits (12px) ou problème de style CSS empêchant l'interaction
**Problème 2: Niveau d'intensité non visuellement sélectionné**
- **Symptôme**: Aucune indication visuelle du bouton d'intensité actif
- **Cause**: Pas de mise à jour du style CSS lors du clic
- **Solution**: Ajouter classe CSS active et mettre à jour dans `_updateBrightnessButtons()`
**Problème 3: Mode par défaut incorrect**
- **Symptôme**: Mode sliders affiché par défaut alors que l'utilisateur préfère la roue
- **Cause**: `this._colorPickerMode = 'sliders'` dans l'initialisation
- **Solution**: Inverser pour `this._colorPickerMode = 'wheel'`
#### 🔧 Correctifs Appliqués
**Correctif 1: Roue chromatique fonctionnelle**
- Augmentation de la taille des cellules: 12px → 18px (+50%)
- Réduction de la grille: 16×16 → 12×12 pour meilleure visibilité
- Ajout de bordure visible `rgba(0,0,0,0.3)` pour feedback visuel
- Ajout de `reactive: true` et `track_hover: true` pour garantir l'interactivité
- Espacement entre cellules: 2px → 3px pour meilleure séparation
**Correctif 2: Surbrillance des boutons d'intensité**
- Classe CSS `.active` déjà implémentée dans stylesheet.css
- Style actif: fond bleu (`rgba(53, 132, 228, 0.8)`), texte blanc, gras
- Fonction `_updateBrightnessButtons()` existante et fonctionnelle
**Correctif 3: Mode roue par défaut**
- Changement de `_colorPickerMode: 'sliders'``'wheel'`
- Roue chromatique affichée en premier au démarrage
- Bouton de bascule pour passer en mode sliders
#### 📊 Résumé des Améliorations
**Interface utilisateur:**
- ✅ Roue chromatique 12×12 avec 113 couleurs cliquables
- ✅ Boutons 18×18px, bien visibles et réactifs
- ✅ Mode roue chromatique par défaut (préférence utilisateur)
- ✅ Surbrillance automatique du niveau d'intensité actif
- ✅ Aperçu couleur dans le header avec correction gamma sRGB
**Ergonomie:**
- ✅ Clic sur la roue chromatique → application immédiate au clavier
- ✅ Slider Luminosité (Master) pour contrôle de l'intensité
- ✅ Bascule facile entre roue et sliders RGB
- ✅ Interface compacte et optimisée
### 📅 2025-12-20
#### ✅ Terminé
- **Analyse du projet** : Compréhension complète des spécifications
- **Architecture définie** : Séparation en 3 modules (ui.js, backend.js, extension.js)
- **Schéma UI créé** : Documentation visuelle complète dans `docs/UI_SCHEMA.md`
- Diagramme Mermaid de l'architecture
- Layout ASCII du popover
- Flux de données
- Gestion des erreurs UI
- **CLAUDE.md créé** : Guide pour futures instances de Claude Code
- **CHANGELOG.md initialisé** : Ce fichier
#### 🔄 En cours
- Prêt pour installation et tests complets
#### ✅ Tests Matériel Réalisés (ASUS TUF Gaming A16 FA608UH)
-**Contrôle brightness** : Changement de niveaux 0-3 fonctionnel
-**Contrôle RGB** : Écriture kbd_rgb_mode validée
-**Permissions udev** : Règle corrigée et fonctionnelle
- Règle finale : `ACTION=="add"` avec `RUN+="/bin/sh -c 'chgrp kbdled ...'"`
- Rechargement module : `modprobe -r asus_nb_wmi && modprobe asus_nb_wmi`
- Permissions validées : `kbdled` groupe appliqué correctement
#### 📋 Terminé (MVP complet)
- ✅ Arborescence complète du projet créée
- ✅ backend.js implémenté (interface sysfs + debouncing)
- ✅ ui.js implémenté (construction du popover complet)
- ✅ extension.js créé (lifecycle GNOME Shell)
- ✅ Schéma GSettings complet avec 6 presets
- ✅ metadata.json créé
- ✅ stylesheet.css créé pour le styling
- ✅ Documentation installation (docs/INSTALL.md)
- ✅ Documentation troubleshooting (docs/TROUBLESHOOTING.md)
- ✅ Documentation tests (docs/TESTING.md)
- ✅ Script d'installation (tools/install-local.sh)
- ✅ README.md complet et détaillé
#### 🎯 Décisions techniques prises
- **Langage**: GJS (JavaScript GNOME Shell)
- **GNOME Shell**: Version 48
- **UUID**: `asus-kbd-rgb@gilles`
- **Master Slider**: Mode "gain" (multiplie R/G/B par 0-100%)
- **Debouncing**: 75ms pour les sliders
- **Permissions**: Règle udev + groupe `kbdled` (approche simple)
- **Step RGB par défaut**: 5
- **Comportement brightness=0**: Mémoriser RGB sans écrire kbd_rgb_mode
#### 📝 Presets couleur par défaut
1. Orange: (255, 165, 0)
2. Rouge: (255, 0, 0)
3. Vert: (0, 255, 0)
4. Bleu: (0, 0, 255)
5. Blanc: (255, 255, 255)
6. Cyan: (0, 255, 255)
#### 🔧 Interface matérielle
- Path brightness: `/sys/class/leds/asus::kbd_backlight/brightness`
- Path max: `/sys/class/leds/asus::kbd_backlight/max_brightness`
- Path RGB: `/sys/class/leds/asus::kbd_backlight/kbd_rgb_mode`
- Format RGB: `1 0 R G B 0\n`
---
## Notes pour reprise du développement
### Prochaines étapes recommandées
1. Créer l'arborescence complète des fichiers
2. Implémenter backend.js en premier (base pour tests)
3. Implémenter ui.js (interface)
4. Créer extension.js pour intégrer les modules
5. Tester avec règles udev configurées
### Points d'attention
- **Permissions critiques**: L'extension ne peut pas fonctionner sans les règles udev
- **Debouncing essentiel**: Éviter de spammer sysfs lors des déplacements de sliders
- **Clamping obligatoire**: Toujours valider 0-255 pour RGB, 0-max pour brightness
- **GNOME Shell 48**: Vérifier la compatibilité API (notamment pour Slider)
- **Wayland vs X11**: Différence pour le rechargement en dev
### Dépendances système
- GNOME Shell 48
- GLib/GIO pour sysfs
- GSettings pour la persistance
- udev pour les permissions
### Structure des modules
```
backend.js → Fonctions exportées:
- checkHardwareSupport()
- checkPermissions()
- readBrightness()
- writeBrightness(value)
- readRGB()
- writeRGB(r, g, b, master)
- applyPreset(presetId)
ui.js → Classe exportée:
- KeyboardRGBIndicator extends PanelMenu.Button
- Méthodes: _buildUI(), _onRGBChanged(), _onBrightnessChanged(), etc.
extension.js → Fonctions requises:
- init()
- enable()
- disable()
```
### Tests à effectuer lors de la reprise
- [ ] Extension se charge sans erreur
- [ ] Popover s'affiche au clic
- [ ] Sliders fonctionnent
- [ ] Debouncing actif (vérifier dans les logs)
- [ ] Écriture sysfs réussie (avec permissions)
- [ ] GSettings sauvegarde correctement
- [ ] Restauration au redémarrage de session

162
CLAUDE.md Normal file
View File

@@ -0,0 +1,162 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. tu fera des reponse en fracais.
## Project Overview
This is a GNOME Shell 48 extension for controlling RGB keyboard backlighting on ASUS laptops (specifically ASUS TUF Gaming A16 FA608UH) running Debian GNU/Linux 13 (trixie). The extension provides a user-friendly panel menu to control keyboard brightness and RGB colors via the `asus-nb-wmi` kernel interface.
**Target Hardware**: ASUS laptops with RGB keyboard support via `/sys/class/leds/asus::kbd_backlight/`
**Language**: GJS (JavaScript for GNOME Shell)
**GNOME Shell Version**: 48
## Architecture
The extension follows a modular architecture with clear separation of concerns:
### Core Modules
1. **`extension/ui.js`**: UI construction and event handling
- Panel menu button with keyboard icon
- Popover with sliders, buttons, and preset color boxes
- Manages user interactions and calls backend functions
2. **`extension/backend.js`**: Hardware interface and business logic
- Reads/writes to sysfs paths (`/sys/class/leds/asus::kbd_backlight/`)
- Implements debouncing for slider changes (50-100ms)
- Handles RGB clamping, master slider logic (gain mode)
- Manages permissions checking and error states
3. **`extension/extension.js`**: Extension lifecycle
- Entry point for GNOME Shell
- Initialization and cleanup
- Restores last saved state on session start
4. **GSettings Schema**: Persistent storage
- Current RGB values, brightness level
- 6 color presets
- Master slider mode and RGB step size
- Located in `extension/schemas/org.gnome.shell.extensions.asuskbdrgb.gschema.xml`
### Key Hardware Interfaces
- **Brightness**: `/sys/class/leds/asus::kbd_backlight/brightness` (0..max)
- **Max Brightness**: `/sys/class/leds/asus::kbd_backlight/max_brightness`
- **RGB Color**: `/sys/class/leds/asus::kbd_backlight/kbd_rgb_mode`
- Format: `1 0 R G B 0\n` (e.g., `1 0 255 165 0 0` for orange)
## Development Workflow
### Installation for Development
1. **Set up permissions** (required for sysfs access):
```bash
# Create udev rule
echo 'SUBSYSTEM=="leds", KERNEL=="asus::kbd_backlight", GROUP="kbdled", MODE="0660"' | sudo tee /etc/udev/rules.d/99-asus-kbd.rules
# Create group and add user
sudo groupadd -f kbdled
sudo usermod -aG kbdled $USER
# Reload udev
sudo udevadm control --reload-rules && sudo udevadm trigger
# Logout/login required for group membership
```
2. **Install extension locally**:
```bash
# Use provided install script
./tools/install-local.sh
# Or manually copy to extensions directory
cp -r extension/ ~/.local/share/gnome-shell/extensions/asus-kbd-rgb@gilles/
```
3. **Compile GSettings schema**:
```bash
glib-compile-schemas extension/schemas/
# Or let install script handle it
```
### Reloading During Development
- **X11**: Press `Alt+F2`, type `r`, press Enter
- **Wayland**: Logout and login (no hot reload available)
### Viewing Logs
```bash
journalctl -f -o cat /usr/bin/gnome-shell
```
## Code Conventions
### Language
- **All code comments**: French
- **All documentation files**: French (in `docs/` directory)
- **User-facing messages**: French
### Master Slider Logic
The "Master" slider uses **Option B (gain mode)** by default:
- Acts as a brightness multiplier for RGB values (0-100%)
- Multiplies each R, G, B component proportionally
- Alternative modes (offset, HSV) can be added in preferences
### Default Color Presets
1. Orange: (255, 165, 0)
2. Red: (255, 0, 0)
3. Green: (0, 255, 0)
4. Blue: (0, 0, 255)
5. White: (255, 255, 255)
6. Cyan: (0, 255, 255)
### Error Handling Requirements
The extension must gracefully handle:
1. **Missing hardware**: Display "Matériel non supporté" if sysfs paths don't exist
2. **Permission denied**: Show setup instructions for udev rule configuration
3. **Invalid values**: Clamp all RGB values to 0-255, brightness to 0-max_brightness
4. **Zero brightness behavior**: Keep RGB values in memory but don't write to `kbd_rgb_mode` when brightness is 0
## Extension Metadata
- **UUID**: `asus-kbd-rgb@gilles`
- **Shell Version**: `["48"]`
- **Location**: `~/.local/share/gnome-shell/extensions/asus-kbd-rgb@gilles/`
## File Structure
```
extension/
├── metadata.json # Extension metadata (UUID, version, shell-version)
├── extension.js # Main entry point
├── ui.js # UI components (panel button, popover, sliders)
├── backend.js # Sysfs interface and business logic
├── stylesheet.css # Optional custom styles
└── schemas/
└── org.gnome.shell.extensions.asuskbdrgb.gschema.xml
docs/ # All documentation files
├── INSTALL.md # Installation and permissions setup
└── TROUBLESHOOTING.md # Common issues and solutions
tools/
└── install-local.sh # Development installation script
```
## Testing Checklist
Before considering the extension complete, verify:
- [ ] Brightness levels change correctly (0 to max)
- [ ] RGB sliders apply colors instantly (with debouncing)
- [ ] Master slider affects RGB according to gain mode
- [ ] Preset colors apply on click
- [ ] Settings persist across session restarts
- [ ] "No permission" case shows udev setup instructions
- [ ] "Hardware absent" case shows clear error message
- [ ] Extension loads without errors on GNOME Shell 48

131
PROJECT_STRUCTURE.txt Normal file
View File

@@ -0,0 +1,131 @@
GNOME ASUS Keyboard RGB - Structure du Projet
==============================================
gnome-asus-kbd-rgb/
├── README.md # Documentation principale du projet
├── CLAUDE.md # Guide pour Claude Code
├── CHANGELOG.md # Historique des modifications
├── gnome_asus_kbd_rgb_claude_prompt.md # Consignes initiales
├── extension/ # Code source de l'extension GNOME Shell
│ ├── extension.js # Point d'entrée (lifecycle: init/enable/disable)
│ ├── ui.js # Interface utilisateur (popover, sliders, presets)
│ ├── backend.js # Interface sysfs et logique métier
│ ├── metadata.json # Métadonnées (UUID, version, shell-version)
│ ├── stylesheet.css # Styles CSS personnalisés
│ └── schemas/
│ └── org.gnome.shell.extensions.asuskbdrgb.gschema.xml
│ # Schéma GSettings (persistance)
├── docs/ # Documentation complète
│ ├── INSTALL.md # Guide d'installation détaillé
│ ├── TROUBLESHOOTING.md # Résolution des problèmes
│ ├── TESTING.md # Checklist de tests (120+ items)
│ └── UI_SCHEMA.md # Schémas de l'interface (Mermaid, ASCII)
└── tools/ # Scripts utilitaires
└── install-local.sh # Script d'installation automatique
Modules Principaux
==================
1. backend.js (Interface Système)
- checkHardwareSupport() : Vérifie la présence du matériel
- checkPermissions() : Vérifie les droits d'accès
- getMaxBrightness() : Lit la valeur max
- readBrightness() : Lit la brightness actuelle
- writeBrightness(level) : Écrit la brightness (0-3)
- writeRGB(r, g, b, master) : Écrit RGB avec master gain
- writeRGBDebounced() : Écrit RGB avec debouncing (75ms)
- parsePreset(string) : Parse "R,G,B" en objet
- rgbToHex(r, g, b) : Convertit RGB en #RRGGBB
- cleanup() : Nettoie les ressources
2. ui.js (Interface Utilisateur)
- KeyboardRGBIndicator : Classe principale (extends PanelMenu.Button)
- _buildUI() : Construit l'interface complète
- _buildBrightnessButtons() : Crée les 4 boutons d'intensité
- _buildRGBSliders() : Crée les sliders RGB + Master
- _buildInfoLine() : Crée la ligne d'information
- _buildPresets() : Crée les 6 boutons preset
- _buildErrorUI() : Affiche les messages d'erreur
- _onBrightnessButtonClicked() : Gère les clics sur boutons
- _onRGBChanged() : Applique les changements RGB
- _onPresetClicked() : Applique un preset
- _applyCurrentState() : Restaure l'état au démarrage
3. extension.js (Lifecycle)
- AsusKeyboardRGBExtension : Classe principale (extends Extension)
- enable() : Active l'extension
- disable() : Désactive l'extension
Fichiers sysfs
==============
/sys/class/leds/asus::kbd_backlight/
├── brightness # Intensité (0..max_brightness)
├── max_brightness # Valeur maximale (lecture seule)
└── kbd_rgb_mode # Couleur RGB (format: "1 0 R G B 0")
Configuration GSettings
=======================
Schéma: org.gnome.shell.extensions.asuskbdrgb
Clés disponibles:
- red (int) : Composante rouge (0-255)
- green (int) : Composante verte (0-255)
- blue (int) : Composante bleue (0-255)
- brightness-level (int) : Niveau d'intensité (0-3)
- master-gain (int) : Gain master (0-100)
- rgb-step (int) : Pas d'ajustement (défaut: 5)
- preset-1..6 (string) : Presets couleur (format "R,G,B")
- master-mode (string) : Mode du master slider (défaut: "gain")
Installation
============
1. Configuration permissions (obligatoire):
sudo tee /etc/udev/rules.d/99-asus-kbd.rules <<< 'SUBSYSTEM=="leds", KERNEL=="asus::kbd_backlight", GROUP="kbdled", MODE="0660"'
sudo groupadd -f kbdled
sudo usermod -aG kbdled $USER
sudo udevadm control --reload-rules && sudo udevadm trigger
# Logout/Login requis !
2. Installation extension:
./tools/install-local.sh
3. Rechargement GNOME Shell:
- X11: Alt+F2, "r", Enter
- Wayland: Logout/Login
Dépendances
===========
Runtime:
- GNOME Shell 48
- GLib/GIO (pour sysfs)
- GSettings (pour persistance)
- Module kernel: asus-nb-wmi
Build:
- glib-compile-schemas
Prochaines Améliorations (Post-MVP)
====================================
- [ ] Page de préférences (prefs.js) pour modifier les presets
- [ ] Support de modes RGB animés (breathing, wave, etc.)
- [ ] Support multi-zones (si matériel compatible)
- [ ] Export/Import de configurations
- [ ] Profils par application
- [ ] Raccourcis clavier globaux
- [ ] Indicateur de synchronisation avec le matériel
- [ ] Support d'autres modes master (offset, HSV)

230
README.md
View File

@@ -1,2 +1,230 @@
# gnome-asus-kbd-rgb
# GNOME Shell Extension - Contrôle RGB Clavier ASUS
Extension GNOME Shell pour contrôler le rétroéclairage RGB des claviers ASUS via l'interface kernel `asus-nb-wmi`.
![GNOME Shell 48](https://img.shields.io/badge/GNOME%20Shell-48-blue)
![License](https://img.shields.io/badge/license-GPL--3.0-green)
## 📋 Fonctionnalités
- **🎡 Roue chromatique** : Sélection visuelle de 113 couleurs en un clic
- **🎨 Mode sliders** : Contrôle RGB précis (0-255) + Master (0-100%)
- **💡 Contrôle d'intensité** : 4 niveaux avec surbrillance visuelle (Off, 1, 2, 3)
- **🎯 Presets couleur** : 6 couleurs prédéfinies personnalisables
- **🌈 Aperçu en temps réel** : Visualisation avec correction gamma sRGB
- **💾 Persistance** : Sauvegarde automatique et restauration au démarrage
- **⚡ Interface compacte** : Bascule facile entre roue et sliders
## 🎯 Compatibilité
### Système
- **OS** : Debian GNU/Linux 13 (trixie) ou compatible
- **GNOME Shell** : Version 48
- **Session** : X11 ou Wayland
### Matériel
- Ordinateurs portables ASUS avec clavier RGB
- Support via le module kernel `asus-nb-wmi`
- Testé sur : **ASUS TUF Gaming A16 FA608UH**
Vérifiez la présence de `/sys/class/leds/asus::kbd_backlight/` sur votre système.
## 🚀 Installation Rapide
### 1. Cloner le dépôt
```bash
cd ~/Documents
git clone https://github.com/gilles/gnome-asus-kbd-rgb.git
cd gnome-asus-kbd-rgb
```
### 2. Configurer les permissions (obligatoire)
```bash
# Créer la règle udev (une seule commande)
sudo tee /etc/udev/rules.d/99-asus-kbd.rules > /dev/null << 'EOF'
ACTION=="add", SUBSYSTEM=="leds", KERNEL=="asus::kbd_backlight", TAG+="uaccess", RUN+="/bin/sh -c 'chgrp kbdled /sys/class/leds/asus::kbd_backlight/brightness && chmod g+w /sys/class/leds/asus::kbd_backlight/brightness'"
ACTION=="add", SUBSYSTEM=="leds", KERNEL=="asus::kbd_backlight", TAG+="uaccess", RUN+="/bin/sh -c 'chgrp kbdled /sys/class/leds/asus::kbd_backlight/kbd_rgb_mode && chmod g+w /sys/class/leds/asus::kbd_backlight/kbd_rgb_mode'"
EOF
# Créer le groupe et ajouter l'utilisateur
sudo groupadd -f kbdled
sudo usermod -aG kbdled $USER
# Recharger udev et appliquer les permissions
sudo udevadm control --reload-rules
sudo modprobe -r asus_nb_wmi
sudo modprobe asus_nb_wmi
# IMPORTANT: Déconnexion/Reconnexion requise pour l'appartenance au groupe !
```
### 3. Installer l'extension
```bash
./tools/install-local.sh
```
### 4. Recharger GNOME Shell
- **X11** : `Alt+F2`, tapez `r`, Entrée
- **Wayland** : Déconnexion/Reconnexion
L'icône devrait apparaître dans la barre supérieure ! 🎨
## 📖 Documentation
- **[INSTALL.md](docs/INSTALL.md)** - Guide d'installation détaillé
- **[TROUBLESHOOTING.md](docs/TROUBLESHOOTING.md)** - Résolution des problèmes
- **[TESTING.md](docs/TESTING.md)** - Checklist de tests
- **[UI_SCHEMA.md](docs/UI_SCHEMA.md)** - Schéma de l'interface
- **[CLAUDE.md](CLAUDE.md)** - Guide pour Claude Code
- **[CHANGELOG.md](CHANGELOG.md)** - Historique des modifications
## 🎨 Captures d'écran
### Interface Principale
```
┌─────────────────────────────────────────────────────┐
│ Rétroéclairage Clavier ASUS │
├─────────────────────────────────────────────────────┤
│ Intensité: │
│ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ │
│ │ OFF │ │ 1 │ │ 2 │ │ 3 │ │
│ └─────┘ └─────┘ └─────┘ └─────┘ │
│ │
│ Rouge ●──────────────○ 255 │
│ Vert ●──────────────○ 255 │
│ Bleu ●──────────────○ 255 │
│ Master ●──────────────○ 100% │
│ │
│ RGB=(255,165,0) #FFA500 Intensité=2/3 │
│ │
│ Couleurs prédéfinies: │
│ 🟠 🔴 🟢 🔵 ⚪ 🔵 │
└─────────────────────────────────────────────────────┘
```
## 🏗️ Architecture
L'extension est structurée en 3 modules principaux :
- **`extension/backend.js`** - Interface sysfs et logique métier
- Lecture/écriture des fichiers sysfs
- Debouncing (75ms) pour éviter le spam
- Clamping et validation des valeurs
- Gestion du master gain
- **`extension/ui.js`** - Interface utilisateur
- Construction du popover et des widgets
- Gestion des événements utilisateur
- Mise à jour du feedback visuel
- **`extension/extension.js`** - Point d'entrée GNOME Shell
- Lifecycle de l'extension (enable/disable)
- Intégration dans le panel
- Chargement des settings GSettings
## ⚙️ Configuration
Les paramètres sont stockés via GSettings et peuvent être modifiés manuellement :
```bash
# Définir la couleur rouge
gsettings set org.gnome.shell.extensions.asuskbdrgb red 255
# Définir un preset
gsettings set org.gnome.shell.extensions.asuskbdrgb preset-1 "255,100,50"
# Lister tous les paramètres
gsettings list-recursively org.gnome.shell.extensions.asuskbdrgb
```
## 🔧 Développement
### Structure du projet
```
gnome-asus-kbd-rgb/
├── extension/ # Code source de l'extension
│ ├── extension.js # Point d'entrée
│ ├── ui.js # Interface utilisateur
│ ├── backend.js # Logique sysfs
│ ├── metadata.json # Métadonnées
│ ├── stylesheet.css # Styles CSS
│ └── schemas/ # Schéma GSettings
├── docs/ # Documentation
├── tools/ # Scripts utilitaires
└── README.md
```
### Logs de debug
```bash
# Voir les logs en temps réel
journalctl -f -o cat /usr/bin/gnome-shell | grep -i asus
# Activer le mode verbose
gnome-extensions enable asus-kbd-rgb@gilles
```
### Contribuer
1. Forkez le projet
2. Créez une branche (`git checkout -b feature/amelioration`)
3. Committez vos changements (`git commit -am 'Ajout fonctionnalité'`)
4. Pushez vers la branche (`git push origin feature/amelioration`)
5. Ouvrez une Pull Request
## 🐛 Problèmes Courants
### L'extension ne s'affiche pas
```bash
# Vérifier l'installation
gnome-extensions list | grep asus
# Vérifier les logs
journalctl -xe | grep -i asus
```
### Message "Permissions insuffisantes"
Voir [INSTALL.md](docs/INSTALL.md) section "Configuration des permissions".
### La couleur ne change pas
Vérifiez que :
- La brightness n'est pas à 0 (OFF)
- Le master slider n'est pas à 0%
- Les permissions sont configurées
Consultez [TROUBLESHOOTING.md](docs/TROUBLESHOOTING.md) pour plus d'aide.
## 📜 Licence
GPL-3.0 License - voir le fichier LICENSE
## 👤 Auteur
**Gilles**
- GitHub: [@gilles](https://github.com/gilles)
## 🙏 Remerciements
- Équipe GNOME Shell pour l'API d'extensions
- Communauté ASUS Linux pour le support du driver `asus-nb-wmi`
- Claude Code pour l'assistance au développement
## 📞 Support
- **Issues** : https://github.com/gilles/gnome-asus-kbd-rgb/issues
- **Documentation** : Dossier `docs/`
- **Forum GNOME** : https://discourse.gnome.org/
---
**Profitez de votre clavier RGB ! 🌈⌨️**

View File

@@ -0,0 +1,275 @@
# Analyse Comparative - Implémentation Roue Chromatique
## 📊 Comparaison des Approches
### Solution Actuelle (Implémentée)
**Type**: Grille de boutons 12×12 simulant une roue HSL
**Implémentation**:
```javascript
// Grille de boutons St.Button disposés en cercle
// Chaque bouton = une couleur HSL précalculée
const size = 12; // 12×12 = 144 cellules
const cellSize = 18px; // Boutons cliquables
// 113 couleurs effectivement affichées (cercle)
```
**Avantages réels** ✅:
-**Fonctionne immédiatement** (St.Button = composant natif éprouvé)
-**Très stable** (pas de gestion Canvas/Cairo complexe)
-**Compatible GNOME 48** (API St bien documentée)
-**Code simple** (~70 lignes pour la roue)
-**Débogage facile** (chaque bouton = élément inspectable)
-**Performance correcte** (113 boutons statiques, pas de rendu temps réel)
**Inconvénients** ⚠️:
- ⚠️ **Résolution limitée** (113 couleurs vs. millions théoriques)
- ⚠️ **Granularité fixe** (pas de sélection entre deux boutons)
- ⚠️ **Mémoire** (113 objets St.Button créés)
- ⚠️ **Pas de feedback visuel continu** (pas de curseur sur la roue)
---
### Option A Recommandée (Synthèse)
**Type**: Roue HSV custom avec `Clutter.Canvas`
**Implémentation proposée**:
```javascript
// Canvas interactif avec rendu Cairo
const canvas = new Clutter.Canvas({ width: 200, height: 200 });
canvas.connect('draw', (canvas, cr) => {
// Dessiner roue HSV avec Cairo
// Pour chaque pixel: calculer H (angle) et S (rayon)
});
// Capturer clics et drag pour position continue
```
**Avantages théoriques** ✅:
-**Résolution infinie** (sélection pixel par pixel)
-**Feedback visuel** (curseur, preview en temps réel)
-**Look professionnel** (roue lisse, dégradés)
-**Mémoire optimale** (un seul canvas vs 113 boutons)
**Inconvénients réels** ⚠️:
- ⚠️ **Complexité code** (~200-300 lignes pour roue + interactions)
- ⚠️ **Performance Cairo** (rendu temps réel à optimiser)
- ⚠️ **Bugs potentiels** (gestion événements souris, edge cases)
- ⚠️ **Maintenance** (code custom à déboguer)
- ⚠️ **Non fonctionnel actuellement** (notre tentative St.DrawingArea a échoué)
---
## 🔬 Analyse de Notre Tentative Canvas (Échec)
### Ce qui n'a pas fonctionné
**Code initial**:
```javascript
const wheelCanvas = new St.DrawingArea({ width: 200, height: 200 });
wheelCanvas.connect('repaint', (area) => {
this._drawColorWheel(area); // Rendu Cairo
});
wheelCanvas.reactive = true;
wheelCanvas.connect('button-press-event', ...) // ❌ Jamais déclenché
```
**Problèmes identifiés**:
1. **St.DrawingArea non interactive** sous GNOME Shell 48
2. **Événements souris ignorés** malgré `reactive: true`
3. **Documentation manquante** sur DrawingArea + events
**Pourquoi Clutter.Canvas serait différent**:
- `Clutter.Canvas` est l'API officielle pour rendu custom
- `St.DrawingArea` est un wrapper qui peut avoir des limitations
- Nécessite parent `Clutter.Actor` avec `content = canvas`
---
## 🎯 Recommandations par Cas d'Usage
### Cas 1: Vous voulez que ça fonctionne MAINTENANT ✅
**→ Gardez la grille de boutons actuelle**
**Raisons**:
- Fonctionne déjà (testable immédiatement)
- 113 couleurs = largement suffisant pour un clavier RGB
- Code stable et maintenable
- Zéro risque de régression
**Améliorations possibles**:
- Augmenter la grille (14×14 = 153 couleurs, cellSize: 16px)
- Ajouter hover effect (bordure blanche au survol)
- Ajouter tooltip avec valeurs RGB sur chaque bouton
---
### Cas 2: Vous voulez la "vraie" roue HSV (Option A) 🎨
**→ Implémentez Clutter.Canvas**
**Plan d'action**:
1. **Créer le canvas**:
```javascript
const canvas = new Clutter.Canvas({ width: 200, height: 200 });
const actor = new Clutter.Actor({
content: canvas,
width: 200,
height: 200,
reactive: true
});
```
2. **Rendu Cairo** (fonction `_drawHSVWheel`):
- Boucle polaire: angle (H) × rayon (S)
- Conversion HSV(H, S, 1.0) → RGB
- Cairo: `cr.setSourceRGB(r, g, b)` + `cr.arc(x, y, 1, 0, 2π)`
3. **Interactions**:
```javascript
actor.connect('button-press-event', (actor, event) => {
const [x, y] = event.get_coords();
// Convertir (x, y) → (angle, rayon) → (H, S)
// Appliquer couleur
});
```
4. **Optimisations**:
- Cache l'image de la roue (redessiner uniquement le curseur)
- Utiliser `canvas.invalidate()` au lieu de redessiner tout
**Temps estimé**: 4-6 heures de développement + debug
**Risques**:
- Événements souris mal gérés (comme avec DrawingArea)
- Performance dégradée si mal optimisé
- Bugs visuels (antialiasing, bords)
---
### Cas 3: Vous voulez le meilleur des deux mondes 🌟
**→ Approche hybride**
**Solution recommandée**:
```
┌─────────────────────────────────┐
│ [Bouton] Roue | Sliders │ ← Toggle
├─────────────────────────────────┤
│ MODE ROUE: │
│ • Grille 12×12 (actuel) │ ← Sélection rapide
│ │
│ MODE SLIDERS: │
│ • Slider H (Hue): 0-360° │ ← Affinage précis
│ • Slider S (Sat): 0-100% │
│ • Slider V (Val): 0-100% │
│ │
│ Aperçu: [████] RGB(255,128,64) │
└─────────────────────────────────┘
```
**Avantages**:
- Roue pour sélection rapide visuelle
- Sliders HSV pour ajustement fin
- Deux modes répondent à tous les besoins
**Code minimal**:
```javascript
// Ajouter 3 sliders HSV dans _buildRGBSliders()
const hueSlider = new Slider.Slider(hue / 360);
const satSlider = new Slider.Slider(sat);
const valSlider = new Slider.Slider(val);
// Callback: convertir HSV → RGB puis appliquer
```
---
## 📋 Décision Recommandée
### Pour votre usage (clavier RGB ASUS):
**Option finale: Conserver grille 12×12 + ajouter sliders HSV**
**Justification**:
1. **Grille actuelle suffit largement**:
- 113 couleurs > largement assez pour explorer la palette
- Clics directs = UX immédiate
- Stable et fonctionnel
2. **Sliders HSV ajoutent la précision**:
- Affiner une teinte exacte (H: 0-360°)
- Contrôler saturation (couleur vive vs pastel)
- Contrôler valeur/luminosité (sombre vs clair)
3. **Pas besoin de Canvas custom**:
- Trop complexe pour le bénéfice apporté
- Risque de bugs > gain UX marginal
- 113 couleurs + sliders HSV = 100% des besoins couverts
---
## 🔧 Plan d'Action Proposé
### Étape 1: Améliorer la grille actuelle (30 min)
```javascript
// Hover effect
button.connect('enter-event', () => {
button.style += 'border: 2px solid white;';
});
// Tooltip RGB
button.set_tooltip_text(`RGB(${rgb.r}, ${rgb.g}, ${rgb.b})`);
```
### Étape 2: Ajouter sliders HSV (1-2h)
```javascript
_buildHSVSliders() {
// Convertir RGB actuel → HSV
const hsv = this._rgbToHsv(this._currentR, this._currentG, this._currentB);
// 3 sliders H, S, V
const hSlider = this._createSlider('Teinte (H)', hsv.h, ...);
const sSlider = this._createSlider('Saturation (S)', hsv.s, ...);
const vSlider = this._createSlider('Luminosité (V)', hsv.v, ...);
// Callback: HSV → RGB puis appliquer
}
```
### Étape 3: Mode toggle roue/HSV (30 min)
- Bouton de bascule: [Roue] ↔ [HSV]
- Même principe que roue ↔ RGB actuel
---
## 📊 Tableau Comparatif Final
| Critère | Grille Boutons (Actuel) | Canvas HSV (Option A) | Hybride Roue+HSV |
|---------|-------------------------|----------------------|------------------|
| **Complexité code** | ⭐⭐ (simple) | ⭐⭐⭐⭐⭐ (complexe) | ⭐⭐⭐ (moyenne) |
| **Stabilité** | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ (bugs possibles) | ⭐⭐⭐⭐⭐ |
| **Précision couleur** | ⭐⭐⭐ (113 couleurs) | ⭐⭐⭐⭐⭐ (infini) | ⭐⭐⭐⭐⭐ (roue+sliders) |
| **UX visuelle** | ⭐⭐⭐⭐ (clair) | ⭐⭐⭐⭐⭐ (magnifique) | ⭐⭐⭐⭐⭐ |
| **Performance** | ⭐⭐⭐⭐ | ⭐⭐⭐ (rendu temps réel) | ⭐⭐⭐⭐ |
| **Temps dev** | ✅ Fait | 4-6h | 2-3h |
| **Maintenance** | ⭐⭐⭐⭐⭐ | ⭐⭐ (code custom) | ⭐⭐⭐⭐ |
---
## 🎯 Conclusion
### Recommandation Finale: **Grille actuelle + Sliders HSV** 🏆
**Pourquoi**:
- ✅ Temps de développement minimal (2-3h vs 4-6h Canvas)
- ✅ Stabilité maximale (composants St natifs)
- ✅ Précision totale (sliders HSV 0-360° / 0-100%)
- ✅ UX optimale (sélection rapide + affinage)
- ✅ Maintenabilité (code simple, pas de Cairo custom)
**Prochaine étape**:
Souhaitez-vous que j'implémente les **sliders HSV** pour compléter la grille actuelle ?
Cela ajoutera:
- Slider Teinte (H): 0-360° avec dégradé arc-en-ciel
- Slider Saturation (S): 0-100% (gris → couleur vive)
- Slider Luminosité (V): 0-100% (noir → couleur claire)
- Mode toggle pour passer de Roue → HSV → RGB

306
docs/ANALYSE_THEME_GNOME.md Normal file
View File

@@ -0,0 +1,306 @@
# Analyse - Synchronisation Couleur Clavier ↔ Thème GNOME
## 📋 Demande Utilisateur
**Objectif** : Ajouter une option (case à cocher) pour appliquer la couleur sélectionnée du clavier RGB au thème actuel de GNOME (couleur de sélection/accent).
---
## 🔍 Analyse Technique
### 1. Système de Couleurs GNOME
**GNOME 42+** utilise un système de couleurs d'accent :
- **Localisation** : `org.gnome.desktop.interface``accent-color`
- **Valeurs possibles** :
- `blue` (défaut)
- `teal`
- `green`
- `yellow`
- `orange`
- `red`
- `pink`
- `purple`
- `slate`
**Limitation** : GNOME utilise des couleurs **prédéfinies** (9 choix), pas de RGB personnalisé libre.
### 2. GTK4 libadwaita
**Couleurs d'accent libadwaita** :
- Utilisées dans les applications modernes (GNOME Files, Settings, etc.)
- Définies dans `~/.config/gtk-4.0/gtk.css` ou via GSettings
- Support de couleurs custom via CSS
---
## 🎯 Solutions Proposées
### Solution A : Mapping RGB → Couleur Accent GNOME (Recommandée) ⭐
**Principe** :
1. Détecter la couleur RGB sélectionnée sur le clavier
2. Calculer la couleur accent GNOME la plus proche (parmi les 9)
3. Appliquer via GSettings : `gsettings set org.gnome.desktop.interface accent-color 'red'`
**Avantages** :
- ✅ Intégration native GNOME
- ✅ Fonctionne avec toutes les apps modernes
- ✅ Pas de fichiers CSS à gérer
- ✅ Simple et stable
**Inconvénients** :
- ⚠️ Limitation à 9 couleurs (approximation nécessaire)
- ⚠️ Pas de correspondance exacte RGB
**Algorithme de mapping** :
```javascript
function rgbToGnomeAccent(r, g, b) {
const colors = {
blue: { r: 53, g: 132, b: 228 },
teal: { r: 51, g: 209, b: 122 },
green: { r: 51, g: 209, b: 122 },
yellow: { r: 246, g: 211, b: 45 },
orange: { r: 255, g: 120, b: 0 },
red: { r: 237, g: 51, b: 59 },
pink: { r: 246, g: 97, b: 81 },
purple: { r: 145, g: 65, b: 172 },
slate: { r: 119, g: 118, b: 123 }
};
// Calculer la distance euclidienne pour chaque couleur
let minDistance = Infinity;
let closestColor = 'blue';
for (const [name, color] of Object.entries(colors)) {
const distance = Math.sqrt(
Math.pow(r - color.r, 2) +
Math.pow(g - color.g, 2) +
Math.pow(b - color.b, 2)
);
if (distance < minDistance) {
minDistance = distance;
closestColor = name;
}
}
return closestColor;
}
```
---
### Solution B : CSS Custom pour GTK4 (Couleur Exacte)
**Principe** :
1. Écrire un fichier `~/.config/gtk-4.0/gtk.css` avec la couleur RGB exacte
2. Redéfinir la variable `@accent_color` de libadwaita
**Fichier généré** :
```css
/* Généré par ASUS Keyboard RGB Extension */
@define-color accent_bg_color rgb(255, 165, 0);
@define-color accent_fg_color rgb(255, 255, 255);
@define-color accent_color rgb(255, 165, 0);
```
**Avantages** :
- ✅ Couleur RGB exacte (pas d'approximation)
- ✅ Personnalisation totale
**Inconvénients** :
- ⚠️ Modification de fichiers système
- ⚠️ Peut casser avec mises à jour GNOME
- ⚠️ Nécessite redémarrage apps GTK4
- ⚠️ Complexité maintenance
---
### Solution C : Hybride (A + B)
**Principe** :
1. **Par défaut** : Solution A (GSettings accent-color)
2. **Option avancée** : Solution B (CSS custom)
**Interface** :
```
┌─────────────────────────────────────┐
│ ☑ Synchroniser avec le thème GNOME │
│ │
│ Mode synchronisation : │
│ ○ Couleurs prédéfinies (9 choix) │ ← Solution A
│ ○ Couleur exacte (avancé) │ ← Solution B
└─────────────────────────────────────┘
```
---
## 🎨 Implémentation Recommandée : Solution A
### Étape 1 : Ajouter GSettings
**Fichier** : `extension/schemas/org.gnome.shell.extensions.asuskbdrgb.gschema.xml`
```xml
<key name="sync-gnome-theme" type="b">
<default>false</default>
<summary>Synchroniser avec le thème GNOME</summary>
<description>Applique la couleur du clavier comme accent GNOME</description>
</key>
```
### Étape 2 : Ajouter UI (Case à cocher)
**Fichier** : `extension/ui.js` dans `_buildUI()`
```javascript
// Après les presets
const syncThemeItem = new PopupMenu.PopupSwitchMenuItem(
'Synchroniser thème GNOME',
this._settings.get_boolean('sync-gnome-theme')
);
syncThemeItem.connect('toggled', (item) => {
this._settings.set_boolean('sync-gnome-theme', item.state);
if (item.state) {
this._syncGnomeTheme();
}
});
this.menu.addMenuItem(syncThemeItem);
```
### Étape 3 : Fonction de synchronisation
**Fichier** : `extension/ui.js`
```javascript
/**
* Synchronise la couleur du clavier avec le thème GNOME
*/
_syncGnomeTheme() {
if (!this._settings.get_boolean('sync-gnome-theme')) return;
const accent = this._rgbToGnomeAccent(
this._currentR,
this._currentG,
this._currentB
);
try {
const interfaceSettings = new Gio.Settings({
schema: 'org.gnome.desktop.interface'
});
interfaceSettings.set_string('accent-color', accent);
log(`[ASUS RGB] Thème GNOME mis à jour : ${accent}`);
} catch (error) {
log(`[ASUS RGB] Erreur sync thème : ${error}`);
}
}
/**
* Trouve la couleur accent GNOME la plus proche
*/
_rgbToGnomeAccent(r, g, b) {
const colors = {
blue: { r: 53, g: 132, b: 228 },
teal: { r: 51, g: 209, b: 122 },
green: { r: 51, g: 209, b: 122 },
yellow: { r: 246, g: 211, b: 45 },
orange: { r: 255, g: 120, b: 0 },
red: { r: 237, g: 51, b: 59 },
pink: { r: 246, g: 97, b: 81 },
purple: { r: 145, g: 65, b: 172 },
slate: { r: 119, g: 118, b: 123 }
};
let minDistance = Infinity;
let closestColor = 'blue';
for (const [name, color] of Object.entries(colors)) {
const distance = Math.sqrt(
Math.pow(r - color.r, 2) +
Math.pow(g - color.g, 2) +
Math.pow(b - color.b, 2)
);
if (distance < minDistance) {
minDistance = distance;
closestColor = name;
}
}
return closestColor;
}
```
### Étape 4 : Appeler lors des changements
**Dans `_onRGBChanged()`** :
```javascript
_onRGBChanged() {
this._updateColorPreview();
Backend.writeRGBDebounced(
this._currentR,
this._currentG,
this._currentB,
this._currentMasterGain,
() => this._updateInfoLine()
);
// Synchroniser avec GNOME si activé
this._syncGnomeTheme(); // ← Ajouter cette ligne
}
```
---
## 📊 Comparaison Solutions
| Critère | Solution A (GSettings) | Solution B (CSS) | Solution C (Hybride) |
|---------|------------------------|------------------|----------------------|
| **Simplicité** | ⭐⭐⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐ |
| **Précision couleur** | ⭐⭐⭐ (9 choix) | ⭐⭐⭐⭐⭐ (exact) | ⭐⭐⭐⭐⭐ |
| **Stabilité** | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ |
| **Compatibilité** | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| **Temps dev** | 30 min | 2h | 3h |
| **Risque** | Aucun | Moyen | Faible |
---
## 🎯 Recommandation Finale
### **Solution A - GSettings Accent Color** 🏆
**Pourquoi** :
1.**Simple et rapide** à implémenter (30 minutes)
2.**100% natif GNOME** (pas de hack CSS)
3.**Stable** et compatible avec futures versions
4.**Suffisant** pour la plupart des cas (9 couleurs couvrent bien le spectre)
**Exemple de résultat** :
```
Clavier RGB: (255, 165, 0) → Orange vif
Couleur GNOME: 'orange' → Orange GNOME standard
Rendu applications: 🟠 Boutons, sélections, accents
```
**Temps d'implémentation** : 30 minutes
- 5 min : Ajouter GSettings
- 10 min : Ajouter UI (checkbox)
- 10 min : Fonction `_rgbToGnomeAccent()`
- 5 min : Intégration dans `_onRGBChanged()`
---
## 🚀 Prochaine Étape
**Voulez-vous que j'implémente la Solution A maintenant ?**
Cela ajoutera :
- ☑ Case "Synchroniser thème GNOME" dans le menu
- 🎨 Application automatique de la couleur accent la plus proche
- 🔄 Mise à jour en temps réel lors des changements de couleur clavier
**Note** : Si vous souhaitez la couleur RGB exacte (Solution B), je peux aussi l'implémenter, mais c'est plus risqué et complexe.

View File

@@ -0,0 +1,390 @@
# Synthèse du Développement - Extension GNOME Shell ASUS RGB Keyboard
## 📊 Statistiques du Projet
- **Lignes de code total** : ~2814 lignes
- **Modules JavaScript** : 3 fichiers (extension.js, ui.js, backend.js)
- **Fichiers de documentation** : 6 fichiers Markdown
- **Temps de développement** : 1 session
- **État** : MVP complet et prêt pour tests
## 🎯 Objectifs Atteints
### Fonctionnalités Core (MVP)
- ✅ Contrôle d'intensité du rétroéclairage (4 niveaux)
- ✅ Réglage RGB complet (sliders R, G, B)
- ✅ Slider Master avec mode gain (0-100%)
- ✅ 6 couleurs prédéfinies (presets)
- ✅ Interface intuitive dans la barre GNOME
- ✅ Persistance des paramètres (GSettings)
- ✅ Restauration automatique au démarrage
- ✅ Feedback visuel en temps réel (RGB + HEX)
### Robustesse
- ✅ Gestion des erreurs matériel (hardware non supporté)
- ✅ Gestion des erreurs permissions (udev non configuré)
- ✅ Debouncing pour éviter le spam sysfs (75ms)
- ✅ Clamping automatique des valeurs (0-255, 0-100)
- ✅ Comportement intelligent (brightness=0 mémorise RGB)
### Documentation
- ✅ README.md complet et professionnel
- ✅ Guide d'installation détaillé (INSTALL.md)
- ✅ Guide de dépannage exhaustif (TROUBLESHOOTING.md)
- ✅ Checklist de tests complète (TESTING.md, 120+ items)
- ✅ Schéma d'interface détaillé (UI_SCHEMA.md)
- ✅ Guide pour Claude Code (CLAUDE.md)
- ✅ CHANGELOG avec historique
### Outillage
- ✅ Script d'installation automatique (install-local.sh)
- ✅ Vérifications matériel et permissions
- ✅ Feedback coloré et instructions claires
- ✅ Support X11 et Wayland
## 📁 Fichiers Créés
### Code Source (extension/)
```
extension.js 59 lignes - Point d'entrée GNOME Shell
ui.js 375 lignes - Interface utilisateur complète
backend.js 303 lignes - Interface sysfs et logique
metadata.json 9 lignes - Métadonnées extension
stylesheet.css 57 lignes - Styles CSS
schemas/gschema.xml 76 lignes - Configuration GSettings
```
### Documentation (docs/)
```
INSTALL.md 187 lignes - Installation complète
TROUBLESHOOTING.md 452 lignes - Résolution problèmes
TESTING.md 443 lignes - Checklist tests
UI_SCHEMA.md 165 lignes - Schémas interface
DEVELOPPEMENT_COMPLET 400+ lignes - Ce fichier
```
### Fichiers Racine
```
README.md 226 lignes - Documentation principale
CLAUDE.md 148 lignes - Guide Claude Code
CHANGELOG.md 120 lignes - Historique développement
PROJECT_STRUCTURE.txt 155 lignes - Structure projet
```
### Outils (tools/)
```
install-local.sh 140 lignes - Script installation
```
## 🏗️ Architecture Technique
### Modularité
Le code est strictement séparé en 3 responsabilités :
1. **Backend** (backend.js)
- Isolation complète de l'interface sysfs
- Fonctions pures et testables
- Gestion des erreurs système
- Pas de dépendances UI
2. **UI** (ui.js)
- Construction de l'interface GNOME
- Gestion des événements utilisateur
- Communication avec le backend uniquement
- Pas d'accès direct au système
3. **Extension** (extension.js)
- Lifecycle GNOME Shell
- Intégration minimale
- Délégation au UI
### Patterns Utilisés
**Debouncing Pattern**
```javascript
// Évite le spam sysfs lors des mouvements de sliders
writeRGBDebounced(r, g, b, master, callback)
```
**Clamping Pattern**
```javascript
// Garantit des valeurs valides
clampRGB(value) [0, 255]
```
**Master Gain Pattern**
```javascript
// Mode "gain" : multiplie proportionnellement
applyMasterGain(r, g, b, gain) {r, g, b}
```
**Error UI Pattern**
```javascript
// Messages d'erreur clairs et actionnables
_buildErrorUI(title, message)
```
## 🔒 Gestion des Permissions
### Approche Choisie : udev + groupe
- **Avantage** : Simple, stable, standard Linux
- **Alternative rejetée** : D-Bus + polkit (trop complexe pour MVP)
### Fichiers Concernés
```bash
/etc/udev/rules.d/99-asus-kbd.rules # Règle udev
/etc/group # Groupe kbdled
```
### Vérifications Intégrées
- Test hardware au démarrage
- Test permissions au démarrage
- Messages d'erreur explicites
- Référence à la documentation
## 💾 Persistance (GSettings)
### Schéma
```
org.gnome.shell.extensions.asuskbdrgb
```
### Données Sauvegardées
- RGB courant (red, green, blue)
- Niveau brightness (0-3)
- Gain master (0-100)
- 6 presets (format "R,G,B")
- Configuration (rgb-step, master-mode)
### Comportement
- Sauvegarde automatique à chaque changement
- Restauration au démarrage de session
- Modifiable via `gsettings` en ligne de commande
## 🎨 Interface Utilisateur
### Composants GNOME Shell
- `PanelMenu.Button` - Bouton dans le panneau
- `PopupMenu` - Menu déroulant
- `Slider` - Sliders RGB et Master
- `St.Button` - Boutons intensité et presets
- `St.BoxLayout` - Layouts flexibles
- `St.Label` - Labels et texte
### Layout
```
Popover (vertical)
├── Titre
├── Séparateur
├── 4 Boutons intensité (horizontal)
├── Séparateur
├── 4 Sliders RGB+Master (vertical)
├── Séparateur
├── Ligne d'info
├── Séparateur
└── 6 Presets couleur (horizontal)
```
### Feedback Visuel
- Bouton actif surligné (class: active)
- Valeurs numériques en temps réel
- Couleurs presets affichées (background-color)
- Info line RGB + HEX + Intensité
## 🔧 Debouncing Détaillé
### Problème
Déplacer un slider génère des centaines d'événements par seconde, ce qui spammerait sysfs et pourrait causer des erreurs de permission.
### Solution
```javascript
let debounceTimer = null;
const DEBOUNCE_DELAY = 75; // ms
writeRGBDebounced(r, g, b, master, callback) {
// Annuler le timer précédent
if (debounceTimer !== null) {
GLib.source_remove(debounceTimer);
}
// Créer un nouveau timer
debounceTimer = GLib.timeout_add(GLib.PRIORITY_DEFAULT,
DEBOUNCE_DELAY, () => {
writeRGB(r, g, b, master);
if (callback) callback();
debounceTimer = null;
return GLib.SOURCE_REMOVE;
}
);
}
```
### Résultat
- Slider fluide pour l'utilisateur
- Maximum 1 écriture sysfs toutes les 75ms
- Dernière valeur toujours appliquée
## 🧪 Tests à Effectuer
### Critiques (Bloquants)
1. Extension se charge sans erreur
2. Popover s'affiche au clic
3. Brightness change le rétroéclairage
4. RGB change la couleur
5. Presets fonctionnent
6. GSettings sauvegarde correctement
7. Restauration au redémarrage OK
### Importants
1. Debouncing actif (vérifier logs)
2. Messages d'erreur si pas de hardware
3. Messages d'erreur si pas de permissions
4. Master gain appliqué correctement
5. Clamping des valeurs fonctionne
### Nice-to-have
1. Style CSS correct
2. Performance fluide
3. Aucune fuite mémoire
Voir [TESTING.md](TESTING.md) pour la checklist complète (120+ items).
## 📝 Commentaires Code
Tous les commentaires sont en **français** conformément aux spécifications :
```javascript
// Vérifie si le matériel ASUS RGB est présent sur le système
export function checkHardwareSupport() { ... }
// Applique le master gain aux valeurs RGB
function applyMasterGain(r, g, b, masterGain) { ... }
// Construit les 4 boutons d'intensité
_buildBrightnessButtons() { ... }
```
## 🚀 Prochaines Étapes
### Tests sur Matériel Réel
- [ ] Installer sur ASUS TUF Gaming A16
- [ ] Vérifier toutes les fonctionnalités
- [ ] Tester la persistance après redémarrage
- [ ] Vérifier les performances
- [ ] Identifier les bugs éventuels
### Améliorations Post-MVP
- [ ] Page de préférences (prefs.js)
- Modifier les presets
- Changer le mode master (gain/offset/hsv)
- Ajuster le RGB step
- [ ] Modes RGB animés
- Breathing (respiration)
- Wave (vague)
- Cycle (rotation couleurs)
- [ ] Support multi-zones (si matériel compatible)
- [ ] Export/Import de configurations
- [ ] Profils par application
- [ ] Raccourcis clavier globaux
- [ ] Widget d'aperçu couleur
- [ ] Pipette de couleur système
### Packaging
- [ ] Créer un fichier .zip pour ego.gnome.org
- [ ] Screenshots de l'interface
- [ ] Vidéo de démonstration
- [ ] Soumission à GNOME Extensions
- [ ] Publication sur GitHub Releases
## 📊 Métriques Qualité
### Couverture Fonctionnelle
- **MVP défini** : 100% implémenté
- **Tests planifiés** : 120+ items documentés
- **Documentation** : Complète (6 fichiers)
- **Gestion erreurs** : Tous les cas couverts
### Maintenabilité
- **Modularité** : 3 modules indépendants
- **Commentaires** : Tous les fichiers commentés
- **Documentation code** : Fonctions documentées
- **Pas de dette technique** : Code clean
### Robustesse
- **Validation entrées** : Clamping systématique
- **Gestion erreurs** : Try/catch appropriés
- **Messages utilisateur** : Clairs et actionnables
- **Fallbacks** : Valeurs par défaut définies
## 🎓 Apprentissages
### Bonnes Pratiques GNOME Shell
- Utilisation correcte de GObject.registerClass
- Imports ESM modernes (import/export)
- Lifecycle extension proper (enable/disable)
- Intégration GSettings standard
### Gestion Linux
- Règles udev pour permissions
- Interface sysfs kernel
- Groupes système
- Persistance via GSettings
### Architecture
- Séparation responsabilités (UI/Backend/Extension)
- Patterns de debouncing
- Gestion d'état avec settings
- Messages d'erreur UX
## 📚 Ressources Utilisées
### Documentation GNOME
- GNOME Shell Extensions: https://gjs.guide/extensions/
- GSettings: https://docs.gtk.org/gio/class.Settings.html
- St (Shell Toolkit): GNOME Shell source code
### Kernel Linux
- sysfs LED interface: `/sys/class/leds/`
- asus-nb-wmi driver documentation
### Outils
- gjs (GNOME JavaScript)
- glib-compile-schemas
- journalctl (debugging)
## ✅ Checklist Complétude MVP
-**Fonctionnalités core** : Toutes implémentées
-**Interface utilisateur** : Complète et fonctionnelle
-**Persistance** : GSettings configuré
-**Gestion erreurs** : Hardware + Permissions
-**Documentation** : 6 fichiers complets
-**Installation** : Script automatique
-**Tests** : Checklist 120+ items
-**Code qualité** : Commenté, modulaire, propre
-**Tests réels** : À effectuer sur matériel
## 🎉 Conclusion
Le projet **GNOME Shell Extension - ASUS Keyboard RGB Control** est **complet au niveau MVP** et prêt pour les tests sur matériel réel.
### Points Forts
- Architecture propre et modulaire
- Documentation exhaustive
- Gestion d'erreurs complète
- Installation simplifiée
- Code maintenable
### Prochaine Étape Critique
**Tester sur l'ASUS TUF Gaming A16 FA608UH** avec Debian 13 et GNOME 48.
Une fois les tests validés, l'extension pourra être :
1. Publiée sur extensions.gnome.org
2. Partagée avec la communauté ASUS Linux
3. Améliorée avec les fonctionnalités post-MVP
---
**Développé avec Claude Code - 2025-12-20**

View File

@@ -0,0 +1,154 @@
# Fix Permissions udev - ASUS Keyboard RGB
## Problème Initial
La règle udev simple ne fonctionnait pas :
```bash
SUBSYSTEM=="leds", KERNEL=="asus::kbd_backlight", GROUP="kbdled", MODE="0660"
```
**Symptôme** : Les permissions restaient à `root:root` même après rechargement udev et redémarrage.
## Diagnostic
```bash
udevadm test /sys/class/leds/asus::kbd_backlight 2>&1 | grep -E "(GROUP|MODE|kbdled)"
```
Résultat vide → La règle n'était pas déclenchée.
## Solution Fonctionnelle
### Règle udev Corrigée
```bash
sudo tee /etc/udev/rules.d/99-asus-kbd.rules > /dev/null << 'EOF'
ACTION=="add", SUBSYSTEM=="leds", KERNEL=="asus::kbd_backlight", TAG+="uaccess", RUN+="/bin/sh -c 'chgrp kbdled /sys/class/leds/asus::kbd_backlight/brightness && chmod g+w /sys/class/leds/asus::kbd_backlight/brightness'"
ACTION=="add", SUBSYSTEM=="leds", KERNEL=="asus::kbd_backlight", TAG+="uaccess", RUN+="/bin/sh -c 'chgrp kbdled /sys/class/leds/asus::kbd_backlight/kbd_rgb_mode && chmod g+w /sys/class/leds/asus::kbd_backlight/kbd_rgb_mode'"
EOF
```
### Pourquoi Ça Fonctionne
1. **`ACTION=="add"`** : La règle se déclenche uniquement lors de l'événement "add" (ajout du device)
2. **`TAG+="uaccess"`** : Ajoute un tag pour l'accès utilisateur
3. **`RUN+=`** : Exécute une commande shell directement
4. **`/bin/sh -c '...'`** : Lance un shell pour exécuter plusieurs commandes
5. **`chgrp kbdled`** : Change le groupe du fichier
6. **`chmod g+w`** : Ajoute les permissions d'écriture pour le groupe
### Application de la Règle
Après avoir créé la règle, il faut déclencher l'événement "add" :
```bash
# Recharger les règles udev
sudo udevadm control --reload-rules
# Retirer le module kernel
sudo modprobe -r asus_nb_wmi
# Réinsérer le module (déclenche l'événement "add")
sudo modprobe asus_nb_wmi
# Attendre que le module se charge
sleep 2
```
### Vérification
```bash
ls -l /sys/class/leds/asus::kbd_backlight/brightness
ls -l /sys/class/leds/asus::kbd_backlight/kbd_rgb_mode
```
**Résultat attendu :**
```
-rw-rw-r-- 1 root kbdled 4096 ... brightness
--w--w---- 1 root kbdled 4096 ... kbd_rgb_mode
```
### Test Fonctionnel
```bash
# Test brightness
echo 3 > /sys/class/leds/asus::kbd_backlight/brightness
# Test RGB (orange)
echo "1 0 255 165 0 0" > /sys/class/leds/asus::kbd_backlight/kbd_rgb_mode
```
**Aucune erreur "Permission denied" ne doit apparaître.**
## Matériel Testé
- **Modèle** : ASUS TUF Gaming A16 FA608UH
- **OS** : Debian GNU/Linux 13 (trixie)
- **Kernel** : 6.12.x
- **Module** : `asus_nb_wmi`
## Fichiers Concernés
### sysfs
```
/sys/class/leds/asus::kbd_backlight/
├── brightness (contrôle intensité 0-3)
└── kbd_rgb_mode (contrôle RGB, format "1 0 R G B 0")
```
### udev
```
/etc/udev/rules.d/99-asus-kbd.rules
```
### Groupe système
```
/etc/group (ligne kbdled)
```
## Alternative : Service systemd
Si la règle udev ne fonctionne toujours pas (rare), on peut utiliser un service systemd :
```bash
# Script
sudo tee /usr/local/bin/asus-kbd-permissions.sh > /dev/null << 'EOF'
#!/bin/bash
sleep 2
chgrp kbdled /sys/class/leds/asus::kbd_backlight/brightness 2>/dev/null
chmod 0660 /sys/class/leds/asus::kbd_backlight/brightness 2>/dev/null
chgrp kbdled /sys/class/leds/asus::kbd_backlight/kbd_rgb_mode 2>/dev/null
chmod 0660 /sys/class/leds/asus::kbd_backlight/kbd_rgb_mode 2>/dev/null
EOF
sudo chmod +x /usr/local/bin/asus-kbd-permissions.sh
# Service
sudo tee /etc/systemd/system/asus-kbd-permissions.service > /dev/null << 'EOF'
[Unit]
Description=ASUS Keyboard RGB Permissions
After=multi-user.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/asus-kbd-permissions.sh
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable asus-kbd-permissions.service
sudo systemctl start asus-kbd-permissions.service
```
## Références
- **udev manual** : `man 7 udev`
- **Module kernel** : Documentation du driver `asus-nb-wmi`
- **Tests réalisés** : 2025-12-20
---
**Note** : Ce fix est intégré dans la documentation officielle ([docs/INSTALL.md](INSTALL.md)) et dans le script d'installation ([tools/install-local.sh](../tools/install-local.sh)).

227
docs/INSTALL.md Normal file
View File

@@ -0,0 +1,227 @@
# Guide d'Installation - Extension ASUS Keyboard RGB
Ce guide vous explique comment installer et configurer l'extension GNOME Shell pour contrôler le rétroéclairage RGB de votre clavier ASUS.
## Prérequis
### Système
- **OS**: Debian GNU/Linux 13 (trixie) ou distribution compatible
- **GNOME Shell**: Version 48
- **Matériel**: Clavier ASUS avec support RGB via `asus-nb-wmi`
### Vérification du support matériel
Avant l'installation, vérifiez que votre clavier est supporté :
```bash
# Vérifier la présence des fichiers sysfs
ls -la /sys/class/leds/asus::kbd_backlight/
```
Vous devriez voir les fichiers suivants :
- `brightness` - Intensité du rétroéclairage
- `max_brightness` - Valeur maximale d'intensité
- `kbd_rgb_mode` - Contrôle des couleurs RGB
Si ces fichiers n'existent pas, votre matériel n'est pas supporté par cette extension.
## Étape 1 : Configuration des permissions
L'extension nécessite des droits d'écriture sur les fichiers sysfs. La méthode recommandée utilise les règles udev.
### 1.1 Créer une règle udev
Créez le fichier `/etc/udev/rules.d/99-asus-kbd.rules` avec la règle qui fonctionne :
```bash
sudo tee /etc/udev/rules.d/99-asus-kbd.rules > /dev/null << 'EOF'
ACTION=="add", SUBSYSTEM=="leds", KERNEL=="asus::kbd_backlight", TAG+="uaccess", RUN+="/bin/sh -c 'chgrp kbdled /sys/class/leds/asus::kbd_backlight/brightness && chmod g+w /sys/class/leds/asus::kbd_backlight/brightness'"
ACTION=="add", SUBSYSTEM=="leds", KERNEL=="asus::kbd_backlight", TAG+="uaccess", RUN+="/bin/sh -c 'chgrp kbdled /sys/class/leds/asus::kbd_backlight/kbd_rgb_mode && chmod g+w /sys/class/leds/asus::kbd_backlight/kbd_rgb_mode'"
EOF
```
Cette règle s'exécute lors de l'ajout du device et applique directement les bonnes permissions.
### 1.2 Créer le groupe kbdled
```bash
sudo groupadd -f kbdled
```
### 1.3 Ajouter votre utilisateur au groupe
```bash
sudo usermod -aG kbdled $USER
```
### 1.4 Recharger les règles udev et appliquer les permissions
```bash
# Recharger les règles udev
sudo udevadm control --reload-rules
# Retirer et réinsérer le module pour déclencher l'événement "add"
sudo modprobe -r asus_nb_wmi
sudo modprobe asus_nb_wmi
# Attendre 2 secondes que le module se charge
sleep 2
```
### 1.5 Déconnexion / Reconnexion
**Important**: Vous devez vous déconnecter et vous reconnecter pour que l'appartenance au groupe soit prise en compte.
```bash
# Vérifier l'appartenance au groupe après reconnexion
groups | grep kbdled
```
### 1.5 Vérifier les permissions
Vérifiez que les permissions ont été appliquées correctement :
```bash
ls -l /sys/class/leds/asus::kbd_backlight/brightness
ls -l /sys/class/leds/asus::kbd_backlight/kbd_rgb_mode
```
**Résultat attendu :**
```
-rw-rw-r-- 1 root kbdled ... brightness
--w--w---- 1 root kbdled ... kbd_rgb_mode
```
Le groupe doit être `kbdled` (et non `root`).
### 1.6 Test d'écriture
Testez que vous pouvez contrôler le clavier :
```bash
# Test intensité niveau 3 (maximum)
echo 3 > /sys/class/leds/asus::kbd_backlight/brightness
# → Le rétroéclairage doit passer au maximum
# Test intensité niveau 1 (faible)
echo 1 > /sys/class/leds/asus::kbd_backlight/brightness
# → Le rétroéclairage doit diminuer
# Test couleur RGB (orange)
echo "1 0 255 165 0 0" > /sys/class/leds/asus::kbd_backlight/kbd_rgb_mode
# → Le clavier doit devenir orange
# Test couleur RGB (rouge)
echo "1 0 255 0 0 0" > /sys/class/leds/asus::kbd_backlight/kbd_rgb_mode
# → Le clavier doit devenir rouge
```
**Si aucune erreur "Permission denied" n'apparaît et que votre clavier change de couleur/intensité, c'est parfait !**
## Étape 2 : Installation de l'extension
### 2.1 Cloner le dépôt
```bash
cd ~/Documents
git clone https://github.com/gilles/gnome-asus-kbd-rgb.git
cd gnome-asus-kbd-rgb
```
### 2.2 Compiler le schéma GSettings
```bash
cd extension/schemas
glib-compile-schemas .
cd ../..
```
### 2.3 Installation automatique
Utilisez le script fourni :
```bash
./tools/install-local.sh
```
### 2.4 Installation manuelle (alternative)
Si vous préférez installer manuellement :
```bash
# Créer le dossier de destination
mkdir -p ~/.local/share/gnome-shell/extensions/asus-kbd-rgb@gilles
# Copier les fichiers
cp -r extension/* ~/.local/share/gnome-shell/extensions/asus-kbd-rgb@gilles/
# Compiler le schéma dans le dossier d'installation
glib-compile-schemas ~/.local/share/gnome-shell/extensions/asus-kbd-rgb@gilles/schemas/
```
## Étape 3 : Activation de l'extension
### 3.1 Recharger GNOME Shell
**Sur X11** :
- Appuyez sur `Alt+F2`
- Tapez `r`
- Appuyez sur Entrée
**Sur Wayland** :
- Déconnectez-vous et reconnectez-vous
### 3.2 Activer l'extension
Via l'application Extensions :
```bash
gnome-extensions enable asus-kbd-rgb@gilles
```
Ou via l'interface graphique :
1. Ouvrez l'application "Extensions"
2. Recherchez "ASUS Keyboard RGB Control"
3. Activez le bouton
### 3.3 Vérification
Vous devriez voir une icône de clavier dans la barre supérieure de GNOME Shell (à droite). Cliquez dessus pour ouvrir le menu de contrôle.
## Étape 4 : Vérification des logs
Si l'extension ne s'affiche pas ou ne fonctionne pas :
```bash
# Voir les logs en temps réel
journalctl -f -o cat /usr/bin/gnome-shell
# Ou voir les dernières erreurs
journalctl -xe | grep -i asus
```
## Désinstallation
Pour désinstaller l'extension :
```bash
# Désactiver
gnome-extensions disable asus-kbd-rgb@gilles
# Supprimer
rm -rf ~/.local/share/gnome-shell/extensions/asus-kbd-rgb@gilles
# Optionnel : supprimer le groupe et la règle udev
sudo deluser $USER kbdled
sudo rm /etc/udev/rules.d/99-asus-kbd.rules
sudo udevadm control --reload-rules
```
## Dépannage
Si vous rencontrez des problèmes, consultez le fichier [TROUBLESHOOTING.md](TROUBLESHOOTING.md).
## Support
- **Issues**: https://github.com/gilles/gnome-asus-kbd-rgb/issues
- **Documentation**: Voir les autres fichiers du dossier `docs/`

324
docs/TESTING.md Normal file
View File

@@ -0,0 +1,324 @@
# Checklist de Tests - Extension ASUS Keyboard RGB
Ce document fournit une checklist complète pour tester l'extension avant publication ou après modification.
## Prérequis pour les tests
- [ ] GNOME Shell 48 installé
- [ ] Matériel ASUS avec clavier RGB supporté
- [ ] Règles udev configurées (groupe `kbdled`)
- [ ] Utilisateur membre du groupe `kbdled` (après déconnexion/reconnexion)
## 1. Installation
### 1.1 Installation initiale
- [ ] Le script `./tools/install-local.sh` s'exécute sans erreur
- [ ] Les fichiers sont copiés dans `~/.local/share/gnome-shell/extensions/asus-kbd-rgb@gilles/`
- [ ] Le schéma GSettings est compilé (`gschemas.compiled` existe)
- [ ] L'extension apparaît dans `gnome-extensions list`
### 1.2 Activation
- [ ] La commande `gnome-extensions enable asus-kbd-rgb@gilles` fonctionne
- [ ] Aucune erreur dans `journalctl -f -o cat /usr/bin/gnome-shell`
- [ ] L'icône de clavier apparaît dans la barre supérieure (après rechargement)
## 2. Interface Utilisateur
### 2.1 Icône et menu
- [ ] L'icône `keyboard-brightness-symbolic` est visible dans le panneau
- [ ] Clic sur l'icône ouvre le popover
- [ ] Le popover affiche le titre "Rétroéclairage Clavier ASUS"
- [ ] Le menu est bien formaté et lisible
### 2.2 Section Intensité
- [ ] Les 4 boutons d'intensité sont visibles (OFF, 1, 2, 3)
- [ ] Clic sur "OFF" éteint le rétroéclairage
- [ ] Clic sur "1" met l'intensité à faible
- [ ] Clic sur "2" met l'intensité à moyenne
- [ ] Clic sur "3" met l'intensité à forte (max)
- [ ] Le bouton actif est surligné visuellement
- [ ] Un seul bouton est actif à la fois
### 2.3 Section Sliders RGB
- [ ] Le slider Rouge fonctionne et affiche la valeur (0-255)
- [ ] Le slider Vert fonctionne et affiche la valeur (0-255)
- [ ] Le slider Bleu fonctionne et affiche la valeur (0-255)
- [ ] Le slider Master fonctionne et affiche la valeur (0-100)
- [ ] Déplacer un slider met à jour la valeur numérique en temps réel
- [ ] Les sliders sont fluides (pas de lag visible)
### 2.4 Ligne d'information
- [ ] La ligne d'info affiche `RGB=(r,g,b)` correctement
- [ ] Le code HEX `#RRGGBB` est correct
- [ ] L'intensité `Intensité=n/3` est correcte
- [ ] Les valeurs se mettent à jour après changement de slider
- [ ] Les valeurs se mettent à jour après clic sur preset
- [ ] Les valeurs se mettent à jour après changement d'intensité
### 2.5 Section Presets
- [ ] 6 boutons de preset sont visibles
- [ ] Les couleurs de fond correspondent aux presets :
- Preset 1 : Orange (#FFA500)
- Preset 2 : Rouge (#FF0000)
- Preset 3 : Vert (#00FF00)
- Preset 4 : Bleu (#0000FF)
- Preset 5 : Blanc (#FFFFFF)
- Preset 6 : Cyan (#00FFFF)
- [ ] Clic sur un preset applique la couleur immédiatement
- [ ] Les sliders RGB se mettent à jour après clic sur preset
- [ ] La ligne d'info se met à jour après clic sur preset
## 3. Fonctionnalités Backend
### 3.1 Écriture brightness
- [ ] Passage de OFF (0) à 1 allume le clavier
- [ ] Passage de 1 à 2 augmente la luminosité
- [ ] Passage de 2 à 3 augmente encore la luminosité
- [ ] Passage de 3 à OFF éteint le clavier
- [ ] Les valeurs sont écrites correctement dans `/sys/class/leds/asus::kbd_backlight/brightness`
### 3.2 Écriture RGB
- [ ] Changement de Rouge modifie la couleur du clavier
- [ ] Changement de Vert modifie la couleur du clavier
- [ ] Changement de Bleu modifie la couleur du clavier
- [ ] Les valeurs RGB sont clampées (0-255)
- [ ] Format dans `kbd_rgb_mode` est correct : `1 0 R G B 0\n`
### 3.3 Master Gain
- [ ] Master à 100% : couleurs normales
- [ ] Master à 50% : couleurs à mi-intensité
- [ ] Master à 0% : noir (aucune couleur visible)
- [ ] Master à 75% : couleurs proportionnellement réduites
- [ ] Le gain est appliqué à toutes les composantes RGB
### 3.4 Debouncing
- [ ] Déplacer rapidement un slider ne spam pas sysfs (vérifier logs)
- [ ] Il y a un délai de ~75ms entre les écritures
- [ ] La dernière valeur est bien appliquée après l'arrêt du slider
- [ ] Aucun message d'erreur de permission dû au spam
### 3.5 Comportement brightness=0
- [ ] Si brightness=0, changement RGB ne modifie pas le clavier (reste éteint)
- [ ] Les valeurs RGB sont mémorisées dans GSettings
- [ ] Passage de brightness 0→1 restaure la dernière couleur RGB
- [ ] Aucun message d'erreur lors du changement RGB avec brightness=0
## 4. Persistance (GSettings)
### 4.1 Sauvegarde
- [ ] Changer Rouge, fermer le menu, rouvrir → valeur conservée
- [ ] Changer Vert, fermer le menu, rouvrir → valeur conservée
- [ ] Changer Bleu, fermer le menu, rouvrir → valeur conservée
- [ ] Changer Master, fermer le menu, rouvrir → valeur conservée
- [ ] Changer Brightness, fermer le menu, rouvrir → valeur conservée
- [ ] Appliquer un preset, fermer le menu, rouvrir → preset appliqué
### 4.2 Restauration au démarrage
- [ ] Configurer RGB (ex: rouge pur), brightness à 2
- [ ] Fermer la session, se reconnecter
- [ ] L'extension restaure automatiquement RGB rouge et brightness 2
- [ ] Le clavier affiche la bonne couleur dès le démarrage
- [ ] Les sliders affichent les bonnes valeurs
### 4.3 Commandes GSettings manuelles
```bash
# Tester la lecture
gsettings get org.gnome.shell.extensions.asuskbdrgb red
gsettings get org.gnome.shell.extensions.asuskbdrgb green
gsettings get org.gnome.shell.extensions.asuskbdrgb blue
gsettings get org.gnome.shell.extensions.asuskbdrgb master-gain
gsettings get org.gnome.shell.extensions.asuskbdrgb brightness-level
```
- [ ] Les commandes retournent les bonnes valeurs
- [ ] Modifier via `gsettings set`, rouvrir le menu → nouvelle valeur affichée
## 5. Gestion des Erreurs
### 5.1 Matériel non supporté
Tester sur une machine sans clavier ASUS :
- [ ] L'extension charge sans crash
- [ ] Le popover affiche "❌ Matériel non supporté"
- [ ] Message clair : "Aucun clavier ASUS RGB détecté"
- [ ] Pas de sliders ni boutons (seulement le message d'erreur)
### 5.2 Permissions insuffisantes
Tester sans règles udev (ou retirer l'utilisateur du groupe `kbdled`) :
- [ ] L'extension charge sans crash
- [ ] Le popover affiche "⚠️ Permissions insuffisantes"
- [ ] Message clair avec référence à `docs/INSTALL.md`
- [ ] Pas de tentative d'écriture sysfs (pas d'erreur dans logs)
### 5.3 Valeurs invalides
- [ ] Entrer une valeur RGB > 255 → clampée à 255
- [ ] Entrer une valeur RGB < 0 → clampée à 0
- [ ] Entrer une valeur Master > 100 → clampée à 100
- [ ] Entrer une valeur Master < 0 → clampée à 0
- [ ] Brightness > 3 → clampée à 3
## 6. Logs et Debug
### 6.1 Logs au démarrage
```bash
journalctl -f -o cat /usr/bin/gnome-shell | grep -i asus
```
- [ ] Message "Activation de l'extension ASUS Keyboard RGB"
- [ ] Message "Extension ASUS Keyboard RGB activée avec succès"
- [ ] Aucune erreur JavaScript
### 6.2 Logs pendant l'utilisation
- [ ] Changement RGB affiche "RGB mis à (r, g, b) [master: X%]"
- [ ] Changement brightness affiche "Brightness mise à N (valeur)"
- [ ] Aucune erreur "Permission denied"
- [ ] Aucun spam (grâce au debouncing)
### 6.3 Logs à la désactivation
```bash
gnome-extensions disable asus-kbd-rgb@gilles
```
- [ ] Message "Désactivation de l'extension ASUS Keyboard RGB"
- [ ] Message "Extension ASUS Keyboard RGB désactivée"
- [ ] Aucune erreur de nettoyage
## 7. Robustesse
### 7.1 Rechargement GNOME Shell
- [ ] Alt+F2, `r` → l'extension se recharge correctement (X11)
- [ ] Logout/login → l'extension se recharge correctement (Wayland)
- [ ] État restauré après rechargement
### 7.2 Désactivation/Réactivation
```bash
gnome-extensions disable asus-kbd-rgb@gilles
gnome-extensions enable asus-kbd-rgb@gilles
```
- [ ] Pas d'erreur lors de la désactivation
- [ ] Pas d'erreur lors de la réactivation
- [ ] L'icône réapparaît
- [ ] Fonctionnalités intactes
### 7.3 Utilisation intensive
- [ ] Déplacer rapidement tous les sliders pendant 30 secondes
- [ ] Cliquer rapidement sur tous les boutons
- [ ] Alterner rapidement entre presets
- [ ] Aucun crash
- [ ] Aucune fuite mémoire visible
- [ ] Performances stables
## 8. Compatibilité
### 8.1 GNOME Shell 48
- [ ] Extension fonctionne sur GNOME 48.0
- [ ] Extension fonctionne sur GNOME 48.x (dernière version)
### 8.2 Debian 13 (Trixie)
- [ ] Installation réussie
- [ ] Toutes les fonctionnalités opérationnelles
- [ ] Aucun conflit de packages
## 9. Documentation
- [ ] README.md est à jour
- [ ] INSTALL.md couvre tous les cas
- [ ] TROUBLESHOOTING.md aide à résoudre les problèmes courants
- [ ] CLAUDE.md guide correctement les futures instances
- [ ] CHANGELOG.md est à jour
- [ ] UI_SCHEMA.md correspond à l'implémentation
## 10. Code Quality
### 10.1 Linting JavaScript
```bash
# Si eslint est disponible
eslint extension/*.js
```
- [ ] Aucune erreur de syntaxe
- [ ] Pas d'imports manquants
- [ ] Variables non utilisées supprimées
### 10.2 Revue de code
- [ ] Commentaires en français présents et clairs
- [ ] Fonctions documentées
- [ ] Code modulaire et lisible
- [ ] Pas de code mort (dead code)
- [ ] Gestion d'erreurs présente
## Résumé des Tests
**Total des tests** : ~120 items
### Statut Critique (Bloquant si échec)
- Installation et activation
- Détection matériel et permissions
- Fonctionnalités core (brightness, RGB, presets)
- Persistance GSettings
- Pas de crash
### Statut Important (À corriger rapidement)
- UI correcte et responsive
- Debouncing fonctionnel
- Messages d'erreur clairs
- Logs appropriés
### Statut Nice-to-have (Améliorations)
- Performance optimale
- Style CSS parfait
- Documentation exhaustive
---
## Rapport de Test
Compléter après les tests :
**Date** : _______________
**Testeur** : _______________
**GNOME Shell version** : _______________
**Matériel** : _______________
**Tests réussis** : ______ / 120
**Tests échoués** : ______
**Bugs trouvés** :
-
-
**Notes** :

445
docs/TROUBLESHOOTING.md Normal file
View File

@@ -0,0 +1,445 @@
# Guide de Dépannage - Extension ASUS Keyboard RGB
Ce document vous aide à résoudre les problèmes courants avec l'extension GNOME Shell ASUS Keyboard RGB.
## Table des matières
1. [L'extension ne s'affiche pas](#lextension-ne-saffiche-pas)
2. [Message "Permissions insuffisantes"](#message-permissions-insuffisantes)
3. [Message "Matériel non supporté"](#message-matériel-non-supporté)
4. [Les sliders ne fonctionnent pas](#les-sliders-ne-fonctionnent-pas)
5. [La couleur ne change pas](#la-couleur-ne-change-pas)
6. [Les paramètres ne sont pas sauvegardés](#les-paramètres-ne-sont-pas-sauvegardés)
7. [Erreurs dans les logs](#erreurs-dans-les-logs)
8. [L'extension se désactive automatiquement](#lextension-se-désactive-automatiquement)
---
## L'extension ne s'affiche pas
### Symptômes
- L'icône de clavier n'apparaît pas dans la barre supérieure
- L'extension est activée mais rien ne se passe
### Solutions
#### 1. Vérifier que l'extension est activée
```bash
gnome-extensions list
gnome-extensions info asus-kbd-rgb@gilles
```
Si elle n'apparaît pas :
```bash
gnome-extensions enable asus-kbd-rgb@gilles
```
#### 2. Vérifier l'installation
```bash
ls -la ~/.local/share/gnome-shell/extensions/asus-kbd-rgb@gilles/
```
Fichiers requis :
- `extension.js`
- `ui.js`
- `backend.js`
- `metadata.json`
- `schemas/org.gnome.shell.extensions.asuskbdrgb.gschema.xml`
- `schemas/gschemas.compiled`
#### 3. Recompiler le schéma GSettings
```bash
cd ~/.local/share/gnome-shell/extensions/asus-kbd-rgb@gilles/schemas/
glib-compile-schemas .
```
#### 4. Recharger GNOME Shell
**X11** : `Alt+F2`, tapez `r`, Entrée
**Wayland** : Déconnexion/Reconnexion
#### 5. Vérifier les logs
```bash
journalctl -f -o cat /usr/bin/gnome-shell | grep -i asus
```
---
## Message "Permissions insuffisantes"
### Symptômes
- Le menu affiche "⚠️ Permissions insuffisantes"
- Message : "Impossible d'accéder au rétroéclairage"
### Cause
L'utilisateur n'a pas les droits d'écriture sur les fichiers sysfs.
### Solutions
#### 1. Vérifier la règle udev
```bash
cat /etc/udev/rules.d/99-asus-kbd.rules
```
Devrait contenir :
```
SUBSYSTEM=="leds", KERNEL=="asus::kbd_backlight", GROUP="kbdled", MODE="0660"
```
Si le fichier n'existe pas, créez-le :
```bash
echo 'SUBSYSTEM=="leds", KERNEL=="asus::kbd_backlight", GROUP="kbdled", MODE="0660"' | sudo tee /etc/udev/rules.d/99-asus-kbd.rules
```
#### 2. Vérifier le groupe kbdled
```bash
getent group kbdled
```
Si le groupe n'existe pas :
```bash
sudo groupadd -f kbdled
```
#### 3. Vérifier l'appartenance au groupe
```bash
groups | grep kbdled
```
Si vous n'êtes pas dans le groupe :
```bash
sudo usermod -aG kbdled $USER
```
**Important** : Déconnexion/Reconnexion requise !
#### 4. Recharger udev
```bash
sudo udevadm control --reload-rules
sudo udevadm trigger
```
#### 5. Vérifier les permissions finales
```bash
ls -l /sys/class/leds/asus::kbd_backlight/brightness
# Devrait afficher : -rw-rw---- 1 root kbdled
```
Test d'écriture :
```bash
echo 2 > /sys/class/leds/asus::kbd_backlight/brightness
```
Si erreur "Permission denied", vérifiez que vous êtes bien déconnecté/reconnecté.
---
## Message "Matériel non supporté"
### Symptômes
- Le menu affiche "❌ Matériel non supporté"
- Message : "Aucun clavier ASUS RGB détecté"
### Cause
Le kernel ne détecte pas le clavier ASUS ou le module `asus-nb-wmi` n'est pas chargé.
### Solutions
#### 1. Vérifier les fichiers sysfs
```bash
ls -la /sys/class/leds/ | grep asus
```
Devrait afficher `asus::kbd_backlight`
Si absent :
```bash
ls -la /sys/class/leds/
```
Cherchez un dossier similaire pour votre clavier.
#### 2. Vérifier le module kernel
```bash
lsmod | grep asus
```
Devrait afficher `asus_nb_wmi` ou `asus_wmi`
Si absent, charger le module :
```bash
sudo modprobe asus-nb-wmi
```
#### 3. Vérifier le matériel
```bash
sudo dmesg | grep -i asus
sudo dmesg | grep -i keyboard
```
Cherchez des messages indiquant la détection du clavier.
#### 4. Vérifier dans le BIOS
Certains ordinateurs ASUS permettent de désactiver le rétroéclairage RGB dans le BIOS. Vérifiez les options "Keyboard Backlight" ou "RGB Lighting".
---
## Les sliders ne fonctionnent pas
### Symptômes
- Les sliders bougent mais la couleur ne change pas
- Pas de feedback visuel
### Solutions
#### 1. Vérifier la brightness
Si la brightness est à 0 (OFF), les changements RGB sont mémorisés mais non appliqués. Augmentez d'abord la brightness.
#### 2. Vérifier les logs
```bash
journalctl -f -o cat /usr/bin/gnome-shell | grep RGB
```
Vous devriez voir des messages comme :
```
RGB mis à (255, 165, 0) [master: 100%]
```
#### 3. Tester manuellement
```bash
# Test RGB rouge
echo "1 0 255 0 0 0" > /sys/class/leds/asus::kbd_backlight/kbd_rgb_mode
```
Si cela ne fonctionne pas, le problème est au niveau matériel/kernel, pas de l'extension.
---
## La couleur ne change pas
### Symptômes
- Les sliders fonctionnent mais la couleur reste la même
### Solutions
#### 1. Vérifier le master slider
Si le master slider est à 0%, toutes les couleurs seront noires. Augmentez-le à 100%.
#### 2. Vérifier la valeur brightness
```bash
cat /sys/class/leds/asus::kbd_backlight/brightness
```
Si c'est 0, la couleur ne s'affichera pas.
#### 3. Redémarrer l'extension
```bash
gnome-extensions disable asus-kbd-rgb@gilles
gnome-extensions enable asus-kbd-rgb@gilles
```
Puis recharger GNOME Shell (Alt+F2, r).
---
## Les paramètres ne sont pas sauvegardés
### Symptômes
- À chaque redémarrage, les couleurs reviennent aux valeurs par défaut
### Solutions
#### 1. Vérifier GSettings
```bash
gsettings list-schemas | grep asuskbdrgb
```
Devrait afficher : `org.gnome.shell.extensions.asuskbdrgb`
#### 2. Vérifier les valeurs stockées
```bash
gsettings get org.gnome.shell.extensions.asuskbdrgb red
gsettings get org.gnome.shell.extensions.asuskbdrgb green
gsettings get org.gnome.shell.extensions.asuskbdrgb blue
```
#### 3. Définir manuellement
```bash
gsettings set org.gnome.shell.extensions.asuskbdrgb red 255
gsettings set org.gnome.shell.extensions.asuskbdrgb green 165
gsettings set org.gnome.shell.extensions.asuskbdrgb blue 0
```
#### 4. Recompiler le schéma
```bash
cd ~/.local/share/gnome-shell/extensions/asus-kbd-rgb@gilles/schemas/
glib-compile-schemas .
```
---
## Erreurs dans les logs
### Comment voir les logs
```bash
# Logs en temps réel
journalctl -f -o cat /usr/bin/gnome-shell
# Dernières erreurs
journalctl -xe | grep -E "(error|Error|ERROR)"
```
### Erreurs courantes
#### "Extension asus-kbd-rgb@gilles had error: ..."
Réinstaller l'extension :
```bash
./tools/install-local.sh
```
#### "Failed to load schema org.gnome.shell.extensions.asuskbdrgb"
Recompiler le schéma GSettings (voir ci-dessus).
#### "Permission denied" dans les logs
Problème de permissions (voir section correspondante).
---
## L'extension se désactive automatiquement
### Symptômes
- L'extension s'active puis se désactive immédiatement
- Ou se désactive après un certain temps
### Solutions
#### 1. Vérifier la compatibilité
```bash
gnome-shell --version
```
Doit afficher : `GNOME Shell 48.x`
Si version différente, modifier `metadata.json` :
```json
"shell-version": [
"48",
"47" // Ajouter votre version
]
```
#### 2. Vérifier les erreurs JavaScript
```bash
journalctl -f -o cat /usr/bin/gnome-shell | grep -i "syntax\|error"
```
#### 3. Mode debug
Activer avec verbose logging :
```bash
gnome-extensions enable asus-kbd-rgb@gilles
journalctl -f /usr/bin/gnome-shell
```
---
## Obtenir de l'aide
Si aucune solution ne fonctionne :
1. **Collecter les informations de debug** :
```bash
# Créer un fichier de debug
{
echo "=== System Info ==="
uname -a
gnome-shell --version
echo -e "\n=== Hardware ==="
ls -la /sys/class/leds/asus::kbd_backlight/
echo -e "\n=== Permissions ==="
ls -l /sys/class/leds/asus::kbd_backlight/brightness
groups
echo -e "\n=== Extension Status ==="
gnome-extensions info asus-kbd-rgb@gilles
echo -e "\n=== GSettings ==="
gsettings list-recursively org.gnome.shell.extensions.asuskbdrgb
echo -e "\n=== Recent Logs ==="
journalctl -xe --no-pager | grep -i asus | tail -20
} > ~/asus-kbd-rgb-debug.txt
```
2. **Ouvrir une issue** sur GitHub avec le fichier `asus-kbd-rgb-debug.txt`
3. **Forum GNOME** : https://discourse.gnome.org/
---
## Réinstallation complète
Si tout échoue, réinstallation complète :
```bash
# 1. Désactiver et supprimer
gnome-extensions disable asus-kbd-rgb@gilles
rm -rf ~/.local/share/gnome-shell/extensions/asus-kbd-rgb@gilles
# 2. Nettoyer GSettings
gsettings reset-recursively org.gnome.shell.extensions.asuskbdrgb
# 3. Réinstaller
cd ~/Documents/gnome-asus-kbd-rgb
./tools/install-local.sh
# 4. Recharger GNOME Shell
# X11: Alt+F2, r
# Wayland: logout/login
# 5. Réactiver
gnome-extensions enable asus-kbd-rgb@gilles
```

170
docs/UI_SCHEMA.md Normal file
View File

@@ -0,0 +1,170 @@
# Schéma de l'Interface Utilisateur
## Vue d'ensemble
L'extension ajoute une icône dans la barre supérieure de GNOME Shell. Au clic, un popover s'affiche avec tous les contrôles.
## Diagramme Mermaid - Architecture UI
```mermaid
graph TD
A[Top Bar GNOME Shell] --> B[Panel Button avec icône clavier]
B -->|Clic| C[Popover Menu]
C --> D[Section Intensité]
C --> E[Section Sliders RGB]
C --> F[Section Info]
C --> G[Section Presets]
D --> D1[Bouton OFF]
D --> D2[Bouton Faible]
D --> D3[Bouton Moyen]
D --> D4[Bouton Fort]
E --> E1[Slider Rouge 0-255]
E --> E2[Slider Vert 0-255]
E --> E3[Slider Bleu 0-255]
E --> E4[Slider Master 0-100%]
F --> F1[Label RGB=r,g,b]
F --> F2[Label HEX=#RRGGBB]
F --> F3[Label Intensity=n/max]
G --> G1[Preset 1: Orange]
G --> G2[Preset 2: Rouge]
G --> G3[Preset 3: Vert]
G --> G4[Preset 4: Bleu]
G --> G5[Preset 5: Blanc]
G --> G6[Preset 6: Cyan]
E1 -->|Change| H[Backend: Debounce]
E2 -->|Change| H
E3 -->|Change| H
E4 -->|Change| H
D1 -->|Click| H
D2 -->|Click| H
D3 -->|Click| H
D4 -->|Click| H
G1 -->|Click| H
G2 -->|Click| H
G3 -->|Click| H
G4 -->|Click| H
G5 -->|Click| H
G6 -->|Click| H
H --> I[Écriture sysfs]
I --> J[/sys/class/leds/asus::kbd_backlight/]
H --> K[Sauvegarde GSettings]
```
## Layout ASCII du Popover
```
┌─────────────────────────────────────────────────────┐
│ Rétroéclairage Clavier ASUS │
├─────────────────────────────────────────────────────┤
│ │
│ Intensité: │
│ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ │
│ │ OFF │ │ 1 │ │ 2 │ │ 3 │ │
│ └─────┘ └─────┘ └─────┘ └─────┘ │
│ │
│ ┌────────────────────────────────────────────┐ │
│ │ Rouge ●─────────────────────○ 255 │ │
│ └────────────────────────────────────────────┘ │
│ ┌────────────────────────────────────────────┐ │
│ │ Vert ●─────────────────────○ 255 │ │
│ └────────────────────────────────────────────┘ │
│ ┌────────────────────────────────────────────┐ │
│ │ Bleu ●─────────────────────○ 255 │ │
│ └────────────────────────────────────────────┘ │
│ ┌────────────────────────────────────────────┐ │
│ │ Master ●─────────────────────○ 100% │ │
│ └────────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────────┐ │
│ │ RGB=(255,165,0) #FFA500 Intensité=2/3 │ │
│ └────────────────────────────────────────────┘ │
│ │
│ Couleurs prédéfinies: │
│ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ │
│ │ 🟠│ │🔴 │ │🟢 │ │🔵 │ │⚪ │ │🔵 │ │
│ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ │
│ │
└─────────────────────────────────────────────────────┘
```
## Flux de Données
```
Utilisateur → Slider/Bouton → Event Handler (ui.js)
Debounce Timer (50-100ms)
Backend.applyRGB() (backend.js)
Clamping + Master Gain
┌────────────────┴────────────────┐
↓ ↓
Écriture sysfs Sauvegarde GSettings
(kbd_rgb_mode, brightness) (persistance)
↓ ↓
Mise à jour matérielle Restauration au démarrage
```
## Composants GNOME Shell Utilisés
- **PanelMenu.Button** : Bouton dans la top bar
- **PopupMenu.PopupBaseMenuItem** : Items personnalisés dans le menu
- **St.BoxLayout** : Layout vertical/horizontal
- **St.Button** : Boutons d'intensité
- **Slider** : Sliders RGB et Master (API GNOME Shell)
- **St.Label** : Labels et texte d'information
- **St.Bin** : Containers pour les presets couleur
## Interactions Utilisateur
### Actions Immédiates (sans confirmation)
- Déplacer un slider RGB → Application immédiate avec debounce
- Cliquer sur un bouton d'intensité → Application immédiate
- Cliquer sur une couleur preset → Application immédiate
- Déplacer le slider Master → Ajuste R/G/B proportionnellement
### Feedback Visuel
- Slider actif → Curseur se déplace
- Bouton intensité actif → Surligné/highlighted
- Info line → Mise à jour en temps réel
- Preset cliqué → Feedback visuel temporaire
## Gestion des Erreurs UI
### Permission refusée
```
┌─────────────────────────────────────────────────────┐
│ ⚠️ Permissions insuffisantes │
│ │
│ Impossible d'accéder au rétroéclairage. │
│ Veuillez configurer les règles udev. │
│ │
│ Voir: docs/INSTALL.md │
└─────────────────────────────────────────────────────┘
```
### Matériel non supporté
```
┌─────────────────────────────────────────────────────┐
│ ❌ Matériel non supporté │
│ │
│ Aucun clavier ASUS RGB détecté sur ce système. │
└─────────────────────────────────────────────────────┘
```
## Notes d'Implémentation
1. **Debouncing**: Utiliser `GLib.timeout_add()` avec timeout de 75ms
2. **Master Slider**: Multiplier R/G/B par (master/100) avant écriture
3. **Presets**: Stocker dans GSettings, charger au démarrage
4. **Info Line**: Mettre à jour via callback après chaque changement
5. **Style**: Utiliser `stylesheet.css` pour personnalisation minimale

View File

@@ -0,0 +1,138 @@
# Synthèse — Mettre en place une roue chromatique (HSV) dans GNOME Shell 48
## Contexte
- GNOME Shell 48 (GJS) utilise **St/Clutter** (pas GTK dans le Shell).
- Il nexiste **pas** de composant natif « roue chromatique » (type `GtkColorChooser`) directement exploitable dans une extension GNOME Shell.
- Objectif : offrir une **roue HSV** pour choisir une couleur (H, S) + un contrôle d**intensité** (V), puis produire un RGB (0255) utilisable pour piloter un matériel (ex. clavier RGB).
---
## Options possibles (du plus recommandé au plus “hybride”)
### Option A — Roue HSV native GNOME Shell (recommandée)
**Principe**
- Créer un widget custom basé sur `Clutter.Canvas`.
- Dessiner une roue HSV (visualisation en V=1 pour lisibilité).
- Capturer les interactions souris :
- angle → **Hue (H)**
- rayon → **Saturation (S)**
- Ajouter un slider pour **Value (V)** (intensité).
- Convertir HSV → RGB (0255) et déclencher un callback.
**Avantages**
- 100% intégré au Shell (look & feel cohérent extension).
- Dépendances minimales (GJS uniquement).
- Utilisable dans un menu top-bar, Quick Settings, ou popup.
- Contrôle immédiat (idéal pour piloter des LED).
**Inconvénients**
- Code à maintenir (rendu + interaction).
- Optimisation possible nécessaire pour performance (cache image).
**Recommandation**
- Cest la meilleure solution pour une extension GNOME 48, surtout si lusage cible est le pilotage hardware RGB.
---
### Option B — Sliders RGB (solution la plus robuste)
**Principe**
- Ne pas faire de roue.
- 3 sliders `St.Slider` ou `PopupSliderMenuItem` :
- R (0255)
- G (0255)
- B (0255)
- Afficher un carré daperçu (preview) `St.Widget` dont la couleur suit les sliders.
**Avantages**
- Très simple, très stable, très maintenable.
- Exact pour piloter des LED (RGB natif).
- Peu de code, faible coût performance.
**Inconvénients**
- Moins intuitif quune roue HSV.
- Expérience utilisateur moins “graphique”.
**Recommandation**
- Excellent si priorité = fiabilité et précision LED.
- Peut être combiné avec la roue (Option A) pour affiner.
---
### Option C — Hybride : application GTK externe (GtkColorChooser) + DBus
**Principe**
- Créer une petite app GTK (hors Shell) utilisant `GtkColorChooser` (roue native GNOME).
- Lextension GNOME Shell lance lapp ou communique via DBus.
- Lapp renvoie la couleur choisie (RGB/HSV) à lextension.
**Avantages**
- UI GNOME native parfaite (roue GTK).
- Moins de code côté Shell pour le rendu.
**Inconvénients**
- Architecture plus lourde (extension + service/app).
- Gestion DBus, packaging, cycle de vie de lapp.
- Moins fluide pour un usage “réglage instantané”.
**Recommandation**
- À considérer si tu veux absolument la roue GTK standard et acceptes la complexité.
---
### Option D — Réutiliser du code existant (extensions / libs)
**Principe**
- Sinspirer dune extension existante (Color Picker, etc.) ou porter un widget JS déjà implémenté.
- Intégrer le code (Canvas, HSV->RGB, interactions) dans ton extension.
**Avantages**
- Gain de temps si un code de roue HSV est déjà éprouvé.
- Possibilité de reprendre des patterns Shell (PopupMenu, Quick Settings, etc.).
**Inconvénients**
- Variabilité de qualité et compatibilité GNOME 48.
- Nécessite vérification licence / maintenance.
**Recommandation**
- Très efficace si tu trouves un code déjà aligné GJS/Clutter moderne.
---
## Rendu “fidèle” vs LED (point important)
- Une roue à lécran (sRGB) ne correspond pas parfaitement au rendu des LED de clavier.
- Recommandé :
- afficher RGB 0255 et/ou HEX
- prévoir un slider dintensité (V) + luminosité matériel
- optionnel : appliquer une correction empirique (ex. réduire le bleu) pour coller au rendu réel.
---
## UX conseillée (pragmatique)
### MVP (simple et efficace)
- Roue HSV (H,S) + slider V
- Aperçu (carré couleur)
- Affichage RGB (0255) + HEX
- Bouton “Appliquer” (ou appliquer en live)
### Version “confort”
- Roue HSV + sliders RGB (affinage)
- Presets (palette)
- Historique des dernières couleurs
- “Appliquer au démarrage” (persist)
---
## Recommandation finale
Pour GNOME Shell 48, le meilleur choix est :
1. **Option A** (roue HSV custom via `Clutter.Canvas`) + slider V
2. compléter par **Option B** (sliders RGB) si tu veux une précision LED maximale
Option C (GTK externe) est valable mais plus lourde et moins adaptée à un réglage rapide dans le Shell.
---
## Livrables possibles (si on passe à limplémentation)
- Widget `HsvWheel` réutilisable (Canvas + interaction)
- Intégration top-bar (PopupMenu) ou Quick Settings
- Callback standard `onColor({r,g,b,h,s,v})`
- Module utilitaire HSV<->RGB
- (Option) pipeline dapplication : sysfs / asusctl / DBus service
s

285
extension/backend.js Normal file
View File

@@ -0,0 +1,285 @@
// backend.js - Interface sysfs et logique métier pour le rétroéclairage ASUS RGB
import Gio from 'gi://Gio';
import GLib from 'gi://GLib';
// Chemins sysfs pour le rétroéclairage ASUS
const SYSFS_BASE = '/sys/class/leds/asus::kbd_backlight';
const BRIGHTNESS_PATH = `${SYSFS_BASE}/brightness`;
const MAX_BRIGHTNESS_PATH = `${SYSFS_BASE}/max_brightness`;
const RGB_MODE_PATH = `${SYSFS_BASE}/kbd_rgb_mode`;
// Niveaux d'intensité (0=Off, 1=Faible, 2=Moyen, 3=Fort)
const BRIGHTNESS_LEVELS = [0, null, null, null]; // Sera rempli dynamiquement avec max_brightness
// Timer pour le debouncing
let debounceTimer = null;
const DEBOUNCE_DELAY = 75; // ms
/**
* Vérifie si le matériel ASUS RGB est présent sur le système
* @returns {boolean} true si le matériel est supporté
*/
export function checkHardwareSupport() {
try {
const brightnessFile = Gio.File.new_for_path(BRIGHTNESS_PATH);
const rgbFile = Gio.File.new_for_path(RGB_MODE_PATH);
return brightnessFile.query_exists(null) && rgbFile.query_exists(null);
} catch (e) {
console.error('Erreur lors de la vérification du matériel:', e);
return false;
}
}
/**
* Vérifie si l'utilisateur a les permissions d'écriture
* @returns {boolean} true si les permissions sont OK
*/
export function checkPermissions() {
try {
const brightnessFile = Gio.File.new_for_path(BRIGHTNESS_PATH);
const info = brightnessFile.query_info('access::*', Gio.FileQueryInfoFlags.NONE, null);
// Vérifier si on peut écrire
return info.get_attribute_boolean('access::can-write');
} catch (e) {
console.error('Erreur lors de la vérification des permissions:', e);
return false;
}
}
/**
* Lit la valeur maximale de brightness
* @returns {number} Valeur max, ou 3 par défaut
*/
export function getMaxBrightness() {
try {
const file = Gio.File.new_for_path(MAX_BRIGHTNESS_PATH);
const [success, contents] = file.load_contents(null);
if (success) {
const maxValue = parseInt(new TextDecoder().decode(contents).trim());
// Initialiser les niveaux de brightness
BRIGHTNESS_LEVELS[1] = Math.floor(maxValue / 3);
BRIGHTNESS_LEVELS[2] = Math.floor(2 * maxValue / 3);
BRIGHTNESS_LEVELS[3] = maxValue;
return maxValue;
}
} catch (e) {
console.error('Erreur lors de la lecture de max_brightness:', e);
}
// Valeurs par défaut si échec
BRIGHTNESS_LEVELS[1] = 1;
BRIGHTNESS_LEVELS[2] = 2;
BRIGHTNESS_LEVELS[3] = 3;
return 3;
}
/**
* Lit la brightness actuelle
* @returns {number} Valeur actuelle, ou -1 en cas d'erreur
*/
export function readBrightness() {
try {
const file = Gio.File.new_for_path(BRIGHTNESS_PATH);
const [success, contents] = file.load_contents(null);
if (success) {
return parseInt(new TextDecoder().decode(contents).trim());
}
} catch (e) {
console.error('Erreur lors de la lecture de brightness:', e);
}
return -1;
}
/**
* Écrit la brightness (niveau 0-3)
* @param {number} level - Niveau d'intensité (0=Off, 1=Faible, 2=Moyen, 3=Fort)
* @returns {boolean} true si succès
*/
export function writeBrightness(level) {
try {
// Valider et clamper le niveau
level = Math.max(0, Math.min(3, Math.floor(level)));
const value = BRIGHTNESS_LEVELS[level];
if (value === null || value === undefined) {
console.error('Niveau de brightness invalide:', level);
return false;
}
const file = Gio.File.new_for_path(BRIGHTNESS_PATH);
const contents = `${value}\n`;
const [success] = file.replace_contents(
new TextEncoder().encode(contents),
null,
false,
Gio.FileCreateFlags.NONE,
null
);
if (success) {
console.log(`Brightness mise à ${level} (${value})`);
}
return success;
} catch (e) {
console.error('Erreur lors de l\'écriture de brightness:', e);
return false;
}
}
/**
* Clamp une valeur RGB entre 0 et 255
* @param {number} value - Valeur à clamper
* @returns {number} Valeur clampée
*/
function clampRGB(value) {
return Math.max(0, Math.min(255, Math.floor(value)));
}
/**
* Applique le master gain aux valeurs RGB
* @param {number} r - Rouge (0-255)
* @param {number} g - Vert (0-255)
* @param {number} b - Bleu (0-255)
* @param {number} masterGain - Gain master (0-100)
* @returns {Object} {r, g, b} avec gain appliqué
*/
function applyMasterGain(r, g, b, masterGain) {
const gain = masterGain / 100.0;
return {
r: clampRGB(r * gain),
g: clampRGB(g * gain),
b: clampRGB(b * gain)
};
}
/**
* Écrit les valeurs RGB dans kbd_rgb_mode
* @param {number} r - Rouge (0-255)
* @param {number} g - Vert (0-255)
* @param {number} b - Bleu (0-255)
* @param {number} masterGain - Gain master (0-100), défaut 100
* @returns {boolean} true si succès
*/
export function writeRGB(r, g, b, masterGain = 100) {
try {
// Clamper les valeurs
r = clampRGB(r);
g = clampRGB(g);
b = clampRGB(b);
// Appliquer le master gain
const adjusted = applyMasterGain(r, g, b, masterGain);
// Vérifier si brightness est > 0, sinon ne pas écrire
const currentBrightness = readBrightness();
if (currentBrightness === 0) {
console.log('Brightness est 0, RGB mémorisé mais non appliqué');
return true; // On considère cela comme un succès
}
// Format: "1 0 R G B 0\n"
const file = Gio.File.new_for_path(RGB_MODE_PATH);
const contents = `1 0 ${adjusted.r} ${adjusted.g} ${adjusted.b} 0\n`;
const [success] = file.replace_contents(
new TextEncoder().encode(contents),
null,
false,
Gio.FileCreateFlags.NONE,
null
);
if (success) {
console.log(`RGB mis à (${adjusted.r}, ${adjusted.g}, ${adjusted.b}) [master: ${masterGain}%]`);
}
return success;
} catch (e) {
console.error('Erreur lors de l\'écriture RGB:', e);
return false;
}
}
/**
* Applique RGB avec debouncing pour éviter de spammer sysfs
* @param {number} r - Rouge
* @param {number} g - Vert
* @param {number} b - Bleu
* @param {number} masterGain - Gain master
* @param {Function} callback - Callback optionnel appelé après l'écriture
*/
export function writeRGBDebounced(r, g, b, masterGain, callback = null) {
// Annuler le timer précédent
if (debounceTimer !== null) {
GLib.source_remove(debounceTimer);
debounceTimer = null;
}
// Créer un nouveau timer
debounceTimer = GLib.timeout_add(GLib.PRIORITY_DEFAULT, DEBOUNCE_DELAY, () => {
writeRGB(r, g, b, masterGain);
if (callback) {
callback();
}
debounceTimer = null;
return GLib.SOURCE_REMOVE;
});
}
/**
* Parse une chaîne preset "R,G,B" en objet
* @param {string} presetString - Format "R,G,B"
* @returns {Object} {r, g, b} ou null si invalide
*/
export function parsePreset(presetString) {
try {
const parts = presetString.split(',').map(s => parseInt(s.trim()));
if (parts.length === 3 && parts.every(n => !isNaN(n))) {
return {
r: clampRGB(parts[0]),
g: clampRGB(parts[1]),
b: clampRGB(parts[2])
};
}
} catch (e) {
console.error('Erreur lors du parsing du preset:', e);
}
return null;
}
/**
* Convertit RGB en hex
* @param {number} r - Rouge (0-255)
* @param {number} g - Vert (0-255)
* @param {number} b - Bleu (0-255)
* @returns {string} Format "#RRGGBB"
*/
export function rgbToHex(r, g, b) {
const toHex = (n) => {
const hex = clampRGB(n).toString(16).toUpperCase();
return hex.length === 1 ? '0' + hex : hex;
};
return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
}
/**
* Nettoie les ressources (annule les timers en cours)
*/
export function cleanup() {
if (debounceTimer !== null) {
GLib.source_remove(debounceTimer);
debounceTimer = null;
}
}

59
extension/extension.js Normal file
View File

@@ -0,0 +1,59 @@
// extension.js - Point d'entrée de l'extension GNOME Shell ASUS RGB Keyboard
import {Extension} from 'resource:///org/gnome/shell/extensions/extension.js';
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
import {KeyboardRGBIndicator} from './ui.js';
/**
* Extension ASUS Keyboard RGB Control
*/
export default class AsusKeyboardRGBExtension extends Extension {
constructor(metadata) {
super(metadata);
this._indicator = null;
this._settings = null;
}
/**
* Active l'extension
*/
enable() {
console.log('Activation de l\'extension ASUS Keyboard RGB');
try {
// Charger les settings
this._settings = this.getSettings();
// Créer l'indicateur dans le panneau
this._indicator = new KeyboardRGBIndicator(this._settings);
// Ajouter au panneau (à droite, avant les menus système)
Main.panel.addToStatusArea(
this.metadata.uuid,
this._indicator,
1,
'right'
);
console.log('Extension ASUS Keyboard RGB activée avec succès');
} catch (e) {
console.error('Erreur lors de l\'activation de l\'extension:', e);
}
}
/**
* Désactive l'extension
*/
disable() {
console.log('Désactivation de l\'extension ASUS Keyboard RGB');
if (this._indicator) {
this._indicator.destroy();
this._indicator = null;
}
this._settings = null;
console.log('Extension ASUS Keyboard RGB désactivée');
}
}

11
extension/metadata.json Normal file
View File

@@ -0,0 +1,11 @@
{
"uuid": "asus-kbd-rgb@gilles",
"name": "ASUS Keyboard RGB Control",
"description": "Contrôle du rétroéclairage RGB du clavier ASUS via asus-nb-wmi",
"version": 1,
"shell-version": [
"48"
],
"url": "https://github.com/gilles/gnome-asus-kbd-rgb",
"settings-schema": "org.gnome.shell.extensions.asuskbdrgb"
}

View File

@@ -0,0 +1,106 @@
<?xml version="1.0" encoding="UTF-8"?>
<schemalist>
<schema id="org.gnome.shell.extensions.asuskbdrgb" path="/org/gnome/shell/extensions/asuskbdrgb/">
<!-- Valeurs RGB courantes -->
<key name="red" type="i">
<default>255</default>
<summary>Composante rouge (0-255)</summary>
<description>Valeur de la composante rouge du rétroéclairage</description>
</key>
<key name="green" type="i">
<default>165</default>
<summary>Composante verte (0-255)</summary>
<description>Valeur de la composante verte du rétroéclairage</description>
</key>
<key name="blue" type="i">
<default>0</default>
<summary>Composante bleue (0-255)</summary>
<description>Valeur de la composante bleue du rétroéclairage</description>
</key>
<!-- Intensité -->
<key name="brightness-level" type="i">
<default>2</default>
<summary>Niveau d'intensité (0-3)</summary>
<description>Niveau d'intensité du rétroéclairage (0=Off, 1=Faible, 2=Moyen, 3=Fort)</description>
</key>
<!-- Master slider -->
<key name="master-gain" type="i">
<default>100</default>
<summary>Gain master (0-100)</summary>
<description>Pourcentage de gain appliqué à toutes les composantes RGB</description>
</key>
<!-- Step pour les sliders RGB -->
<key name="rgb-step" type="i">
<default>5</default>
<summary>Pas d'ajustement RGB</summary>
<description>Incrément lors de l'utilisation des sliders RGB</description>
</key>
<!-- Presets couleur (9 presets GNOME officiels, stockés comme "R,G,B") -->
<key name="preset-1" type="s">
<default>"53,132,228"</default>
<summary>Preset 1 - Bleu GNOME</summary>
</key>
<key name="preset-2" type="s">
<default>"51,209,122"</default>
<summary>Preset 2 - Turquoise</summary>
</key>
<key name="preset-3" type="s">
<default>"87,227,137"</default>
<summary>Preset 3 - Vert</summary>
</key>
<key name="preset-4" type="s">
<default>"246,211,45"</default>
<summary>Preset 4 - Jaune</summary>
</key>
<key name="preset-5" type="s">
<default>"255,120,0"</default>
<summary>Preset 5 - Orange</summary>
</key>
<key name="preset-6" type="s">
<default>"237,51,59"</default>
<summary>Preset 6 - Rouge</summary>
</key>
<key name="preset-7" type="s">
<default>"246,97,81"</default>
<summary>Preset 7 - Rose</summary>
</key>
<key name="preset-8" type="s">
<default>"145,65,172"</default>
<summary>Preset 8 - Violet</summary>
</key>
<key name="preset-9" type="s">
<default>"119,118,123"</default>
<summary>Preset 9 - Gris ardoise</summary>
</key>
<!-- Mode master slider (pour évolutions futures) -->
<key name="master-mode" type="s">
<default>"gain"</default>
<summary>Mode du slider master</summary>
<description>Mode de fonctionnement du slider master: gain, offset, ou hsv</description>
</key>
<!-- Synchronisation avec le thème GNOME -->
<key name="sync-gnome-theme" type="b">
<default>false</default>
<summary>Synchroniser avec le thème GNOME</summary>
<description>Applique automatiquement la couleur du clavier comme couleur d'accentuation GNOME</description>
</key>
</schema>
</schemalist>

72
extension/stylesheet.css Normal file
View File

@@ -0,0 +1,72 @@
/* stylesheet.css - Styles pour l'extension ASUS Keyboard RGB */
/* Titre du menu */
.rgb-title {
font-weight: bold;
font-size: 1.1em;
padding: 8px 0;
}
/* Boutons d'intensité */
.brightness-button {
background-color: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 6px;
padding: 8px 16px;
font-weight: normal;
transition: all 0.2s;
}
.brightness-button:hover {
background-color: rgba(255, 255, 255, 0.1);
border-color: rgba(255, 255, 255, 0.2);
}
.brightness-button.active {
background-color: rgba(53, 132, 228, 0.8);
border-color: rgba(53, 132, 228, 1);
font-weight: bold;
color: #ffffff;
}
/* Ligne d'information */
.info-line {
font-family: monospace;
font-size: 0.9em;
color: rgba(255, 255, 255, 0.7);
padding: 4px 0;
}
/* Boutons preset */
.preset-button {
border: 2px solid rgba(255, 255, 255, 0.2);
transition: all 0.2s;
}
.preset-button:hover {
border-color: rgba(255, 255, 255, 0.6);
transform: scale(1.05);
}
.preset-button:active {
transform: scale(0.95);
}
/* Boîte d'erreur */
.error-box {
padding: 12px;
margin: 8px;
}
.error-title {
font-weight: bold;
font-size: 1.1em;
color: #ff6b6b;
margin-bottom: 8px;
}
.error-message {
font-size: 0.9em;
color: rgba(255, 255, 255, 0.8);
line-height: 1.4;
}

852
extension/ui.js Normal file
View File

@@ -0,0 +1,852 @@
// ui.js - Interface utilisateur pour le contrôle RGB du clavier ASUS
import St from 'gi://St';
import Clutter from 'gi://Clutter';
import GObject from 'gi://GObject';
import Gio from 'gi://Gio';
import * as PanelMenu from 'resource:///org/gnome/shell/ui/panelMenu.js';
import * as PopupMenu from 'resource:///org/gnome/shell/ui/popupMenu.js';
import * as Slider from 'resource:///org/gnome/shell/ui/slider.js';
import * as Backend from './backend.js';
/**
* Indicateur du panneau pour le contrôle RGB du clavier
*/
export const KeyboardRGBIndicator = GObject.registerClass(
class KeyboardRGBIndicator extends PanelMenu.Button {
_init(settings) {
super._init(0.0, 'ASUS Keyboard RGB');
this._settings = settings;
this._maxBrightness = Backend.getMaxBrightness();
// Charger les valeurs depuis GSettings
this._currentR = this._settings.get_int('red');
this._currentG = this._settings.get_int('green');
this._currentB = this._settings.get_int('blue');
this._currentMasterGain = this._settings.get_int('master-gain');
this._currentBrightnessLevel = this._settings.get_int('brightness-level');
// Mode d'affichage (roue chromatique par défaut)
this._colorPickerMode = 'wheel'; // 'sliders' ou 'wheel'
// Créer l'icône dans la top bar
this._icon = new St.Icon({
icon_name: 'keyboard-brightness-symbolic',
style_class: 'system-status-icon'
});
this.add_child(this._icon);
// Vérifier le support matériel et les permissions
if (!Backend.checkHardwareSupport()) {
this._buildErrorUI('Matériel non supporté',
'Aucun clavier ASUS RGB détecté sur ce système.');
return;
}
if (!Backend.checkPermissions()) {
this._buildErrorUI('Permissions insuffisantes',
'Impossible d\'accéder au rétroéclairage.\nVeuillez configurer les règles udev.\n\nVoir: docs/INSTALL.md');
return;
}
// Construire l'UI normale
this._buildUI();
// Restaurer l'état au démarrage
this._applyCurrentState();
}
/**
* Construit une UI d'erreur simplifiée
*/
_buildErrorUI(title, message) {
const errorItem = new PopupMenu.PopupMenuItem('');
const box = new St.BoxLayout({
vertical: true,
style_class: 'error-box',
x_expand: true
});
const titleLabel = new St.Label({
text: `⚠️ ${title}`,
style_class: 'error-title'
});
const messageLabel = new St.Label({
text: message,
style_class: 'error-message'
});
box.add_child(titleLabel);
box.add_child(messageLabel);
errorItem.actor.add_child(box);
this.menu.addMenuItem(errorItem);
}
/**
* Construit l'interface utilisateur complète
*/
_buildUI() {
// Section: Header avec titre et bouton de bascule
this._buildHeader();
// Section: Boutons d'intensité (compact)
this._buildBrightnessButtons();
// Section: Color picker (sliders ou roue chromatique)
this._colorPickerContainer = new PopupMenu.PopupBaseMenuItem({
reactive: false,
can_focus: false
});
this.menu.addMenuItem(this._colorPickerContainer);
// Construire le mode par défaut
this._rebuildColorPicker();
// Section: Presets (compact)
this._buildPresets();
// Section: Synchronisation thème GNOME
this._buildSyncThemeOption();
}
/**
* Construit le header avec titre et bouton de bascule
*/
_buildHeader() {
const headerItem = new PopupMenu.PopupBaseMenuItem({
reactive: false,
can_focus: false,
style_class: 'rgb-header'
});
const headerBox = new St.BoxLayout({
vertical: false,
x_expand: true,
style: 'spacing: 8px;'
});
// Bouton de bascule slider/roue
const toggleButton = new St.Button({
style_class: 'button',
x_expand: false,
style: 'padding: 4px 8px; min-width: 32px;'
});
const toggleIcon = new St.Icon({
icon_name: this._colorPickerMode === 'sliders' ? 'view-grid-symbolic' : 'view-list-symbolic',
icon_size: 16
});
toggleButton.set_child(toggleIcon);
toggleButton.connect('clicked', () => {
this._colorPickerMode = this._colorPickerMode === 'sliders' ? 'wheel' : 'sliders';
toggleIcon.icon_name = this._colorPickerMode === 'sliders' ? 'view-grid-symbolic' : 'view-list-symbolic';
this._rebuildColorPicker();
});
// Titre
const titleLabel = new St.Label({
text: 'Clavier RGB',
style: 'font-weight: bold;',
x_expand: true,
y_align: Clutter.ActorAlign.CENTER
});
// Aperçu de couleur (déplacé dans le header)
this._colorPreview = new St.Bin({
style_class: 'color-preview',
style: 'width: 40px; height: 24px; border-radius: 4px; border: 1px solid rgba(255,255,255,0.3);'
});
headerBox.add_child(toggleButton);
headerBox.add_child(titleLabel);
headerBox.add_child(this._colorPreview);
headerItem.actor.add_child(headerBox);
this.menu.addMenuItem(headerItem);
// Initialiser l'aperçu
this._updateColorPreview();
}
/**
* Reconstruit le color picker selon le mode actuel
*/
_rebuildColorPicker() {
// Vider le container
this._colorPickerContainer.actor.remove_all_children();
if (this._colorPickerMode === 'sliders') {
this._buildRGBSliders();
} else {
this._buildColorWheel();
}
}
/**
* Construit les 4 boutons d'intensité (version compacte)
*/
_buildBrightnessButtons() {
const buttonItem = new PopupMenu.PopupBaseMenuItem({
reactive: false,
can_focus: false
});
const container = new St.BoxLayout({
vertical: false,
x_expand: true,
style: 'spacing: 8px;'
});
// Label compact
const intensityLabel = new St.Label({
text: 'Intensité :',
style: 'font-weight: bold; font-size: 0.9em;',
y_align: Clutter.ActorAlign.CENTER
});
container.add_child(intensityLabel);
// Boutons compacts
const buttonBox = new St.BoxLayout({
vertical: false,
x_expand: true,
style: 'spacing: 6px;'
});
const buttonLabels = ['OFF', '1', '2', '3'];
this._brightnessButtons = [];
for (let i = 0; i < 4; i++) {
const button = new St.Button({
label: buttonLabels[i],
style_class: 'brightness-button',
x_expand: true,
can_focus: true,
style: 'padding: 4px 8px; font-size: 0.9em;'
});
button.level = i;
button.connect('clicked', () => this._onBrightnessButtonClicked(i));
this._brightnessButtons.push(button);
buttonBox.add_child(button);
}
container.add_child(buttonBox);
buttonItem.actor.add_child(container);
this.menu.addMenuItem(buttonItem);
// Mettre à jour l'état actif
this._updateBrightnessButtons();
}
/**
* Met à jour le style des boutons brightness (active/inactive)
*/
_updateBrightnessButtons() {
this._brightnessButtons.forEach((button, index) => {
if (index === this._currentBrightnessLevel) {
button.add_style_class_name('active');
} else {
button.remove_style_class_name('active');
}
});
}
/**
* Callback: clic sur un bouton brightness
*/
_onBrightnessButtonClicked(level) {
this._currentBrightnessLevel = level;
this._settings.set_int('brightness-level', level);
Backend.writeBrightness(level);
this._updateBrightnessButtons();
this._updateInfoLine();
// Si brightness > 0, réappliquer RGB
if (level > 0) {
Backend.writeRGB(this._currentR, this._currentG, this._currentB, this._currentMasterGain);
}
}
/**
* Construit les sliders RGB + Master (version compacte)
*/
_buildRGBSliders() {
const container = new St.BoxLayout({
vertical: true,
x_expand: true,
style: 'spacing: 4px; padding: 4px;'
});
// Sliders RGB compacts
const sliders = [
{ label: 'R', color: '#ff4444', prop: '_currentR', key: 'red', max: 255 },
{ label: 'V', color: '#44ff44', prop: '_currentG', key: 'green', max: 255 },
{ label: 'B', color: '#4444ff', prop: '_currentB', key: 'blue', max: 255 },
{ label: 'M', color: '#ffffff', prop: '_currentMasterGain', key: 'master-gain', max: 100 }
];
sliders.forEach(({ label, color, prop, key, max }) => {
const sliderBox = new St.BoxLayout({
vertical: false,
x_expand: true,
style: 'spacing: 8px;'
});
const sliderLabel = new St.Label({
text: label,
style: `min-width: 12px; color: ${color}; font-weight: bold; font-size: 0.9em;`,
y_align: Clutter.ActorAlign.CENTER
});
const slider = new Slider.Slider(this[prop] / max);
slider.accessible_name = label;
slider.connect('notify::value', () => {
const newValue = Math.floor(slider.value * max);
this[prop] = newValue;
this._settings.set_int(key, newValue);
this._onRGBChanged();
});
// Stocker la référence
if (label === 'R') this._redSlider = slider;
else if (label === 'V') this._greenSlider = slider;
else if (label === 'B') this._blueSlider = slider;
else if (label === 'M') this._masterSlider = slider;
sliderBox.add_child(sliderLabel);
sliderBox.add_child(slider);
container.add_child(sliderBox);
});
this._colorPickerContainer.actor.add_child(container);
}
/**
* Construit la roue chromatique (grille de couleurs cliquables)
*/
_buildColorWheel() {
const container = new St.BoxLayout({
vertical: true,
x_expand: true,
style: 'spacing: 8px; padding: 8px;'
});
// Grille de couleurs en forme de cercle (optimisée pour la visibilité)
const gridBox = new St.BoxLayout({
vertical: true,
style: 'spacing: 3px;'
});
const size = 12; // Grille 12x12 (réduit pour boutons plus grands)
const cellSize = 18; // Augmenté de 12px à 18px
const centerX = size / 2;
const centerY = size / 2;
const maxRadius = size / 2 - 1;
// Stocker les boutons de la roue pour la surbrillance
this._wheelButtons = [];
for (let y = 0; y < size; y++) {
const row = new St.BoxLayout({
vertical: false,
style: 'spacing: 3px;'
});
for (let x = 0; x < size; x++) {
const dx = x - centerX;
const dy = y - centerY;
const distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= maxRadius) {
// Calculer teinte et saturation
const angle = Math.atan2(dy, dx);
const hue = ((angle * 180 / Math.PI) + 360) % 360;
const saturation = distance / maxRadius;
// Convertir HSL vers RGB
const rgb = this._hslToRgb(hue, saturation, 0.5);
const hex = Backend.rgbToHex(rgb.r, rgb.g, rgb.b);
const button = new St.Button({
style: `
background-color: ${hex};
width: ${cellSize}px;
height: ${cellSize}px;
border-radius: 3px;
padding: 0;
min-width: ${cellSize}px;
min-height: ${cellSize}px;
border: 1px solid rgba(0,0,0,0.3);
`,
reactive: true,
track_hover: true
});
// Stocker les infos de couleur pour comparaison
button._rgb = { r: rgb.r, g: rgb.g, b: rgb.b };
button._baseStyle = `
background-color: ${hex};
width: ${cellSize}px;
height: ${cellSize}px;
border-radius: 3px;
padding: 0;
min-width: ${cellSize}px;
min-height: ${cellSize}px;
border: 1px solid rgba(0,0,0,0.3);
`;
button.connect('clicked', () => {
this._currentR = rgb.r;
this._currentG = rgb.g;
this._currentB = rgb.b;
this._settings.set_int('red', this._currentR);
this._settings.set_int('green', this._currentG);
this._settings.set_int('blue', this._currentB);
// Mettre à jour la surbrillance
this._updateWheelSelection();
this._onRGBChanged();
});
this._wheelButtons.push(button);
row.add_child(button);
} else {
// Espace vide en dehors du cercle
const spacer = new St.Bin({
style: `width: ${cellSize}px; height: ${cellSize}px;`
});
row.add_child(spacer);
}
}
gridBox.add_child(row);
}
container.add_child(gridBox);
// Slider Master en dessous
const masterBox = new St.BoxLayout({
vertical: false,
x_expand: true,
style: 'spacing: 8px; margin-top: 8px;'
});
const masterLabel = new St.Label({
text: 'Luminosité',
style: 'font-weight: bold; font-size: 0.9em; min-width: 60px;',
y_align: Clutter.ActorAlign.CENTER
});
const masterSlider = new Slider.Slider(this._currentMasterGain / 100);
masterSlider.accessible_name = 'Master';
masterSlider.connect('notify::value', () => {
this._currentMasterGain = Math.floor(masterSlider.value * 100);
this._settings.set_int('master-gain', this._currentMasterGain);
this._onRGBChanged();
});
this._masterSlider = masterSlider;
masterBox.add_child(masterLabel);
masterBox.add_child(masterSlider);
container.add_child(masterBox);
this._colorPickerContainer.actor.add_child(container);
// Initialiser la surbrillance de la couleur actuelle
this._updateWheelSelection();
}
/**
* Met à jour la surbrillance de la couleur sélectionnée dans la roue
*/
_updateWheelSelection() {
if (!this._wheelButtons) return;
this._wheelButtons.forEach(button => {
const rgb = button._rgb;
// Comparer avec une tolérance (les couleurs HSL peuvent varier légèrement)
const tolerance = 10;
const matches =
Math.abs(rgb.r - this._currentR) <= tolerance &&
Math.abs(rgb.g - this._currentG) <= tolerance &&
Math.abs(rgb.b - this._currentB) <= tolerance;
if (matches) {
// Bordure blanche épaisse pour la sélection
button.style = button._baseStyle.replace(
'border: 1px solid rgba(0,0,0,0.3)',
'border: 3px solid white; box-shadow: 0 0 5px rgba(255,255,255,0.8)'
);
} else {
// Style normal
button.style = button._baseStyle;
}
});
}
/**
* Met à jour la surbrillance du preset sélectionné
*/
_updatePresetSelection() {
if (!this._presetButtons) return;
this._presetButtons.forEach(button => {
const preset = button._preset;
// Comparer avec une tolérance
const tolerance = 10;
const matches =
Math.abs(preset.r - this._currentR) <= tolerance &&
Math.abs(preset.g - this._currentG) <= tolerance &&
Math.abs(preset.b - this._currentB) <= tolerance;
if (matches) {
// Cercle blanc épais autour du preset sélectionné
button.style = button._baseStyle + ' border: 3px solid white; box-shadow: 0 0 5px rgba(255,255,255,0.8);';
} else {
// Style normal
button.style = button._baseStyle + ' border: 2px solid rgba(255,255,255,0.3);';
}
});
}
/**
* Trouve la couleur accent GNOME la plus proche d'une couleur RGB
*/
_rgbToGnomeAccent(r, g, b) {
const colors = {
blue: { r: 53, g: 132, b: 228 }, // Bleu GNOME
teal: { r: 51, g: 209, b: 122 }, // Turquoise
green: { r: 87, g: 227, b: 137 }, // Vert
yellow: { r: 246, g: 211, b: 45 }, // Jaune
orange: { r: 255, g: 120, b: 0 }, // Orange
red: { r: 237, g: 51, b: 59 }, // Rouge
pink: { r: 246, g: 97, b: 81 }, // Rose
purple: { r: 145, g: 65, b: 172 }, // Violet
slate: { r: 119, g: 118, b: 123 } // Gris ardoise
};
let minDistance = Infinity;
let closestColor = 'blue';
// Calculer la distance euclidienne dans l'espace RGB
for (const [name, color] of Object.entries(colors)) {
const distance = Math.sqrt(
Math.pow(r - color.r, 2) +
Math.pow(g - color.g, 2) +
Math.pow(b - color.b, 2)
);
if (distance < minDistance) {
minDistance = distance;
closestColor = name;
}
}
return closestColor;
}
/**
* Synchronise la couleur du clavier avec le thème GNOME
*/
_syncGnomeTheme() {
// Vérifier si la synchronisation est activée
if (!this._settings.get_boolean('sync-gnome-theme')) {
return;
}
// Trouver la couleur accent GNOME la plus proche
const accentColor = this._rgbToGnomeAccent(
this._currentR,
this._currentG,
this._currentB
);
try {
// Appliquer la couleur d'accentuation GNOME
const interfaceSettings = new Gio.Settings({
schema: 'org.gnome.desktop.interface'
});
interfaceSettings.set_string('accent-color', accentColor);
log(`[ASUS RGB] Thème GNOME synchronisé → ${accentColor} (RGB: ${this._currentR}, ${this._currentG}, ${this._currentB})`);
} catch (error) {
logError(error, '[ASUS RGB] Erreur lors de la synchronisation du thème GNOME');
}
}
/**
* Callback: RGB ou Master a changé
*/
_onRGBChanged() {
// Mettre à jour l'aperçu de couleur
this._updateColorPreview();
// Mettre à jour les surbrillances
this._updateWheelSelection();
this._updatePresetSelection();
// Synchroniser avec le thème GNOME si activé
this._syncGnomeTheme();
// Appliquer avec debouncing
Backend.writeRGBDebounced(
this._currentR,
this._currentG,
this._currentB,
this._currentMasterGain,
() => this._updateInfoLine()
);
}
/**
* Convertit RGB (0-255) vers HSL (H: 0-360, S: 0-1, L: 0-1)
*/
_rgbToHsl(r, g, b) {
r /= 255;
g /= 255;
b /= 255;
const max = Math.max(r, g, b);
const min = Math.min(r, g, b);
let h, s, l = (max + min) / 2;
if (max === min) {
h = s = 0; // Gris (pas de saturation)
} else {
const d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
switch (max) {
case r: h = ((g - b) / d + (g < b ? 6 : 0)) / 6; break;
case g: h = ((b - r) / d + 2) / 6; break;
case b: h = ((r - g) / d + 4) / 6; break;
}
}
return { h: h * 360, s: s, l: l };
}
/**
* Convertit HSL (H: 0-360, S: 0-1, L: 0-1) vers RGB (0-255)
*/
_hslToRgb(h, s, l) {
h /= 360;
let r, g, b;
if (s === 0) {
r = g = b = l; // Gris
} else {
const hue2rgb = (p, q, t) => {
if (t < 0) t += 1;
if (t > 1) t -= 1;
if (t < 1/6) return p + (q - p) * 6 * t;
if (t < 1/2) return q;
if (t < 2/3) return p + (q - p) * (2/3 - t) * 6;
return p;
};
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
const p = 2 * l - q;
r = hue2rgb(p, q, h + 1/3);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1/3);
}
return {
r: Math.round(r * 255),
g: Math.round(g * 255),
b: Math.round(b * 255)
};
}
/**
* Met à jour l'aperçu de couleur (version HSL avec correction gamma)
*/
_updateColorPreview() {
if (this._colorPreview) {
// Convertir RGB vers HSL
const hsl = this._rgbToHsl(this._currentR, this._currentG, this._currentB);
// Appliquer correction gamma pour progression perceptuelle naturelle
// Gamma 2.2 est la norme pour les écrans sRGB
const GAMMA = 2.2;
const gain = this._currentMasterGain / 100.0;
// Linéariser la luminosité, appliquer le gain, puis re-gamma
const linearL = Math.pow(hsl.l, GAMMA);
const adjustedLinearL = linearL * gain;
hsl.l = Math.pow(adjustedLinearL, 1 / GAMMA);
// Reconvertir HSL vers RGB
const rgb = this._hslToRgb(hsl.h, hsl.s, hsl.l);
const hex = Backend.rgbToHex(rgb.r, rgb.g, rgb.b);
this._colorPreview.style = `background-color: ${hex}; width: 50px; height: 30px; border-radius: 4px; border: 1px solid rgba(255,255,255,0.3);`;
}
}
/**
* Construit la ligne d'information
*/
/**
* Met à jour la ligne d'information (vide - infos dans l'aperçu)
*/
_updateInfoLine() {
// Les informations sont maintenant affichées via l'aperçu de couleur dans le header
}
/**
* Construit les 6 presets couleur
*/
/**
* Construit les presets de couleurs (version compacte)
*/
_buildPresets() {
const presetItem = new PopupMenu.PopupBaseMenuItem({
reactive: false,
can_focus: false
});
const container = new St.BoxLayout({
vertical: false,
x_expand: true,
style: 'spacing: 6px;'
});
const presetLabel = new St.Label({
text: 'Presets :',
style: 'font-weight: bold; font-size: 0.9em;',
y_align: Clutter.ActorAlign.CENTER
});
container.add_child(presetLabel);
// Créer 9 boutons preset compacts (couleurs GNOME) - ronds
const buttonBox = new St.BoxLayout({
vertical: false,
x_expand: true,
style: 'spacing: 3px;'
});
// Stocker les boutons pour la mise à jour de la sélection
this._presetButtons = [];
for (let i = 1; i <= 9; i++) {
const presetString = this._settings.get_string(`preset-${i}`);
const preset = Backend.parsePreset(presetString);
if (preset) {
const button = new St.Button({
style_class: 'button',
x_expand: true,
can_focus: true
});
const hex = Backend.rgbToHex(preset.r, preset.g, preset.b);
// Ronds avec border-radius 50%
const baseStyle = `background-color: ${hex}; width: 26px; height: 26px; border-radius: 50%; padding: 0;`;
button.style = baseStyle + ' border: 2px solid rgba(255,255,255,0.3);';
// Stocker les infos pour la mise à jour
button._preset = preset;
button._baseStyle = baseStyle;
button.connect('clicked', () => this._onPresetClicked(preset));
buttonBox.add_child(button);
this._presetButtons.push(button);
}
}
container.add_child(buttonBox);
presetItem.actor.add_child(container);
this.menu.addMenuItem(presetItem);
// Initialiser la surbrillance du preset actuel
this._updatePresetSelection();
}
/**
* Construit l'option de synchronisation avec le thème GNOME
*/
_buildSyncThemeOption() {
const syncItem = new PopupMenu.PopupSwitchMenuItem(
'Synchroniser thème GNOME',
this._settings.get_boolean('sync-gnome-theme')
);
syncItem.connect('toggled', (item) => {
this._settings.set_boolean('sync-gnome-theme', item.state);
// Si activé, appliquer immédiatement
if (item.state) {
this._syncGnomeTheme();
} else {
// Si désactivé, restaurer la couleur GNOME par défaut (blue)
try {
const interfaceSettings = new Gio.Settings({
schema: 'org.gnome.desktop.interface'
});
interfaceSettings.set_string('accent-color', 'blue');
log('[ASUS RGB] Thème GNOME restauré → blue (défaut)');
} catch (error) {
logError(error, '[ASUS RGB] Erreur lors de la restauration du thème GNOME');
}
}
});
this.menu.addMenuItem(syncItem);
}
/**
* Callback: clic sur un preset
*/
_onPresetClicked(preset) {
this._currentR = preset.r;
this._currentG = preset.g;
this._currentB = preset.b;
// Sauvegarder
this._settings.set_int('red', this._currentR);
this._settings.set_int('green', this._currentG);
this._settings.set_int('blue', this._currentB);
// Mettre à jour les sliders si en mode sliders
if (this._redSlider) {
this._redSlider.value = this._currentR / 255;
this._greenSlider.value = this._currentG / 255;
this._blueSlider.value = this._currentB / 255;
}
// Appliquer via _onRGBChanged qui gère tout (aperçu, surbrillances, sync thème, etc.)
this._onRGBChanged();
}
/**
* Applique l'état actuel au matériel (au démarrage)
*/
_applyCurrentState() {
Backend.writeBrightness(this._currentBrightnessLevel);
if (this._currentBrightnessLevel > 0) {
Backend.writeRGB(this._currentR, this._currentG, this._currentB, this._currentMasterGain);
}
}
/**
* Nettoyage lors de la destruction
*/
destroy() {
Backend.cleanup();
super.destroy();
}
});

View File

@@ -167,13 +167,22 @@ Claude doit demander au début, puis implémenter par défaut si pas de réponse
## 13) Prompt dexécution pour Claude Code
Tu es **Claude Code** (mode dev). Tu dois produire un projet complet dans un repo Git.
Contraintes :
- tes reponse seront en francais
- commentaires en francais
- GNOME Shell 48 (GJS)
- Pas de dépendances externes
- Code lisible, modulaire, commenté
- Robustesse permissions + erreurs
- UX immédiate et fluide
- choix des icones parmis des elemnt gratuit, libre ou opensource
- les fichiers de documentation seront dans un dossier 'docs'
- maintien a jours un changelog qui sera utilise pour reprendre le devellopement de l'app
Plan de travail exigé :
0.0 Analyse complete du projet
0.1 Popose un schema webui (format ascii draw, mermaid, excalidraw, ....)
0.2 Creation d'un ToDO evolutif que tu mettra jours ( a faire, terminer, a tester, annulé, amelioration, ...)
0.3 Creation d'un changelog a mettre ajours frequement ( tu me posera la question) . les element qui y seront inscrit seront pertinent pour une reprise du devellopement
1. Générer larborescence complète
2. Implémenter backend sysfs + debounce
3. Implémenter UI popover (table + sliders + presets)
@@ -181,4 +190,6 @@ Plan de travail exigé :
5. Documenter installation + règle udev + troubleshooting
6. Tester et fournir checklist
Fin.

165
tools/install-local.sh Executable file
View File

@@ -0,0 +1,165 @@
#!/bin/bash
# install-local.sh - Script d'installation locale pour l'extension ASUS Keyboard RGB
set -e # Arrêter en cas d'erreur
# Couleurs pour l'affichage
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Configuration
EXTENSION_UUID="asus-kbd-rgb@gilles"
EXTENSION_DIR="$HOME/.local/share/gnome-shell/extensions/$EXTENSION_UUID"
SOURCE_DIR="$(cd "$(dirname "$0")/.." && pwd)/extension"
echo -e "${BLUE}=== Installation de l'extension ASUS Keyboard RGB ===${NC}\n"
# Vérifier que le dossier source existe
if [ ! -d "$SOURCE_DIR" ]; then
echo -e "${RED}Erreur: Dossier source non trouvé: $SOURCE_DIR${NC}"
exit 1
fi
# Vérifier GNOME Shell
if ! command -v gnome-shell &> /dev/null; then
echo -e "${RED}Erreur: GNOME Shell n'est pas installé${NC}"
exit 1
fi
GNOME_VERSION=$(gnome-shell --version | grep -oP '\d+' | head -1)
echo -e "${GREEN}${NC} GNOME Shell version: $GNOME_VERSION"
if [ "$GNOME_VERSION" != "48" ]; then
echo -e "${YELLOW}⚠ Attention: Cette extension est conçue pour GNOME Shell 48${NC}"
echo -e "${YELLOW} Votre version: $GNOME_VERSION${NC}"
read -p "Continuer quand même ? (o/N) " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Oo]$ ]]; then
exit 1
fi
fi
# Vérifier le support matériel
echo -e "\n${BLUE}Vérification du support matériel...${NC}"
if [ ! -d "/sys/class/leds/asus::kbd_backlight" ]; then
echo -e "${RED}✗ Clavier ASUS RGB non détecté${NC}"
echo -e "${YELLOW} Les fichiers sysfs sont absents: /sys/class/leds/asus::kbd_backlight/${NC}"
echo -e "${YELLOW} L'extension s'installera mais ne fonctionnera pas sur ce système.${NC}"
read -p "Continuer quand même ? (o/N) " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Oo]$ ]]; then
exit 1
fi
else
echo -e "${GREEN}${NC} Clavier ASUS RGB détecté"
fi
# Vérifier les permissions
echo -e "\n${BLUE}Vérification des permissions...${NC}"
if [ -w "/sys/class/leds/asus::kbd_backlight/brightness" ]; then
echo -e "${GREEN}${NC} Permissions d'écriture OK"
# Vérifier que le groupe est bien kbdled
BRIGHTNESS_GROUP=$(stat -c '%G' /sys/class/leds/asus::kbd_backlight/brightness 2>/dev/null)
if [ "$BRIGHTNESS_GROUP" = "kbdled" ]; then
echo -e "${GREEN}${NC} Groupe kbdled configuré correctement"
fi
else
echo -e "${YELLOW}⚠ Permissions insuffisantes${NC}"
echo -e "${YELLOW} Vous devez configurer les règles udev pour utiliser l'extension.${NC}"
echo -e "${YELLOW} Voir: docs/INSTALL.md section 'Configuration des permissions'${NC}"
echo -e ""
echo -e "${BLUE}Commandes rapides :${NC}"
echo -e " sudo tee /etc/udev/rules.d/99-asus-kbd.rules > /dev/null << 'EOF'"
echo -e " ACTION==\"add\", SUBSYSTEM==\"leds\", KERNEL==\"asus::kbd_backlight\", TAG+=\"uaccess\", RUN+=\"/bin/sh -c 'chgrp kbdled /sys/class/leds/asus::kbd_backlight/brightness && chmod g+w /sys/class/leds/asus::kbd_backlight/brightness'\""
echo -e " ACTION==\"add\", SUBSYSTEM==\"leds\", KERNEL==\"asus::kbd_backlight\", TAG+=\"uaccess\", RUN+=\"/bin/sh -c 'chgrp kbdled /sys/class/leds/asus::kbd_backlight/kbd_rgb_mode && chmod g+w /sys/class/leds/asus::kbd_backlight/kbd_rgb_mode'\""
echo -e " EOF"
echo -e " sudo groupadd -f kbdled"
echo -e " sudo usermod -aG kbdled \$USER"
echo -e " sudo udevadm control --reload-rules"
echo -e " sudo modprobe -r asus_nb_wmi && sudo modprobe asus_nb_wmi"
echo -e ""
fi
# Désactiver l'extension si elle est active
if gnome-extensions list | grep -q "$EXTENSION_UUID"; then
echo -e "\n${BLUE}Désactivation de l'extension existante...${NC}"
gnome-extensions disable "$EXTENSION_UUID" 2>/dev/null || true
echo -e "${GREEN}${NC} Extension désactivée"
fi
# Créer le dossier de destination
echo -e "\n${BLUE}Création du dossier d'installation...${NC}"
mkdir -p "$EXTENSION_DIR"
echo -e "${GREEN}${NC} Dossier créé: $EXTENSION_DIR"
# Copier les fichiers
echo -e "\n${BLUE}Copie des fichiers...${NC}"
cp -v "$SOURCE_DIR/extension.js" "$EXTENSION_DIR/"
cp -v "$SOURCE_DIR/ui.js" "$EXTENSION_DIR/"
cp -v "$SOURCE_DIR/backend.js" "$EXTENSION_DIR/"
cp -v "$SOURCE_DIR/metadata.json" "$EXTENSION_DIR/"
cp -v "$SOURCE_DIR/stylesheet.css" "$EXTENSION_DIR/"
# Copier le schéma GSettings
echo -e "\n${BLUE}Copie du schéma GSettings...${NC}"
mkdir -p "$EXTENSION_DIR/schemas"
cp -v "$SOURCE_DIR/schemas/org.gnome.shell.extensions.asuskbdrgb.gschema.xml" "$EXTENSION_DIR/schemas/"
# Compiler le schéma
echo -e "\n${BLUE}Compilation du schéma GSettings...${NC}"
if command -v glib-compile-schemas &> /dev/null; then
glib-compile-schemas "$EXTENSION_DIR/schemas/"
echo -e "${GREEN}${NC} Schéma compilé"
else
echo -e "${RED}✗ glib-compile-schemas non trouvé${NC}"
echo -e "${YELLOW} Installez glib-2.0-dev ou libglib2.0-bin${NC}"
exit 1
fi
# Vérifier l'installation
echo -e "\n${BLUE}Vérification de l'installation...${NC}"
if [ -f "$EXTENSION_DIR/extension.js" ] && [ -f "$EXTENSION_DIR/schemas/gschemas.compiled" ]; then
echo -e "${GREEN}${NC} Installation réussie"
else
echo -e "${RED}✗ Installation incomplète${NC}"
exit 1
fi
# Activer l'extension
echo -e "\n${BLUE}Activation de l'extension...${NC}"
gnome-extensions enable "$EXTENSION_UUID"
echo -e "${GREEN}${NC} Extension activée"
# Instructions finales
echo -e "\n${GREEN}=== Installation terminée ===${NC}\n"
echo -e "${BLUE}Prochaines étapes :${NC}"
# Vérifier le type de session
if [ "$XDG_SESSION_TYPE" = "wayland" ]; then
echo -e " 1. ${YELLOW}Déconnectez-vous et reconnectez-vous${NC} (session Wayland)"
else
echo -e " 1. Rechargez GNOME Shell : ${YELLOW}Alt+F2${NC}, tapez ${YELLOW}r${NC}, appuyez sur Entrée"
fi
echo -e " 2. L'icône devrait apparaître dans la barre supérieure"
echo -e " 3. Cliquez sur l'icône pour contrôler le rétroéclairage\n"
if [ ! -w "/sys/class/leds/asus::kbd_backlight/brightness" ]; then
echo -e "${YELLOW}⚠ IMPORTANT :${NC}"
echo -e " Vous devez configurer les permissions udev avant utilisation."
echo -e " Consultez ${BLUE}docs/INSTALL.md${NC} pour les instructions.\n"
fi
echo -e "${BLUE}Logs en temps réel :${NC}"
echo -e " journalctl -f -o cat /usr/bin/gnome-shell | grep -i asus\n"
echo -e "${BLUE}Désinstallation :${NC}"
echo -e " gnome-extensions disable $EXTENSION_UUID"
echo -e " rm -rf $EXTENSION_DIR\n"
echo -e "${GREEN}Profitez de votre clavier RGB ! 🎨${NC}"