Problem mit Code für Button Box

Hallo,
Ich baue grad eine Button Box für AssettoCorsaCompetitione PS5. Ich habe ein Arduino Micro Pro mit 4 Encodern und 20 Buttons. Den Code hab ich im Netz gefunden und für mich angepaßt. Ich kann jedem Encoder und Button einen Buchstaben zu weisen. Und da liegt das Problem: Ich brauche Tasten-Kombinationen (zB für die '5' brauche ich Shift+i)

In der Defention der Matrix am Anfang kann ich nur einen Wert eingeben. An der Stelle kann ich das also nicht einfügen!?

Ich habe in anderen Codes gesehen, daß case'1', case'2' defeniert werden können. An welcher Stelle kann ich so etwas in meine Code einbauen?

#include <Keypad.h>
#include <Keyboard.h>


#define ENABLE_PULLUPS
#define NUMROTARIES 4
#define NUMBUTTONS 20
#define NUMROWS 4
#define NUMCOLS 5


char buttons[NUMROWS][NUMCOLS] = {
  {'1','2','3','4','5'},
  {'6','7','8','9','0'},
  {'a','b','c','d','e'},
  {'f','g','h','i','j'},
};



struct rotariesdef {
  byte pin1;
  byte pin2;
  int ccwchar;
  int cwchar;
  volatile unsigned char state;
};

rotariesdef rotaries[NUMROTARIES] {
  {0,1,'n','m',0},
  {2,3,'o','t',p},
  {4,5,'q','r',0},
  {6,7,'s','t',0},
};


#define DIR_CCW 0x10
#define DIR_CW 0x20

#define R_START 0x0
#define R_CW_FINAL 0x1
#define R_CW_BEGIN 0x2
#define R_CW_NEXT 0x3
#define R_CCW_BEGIN 0x4
#define R_CCW_FINAL 0x5
#define R_CCW_NEXT 0x6

const unsigned char ttable[7][4] = {
  // R_START
  {R_START,    R_CW_BEGIN,  R_CCW_BEGIN, R_START},
  // R_CW_FINAL
  {R_CW_NEXT,  R_START,     R_CW_FINAL,  R_START | DIR_CW},
  // R_CW_BEGIN
  {R_CW_NEXT,  R_CW_BEGIN,  R_START,     R_START},
  // R_CW_NEXT
  {R_CW_NEXT,  R_CW_BEGIN,  R_CW_FINAL,  R_START},
  // R_CCW_BEGIN
  {R_CCW_NEXT, R_START,     R_CCW_BEGIN, R_START},
  // R_CCW_FINAL
  {R_CCW_NEXT, R_CCW_FINAL, R_START,     R_START | DIR_CCW},
  // R_CCW_NEXT
  {R_CCW_NEXT, R_CCW_FINAL, R_CCW_BEGIN, R_START},
};


byte rowPins[NUMROWS] = {21,20,19,18}; //connect to the row pinouts of the keypad
byte colPins[NUMCOLS] = {15,14,16,10,9}; //connect to the column pinouts of the keypad

//initialize an instance of class NewKeypad
Keypad buttbx = Keypad( makeKeymap(buttons), rowPins, colPins, NUMROWS, NUMCOLS); 



void setup() {
  Keyboard.begin();
  rotary_init();
}



void loop() { 

  CheckAllEncoders();

  CheckAllButtons();

}


void CheckAllButtons(void) {
  char key = buttbx.getKey();
  if (key != NO_KEY)  {
    Keyboard.press(key);
    delay(150);
    Keyboard.releaseAll();
  }
}


/* Call this once in setup(). */
void rotary_init() {
  for (int i=0;i<NUMROTARIES;i++) {
    pinMode(rotaries[i].pin1, INPUT);
    pinMode(rotaries[i].pin2, INPUT);
    #ifdef ENABLE_PULLUPS
      digitalWrite(rotaries[i].pin1, HIGH);
      digitalWrite(rotaries[i].pin2, HIGH);
    #endif
  }
}


/* Read input pins and process for events. Call this either from a
 * loop or an interrupt (eg pin change or timer).
 *
 * Returns 0 on no event, otherwise 0x80 or 0x40 depending on the direction.
 */
unsigned char rotary_process(int _i) {
   unsigned char pinstate = (digitalRead(rotaries[_i].pin2) << 1) | digitalRead(rotaries[_i].pin1);
  rotaries[_i].state = ttable[rotaries[_i].state & 0xf][pinstate];
  return (rotaries[_i].state & 0x30);
}

void CheckAllEncoders(void) {
  for (int i=0;i<NUMROTARIES;i++) {
    unsigned char result = rotary_process(i);
    if (result) {
      Keyboard.write(result == DIR_CCW ? rotaries[i].ccwchar : rotaries[i].cwchar ); 
    }
  }
}

Willkommen im Forum!

Funktioniert statt der '5' vielleicht KEY_LEFT_SHIFT + 'i'?

das hab ich schon probiert gehabt. Da kommt dann irgendwas völlig absurdes in meinem Keyboard Test an. Bei der Combination ist das glaub ich 'r'.

In einem anderen gefundenen Code wird das im Loop mit case'1' usw defeniert. Ich hab aber keine Idee, wo ich so etwas bei mir einfügen kann.

// --------------------------------------------------------------
// Standard Libraries
// --------------------------------------------------------------
#include <Keyboard.h>  // USB HID Keyboard (Leonardo or Micro)
#include <Keypad.h>
// This library is for interfacing with the 3x4 Matrix
// Can be installed from the library manager, search for "keypad"
// and install the one by Mark Stanley and Alexander Brevig
// https://playground.arduino.cc/Code/Keypad/

const byte ROWS = 3; //four rows
const byte COLS = 4; //four columns

