Autor Thema: kprintf char ausgeben  (Gelesen 6403 mal)

Savatage

  • Beiträge: 28
    • Profil anzeigen
Gespeichert
« am: 28. April 2016, 10:04 »
Hallo Team,

dank des tollen Forums, des Wikis und des Tutorials habe ich es nun fast geschafft einen Tastaturtreiber zu schreiben. D.h:
- kprintf zum Zeichen ausgeben
- Interrupts funktionieren wie sie sollen
- Meine Tastatur ist initialisiert
- die Keycodes kann ich auf dem Bildschirm ausgeben

Natürlich möchte ich jetzt nicht die Keycodes ausgeben sondern die tatsächlichen Zeichen. Dafür muss meine kprintf-Funktion %c unterstützen. An der Stelle scheitere ich nun und hoffe auf die Community =)
Meine aktuelle kprintf entspricht dem Tutorium. Ich habe auch schon im Code von týndur gespickt und bin da doch etwas überfordert.

Gruß
Sava

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #1 am: 28. April 2016, 10:27 »
Im Prinzip ist alles, was du brauchst, ein großes Array, das dir die Scancodes auf ASCII-Zeichen mappt:

static const char sc_to_char[0x7f] = {
  0, 27 /* Escape */, '1', '2', '3', ...
};

Und dann nochmal ein zweites Array für wenn Shift gedrückt ist.

Ach so, und die Umwandlung gehört natürlich nicht ins kprintf(), das einfach das ASCII-Zeichen ausgibt (machst du ja für Strings auch schon), sondern in deine Eingabefunktion.
« Letzte Änderung: 28. April 2016, 10:28 von kevin »
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

Savatage

  • Beiträge: 28
    • Profil anzeigen
Gespeichert
« Antwort #2 am: 28. April 2016, 10:56 »
Hallo danke für die schnelle Antwort!

Im Prinzip ist alles, was du brauchst, ein großes Array, das dir die Scancodes auf ASCII-Zeichen mappt:

static const char sc_to_char[0x7f] = {
  0, 27 /* Escape */, '1', '2', '3', ...
};

Und dann nochmal ein zweites Array für wenn Shift gedrückt ist.
Die zwei Array habe ich schon (bzw. erst mal das eine - ohne shift, zum testen)

Ach so, und die Umwandlung gehört natürlich nicht ins kprintf(), das einfach das ASCII-Zeichen ausgibt (machst du ja für Strings auch schon), sondern in deine Eingabefunktion.
da hängt es jetzt noch ein wenig.
ich rufe das ganze auf mit:
char zeichen = kc2c(int keycode);
kprintf("%c", zeichen);

kc2c(int keycode) greift auf die Array zu, die die keycodes mappen. soweit so klar. Mein kprintf funktioniert z.B. mit kprintf("test"); Das meinst du mit "machst du ja für Strings schon", oder? Irgendwie muss ich meinem kprintf doch aber %c beibringen. Und was meinst du mit Eingabefunktion?

was bedeutet eigentlich das [0x7f]?
« Letzte Änderung: 28. April 2016, 12:09 von kevin »

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #3 am: 28. April 2016, 12:08 »
kc2c(int keycode) greift auf die Array zu, die die keycodes mappen. soweit so klar. Mein kprintf funktioniert z.B. mit kprintf("test"); Das meinst du mit "machst du ja für Strings schon", oder? Irgendwie muss ich meinem kprintf doch aber %c beibringen.
Okay, dein Ansatz sieht gut aus. Ich glaube, ich habe missverstanden, an welcher Stelle genau dein Problem liegt.:)

Du hast bisher wahrscheinlich gar keine Formatstring-Funktionalität in deinem kprintf(). Du hast aber sicher schon eine Schleife, die über die einzelnen Zeichen des Strings geht und sie dann ausgibt. An sich musst du nur hier prüfen, ob das Zeichen ein '%' ist und falls ja, statt das Prozentzeichen auszugeben, abhängig vom nächsten Zeichen irgendetwas anderes machen. Bei '%c' wäre das, dass du dir mit va_arg(ap, int) den nächten Parameter holst (schau dir Beispiele für die Verwendung von stdarg.h an, wenn du nicht weißt, wie Funktionen mit beliebig vielen Parametern gehen) und dann das Ergebnis als Zeichen ausgibst.

