Korrekte Abfrage der Spezialtasten

Einleitung und Motivation

In vielen Programmen treffe ich immer wieder folgende, wie Sie auch noch erkennen werden, effektiv falsch programmierten Tastaturabfrageschleifen:

' So besser nicht!

SCREEN 0: WIDTH 40, 25: CLS
x% = 20
y%= 13

DO
  LOCATE y%, x%
  PRINT "*";
  DO
    t$ = INKEY$
  LOOP WHILE t$ = ""
  LOCATE y%, x%
  PRINT " ";

  ' hier wird etwas ganz FATALES gemacht!
  IF LEN(t$) = 2 THEN
    t$ = RIGHT$(t$, 1)
  END IF

  SELECT CASE t$
  CASE "H"    ' Pfeil oben
    IF y% > 1 THEN
      y% = y% - 1
    ELSE
      BEEP
    END IF
  CASE "P"   ' Pfeil unten
    IF y% < 25 THEN
      y% = y% + 1
    ELSE
      BEEP
    END IF
  CASE "K"    ' Pfeil links
    IF x% > 1 THEN
      x% = x% - 1
    ELSE
      BEEP
    END IF
  CASE "M"    ' Pfeil rechts
    IF y% < 40 THEN
      x% = x% + 1
    ELSE
      BEEP
    END IF
  CASE CHR$(27)         ' Esc-Taste
    ' Verlassen => nichts tun!
  CASE ELSE             ' übrige Tasten
    BEEP
  END SELECT
LOOP UNTIL t$ = CHR$(27)

Um den Fehler genau zu verstehen, kommt eine kleine Zusatzaufgabe: Versuchen Sie das obige Programm um eine Funktion »Pause« zu ergänzen, welche mit Umschalt+P, also dem grossen P aufgerufen werden soll! Ausserdem fällt Ihnen auch auf, dass man bei dieser Variante bei aktiviertem Caps Lock den Stern auch mit H, K, M und P steuern kann, was in diesem Fall sicherlich nicht erwünscht wird (spezieller Seiteneffekt). Sie sehen nun hoffentlich selber, dass Sie mit diesem RIGHT$ in der Programmitte den von QuickBASIC eindeutigen Tastencode zerstören. Und genau dies sollten Sie nicht tun!

' So macht man es richtig!

SCREEN 0: WIDTH 40, 25: CLS
x% = 20
y%= 13

DO
  LOCATE y%, x%
  PRINT "*";
  DO
    t$ = INKEY$
  LOOP WHILE t$ = ""
  LOCATE y%, x%
  PRINT " ";

  SELECT t$
  CASE CHR$(0) + "H"    ' Pfeil hoch
    IF y% > 1 THEN
      y% = y% - 1
    ELSE
      BEEP
    END IF
  CASE CHR$(0) + "P"    ' Pfeil unten
    IF y% < 25 THEN
      y% = y% + 1
    ELSE
      BEEP
    END IF
  CASE CHR$(0) + "K"    ' Pfeil links
    IF x% > 1 THEN
      x% = x% - 1
    ELSE
      BEEP
    END IF
  CASE CHR$(0) + "M"    ' Pfeil rechts
    IF y% < 40 THEN
      x% = x% + 1
    ELSE
      BEEP
    END IF
  CASE CHR$(27)         ' Esc-Taste
    ' Beenden => nichts tun
  CASE ELSE             ' übrige Tasten
    BEEP
  END SELECT
LOOP WHILE Drinbleib%

Auf diesen Aspekt müssen Sie besonders sorgsam achten, wenn Sie einen Ersatz für LINE INPUT für Bildschirmmasken, wie unter Programmierung professioneller Bildschirmmasken beschrieben, erstellen möchten, da dort die regulären Zeichen (Buchstaben, Zahlen und Satzzeichen) sowie die Spezialtasten wie Pos1 und Ende usw. gleichzeitig abgefragt werden müssen.

Auswertung via ASCII-Code

Viele QuickBASIC-Programmierer begehen den anfänglich beschriebenen Fehler dadurch, weil sie den Tastencode als Zahl auswerten möchten:

' So nicht!
DO
  t$ = INKEY$
LOOP WHILE t$ = ""

taste% = ASC(RIGHT$(t$, 1))  ' Ganz FATAL falsch!

SELECT CASE taste%
CASE 72 ' Pfeil hoch
  ' ..
CASE 75 ' Pfeil links
  ' ..
' ..
END SELECT

Die Auswertung mittels ASCII-Wert kann man wie folgt lösen:

' So ist es richtig!
DO
  t$ = INKEY$
LOOP WHILE t$ = ""

IF LEN(t$) = 2
  taste% = ASC(RIGHT$(t$, 1)) OR 256
ELSE
  taste% = ASC(t$)
END IF

' das normale Umschalt+P hat jetzt 72
SELECT CASE taste%
CASE 328 ' Pfeil hoch
  ' ..
CASE 331 ' Pfeil links
  ' ..
' ..
END SELECT

Anmerkungen für C-, Turbo-Pascal- und Assemblerprogrammierer

Bei den dortigen Sprachen lesen Sie bekanntlich aus conio.h mit getch() üblicherweise nur ein einzelnes Byte ein:

int lies_taste(void) {
  int code;
  if (kbhit()) {
    code = getch();
    if(code == 0)   /* Spezialtaste */
      code = 256 | getch();
  } else
    code = -1;
  return code;
}

Genau auf demselben Prinzip arbeitet auch INKEY$ sowie das letzte BASIC-Beispiel.


Wieder zurück zur Übersicht


© 2000 by Andreas Meile