v1
This commit is contained in:
255
CHANGELOG.md
Normal file
255
CHANGELOG.md
Normal 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
162
CLAUDE.md
Normal 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
131
PROJECT_STRUCTURE.txt
Normal 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
230
README.md
@@ -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`.
|
||||||
|
|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
|
## 📋 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 ! 🌈⌨️**
|
||||||
|
|||||||
275
docs/ANALYSE_ROUE_CHROMATIQUE.md
Normal file
275
docs/ANALYSE_ROUE_CHROMATIQUE.md
Normal 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
306
docs/ANALYSE_THEME_GNOME.md
Normal 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.
|
||||||
390
docs/DEVELOPPEMENT_COMPLET.md
Normal file
390
docs/DEVELOPPEMENT_COMPLET.md
Normal 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**
|
||||||
154
docs/FIX_UDEV_PERMISSIONS.md
Normal file
154
docs/FIX_UDEV_PERMISSIONS.md
Normal 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
227
docs/INSTALL.md
Normal 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
324
docs/TESTING.md
Normal 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
445
docs/TROUBLESHOOTING.md
Normal 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
170
docs/UI_SCHEMA.md
Normal 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
|
||||||
138
docs/synthese roue chromatique.md
Normal file
138
docs/synthese roue chromatique.md
Normal 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 n’existe **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 (0–255) 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 (0–255) 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**
|
||||||
|
- C’est la meilleure solution pour une extension GNOME 48, surtout si l’usage 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 (0–255)
|
||||||
|
- G (0–255)
|
||||||
|
- B (0–255)
|
||||||
|
- Afficher un carré d’aperç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 qu’une 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).
|
||||||
|
- L’extension GNOME Shell lance l’app ou communique via DBus.
|
||||||
|
- L’app renvoie la couleur choisie (RGB/HSV) à l’extension.
|
||||||
|
|
||||||
|
**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 l’app.
|
||||||
|
- 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**
|
||||||
|
- S’inspirer d’une 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 0–255 et/ou HEX
|
||||||
|
- prévoir un slider d’intensité (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 (0–255) + 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 à l’implé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 d’application : sysfs / asusctl / DBus service
|
||||||
|
s
|
||||||
285
extension/backend.js
Normal file
285
extension/backend.js
Normal 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
59
extension/extension.js
Normal 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
11
extension/metadata.json
Normal 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"
|
||||||
|
}
|
||||||
@@ -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
72
extension/stylesheet.css
Normal 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
852
extension/ui.js
Normal 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();
|
||||||
|
}
|
||||||
|
});
|
||||||
@@ -167,13 +167,22 @@ Claude doit demander au début, puis implémenter par défaut si pas de réponse
|
|||||||
## 13) Prompt d’exécution pour Claude Code
|
## 13) Prompt d’exécution pour Claude Code
|
||||||
Tu es **Claude Code** (mode dev). Tu dois produire un projet complet dans un repo Git.
|
Tu es **Claude Code** (mode dev). Tu dois produire un projet complet dans un repo Git.
|
||||||
Contraintes :
|
Contraintes :
|
||||||
|
- tes reponse seront en francais
|
||||||
|
- commentaires en francais
|
||||||
- GNOME Shell 48 (GJS)
|
- GNOME Shell 48 (GJS)
|
||||||
- Pas de dépendances externes
|
- Pas de dépendances externes
|
||||||
- Code lisible, modulaire, commenté
|
- Code lisible, modulaire, commenté
|
||||||
- Robustesse permissions + erreurs
|
- Robustesse permissions + erreurs
|
||||||
- UX immédiate et fluide
|
- 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é :
|
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 l’arborescence complète
|
1. Générer l’arborescence complète
|
||||||
2. Implémenter backend sysfs + debounce
|
2. Implémenter backend sysfs + debounce
|
||||||
3. Implémenter UI popover (table + sliders + presets)
|
3. Implémenter UI popover (table + sliders + presets)
|
||||||
@@ -181,4 +190,6 @@ Plan de travail exigé :
|
|||||||
5. Documenter installation + règle udev + troubleshooting
|
5. Documenter installation + règle udev + troubleshooting
|
||||||
6. Tester et fournir checklist
|
6. Tester et fournir checklist
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Fin.
|
Fin.
|
||||||
|
|||||||
165
tools/install-local.sh
Executable file
165
tools/install-local.sh
Executable 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}"
|
||||||
Reference in New Issue
Block a user