[gelöst]Tastatureingaben variabel abfangen

Für Fragen von Einsteigern und Programmieranfängern...
Antworten
Marsmännchen
Beiträge: 294
Registriert: So 4. Mai 2014, 21:32
OS, Lazarus, FPC: Windows 10 64bit, Lazarus 2.0.10
CPU-Target: 64bit
Wohnort: Oranienburg

[gelöst]Tastatureingaben variabel abfangen

Beitrag von Marsmännchen »

Bevor ich mich totcode:

Ich habe mir ein kleines Tool gebastelt, mit dem ich a) ausprobiere, wie ich Tastatureingaben abfangen kann und b) mir eben diese Eingaben zur weiteren Verwendung ansehen kann. Folgender Code funktioniert:

Code: Alles auswählen

procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
var
  zeichen : String;
  VK_Code : String;
 
begin
  if Key = VK_BACK then
  begin
    zeichen := '#8';
    VK_Code := 'VK_Back';
  end;
  if Key = VK_RETURN then
  begin
    zeichen := '#13';
    VK_Code := 'VK_Return';
  end;
 
  AsciiLabel.Caption:=zeichen;
  VKLabel.Caption:=VK_Code;
end;
 
 
end.                             
Nur: Das kann's doch net sein, dass ich jetzt alle Tasten dem Prog händisch bekannt machen muss, oder? Ich hab schonmal mit Chr rumgespielt, doch da bekomme ich Meckermeldung wegen inkompatibler Typen. Durch Dokumentationen / Tutorials bin ich bisher nur soweit gekommen, wie der obige Code zeigt. Hat jemand einen Tipp für mich, wie ich das eleganter hinbekomme?
Zuletzt geändert von Marsmännchen am So 28. Feb 2016, 13:08, insgesamt 1-mal geändert.
Ich mag Pascal...

Benutzeravatar
theo
Beiträge: 10872
Registriert: Mo 11. Sep 2006, 19:01

Re: Tastatureingaben variabel abfangen

Beitrag von theo »

Den Key kannst du ja so ausgeben.

Code: Alles auswählen

Caption:=inttostr(Key);   
Aber ein Key ist kein Zeichen, sondern eine Taste.

Marsmännchen
Beiträge: 294
Registriert: So 4. Mai 2014, 21:32
OS, Lazarus, FPC: Windows 10 64bit, Lazarus 2.0.10
CPU-Target: 64bit
Wohnort: Oranienburg

Re: Tastatureingaben variabel abfangen

Beitrag von Marsmännchen »

... seufz... so simpel! Ich habe mal wieder viel zu kompliziert gedacht. Danke schön, das hilft mir weiter. Damit kann ich problemlos die Tastatureingaben auf einer Form abfangen und auswerten. Die VK-Konstanten behalte ich mal im Hinterkopf.
Ich mag Pascal...

Marsmännchen
Beiträge: 294
Registriert: So 4. Mai 2014, 21:32
OS, Lazarus, FPC: Windows 10 64bit, Lazarus 2.0.10
CPU-Target: 64bit
Wohnort: Oranienburg

Re: Tastatureingaben variabel abfangen

Beitrag von Marsmännchen »

