| Autor |
Beitrag |
Logikmensch
      
Beiträge: 390
Win XP
Delphi 2007 Prof., XE2, XE5
|
Verfasst: Fr 23.12.05 07:00
Hallo, liebes Delphi-Forum-Team,
ich arbeite seit geraumer Zeit an einer besonderen Textverarbeitung, die im Grunde auch hervorragend arbeitet. Allerdings habe ich das Problem, dass die Tastaturabfrage nicht ganz so hinhaut, wie ich mir das vorstelle. Und zwar wird das Loslassen von Tasten genau dann nicht erfasst, sobald man z.B. einen Dialog öffnet, z.B. durch Drücken eines Shortcuts. Um diese Frage nicht unnötig aufzublähen, habe ich mein Problem mal extrahiert und hier in ein kleines Demoprogramm reingepackt, das ein Gitter für alle 256 Tasten anzeigt. Man kann auch mehr als eine Taste auf einmal drücken - im Gitter werden die gedrückten Tasten rot angezeigt. Beim loslassen einer Taste wird die korrespondierende Gitterzelle wieder weiß. Soweit so gut. Hier erst einmal der Code (für Delphi 7, 2005 etc.). Man benötigt nur ein leeres Formular:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106:
| unit Unit1;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, Grids, Menus;
type TForm1 = class(TForm) procedure FormDestroy(Sender: TObject); procedure StringGridDrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState); procedure FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); procedure FormCreate(Sender: TObject); private keys:array[0..255] of boolean; grid:TStringGrid; menu:TMainMenu; procedure Menu_Datei(Sender: TObject); public end;
var Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject); var x,y:integer; m:TMenuItem; begin grid:=TStringGrid.Create(self); grid.Parent:=self; with grid do begin align:=alClient; defaultdrawing:=false; ondrawcell:=StringGridDrawCell; fixedcols:=0; fixedrows:=0; colcount:=16; rowcount:=16; for y:=0 to 15 do for x:=0 to 15 do cells[x,y]:=inttostr(y*16+x); for x:=0 to 15 do colwidths[x]:=32; tabstop:=false; end; fillchar(keys,sizeof(keys),0); menu:=TMainMenu.Create(self); m:=TMenuItem.Create(self); m.OnClick:=Menu_Datei; m.Caption:='&Datei'; m.ShortCut:=ShortCut(Word('F'), [ssCtrl]); menu.Items.Add(m); end;
procedure TForm1.Menu_Datei; begin showmessage('Dies wäre der Datei-Dialog'); end;
procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin if key<=255 then keys[key]:=true; grid.Invalidate; end;
procedure TForm1.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); begin if key<=255 then keys[key]:=false; grid.Invalidate; end;
procedure TForm1.StringGridDrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState); var key:integer; begin key:=ARow*16+ACol; with grid,canvas do begin brush.Style:=bsSolid; if keys[key] then brush.Color:=clRed else brush.Color:=clWindow; textrect(rect,rect.Left,rect.Top,cells[ACol,ARow]); end; end;
procedure TForm1.FormDestroy(Sender: TObject); begin grid.Free; menu.Free; end;
end. |
Nun das Problem: Wenn man z.B. den kleinen Test-Menüpunkt "Datei" durch Drücken von ALT+D oder STRG+F aufruft, erscheint die kleine Messagebox und wenigstens eine der Systemtasten ALT oder STRG bleibt gedrückt. Einfach deswegen, weil das Formular das entsprechende KeyUp-Ereignis nicht mehr bekommt, weil es nicht mehr den Focus hat.
Ich möchte aber, dass das Formular diese Tastenloslasser trotzdem mitbekommt. Habt ihr da eine Idee?
Es nützt mir nämlich gar nichts, auf das Deaktivieren des Fensters zu reagieren und dort meine Tastaturmerker zu löschen:
Delphi-Quelltext 1: 2: 3: 4: 5: 6:
| procedure TForm1.FormDeactivate(Sender: TObject); var i:integer; begin fillchar(keys,sizeof(keys),0); end; |
Weil dieser Event leider nicht ausgelöst wird, sobald eine Message oder ein anderer Dialog aufgerufen wird.
Für Ideen oder Anregungen wäre ich SEHR dankbar!
Liebe Grüße,
Claus.
|
|
NeoInDerMATRIX
      