Zitat
was bedeutet eigentlich das [0x7f]?
Das ist die Arraylänge (und sie ist natürlich falsch, müsste eins mehr, also 0x80 sein). Ich bin davon ausgegangen, dass deine möglichen Keycodes von 0 bis 127 gehen, dass du also direkt die Scancodes nimmt und die Funktion nicht für Breakcodes aufrufst. Das stimmt natürlich auch nur am Anfang, weil es noch die erweiterten Scancodes gibt, die aus mehreren Bytes bestehen.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

Savatage

  • Beiträge: 28
    • Profil anzeigen
Gespeichert
« Antwort #4 am: 28. April 2016, 14:04 »
Ok alles klar. danke für die Erklärung. Ich melde mich wieder =)

Savatage

  • Beiträge: 28
    • Profil anzeigen
Gespeichert
« Antwort #5 am: 06. May 2016, 19:25 »
So, nun habe ich mich ja ewig nicht gemeldet, und dabei waren das nur 2 Zeilen Code und 5 Minuten Zeit. Falls das noch mal jemand braucht, das ist die Lösung:

case 'c':
    n = va_arg(ap, int);
    kputc(n);
    break;

Funktioniert soweit super. Allerdings komme ich gleich zur nächsten Frage:
Ich möchte gern Umlaute ausgeben. In meinem keymap array stehen dazu die Umlaute ganz normal als chars drin (Bsp.: 'ö').  Ich erhalte beim compilieren Warnungen wegen der Umlaute und Sonderzeichen:

warning: multi-character character constant [-Wmultichar]
warning: overflow in implicit constant conversion [-Woverflow]

Ich verstehe die Warnungen, aber ich kann sie nicht auf mein Problem übertragen.
Wenn ich dann einen Umlaut eingeben möchte gibt er mir kryptische Zeichen aus.

Ich weiß gar nicht ob mein Kernel schon Umlaute kann oder ob das nur ein Darstellungsproblem ist.

Gruß
Sava



kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #6 am: 06. May 2016, 22:36 »
Dein Editor wird die Umlaute vermutlich als UTF-8 abspeichern, deswegen sind das mehrere Bytes und ungültig für einen char, der nur ein einziges Byte speichern kann.

Der Zeichensatz, den die Grafikkarte für den Textmodus benutzt, wenn du nichts umgestellt hast, ist Codepage 437. Entweder du weist deinen Editor an, die Datei in diesem Zeichensatz zu speichern, oder du benutzt Escapesequenzen wie \x84 für ä, oder du baust in deinen Kernel UTF-8-Unterstützung ein, d.h. du wandelst deine UTF-8-Strings zur Laufzeit in CP-437 um. Letzteres ist wahrscheinlich das schönste, weil du dein OS dann nicht später komplett von einem beschränkten Zeichensatz auf Unicode umstellen musst, aber natürlich auch das komplizierteste.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

Savatage

  • Beiträge: 28
    • Profil anzeigen
Gespeichert
« Antwort #7 am: 07. May 2016, 11:13 »
Danke für die Antwort. Ich denke ich werde erstmal die Escapesequenzen benutzen und wenn der Tastaturtreiber fertig ist (der Rest ist ja nur noch Fleißarbeit) schau ich mal wie ich die UTF8-Unterstützung in den Kernel einbaue.

besten Dank nochmal!
(selten ein so hilfsbereites und kompetentes Forum gesehen)

Savatage

  • Beiträge: 28
    • Profil anzeigen
Gespeichert
« Antwort #8 am: 11. May 2016, 11:09 »
So ich bin jetzt an der Umsetzung der Übersetzung von UTF8 in CP437.
Vom Ablauf habe ich mir das so gedacht:
Array mit keycodes -> Array mit UTF-8 Eingaben -> Array mit CP437 (wobei der Pfeil fürs mappen stehen soll)
Erst die CP437 gehen an meine kprintf, die ja dann tatsächlich "malt"
In meinem CP437 Array hätte ich dann nur noch die Hex Werte.

Dann habe ich noch eine Frage zu den Funktionstasten. Enter, Tab und Return (\n, \t, \r) umzusetzen habe ich hinbekommen. Wie mache ich das jetzt bei Tasten die nicht so eine Escapesequenz haben? Bspw.: Pfeiltasten, Pos1 usw.
Theoretisch kann ich mir ja hier was ausdenken allerdings ist dass nicht wirklich schön und zieht viel Dokumentation nach sich. Ab gesehen davon wirft der Compiler Warnings dass er die Escapesequenzen nicht kennt oder diese anders belegt sind (Bsp: \x für hex). Gibt es für sowas einen Standard oder bastelt man sich da tatsächlich irgendwas zusammen?