char keys[ROWS][COLS] =
{
  {'1', '2', '3', '4'},  //  the keyboard hardware is  a 3x4 grid...
  {'5', '6', '7', '8'},
  {'9', '0', 'A', 'B'},  // these values need  to be single char, so...
};
// The library will return the character inside this array when the appropriate
// button is pressed then look for that case statement. This is the key assignment lookup table.
// Layout(key/button order) looks like this
//     |----------------------------|
//     |                  [2/3]*    |     *TRS breakout connection. Keys 5 and 6 are duplicated at the TRS jack
//     |      [ 1] [ 2] [ 3] [ 4]   |     * Encoder A location = key[1]
//     |      [ 5] [ 6] [ 7] [ 8]   |     * Encoder B location = Key[4]
//     |      [ 9] [10] [11] [12]   |      NOTE: The mode button is not row/column key, it's directly wired to A0!!
//     |----------------------------|


byte rowPins[ROWS] = {4, 5, A3 };    //connect to the row pinouts of the keypad
byte colPins[COLS] = {6, 7, 8, 9 };  //connect to the column pinouts of the keypad

Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

void setup()
{
  Serial.begin(9600);
  delay(200);

  Keyboard.begin();
}

void loop()
{
  char key = keypad.getKey();

  if (key == NO_KEY)
    return;

  //Serial.println(key);
  switch (key)
  {
    case '1': //macro example!!! Windows_Key+R = Run then type "mspaint" and press enter. Opens MS Paint
      Keyboard.press(KEY_LEFT_GUI);
      Keyboard.press('r'); 
      delay(150);
      Keyboard.release(KEY_LEFT_GUI);
      Keyboard.release('r');
      delay(150); //give your system time to catch up with these android-speed keyboard presses
      Keyboard.println("mspaint");
      break;

    case '2':
      Keyboard.press(KEY_LEFT_GUI);
      Keyboard.press(KEY_LEFT_ARROW); 
      delay(150);  //snaps window to left side of screen.
      break;

    case '3':
      Keyboard.press(KEY_LEFT_GUI);
      Keyboard.press(KEY_RIGHT_ARROW); 
      delay(150);  //snaps window to right side of screen.
      break;

    case '4':
      Keyboard.press(KEY_LEFT_ALT);
      Keyboard.press(KEY_F4); 
      delay(150);  //Closes active window
      break;

    case '5': //macro example: Windows_Key+R = Run then type "calc" and press enter. Opens MS Calculator
      Keyboard.press(KEY_LEFT_GUI);
      Keyboard.press('r'); 
      delay(150);
      Keyboard.release(KEY_LEFT_GUI);
      Keyboard.release('r');
      delay(150);                 //give your system time to catch up with these android-speed keyboard presses
      Keyboard.println("calc");
      break;

    case '6': //macro example: Windows_Key+R = Run then type "excel" and press enter. Opens MS Excel
      Keyboard.press(KEY_LEFT_GUI);
      Keyboard.press('r'); 
      delay(150);
      Keyboard.release(KEY_LEFT_GUI);
      Keyboard.release('r');
      delay(150);                 //give your system time to catch up with these android-speed keyboard presses
      Keyboard.println("excel");
      break;

    case '7': //macro example: Windows_Key+R = Run then type "winword" and press enter. Opens MS Word
      Keyboard.press(KEY_LEFT_GUI);
      Keyboard.press('r'); 
      delay(150);
      Keyboard.release(KEY_LEFT_GUI);
      Keyboard.release('r');
      delay(150);                 //give your system time to catch up with these android-speed keyboard presses
      Keyboard.println("winword");
      break;

    case '8': //macro that opens chrome and a random wiki page for learning.
      Keyboard.press(KEY_LEFT_GUI);
      Keyboard.press('r');
      Keyboard.release(KEY_LEFT_GUI);
      Keyboard.release('r');
      delay(50); //give your system time to catch up with these android-speed keyboard presses
      Keyboard.println("chrome"); 
      delay(500);
      Keyboard.println("https://en.wikipedia.org/wiki/Special:Random");
      break;

    case '9': //macro that opens Chrome & Rick Rolls you like a chump
      Keyboard.press(KEY_LEFT_GUI);
      Keyboard.press('r');
      Keyboard.release(KEY_LEFT_GUI);
      Keyboard.release('r');
      delay(50); //give your system time to catch up with these android-speed keyboard presses
      Keyboard.println("chrome"); 
      delay(500);
      Keyboard.println("https://www.youtube.com/watch?v=dQw4w9WgXcQ");
      break;

    case '0': //macro that opens Chrome and goes to my youtube channel!
      Keyboard.press(KEY_LEFT_GUI);
      Keyboard.press('r');
      Keyboard.release(KEY_LEFT_GUI);
      Keyboard.release('r');
      delay(50); //give your system time to catch up with these android-speed keyboard presses
      Keyboard.println("chrome"); 
      delay(500);
      Keyboard.println("https://www.youtube.com/c/ryanbatesrbg");
      break;

    case 'A': //minimize all windows (view desktop)
      Keyboard.press(KEY_LEFT_GUI);
      Keyboard.press('m');
      break;

    case 'B':
      Keyboard.press(KEY_LEFT_GUI);  //Opens Snip-it
      Keyboard.release(KEY_LEFT_GUI); 
      delay(25);
      Keyboard.println("snip");  //type "snip" and press "return"
      break;
  }
  delay(100); 
  Keyboard.releaseAll(); // this releases the buttons
}

Die Frage ist, was kommt wann zurück.
Wenn Du mit 2 Tastendrücken arbeiten willst, musst Du sicherstellen, dass nicht erst eine Taste (und ggfls. dann die andere Taste) und dann erst bedei Tasten als Summer erkannt werden.

Kann die lib das abhandeln?

  • Was bekommst Du zurück, wenn beide Tasten gedrückt sind?
  • Kann die lib unterscheiden zwischen einer und mehr gedrückten Tasten?

Alles andere ist Fleißarbeit.

Mißverständniss!? Ich möchte mit einer Taste (bzw Encoder) ein Macro mit 2-3 Tasten-Ausgabe.