Ich hatte dann doch noch einige Huddelei, weil KeyDown mir zwar einen Key liefert, den ich aber nicht so ohne weiteres in einen Char umwandeln kann. Da kam teilweise Quark raus (falsche Codes für Komma und auch für die NumBlockTasten). Erster Lösungsschritt war dann, dass ich stattdessen die UTF8KeyPress verwendet habe. Damit las er mir alle Zeichen wunderbar ein, jedoch... gab's dann Schwierigkeiten, den UTF8Char in einen normalen Char zu kriegen.
Ich hab dann einen Post von Theo im englischsprachigen Lazarusforum gefunden (http://forum.lazarus.freepascal.org/ind ... pic=9936.0) und daraus folgende Lösung gebastelt, die bei mir tadellos funktioniert:

Code: Alles auswählen

procedure TForm1.FormUTF8KeyPress(Sender: TObject; var UTF8Key: TUTF8Char);
var temp : WideString;
begin
  temp := UTF8Decode(UTF8Key);
  Rechner.EingabeAnfuegen(temp[1]);  // Die Funktion erwartet einen Char!
end;               
In der dortigen Diskussion hat Theo allerdings angemerkt, dass man bei dieser Umwandlei besser noch die Länge des Zwischenstrings testen sollte. Kann mir jemand sagen, warum und worauf man genau testen soll? Dass Length nicht gleich null sein darf? (Was ich vermute, ohne es zu verstehen).
Ich mag Pascal...

Michl
Beiträge: 2511
Registriert: Di 19. Jun 2012, 12:54

Re: Tastatureingaben variabel abfangen

Beitrag von Michl »

Kannst du etwas mehr erklären, was du vorhast? Es scheint mir keine gute Idee ein Char über den UTF8 kodierten String (was ein TUTF8Char ist) zu extrahieren (theo hatte in dem Beispiel auch ein WideChar und kein Char verwendet). Vermutlich wird das, was auch immer du vorhast, spätestens bei Umlauten (Multibytezeichen) nicht funktionieren.
Marsmännchen hat geschrieben:Kann mir jemand sagen, warum und worauf man genau testen soll? Dass Length nicht gleich null sein darf?
Weil man sonst mit temp[1] auf ein nicht vorhandenes Zeichen zugreift (es existiert kein String im Speicher).

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection;  

Benutzeravatar
theo
Beiträge: 10872
Registriert: Mo 11. Sep 2006, 19:01

Re: Tastatureingaben variabel abfangen

Beitrag von theo »

Doch das geht schon.
Die Bemerkung damals..

Code: Alles auswählen

St:=UTF8Decode(UTF8Key);
Key:=St[1]; //better check for length first.
war deshalb, weil ein WideString nicht den ganzen Unicode Range in einem WideChar darstellen kann. D.h. Es kann theoretisch auch ein "zweistelliger" WideString zurückkommen.

S.a. Surrogate : https://de.wikipedia.org/wiki/UTF-16

Ist aber für unsere normalen Zeichen irrelevant.

Michl
Beiträge: 2511
Registriert: Di 19. Jun 2012, 12:54

Re: Tastatureingaben variabel abfangen

Beitrag von Michl »

theo hat geschrieben:Doch das geht schon.
Evtl. verstehe ich dich falsch, doch wie du weißt, geht das nicht mit einem Char (wie vom Marsmännchen gewünscht).

z.B. schlägt das bei jedem Multibytechar fehl ("ä", "ö", "ü" usw.):

Code: Alles auswählen

procedure TForm1.FormUTF8KeyPress(Sender: TObject;
  var UTF8Key: TUTF8Char);
var
  temp : WideString;
begin
  temp := UTF8Decode(UTF8Key);
  test(temp[1]);
end;
 
procedure TForm1.Test(c: Char);
begin
  Caption := '[' + c + ']';
end; 

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection;  

Benutzeravatar
theo
Beiträge: 10872
Registriert: Mo 11. Sep 2006, 19:01

Re: Tastatureingaben variabel abfangen

Beitrag von theo »

Nö mit Char nicht, aber mit WideChar schon.

Marsmännchen
Beiträge: 294
Registriert: So 4. Mai 2014, 21:32
OS, Lazarus, FPC: Windows 10 64bit, Lazarus 2.0.10
CPU-Target: 64bit
Wohnort: Oranienburg

Re: Tastatureingaben variabel abfangen

Beitrag von Marsmännchen »

Michl hat geschrieben:Kannst du etwas mehr erklären, was du vorhast?
Naja, ich bastel an meinem Taschenrechner rum. Ich habe eine 'dumme' Form, die jegliche Eingaben an eine Rechnerklasse weiterreicht, wo dann diese Eingaben validiert und verarbeitet werden. Die Klasse stellt der Form dafür die Methode TRechner.EingabeAnfuegen(zeichen:char) zur Verfügung.
In einem ersten Schritt habe ich die Eingaben über Buttons auf der Form realisiert. Ihr wisst schon: Nummernfeld und Tasten für die Operatoren usw. Das funktioniert auch prima über das OnClick-Ereignis. Der Button meldet sich bei einer zentralen Prozedur, die seine Caption (da ist ja die Zahl /der Operator drauf) als Char-Argument an mein Rechnerobjekt übergibt.
Aber man will ja einen Rechner nicht nur über Mausgeschubse bedienen, sondern häufiger wird man seine Eingaben in die Tastatur tippen. Also habe ich versucht, Tastaturevents abzufangen. Meine Form filtert die raus (KeyPreview steht auf True) und soll sie natürlich auch an die o.g. Klassenmethode weiterreichen. Ich brauche also als Parameter ein Char. Die Form reicht alles an Keys weiter, was ihr eingegeben wird, sie kümmert sich nicht darum, ob die in einer Rechenformel Sinn machen. Das ist der Job des Rechner-Objektes.
Zuerst habe ich es über das KeyDown-Ereignis der Form versucht. Da bekomme ich den Key als Word übergeben. Ich habe versucht, das via Chr(Key) weiter zu reichen, aber das klappt nicht. Die Zahlen 0-9 auf der normalen Tastatur werden korrekt erkannt, aber bei Komma, Operatoren und Tasten des Nummernblocks kommen bei Chr(Key) die falschen ASCII-Codes raus (Komma zB Code 188).
Deswegen bin ich auf diese UTF8KeyPress-Geschichte gekommen. Da werden alle Zeichen, die ich für meinen Rechner brauche, korrekt über den UTF8Key erkannt und übergeben. Ich hatte nur das Problem, dass ich keinen direkten Konverter von UTF8Key nach Char gefunden habe und deswegen auf Theos Lösung aus dem anderen Thread gestoßen bin. Bei mir funktioniert er bisher tadellos. Mal sehen, was passiert, wenn ich noch Backspace und Enter einbinden (Enter auf dem Nummernblock erzeugt bei mir eine '1'). Aber soweit war ich noch nicht. Wenn jemand eine bessere Lösung weiß, ich bin zu jeder Schandtat bereit :wink:
Wer nachsehen will, der Code ist angehangen (der ist aber noch nicht vollständig).
Dateianhänge
Taschenrechner.zip
(5.3 MiB) 69-mal heruntergeladen
Ich mag Pascal...

Michl
Beiträge: 2511
Registriert: Di 19. Jun 2012, 12:54

Re: Tastatureingaben variabel abfangen

Beitrag von Michl »

Hallo Marsmännchen,

ich habe mir mal dein Programm runtergeladen und getestet. Eine Anmerkung vorweg, es ist besser nur die Quelldateien (*.lpi, *.lpr, *.pas, *.lfm) in ein Beispiel-Zip zu packen und alle compilierten Dateien wegzulassen. Das spart jede Menge Platz und Ärger.

Es hätte auch ein anderes Ereignis vom Formular gegeben (OnKeyPress), was für deine Zwecke besser geeignet gewesen wäre. Dort kommt bereits ein Char an, was dann zur weiteren Auswertung zur Verfügung stände.
Dann könntest du einfach alle Zeichen, die nicht in dem TEdit verarbeitet werden sollen löschen. z.B.:

Code: Alles auswählen

procedure TForm1.FormKeyPress(Sender: TObject; var Key: char);
begin
  case Key of
    '0'..'9', '+', '-', '*', '/', #13, #8, ',', '.', '(', ')': Exit;  //Nur die hier definierten Chars werden durchgelassen
  end;
  Key := #0;  //ansonsten werden sie gelöscht
end;
Ist aber nicht so wichtig, hauptsache das Programm tut, was du willst und es ist selber geschrieben. Weiter so!

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection;  

Marsmännchen
Beiträge: 294
Registriert: So 4. Mai 2014, 21:32
OS, Lazarus, FPC: Windows 10 64bit, Lazarus 2.0.10
CPU-Target: 64bit
Wohnort: Oranienburg

Re: Tastatureingaben variabel abfangen

Beitrag von Marsmännchen »

Hi,
Michl hat geschrieben:Eine Anmerkung vorweg, es ist besser nur die Quelldateien (*.lpi, *.lpr, *.pas, *.lfm) in ein Beispiel-Zip zu packen und alle compilierten Dateien wegzulassen. Das spart jede Menge Platz und Ärger.
Okay, mache ich künftig :oops:

Deinen Beispielcode schaue ich mir morgen nochmal in Ruhe an, heute ist Hochzeitstag, da muss ich mich um Frauchen kümmern :wink: .
Was ich jetzt schon auf jeden Fall mir behalten werde ist, dass man über Case sehr schön einen Zeichenfilter für Eingaben realisieren kann. Das wird man gelegentlich brauchen.

Danke für deine ganze Mühe!
Ich mag Pascal...

Antworten