Gruß
Sava

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #9 am: 11. May 2016, 11:19 »
Am sinnvollsten wäre es, für solche Tasten ein Interface bereitzustellen, das Keycodes benutzt und nicht ASCII- oder Unicode-Zeichen. In der Praxis gibt es das letztere aber trotzdem und ist sogar ziemlich verbreitet. Unter Linux bekommst du Escapesequenzen, eingeleitet von \033 (auch als ^[ dargestellt). Wenn du mal auf der Konsole einfach "cat" machst und dann die Tasten drückst, kommen die auch genau so raus. Pfeil hoch produziert z.B. "^[[A". Unter DOS kamen dabei Zwei-Byte-Codes heraus, wobei das erste Byte \0 war. Für beides müsstest du im Internet komplette Tabellen finden, wenn du eins davon nachbauen willst.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

Savatage

  • Beiträge: 28
    • Profil anzeigen
Gespeichert
« Antwort #10 am: 11. May 2016, 11:30 »
Da du bei deiner Antwort nicht weiter auf die Übersetzung von UTF8 auf CP437 eingegangen bist, gehe ich davon aus, dass ich das so Umsetzen kann?

Zitat
Am sinnvollsten wäre es, für solche Tasten ein Interface bereitzustellen, das Keycodes benutzt
Tatsächliche habe ich sowas schon versucht. Ich habe also für Pos1 den dazu gehörigen Keycode (71) an meine Ausgabe gesendet und dann entsprechend abgefragt. Bei Pos1 hat das auch gut funktioniert. Für die Pfeiltasten (72,75,77,80) hat dies nicht mehr geklappt. Ich kann mir nicht erklären was schief gegangen ist, aber meine Cursorposition wurde seltsam verschoben. Wenn dies aber eine Lösung dafür ist, denke ich mich da noch mal rein.

danke!

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #11 am: 11. May 2016, 11:59 »
Da du bei deiner Antwort nicht weiter auf die Übersetzung von UTF8 auf CP437 eingegangen bist, gehe ich davon aus, dass ich das so Umsetzen kann?
Hups, ganz vergessen.

Ich würde kprintf() (und vor allem die für den Userspace sichtbaren Terminals) UTF-8 nehmen lassen und erst den Konsolentreiber, der dann tatsächlich in den Videospeicher schreibt, die Umwandlung in CP-437 machen lassen. Das kann grob auf derselben Ebene passieren, wie man auch Escapesequenzen z.B. zum Cursor-Bewegen oder für farbige Ausgabe umsetzen würde.

Zitat
Tatsächliche habe ich sowas schon versucht. Ich habe also für Pos1 den dazu gehörigen Keycode (71) an meine Ausgabe gesendet und dann entsprechend abgefragt.
Was meinst du mit Ausgabe? Der Keycode ist doch eine Eingabe und keine Ausgabe?

Im Prinzip verlagerst du bei so einem Interface die Übersetzung von Keycode nach UTF-8 in das aufrufende Programm. Das Programm kann dann erstmal schauen, ob es eine Funktionstaste ist, mit der es irgendetwas anfangen kann, und wenn nicht, versucht es ein lesbares Zeichen daraus zu machen.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

Svenska

  • Beiträge: 1 778
    • Profil anzeigen
Gespeichert
« Antwort #12 am: 12. May 2016, 02:31 »
Array mit keycodes -> Array mit UTF-8 Eingaben -> Array mit CP437 (wobei der Pfeil fürs mappen stehen soll)
Das ist eine eher schlechte Idee, denn dann kannst du auch direkt Keycodes -> CP437 mappen und auf UTF-8 verzichten.

Wenn du UTF-8 Unterstützung einbauen willst, dann baue sie am besten so ein, dass alles intern mit UTF-8 arbeitet. Das heißt, dass dein Tastaturtreiber "Keycode -> UTF-8" wandelt und deine Konsole "UTF-8 -> CP437". Das heißt auch, dass alle API-Funktionen, die irgendwas mit Strings zu tun haben, UTF-8 nehmen - auch kprintf(). Du musst aber keinen vollständigen Unicode-Support anbieten.

Dann habe ich noch eine Frage zu den Funktionstasten. Enter, Tab und Return (\n, \t, \r) umzusetzen habe ich hinbekommen. Wie mache ich das jetzt bei Tasten die nicht so eine Escapesequenz haben?
Da gibt es mehrere Möglichkeiten:
(a) Du kannst die Tasten ignorieren und eine zusätzliche API anbieten, die mit Keycodes arbeitet. Das ist die beste Methode, wenn du an z.B. Multimedia-Tastaturen oder andere Eingabegeräte mit irgendwelchen Sondertasten denkst. Dafür hast du dann zwei Programmierschnittstellen.

(b) Alle diese Tasten haben ein Logo aufgedruckt, und dieses Logo gibt es auch als Unicode-Zeichen, z.B. U+2190 ist "Pfeil nach links". In UTF-8 wäre das dann die Bytesequenz 0xE2 0x86 0x90. Die kannst du nehmen.

(c) Unicode reserviert in der Basic Multilingual Plane (BMP) den Bereich U+E000 bis U+F8FF für "private Nutzung", d.h. dort wird nie ein Zeichen standardisiert werden. Du kannst allen Sondertasten ein Zeichen aus diesem Bereich zuweisen.

(d) Du kannst ein anderes Codeschema nutzen. Die Konsole unter Linux bildet grob ein ANSI-Terminal nach (bzw. ein Subset von VT102/VT220). Solche Terminals (Bildschirm, Tastatur und serielle Schnittstelle) wirst du allerdings kaum noch finden. Daher kommen die ANSI-Codes, die kevin beschrieben hat. Der Nachteil an ANSI-Codes ist, dass sie alle mit einem ESC-Zeichen beginnen und damit von einem Druck auf die ESC-Taste nicht ordentlich zu unterscheiden sind.

Bedenke, dass UTF-8 mehrere Bytes für ein Zeichen benutzen kann, was so Dinge wie "ein Zeichen rückwärts gehen" wesentlich komplizierter macht als ein z.B. single-byte Zeichensatz. Aus diesem Grund nutzt Windows intern durchgängig UTF-16, womit allerdings nur die BMP abgedeckt werden kann (das war Anfang der 90er noch kein Problem). Mit UTF-32 hast du damit keine Probleme, dafür brauchen normale ASCII-Texte viermal so viel Speicher.

Gruß,
Svenska

Savatage

  • Beiträge: 28
    • Profil anzeigen
Gespeichert
« Antwort #13 am: 12. May 2016, 08:26 »
Uff, das war erst mal viel Information.
Aber ich denke ich habe einen ganz guten Überblick wie's weiter geht (und noch viel zu tun ^^)

Zitat
Was meinst du mit Ausgabe? Der Keycode ist doch eine Eingabe und keine Ausgabe?
Der Keycode ist die Eingabe. Ich meinte dass ich den Keycode weiterreiche an meinen Konsolentreiber, der dann die tatsächliche Ausgabe auf den Bildschirm macht.

Danke, den Rest krieg ich hin.
Gruß
Sava

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #14 am: 12. May 2016, 09:12 »
Was ich meinte, ist dass nicht jede Ausgabe von der Tastatur kommt (der größte Teil sind feste Strings) und dass nicht jede Eingabe auf dem Bildschirm sichtbar werden soll (z.B. Passwörter). Von daher würde ich diese beiden Sachen getrennt betrachten und erst ein Programm, das sowohl Eingaben nimmt als auch Ausgaben macht, verbindet beides miteinander.

Wenn eine Ausgabefunktion Keycodes benutzt, klingt das irgendwie komisch. Wie sollte das denn aussehen? Ein kprintf(), das ein Array von Keycodes statt einem String als Parameter bekommt, nur Zeichen ausgeben kann, die auch auf der Tastatur sind, und Funktionstasten ignoriert?
« Letzte Änderung: 12. May 2016, 09:15 von kevin »
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

Savatage

  • Beiträge: 28
    • Profil anzeigen
Gespeichert
« Antwort #15 am: 12. May 2016, 09:38 »
Ich glaube wir reden an einander vorbei. Ich bin noch nicht so fit mit den Begriffen und werfe da bestimmt was durcheinander. Meine Eingabe ist von der Ausgabe getrennt.
Tatsächlich hat nicht meine Ausgabefunktion ( = kprintf) die Keycodes benutzt sondern mein Konsolentreiber ( macht die tatsächlichen Ausgaben auf dem Bildschirm).
Wobei ich gestehen muss, dass ich jetzt erst mal meinen Code besser strukturiert habe (und da sicher noch Optimierungsbedarf besteht).
Ich denke ich komm erst mal klar. Die Übersetzung von UTF-8 in CP437 steht auch schon, sodass mein Tastaturtreiber komplett mit UTF8 arbeitet und die Übersetzung erst im Konsolentreiber stattfindet.
Wenn ich noch ne Portion Mut finde lade ich das ganze Projekt mal irgendwo hoch und lass mir ein dickes Fell wachsen für die ganze Kritik ;)
danke!

 

Einloggen