Der Rest vom Code ist so geschrieben, daß man (anders als beim normalen Keyboard) immer nur eine Eingabe zZ machen kann und auch nur 1mal ausgaben wird, egal wie lange man drückt (Wenn ich das richtig verstanden habe :face_with_peeking_eye:)

In der Funktion CheckAllButtons() im Code aus Post #1
Da hast Du ja auch eine Variable key (die Taste auf dem Keypad) und statt die einfach als Einzeltaste gedrückt (press) rauszugeben, machst Du die Fallunterscheidung mit dem switch/case Konstrukt.

Hab´s für die Buttons hin bekommen :grinning_face:
Danke Für Hilfe! Da war der endscheidene Tip dabei :+1: :+1:
Jetzt hängt es noch an den Encodern, die sollen auch 2Tasten-Makros rausgeben. Geht das überhaupt?

#include <Keypad.h>
#include <Keyboard.h>


#define ENABLE_PULLUPS
#define NUMROTARIES 4
#define NUMBUTTONS 20
#define NUMROWS 4
#define NUMCOLS 5


//define the symbols on the buttons of the keypads
char buttons[NUMROWS][NUMCOLS] = {
  {'1','2','3','4','5'},
  {'6','7','8','9','0'},
  {'a','b','c','d','e'},
  {'f','g','h','i','j'},
};



struct rotariesdef {
  byte pin1;
  byte pin2;
  int ccwchar;
  int cwchar;
  volatile unsigned char state;
};

rotariesdef rotaries[NUMROTARIES] {
  {0,1,'n','m',0},
  {2,3,'o','p',0},
  {4,5,'q','r',0},
  {6,7,'s','t',0},
};


// 
//Encoders code from Ben Buxton
//More info: http://www.buxtronix.net/2011/10/rotary-encoders-done-properly.html
// 

#define DIR_CCW 0x10
#define DIR_CW 0x20

#define R_START 0x0
#define R_CW_FINAL 0x1
#define R_CW_BEGIN 0x2
#define R_CW_NEXT 0x3
#define R_CCW_BEGIN 0x4
#define R_CCW_FINAL 0x5
#define R_CCW_NEXT 0x6

const unsigned char ttable[7][4] = {
  // R_START
  {R_START,    R_CW_BEGIN,  R_CCW_BEGIN, R_START},
  // R_CW_FINAL
  {R_CW_NEXT,  R_START,     R_CW_FINAL,  R_START | DIR_CW},
  // R_CW_BEGIN
  {R_CW_NEXT,  R_CW_BEGIN,  R_START,     R_START},
  // R_CW_NEXT
  {R_CW_NEXT,  R_CW_BEGIN,  R_CW_FINAL,  R_START},
  // R_CCW_BEGIN
  {R_CCW_NEXT, R_START,     R_CCW_BEGIN, R_START},
  // R_CCW_FINAL
  {R_CCW_NEXT, R_CCW_FINAL, R_START,     R_START | DIR_CCW},
  // R_CCW_NEXT
  {R_CCW_NEXT, R_CCW_FINAL, R_CCW_BEGIN, R_START},
};


byte rowPins[NUMROWS] = {21,20,19,18}; //connect to the row pinouts of the keypad
byte colPins[NUMCOLS] = {15,14,16,10,9}; //connect to the column pinouts of the keypad

//initialize an instance of class NewKeypad
Keypad buttbx = Keypad( makeKeymap(buttons), rowPins, colPins, NUMROWS, NUMCOLS); 



void setup() {
  Keyboard.begin();
  rotary_init();
}



void loop() { 

  CheckAllEncoders();

  CheckAllButtons();

}





/* Call this once in setup(). */
void rotary_init() {
  for (int i=0;i<NUMROTARIES;i++) {
    pinMode(rotaries[i].pin1, INPUT);
    pinMode(rotaries[i].pin2, INPUT);
    #ifdef ENABLE_PULLUPS
      digitalWrite(rotaries[i].pin1, HIGH);
      digitalWrite(rotaries[i].pin2, HIGH);
    #endif
  }
}


/* Read input pins and process for events. Call this either from a
 * loop or an interrupt (eg pin change or timer).
 *
 * Returns 0 on no event, otherwise 0x80 or 0x40 depending on the direction.
 */
unsigned char rotary_process(int _i) {
   unsigned char pinstate = (digitalRead(rotaries[_i].pin2) << 1) | digitalRead(rotaries[_i].pin1);
  rotaries[_i].state = ttable[rotaries[_i].state & 0xf][pinstate];
  return (rotaries[_i].state & 0x30);
}

void CheckAllEncoders(void) {
  for (int i=0;i<NUMROTARIES;i++) {
    unsigned char result = rotary_process(i);
    if (result) {
      Keyboard.write(result == DIR_CCW ? rotaries[i].ccwchar : rotaries[i].cwchar ); 
    }
  }
}

void CheckAllButtons(void) {
  char key = buttbx.getKey();
  if (key != NO_KEY) 
  
   {
    switch (key)
    {
      case '1':
       Keyboard.press('l');
       break;
      case '2':
       Keyboard.press(KEY_LEFT_CTRL);
       Keyboard.press('l');
       break;
      case '3':
       Keyboard.press(KEY_LEFT_ALT);
       Keyboard.press('r');
       break;
      case '4':
       Keyboard.press('s');
       break;
      case '5':
       Keyboard.press('I');
       break; 
      case '6':
       Keyboard.press(KEY_INSERT);
       break; 
      case '7':
       Keyboard.press(KEY_LEFT_ARROW);
       break; 
      case '8':
       Keyboard.press(KEY_RIGHT_ARROW);
       break;  
      case '9':
       Keyboard.press(KEY_UP_ARROW);
       break;  
      case '0':
       Keyboard.press(KEY_DOWN_ARROW);
       break;                                        
      case 'a':
       Keyboard.press(KEY_LEFT_ALT);
       Keyboard.press('l');
       break; 
      case 'b':
       Keyboard.press('D');
       break;  
      case 'c':
       Keyboard.press(KEY_F1);
       break;                       

      case 'f':
       Keyboard.press(KEY_LEFT_ALT);
       Keyboard.press('d');
       break; 
      case 'g':
       Keyboard.press(KEY_LEFT_CTRL);
       Keyboard.press('d');
       break; 
      case 'h':
       Keyboard.press(KEY_F2);
       break;         

       }
    delay(150);
    Keyboard.releaseAll();
  }
}