Beiträge: 245
Win95, Win98(+se), WinNT, Win2000, WinME, WinXP(+pro), VISTA, Linux(SuSe), DOS [MultiMon(3)], Vista
D6 PeE + (FP 2.0l) + D3 Pe + D2005+ D2006 Arch
|
Verfasst: Sa 24.12.05 00:06
Hi,
dafür must du nur die Nachrichten die dir Windows sendet in der Application abfangen.
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47:
| Unit KeyMapper;
Interface
Uses Windows, Forms;
Type TKeyMapper = Class Private App: TApplication; Key: Array[0..256] Of Boolean; Public Constructor Create(AApp: TApplication); Destructor Destroy; Override; Procedure WndProc(Var Msg: TMsg; Var Handled: Boolean); End;
Implementation
Uses SysUtils, Messages;
Constructor TOCtrlKeyMapper.Create(AApp: TApplication); Begin FillChar(Key, SizeOf(Key), False); AApp.OnMessage := WndProc; App := AApp; End;
Destructor TOCtrlKeyMapper.Destroy; Begin App.OnMessage := Nil; App := Nil; End;
Procedure TOCtrlKeyMapper.WndProc(Var Msg: TMsg; Var Handled: Boolean); Begin Case Msg.Message Of wm_KeyUp: Self.Key[Msg.wParam] := False; wm_KeyDown: Self.Key[Msg.wParam] := True; End; End; |
Einbinden am besten in der MainForm mit:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| Type tForumX = Class(...) ... KeyMapper: tOCtrlKeyMapper; ... End;
Function tFormX.onCreate(...); Begin KeyMapper:=tKeyMapper.Create(Application); End; |
Damit sollten die Klasse KeyMapper, immer aktuelle werte haben.
Cu
Neo
|
|
F34r0fTh3D4rk
      
Beiträge: 5285
Erhaltene Danke: 29
Win Vista (32), Win 7 (64)
Eclipse, SciTE, Lazarus
|
Verfasst: Sa 24.12.05 09:27
warum benutzt du dann nicht getasynckeystate ?
|
|
BenBE
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: So 25.12.05 21:54
Probier doch mal die TActionList, die sollte das eigentlich können ...
//Edit: Ansonsten schau Dir mal die OCtrlKeyMapper.pas an.
_________________ Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
Zuletzt bearbeitet von BenBE am So 25.12.05 22:00, insgesamt 1-mal bearbeitet
|
|
NeoInDerMATRIX
      
Beiträge: 245
Win95, Win98(+se), WinNT, Win2000, WinME, WinXP(+pro), VISTA, Linux(SuSe), DOS [MultiMon(3)], Vista
D6 PeE + (FP 2.0l) + D3 Pe + D2005+ D2006 Arch
|
Verfasst: So 25.12.05 21:54
Hi,
Tasten Polling, ich dachte wir sind aus dem Zeitalter von Dos raus!
Diese Methode die ich hier aufzeige ist die einfachste die ich kenne. Polling sollte man in der heutigen Zeit nur für bereiche anwenden wo es nicht anderst geht.
Cu
Neo
|
|
Logikmensch 
      
Beiträge: 390
Win XP
Delphi 2007 Prof., XE2, XE5
|
Verfasst: Mo 26.12.05 21:01
Titel: Vielen Dank!
Hallo ihr Denker!
Besonderen Dank für die Ideen und Anregungen. Besonders während der Weihnachtsfeiertage, an denen man doch nicht immer am PC hängt. *grins*
In der Tat hatte ich ganz zu Anfang mit GetAsyncKeyState gearbeitet, aber war mit den Ergebnissen in meinem Code mehr als unzufrieden und habe mich dann mit dem KEYS-Array eigentlich recht wohl gefühlt. Ich denke, NeoInDerMatrix hat eine gute Lösung, die Windows-Botschaften ganz unten abzufangen. Vielen Dank für den Code. Ich kann es kaum erwarten, es auszuprobieren - bin im Moment verreist und habe meinen Delphi-PC nicht mit.
Es bedankt sich ein Entenbraten-gestärkter Claus!
P.S.: BenBE: Ich konnte OCtrlKeyMapper.pas nicht runterladen, ich versuche es später erneut. Danke auch für den Tipp!
|
|
NeoInDerMATRIX
      
Beiträge: 245
Win95, Win98(+se), WinNT, Win2000, WinME, WinXP(+pro), VISTA, Linux(SuSe), DOS [MultiMon(3)], Vista
D6 PeE + (FP 2.0l) + D3 Pe + D2005+ D2006 Arch
|
Verfasst: Di 27.12.05 04:09
Hi,
Der Link den BenBE dir gepostet hat ist kein DL sondern er zeigt dir den Source im Browser an! Soweit ich mich erinnere. Aber dieser Source ist genau das gleiche nur halt für ein game angepasst. (Ist nähmlich von mir.)
Fals du noch fragen haben solltest BenBE und Ich helfen dir sehr gerne.
Würde mich freuen wenn du mich über dein Forankommen Informieren würdest.
Cu
Neo
|
|
Logikmensch 
      
Beiträge: 390
Win XP
Delphi 2007 Prof., XE2, XE5
|
Verfasst: Di 03.01.06 05:43
Titel: Vielen Dank!
Hallo und allen ein frohes neues Jahr!
Nochmals danke für die Tipps. Ich habe mit eurer Hilfe geschafft, das Problem zu beseitigen.
Liebe Grüße,
Claus
|
|
|