So, ich habe jetzt einen funktionierende Programmcode

Gratulation!
Jetzt mit Struktur und mit Funktion!
Einige kleine Anmerkungen zu Deinem Code noch:
RAM-Speicher sparen:
Nachdem Du mit den vier Tasten keine fünf Modifier-Zustände abfragst (kein Modifier, oder eine der vier Modifier-Tasten) sondern nur vier (immer die zuletzt betätigte Modifier-Taste) reicht es natürlich, die charTable kleiner zu definieren, das "+1" im ersten Index wird nicht mehr benötigt:
char charTable[MODIFIERBUTTONS][CHARBUTTONS]
Schleifenzähler:
Bei hochzählenden Schleifen schreiben C-Programmierer die Schleifenbedingung üblicherweise mit "<" und dann steht dahinter genau die Zahl, wie oft die Schleife ausgeführt wird.
Statt:
for(int i = 0 ; i <=11 ; i++) ==> wird 12 mal ausgeführt, aber die 12 steht nicht da
Üblicher Programmierstandard:
for(int i = 0 ; i <12 ; i++) ==> Schleife wird 12 mal ausgeführt, und die Zahl 12 steht da
Nochmal der Schleifenzähler:
Mit define-Statements sind im Programm die Anzahl der Tasten festgelegt worden:
#define CHARBUTTONS 12
#define MODIFIERBUTTONS 4
Üblicherweise codet man dann überall wo im Programm auf die 12 CHARBUTTONS und die 4 MODIFIERBUTTONS Bezug genommen wird, zum Beispiel in Zählschleifen, nicht durch erneute Angabe der Zahl, sondern durch Angabe des definierten Platzhalters:
Statt:
for(int i = 0 ; i <12 ; i++)
Besser
for(int i = 0 ; i <CHARBUTTONS ; i++)
Und statt:
for(int i = 0 ; i < 4 ; i++)
Besser:
for(int i = 0 ; i < MODIFIERBUTTONS ; i++)
Das mag auf den ersten Blick nur zu einem mehr "sprechenden Code" führen, der auch ohne großartige Kommentierung selbsterklärend ist, wieso und weshalb irgendwo eine Konstante steht.
Aber es hat auch große Vorteile, wenn der Code irgendwann später einmal geändert werden soll, sagen wir mal angenommen: Irgenwann möchtest Du ein genau solches Programm machen, aber es soll dann für 15 CHARBUTTONS und 3 MODIFIERBUTTONS sein. Dann wäre es von großem Vorteil, wenn Du praktisch nur oben die Werte in den #define Statements ändern mußt, und automatisch sind auch alle Schleifenendbedingungen und so weiter ebenfalls auf die neuen Werte angepaßt.
Kommentare:
In Programme, die länger als eine Bildschirmseite sind, dürfen auch gerne einige Kommentarzeilen eingefügt werden, die erklären, was der Code macht. Insbesondere bei komplexen Programmen und Funktionen ist es hilfreich, wenn Kommentare vorhanden sind, falls man den Code später noch einmal zur Hand nimmt und nachvollziehen möchte, was man da ehemals programmiert hat.
Aber das fällt natürlich unter ein "Schönheit der Arbeit" Programm und ist für das Funktionieren nicht entscheidend.
Na dann noch viel Erfolg mit Deinem Projekt!