Du willst kein delay() im Code haben, da dann deine Encoderauswertung steht.

Wenn du deinen Code an der Stelle auf non-blocking umbaust müsste das mit den Macro-codes auch mit dem Encoder gehen:

bool keyDown = false;
unsigned long keyStart;
constexpr auto keyWait = 150;

if(...)
case ...:
{
  Keyboard.press(XXX);
  keyDown = true;
  keyStart = milis();
}


if(keyDown && (milis() - keyStart) > keyWait))
{
  Keyboard.releaseAll();
  keyDown = false;
}

Wobei wenn ich mir das recht überlege... Encoder und Keypad sollten Events erzeugen.
Anstatt Keyboard.press() rufen die dann handleKey() auf.
Diese kannst du dann in einer Funktion auswerten.

void handleKey(char event)
{
  switch(event)
  {
    case 'A':
      Keyboard.press(xxx);
      Keyboard.press(yyy);
      keyDown = true;
      keyStart = milis();
      break;
    case 'B':
      ....
  }      
}

void loop() { 
  CheckAllEncoders();
  CheckAllButtons();
  if(keyDown && (milis() - keyStart) > keyWait))
  {
    Keyboard.releaseAll();
    keyDown = false;
  }
}

Ich hab´s geschafft!
Ich hab nochmal alle Encoder--Befehle gelöscht und ganz einfachen Code dafür nue eingefügt. Beim ersten Test hat alles so funtioniert, wie ich mir das gedacht hatte.

Danke allen die geholfen haben!

#include <Keypad.h>
#include <Keyboard.h>
#include <Encoder.h>



#define ENABLE_PULLUPS
#define NUMBUTTONS 20
#define NUMROWS 4
#define NUMCOLS 5

char buttons[NUMROWS][NUMCOLS] = {
  {'1','2','3','4','5'},
  {'6','7','8','9','0'},
  {'a','b','c','d','e'},
  {'f','g','h','i','j'},
};

byte rowPins[NUMROWS] = {21,20,19,18}; 
byte colPins[NUMCOLS] = {15,14,16,10,9}; 

Keypad buttbx = Keypad( makeKeymap(buttons), rowPins, colPins, NUMROWS, NUMCOLS); 



Encoder RotaryEncoderA(0, 1);
Encoder RotaryEncoderB(2, 3);
Encoder RotaryEncoderC(4, 5);
Encoder RotaryEncoderD(6, 7);

long positionEncoderA  = -999;
long positionEncoderB  = -999;
long positionEncoderC  = -999;
long positionEncoderD  = -999;


void setup() {
  Keyboard.begin();
  Serial.begin(9600);
}



void loop() { 
  encoderA();
  encoderB();
  encoderC();
  encoderD();

  CheckAllButtons();

}



void CheckAllButtons(void) {
  char key = buttbx.getKey();
  if (key != NO_KEY) 
  
   {
    switch (key)
    {
      case '1':
       Keyboard.press('l');
       break;
      case '2':
       Keyboard.press(KEY_LEFT_CTRL);
       Keyboard.press('l');
       break;
      case '3':
       Keyboard.press(KEY_LEFT_ALT);
       Keyboard.press('r');
       break;
      case '4':
       Keyboard.press('s');
       break;
      case '5':
       Keyboard.press(KEY_LEFT_SHIFT);
       Keyboard.press('i');
       break; 
      case '6':
       Keyboard.press(KEY_INSERT);
       break; 
      case '7':
       Keyboard.press(KEY_LEFT_ARROW);
       break; 
      case '8':
       Keyboard.press(KEY_RIGHT_ARROW);
       break;  
      case '9':
       Keyboard.press(KEY_UP_ARROW);
       break;  
      case '0':
       Keyboard.press(KEY_DOWN_ARROW);
       break;                                        
      case 'a':
       Keyboard.press(KEY_LEFT_ALT);
       Keyboard.press('l');
       break; 
      case 'b':
       Keyboard.press(KEY_LEFT_SHIFT);
       Keyboard.press('d');
       break;  
      case 'c':
       Keyboard.press(KEY_F1);
       break;                       

      case 'f':
       Keyboard.press(KEY_LEFT_ALT);
       Keyboard.press('d');
       break; 
      case 'g':
       Keyboard.press(KEY_LEFT_CTRL);
       Keyboard.press('d');
       break; 
      case 'h':
       Keyboard.press(KEY_F2);
       break;         

       }
    delay(150);
    Keyboard.releaseAll();
  }
}


void encoderA(){
  long newPos = RotaryEncoderA.read()/4;
  if (newPos != positionEncoderA && newPos > positionEncoderA) {
    positionEncoderA = newPos;
    Keyboard.press(KEY_LEFT_SHIFT);
    Keyboard.press('a');
    delay(150);   
    Keyboard.release(KEY_LEFT_SHIFT);
    Keyboard.release('a');                           }

  if (newPos != positionEncoderA && newPos < positionEncoderA) {
    positionEncoderA = newPos;
    Keyboard.press(KEY_LEFT_CTRL);
    Keyboard.press('a');
    delay(150);   
    Keyboard.release(KEY_LEFT_CTRL);
    Keyboard.release('a');                   }
}

void encoderB(){
  long newPos = RotaryEncoderB.read()/4;
  if (newPos != positionEncoderB && newPos > positionEncoderB) {
    positionEncoderB = newPos;
    Keyboard.press(KEY_LEFT_SHIFT);
    Keyboard.press('b');
    delay(150);   
    Keyboard.release(KEY_LEFT_SHIFT);
    Keyboard.release('b');                           }

  if (newPos != positionEncoderB && newPos < positionEncoderB) {
    positionEncoderB = newPos;
    Keyboard.press(KEY_LEFT_CTRL);
    Keyboard.press('b');
    delay(150);   
    Keyboard.release(KEY_LEFT_CTRL);
    Keyboard.release('b');                   }
}

void encoderC(){
  long newPos = RotaryEncoderC.read()/4;
  if (newPos != positionEncoderC && newPos > positionEncoderC) {
    positionEncoderC = newPos;
    Keyboard.press(KEY_LEFT_SHIFT);
    Keyboard.press('e');
    delay(150);   
    Keyboard.release(KEY_LEFT_SHIFT);
    Keyboard.release('e');                           }

  if (newPos != positionEncoderC && newPos < positionEncoderC) {
    positionEncoderC = newPos;
    Keyboard.press(KEY_LEFT_CTRL);
    Keyboard.press('e');
    delay(150);   
    Keyboard.release(KEY_LEFT_CTRL);
    Keyboard.release('e');                   }
}

void encoderD(){
  long newPos = RotaryEncoderD.read()/4;
  if (newPos != positionEncoderD && newPos > positionEncoderD) {
    positionEncoderD = newPos;
    Keyboard.press(KEY_LEFT_SHIFT);
    Keyboard.press('t');
    delay(150);   
    Keyboard.release(KEY_LEFT_SHIFT);
    Keyboard.release('t');                           }

  if (newPos != positionEncoderD && newPos < positionEncoderD) {
    positionEncoderD = newPos;
    Keyboard.press(KEY_LEFT_CTRL);
    Keyboard.press('t');
    delay(150);   
    Keyboard.release(KEY_LEFT_CTRL);
    Keyboard.release('t');                   }
}

Also ich finde du machst das zu kompliziert.

Du brauchst keine Tasten zu definieren.

Du fragst einfach das Keyboard ab, und löst mit der CASE oder IF-Abfrage eine Unterroutine aus. Fertig ist.

Hier ein kleiner Teil eines Codes für meine Bewässerungsanlage V 2.

  taste = MyKey.receiveKey(-1);  // nur einmal abfragen
  if (taste < 20) {
    Serial.println(taste);
  }

  if (taste == 1) {  // Pumpe 1 an
    digitalWrite(Relais_pin_1, HIGH);
  }

  if (taste == 2) {  // Pumpe 1 aus
    sub_mache_tasten_reihenfolge
  }
}


Ich benutze hier zwar eine andere Libs ist aber egal da das auch mit deiner Libs geht.
Die andere Libs benutze ich nur weil das Keyboard (4x4 Membrane) an einen I2C-Board angeschlossen ist.

Du weißt einfach JEDER Taste eine Unterroutine zu. Wenn nun eine Taste den Druck mehrere Taste simulieren soll, ruftst du einfach die Unterroutinen der Reihe nach auf.

Gruß

Pucki

ich versteh nicht so ganz was meinst. Ich hab erst probiert nur für die Tasten mit Macro ein case zu schreiben, das hat aber nicht hingehauen, also hab ich auch für die einfachen Tasten case geschrieben.
Der verbrauchte Speicher ist mir recht egal. Funktioniert, bleib also so.
Trotzdem Danke.

Ich habe jetzt allerdings das Problem, daß die Encoder "rum zappeln". Die zählen oft in eine Richtung und springen in die andere Richtung zurück zum Ausgangswert, oder gehen direkt in die falsche Richtung.
Wenn ich die ganz langsam und vorsichtig bewege, geht´s. Qualitätsunterschiede haben meine Encoder scheinbar auch noch: ein Encoder läuft tadellos, egal wie schnell der gedreht wird.

Ich bin jetzt für die Encoder zu meinem ursprüglichen Code zurück und hab auch da switch/case einfügt. Allerdings kommen da wieder falsche Macros raus.

Was hab ich falsch gemacht?

#include <Keypad.h>
#include <Keyboard.h>


#define ENABLE_PULLUPS
#define NUMROTARIES 4
#define NUMBUTTONS 20
#define NUMROWS 4
#define NUMCOLS 5


char buttons[NUMROWS][NUMCOLS] = {
  {'1','2','3','4','5'},
  {'6','7','8','9','0'},
  {'a','b','c','d','e'},
  {'f','g','h','i','j'},
};



struct rotariesdef {
  byte pin1;
  byte pin2;
  int ccwchar;
  int cwchar;
  volatile unsigned char state;
};

rotariesdef rotaries[NUMROTARIES] {
  {0,1,'n','m',0},
  {2,3,'o','p',0},
  {4,5,'q','r',0},
  {6,7,'s','t',0},
};



#define DIR_CCW 0x10
#define DIR_CW 0x20

#define R_START 0x0
#define R_CW_FINAL 0x1
#define R_CW_BEGIN 0x2
#define R_CW_NEXT 0x3
#define R_CCW_BEGIN 0x4
#define R_CCW_FINAL 0x5
#define R_CCW_NEXT 0x6

const unsigned char ttable[7][4] = {
  // R_START
  {R_START,    R_CW_BEGIN,  R_CCW_BEGIN, R_START},
  // R_CW_FINAL
  {R_CW_NEXT,  R_START,     R_CW_FINAL,  R_START | DIR_CW},
  // R_CW_BEGIN
  {R_CW_NEXT,  R_CW_BEGIN,  R_START,     R_START},
  // R_CW_NEXT
  {R_CW_NEXT,  R_CW_BEGIN,  R_CW_FINAL,  R_START},
  // R_CCW_BEGIN
  {R_CCW_NEXT, R_START,     R_CCW_BEGIN, R_START},
  // R_CCW_FINAL
  {R_CCW_NEXT, R_CCW_FINAL, R_START,     R_START | DIR_CCW},
  // R_CCW_NEXT
  {R_CCW_NEXT, R_CCW_FINAL, R_CCW_BEGIN, R_START},
};


byte rowPins[NUMROWS] = {21,20,19,18}; 
byte colPins[NUMCOLS] = {15,14,16,10,9}; 


Keypad buttbx = Keypad( makeKeymap(buttons), rowPins, colPins, NUMROWS, NUMCOLS); 



void setup() {
  Keyboard.begin();
  rotary_init();
}



void loop() { 

  CheckAllEncoders();

  CheckAllButtons();

}





void rotary_init() {
  for (int i=0;i<NUMROTARIES;i++) {
    pinMode(rotaries[i].pin1, INPUT);
    pinMode(rotaries[i].pin2, INPUT);
    #ifdef ENABLE_PULLUPS
      digitalWrite(rotaries[i].pin1, HIGH);
      digitalWrite(rotaries[i].pin2, HIGH);
    #endif
  }
}



unsigned char rotary_process(int _i) {
   unsigned char pinstate = (digitalRead(rotaries[_i].pin2) << 1) | digitalRead(rotaries[_i].pin1);
  rotaries[_i].state = ttable[rotaries[_i].state & 0xf][pinstate];
  return (rotaries[_i].state & 0x30);
}

void CheckAllEncoders(void) {
  for (int i=0;i<NUMROTARIES;i++) {
    unsigned char result = rotary_process(i);
    if (result) {
      Keyboard.write(result == DIR_CCW ? rotaries[i].ccwchar : rotaries[i].cwchar ); 
      {
        switch (NUMROTARIES)
         {
          case 'n':
          Keyboard.press(KEY_LEFT_SHIFT);          
          Keyboard.press('a');
          break;
          case 'm':
          Keyboard.press(KEY_LEFT_CTRL);          
          Keyboard.press('a');
          break;
          case 'o':
          Keyboard.press(KEY_LEFT_SHIFT);          
          Keyboard.press('b');
          break;
          case 'p':
          Keyboard.press(KEY_LEFT_CTRL);          
          Keyboard.press('b');
          break;
          case 'q':
          Keyboard.press(KEY_LEFT_SHIFT);          
          Keyboard.press('e');
          break;
          case 'r':
          Keyboard.press(KEY_LEFT_CTRL);          
          Keyboard.press('e');
          break;
          case 's':
          Keyboard.press(KEY_LEFT_SHIFT);          
          Keyboard.press('t');
          break;
          case 't':
          Keyboard.press(KEY_LEFT_CTRL);          
          Keyboard.press('t');
          break;



         }
          delay(100);
          Keyboard.releaseAll();
      }
    }
  }
}

void CheckAllButtons(void) {
  char key = buttbx.getKey();
  if (key != NO_KEY) 
  
   {
    switch (key)
    {
      case '1':
       Keyboard.press('l');
       break;
      case '2':
       Keyboard.press(KEY_LEFT_CTRL);
       Keyboard.press('l');
       break;
      case '3':
       Keyboard.press(KEY_LEFT_ALT);
       Keyboard.press('r');
       break;
      case '4':
       Keyboard.press('s');
       delay(1000);
       break;
      case '5':
       Keyboard.press(KEY_LEFT_SHIFT);
       Keyboard.press('i');
       break; 
      case '6':
       Keyboard.press(KEY_INSERT);
       break; 
      case '7':
       Keyboard.press(KEY_LEFT_ARROW);
       break; 
      case '8':
       Keyboard.press(KEY_RIGHT_ARROW);
       break;  
      case '9':
       Keyboard.press(KEY_UP_ARROW);
       break;  
      case '0':
       Keyboard.press(KEY_DOWN_ARROW);
       break;                                        
      case 'a':
       Keyboard.press(KEY_LEFT_ALT);
       Keyboard.press('d');
       break; 
      case 'b':
       Keyboard.press(KEY_LEFT_SHIFT);
       Keyboard.press('d');
       break;  
      case 'c':
       Keyboard.press(KEY_F1);
       break;                       

      case 'f':
       Keyboard.press(KEY_LEFT_ALT);
       Keyboard.press('l');
       break; 
      case 'g':
       Keyboard.press(KEY_LEFT_CTRL);
       Keyboard.press('d');
       break; 
      case 'h':
       Keyboard.press(KEY_F2);
       break;         

       }
    delay(100);
    Keyboard.releaseAll();
  }
}

Las es so, wie es ist. Das ist gut so.
Aus den #defines solltest Du const machen.

Bei der letzten Version (und der ersten) funktionieren die Encoder viel besser. Mit dem einfachen Code sind die Encoder leider nicht für mein Spiel zugebrauchen.

Ich hab grade noch einmal getestet und hab fest gestellt, daß der Encoder 'n' und 'm' ausgibt. Die Zeilen mit switch (NUMROTARIES) und den Macros sind also wirkungslos.

Wie und wo muß ich diesen Switch einfügen, damit 'n' zu meinem Marco wird?

void CheckAllEncoders(void) {
  for (int i=0;i<NUMROTARIES;i++) {
    unsigned char result = rotary_process(i);
    if (result) {
      Keyboard.write(result == DIR_CCW ? rotaries[i].ccwchar : rotaries[i].cwchar ); 
      {
        switch (NUMROTARIES)
         {
          case 'n':
          Keyboard.press(KEY_LEFT_SHIFT);          
          Keyboard.press('a');
          break;
          case 'm':
          Keyboard.press(KEY_LEFT_CTRL);          
          Keyboard.press('a');
          break;
          case 'o':
          Keyboard.press(KEY_LEFT_SHIFT);          
          Keyboard.press('b');
          break;
          case 'p':
          Keyboard.press(KEY_LEFT_CTRL);          
          Keyboard.press('b');
          break;
          case 'q':
          Keyboard.press(KEY_LEFT_SHIFT);          
          Keyboard.press('e');
          break;
          case 'r':
          Keyboard.press(KEY_LEFT_CTRL);          
          Keyboard.press('e');
          break;
          case 's':
          Keyboard.press(KEY_LEFT_SHIFT);          
          Keyboard.press('t');
          break;
          case 't':
          Keyboard.press(KEY_LEFT_CTRL);          
          Keyboard.press('t');
          break;
         }
          delay(100);
          Keyboard.releaseAll();
      }
    }
  }
}

'n' und 'm' kommen wohl aus dem Keyboard.write().

ist ein #define (oder inzwischen eine Konstante).
Da steht also

switch (4)
{
...

Es ist dann nicht verwunderlich, dass da nix bei rauskommt. Wenn Du noch einen default:-Zweig einfügst wirst Du den oft immer sehen.

Ob es das ist was Du willst?

'n' und 'm' kommen aus rotariesdef (siehe Post#11)
Die möchte ich, so wie ich das bei den Tastern gemacht habe, umwandeln in Shift+a

Wenn ich im rotariesdef 'n' zu KEY_LEFT_SHIFT + 'a' ändere, wird eine NumPadTaste gedrückt. Das geht also nicht. Deshalb der Versuch das nach dem Loop mit switch und case 'n' zu ändern. Ist das nicht mit irgendeinem Befehl möglich aus einem 'n' ein KEY_LEFT_SHIFT + 'a' zu machen?

in Post#9 hab ich die Encoder komplett anders geschrieben. Da kommt das gewüschte Macro raus, aber die Encoder sind nicht debounched und das Programm gibt keine vernüftigen Werte raus. Also unbrauchbar für mich.

Final working code:

#include <Keypad.h>
#include <Keyboard.h>
#include <Encoder.h>



#define ENABLE_PULLUPS
#define NUMBUTTONS 20
#define NUMROWS 4
#define NUMCOLS 5

char buttons[NUMROWS][NUMCOLS] = {
  {'1','2','3','4','5'},
  {'6','7','8','9','0'},
  {'a','b','c','d','e'},
  {'f','g','h','i','j'},
};

byte rowPins[NUMROWS] = {21,20,19,18}; 
byte colPins[NUMCOLS] = {15,14,16,10,9}; 

Keypad buttbx = Keypad( makeKeymap(buttons), rowPins, colPins, NUMROWS, NUMCOLS); 



Encoder RotaryEncoderA(0, 1);
Encoder RotaryEncoderB(2, 3);
Encoder RotaryEncoderC(4, 5);
Encoder RotaryEncoderD(6, 7);

long positionEncoderA  = -999;
long positionEncoderB  = -999;
long positionEncoderC  = -999;
long positionEncoderD  = -999;


void setup() {
  Keyboard.begin();
  Serial.begin(9600);
}



void loop() { 
  encoderA();
  encoderB();
  encoderC();
  encoderD();

  CheckAllButtons();

}



void CheckAllButtons(void) {
  char key = buttbx.getKey();
  if (key != NO_KEY) 
  
   {
    switch (key)
    {
      case '1':
       Keyboard.press('l');
       break;
      case '2':
       Keyboard.press(KEY_LEFT_CTRL);
       Keyboard.press('l');
       break;
      case '3':
       Keyboard.press(KEY_LEFT_ALT);
       Keyboard.press('r');
       break;
      case '4':
       Keyboard.press('s');
       break;
      case '5':
       Keyboard.press(KEY_LEFT_SHIFT);
       Keyboard.press('i');
       break; 
      case '6':
       Keyboard.press(KEY_INSERT);
       break; 
      case '7':
       Keyboard.press(KEY_LEFT_ARROW);
       break; 
      case '8':
       Keyboard.press(KEY_RIGHT_ARROW);
       break;  
      case '9':
       Keyboard.press(KEY_UP_ARROW);
       break;  
      case '0':
       Keyboard.press(KEY_DOWN_ARROW);
       break;                                        
      case 'a':
       Keyboard.press(KEY_LEFT_ALT);
       Keyboard.press('l');
       break; 
      case 'b':
       Keyboard.press(KEY_LEFT_SHIFT);
       Keyboard.press('d');
       break;  
      case 'c':
       Keyboard.press(KEY_F1);
       break;                       

      case 'f':
       Keyboard.press(KEY_LEFT_ALT);
       Keyboard.press('d');
       break; 
      case 'g':
       Keyboard.press(KEY_LEFT_CTRL);
       Keyboard.press('d');
       break; 
      case 'h':
       Keyboard.press(KEY_F2);
       break;         

       }
    delay(150);
    Keyboard.releaseAll();
  }
}


void encoderA(){
  long newPos = RotaryEncoderA.read()/4;
  if (newPos != positionEncoderA && newPos > positionEncoderA) {
    positionEncoderA = newPos;
    Keyboard.press(KEY_LEFT_SHIFT);
    Keyboard.press('a');
    delay(150);   
    Keyboard.release(KEY_LEFT_SHIFT);
    Keyboard.release('a');                           }

  if (newPos != positionEncoderA && newPos < positionEncoderA) {
    positionEncoderA = newPos;
    Keyboard.press(KEY_LEFT_CTRL);
    Keyboard.press('a');
    delay(150);   
    Keyboard.release(KEY_LEFT_CTRL);
    Keyboard.release('a');                   }
}

void encoderB(){
  long newPos = RotaryEncoderB.read()/4;
  if (newPos != positionEncoderB && newPos > positionEncoderB) {
    positionEncoderB = newPos;
    Keyboard.press(KEY_LEFT_SHIFT);
    Keyboard.press('b');
    delay(150);   
    Keyboard.release(KEY_LEFT_SHIFT);
    Keyboard.release('b');                           }

  if (newPos != positionEncoderB && newPos < positionEncoderB) {
    positionEncoderB = newPos;
    Keyboard.press(KEY_LEFT_CTRL);
    Keyboard.press('b');
    delay(150);   
    Keyboard.release(KEY_LEFT_CTRL);
    Keyboard.release('b');                   }
}

void encoderC(){
  long newPos = RotaryEncoderC.read()/4;
  if (newPos != positionEncoderC && newPos > positionEncoderC) {
    positionEncoderC = newPos;
    Keyboard.press(KEY_LEFT_SHIFT);
    Keyboard.press('e');
    delay(150);   
    Keyboard.release(KEY_LEFT_SHIFT);
    Keyboard.release('e');                           }

  if (newPos != positionEncoderC && newPos < positionEncoderC) {
    positionEncoderC = newPos;
    Keyboard.press(KEY_LEFT_CTRL);
    Keyboard.press('e');
    delay(150);   
    Keyboard.release(KEY_LEFT_CTRL);
    Keyboard.release('e');                   }
}

void encoderD(){
  long newPos = RotaryEncoderD.read()/4;
  if (newPos != positionEncoderD && newPos > positionEncoderD) {
    positionEncoderD = newPos;
    Keyboard.press(KEY_LEFT_SHIFT);
    Keyboard.press('t');
    delay(150);   
    Keyboard.release(KEY_LEFT_SHIFT);
    Keyboard.release('t');                           }

  if (newPos != positionEncoderD && newPos < positionEncoderD) {
    positionEncoderD = newPos;
    Keyboard.press(KEY_LEFT_CTRL);
    Keyboard.press('t');
    delay(150);   
    Keyboard.release(KEY_LEFT_CTRL);
    Keyboard.release('t');                   }
}

Danke für die Rückmeldung!

Anregung:
Es ist weniger schön, den im Wesentlichen gleichen Code für die Encoder viermal hinzuschreiben.

angepasster Code

Mangels Hardware nur kompiliert, nicht getestet!

#include <Keypad.h>
#include <Keyboard.h>
#include <Encoder.h>



#define ENABLE_PULLUPS
#define NUMBUTTONS 20
#define NUMROWS 4
#define NUMCOLS 5

char buttons[NUMROWS][NUMCOLS] = {
  {'1','2','3','4','5'},
  {'6','7','8','9','0'},
  {'a','b','c','d','e'},
  {'f','g','h','i','j'},
};

byte rowPins[NUMROWS] = {21,20,19,18}; 
byte colPins[NUMCOLS] = {15,14,16,10,9}; 

Keypad buttbx = Keypad( makeKeymap(buttons), rowPins, colPins, NUMROWS, NUMCOLS); 


Encoder RotaryEncoderA(0, 1);
Encoder RotaryEncoderB(2, 3);
Encoder RotaryEncoderC(4, 5);
Encoder RotaryEncoderD(6, 7);

struct EncoderInfo {
  Encoder enc;
  long position;
  byte key;
};

constexpr byte NUM_ENC {4};
EncoderInfo encoders[NUM_ENC] = {
  { RotaryEncoderA, -999, 'a'},
  { RotaryEncoderB, -999, 'b'},
  { RotaryEncoderC, -999, 'e'},
  { RotaryEncoderD, -999, 't'}
};




void setup() {
  Keyboard.begin();
  Serial.begin(9600);
}



void loop() { 
  for (byte i = 0; i < NUM_ENC; i++)
    runEncoder(encoders[i]);

  CheckAllButtons();

}



void CheckAllButtons(void) {
  char key = buttbx.getKey();
  if (key != NO_KEY) 
  
   {
    switch (key)
    {
      case '1':
       Keyboard.press('l');
       break;
      case '2':
       Keyboard.press(KEY_LEFT_CTRL);
       Keyboard.press('l');
       break;
      case '3':
       Keyboard.press(KEY_LEFT_ALT);
       Keyboard.press('r');
       break;
      case '4':
       Keyboard.press('s');
       break;
      case '5':
       Keyboard.press(KEY_LEFT_SHIFT);
       Keyboard.press('i');
       break; 
      case '6':
       Keyboard.press(KEY_INSERT);
       break; 
      case '7':
       Keyboard.press(KEY_LEFT_ARROW);
       break; 
      case '8':
       Keyboard.press(KEY_RIGHT_ARROW);
       break;  
      case '9':
       Keyboard.press(KEY_UP_ARROW);
       break;  
      case '0':
       Keyboard.press(KEY_DOWN_ARROW);
       break;                                        
      case 'a':
       Keyboard.press(KEY_LEFT_ALT);
       Keyboard.press('l');
       break; 
      case 'b':
       Keyboard.press(KEY_LEFT_SHIFT);
       Keyboard.press('d');
       break;  
      case 'c':
       Keyboard.press(KEY_F1);
       break;                       

      case 'f':
       Keyboard.press(KEY_LEFT_ALT);
       Keyboard.press('d');
       break; 
      case 'g':
       Keyboard.press(KEY_LEFT_CTRL);
       Keyboard.press('d');
       break; 
      case 'h':
       Keyboard.press(KEY_F2);
       break;         

       }
    delay(150);
    Keyboard.releaseAll();
  }
}


void runEncoder(EncoderInfo encoder) {
  long newPos = encoder.enc.read()/4;
  if (newPos != encoder.position && newPos > encoder.position) {
    encoder.position = newPos;
    Keyboard.press(KEY_LEFT_SHIFT);
    Keyboard.press(encoder.key);
    delay(150);   
    Keyboard.release(KEY_LEFT_SHIFT);
    Keyboard.release(encoder.key);                           }

  if (newPos != encoder.position && newPos < encoder.position) {
    encoder.position = newPos;
    Keyboard.press(KEY_LEFT_CTRL);
    Keyboard.press(encoder.key);
    delay(150);   
    Keyboard.release(KEY_LEFT_CTRL);
    Keyboard.release(encoder.key);                   }
}