[code] HitKey() : Erster Druck auf Taste per KeyboardLib

Hier könnt Ihr gute, von Euch geschriebene Codes posten. Sie müssen auf jeden Fall funktionieren und sollten möglichst effizient, elegant und beispielhaft oder einfach nur cool sein.
Kaeru Gaman
Beiträge: 17389
Registriert: 10.11.2004 03:22

[code] HitKey() : Erster Druck auf Taste per KeyboardLib

Beitrag von Kaeru Gaman »

[ScreenMode, OpenScreen, Keyboard Lib, InitKeyboard, KeyboardPushed]

um einen ersten tastendruck zu verarbeiten, muss man mit Flags arbeiten.
für die Flags kann man genauso ein Array anlegen wie intern für die Tastendrücke selber angelegt wird.

Code: Alles auswählen

Global Dim KeyOld.l(255)

Procedure.l KeyHit( Key.l )
  Protected HIT = #False
  If KeyboardPushed(Key)
    If Not KeyOld(Key)    ; first press
      KeyOld(Key) = #True  ; set KeyFlag
      HIT = #True
    EndIf
  Else
    KeyOld(Key) = #False   ; reset KeyFlag
  EndIf
  ProcedureReturn HIT
EndProcedure
funktioniert genauso wie KeyboardPushed(#Key), gibt aber nur beim ersten Aufruf #True zurück, falls die Taste gedrückt bleibt.
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8812
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Beitrag von NicTheQuick »

Man könnte das Array auch mit in die Procedure nehmen und 'Hit' weglassen.

Code: Alles auswählen

Procedure.l KeyHit( Key.l )
  Static Dim KeyOld.l(255)
  If KeyboardPushed(Key)
    If Not KeyOld(Key)    ; first press
      KeyOld(Key) = #True  ; set KeyFlag
      ProcedureReturn #True
    EndIf
  Else
    KeyOld(Key) = #False
  EndIf
  ProcedureReturn #False
EndProcedure
Das ist zwar nicht besser, aber mir würde es so besser gefallen. Wenn man dann ganz wild
darauf is, Speicher zu sparen, kann man statt des Long-Arrays auch ein Byte-Array nutzen.
Kaeru Gaman
Beiträge: 17389
Registriert: 10.11.2004 03:22

Beitrag von Kaeru Gaman »

> kann man statt des Long-Arrays auch ein Byte-Array nutzen.

richtig, wird ja von GetKeyboardState_() auch gemacht.
mich störte das jetzt nicht, ein ganzes KB zu benutzen statt eines Viertels,
und der Array-Zugriff ist möglicherweise minimal performanter, weil Long.

> Man könnte das Array auch mit in die Procedure nehmen

auch richtig. ich weiß aber noch nicht, ob ich das nicht noch in ner anderen Proc brauchen könnte.

> und 'Hit' weglassen.

ich war mir nicht mehr sicher, ob das "ProcedureReturn #False" wirklich außerhalb aller Ifs stehen darf...
war schon spät...

im endeffekt ist das "gewachsener Code".
zuerst kam die Idee, dieses Array anzulegen, um nicht für jede Taste mit nem Flag rumdaddeln zu müssen.
dann erst kam die idee, eine Proc draus zu machen, um nicht die Ifs bei jedem Key stehen zu haben.
...und dann war es SO spät in der nacht, dass ich nicht mal mehr ne schleife mit drei verschiedenen transformationen hinbekommen hab, und ich bin in die kiste...
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
Benutzeravatar
Shardik
Beiträge: 746
Registriert: 25.01.2005 12:19

Beitrag von Shardik »

NicTheQuick hat geschrieben: Wenn man dann ganz wild darauf is, Speicher zu sparen, kann man statt des Long-Arrays auch ein Byte-Array nutzen.
Nur einmal zum Vergleich:
- ein Long-Array benötigt 255 * 4 Bytes = 1020 Bytes, um 255 Bits zu speichern
- ein Byte-Array benötigt nur 255 Bytes
- eigentlich benötigt man ja nur 8 Bytes (= 256 Bits) zur platzsparendsten Speicherung

Ich habe daher einmal ein Code-Beispiel erstellt, das mit den 8 Bytes auskommt und das ganze in Assembler realisiert, um durch den Umrechnungsaufwand nicht zu sehr Performance zu verlieren. Letztendlich muß jeder selbst entscheiden, was ihm wichtiger ist: Platzverbrauch oder Performance :wink:

Code: Alles auswählen

Procedure ReadKeyBit(ByteOffset.L, BitOffset.L)
  !PUSH EBX
  !XOR  EAX,EAX
  !MOV  EBX,DWORD[ESP+12]
  !BT   DWORD[ESP+8],EBX
  !JNC  $+3
  !INC  EAX
  !POP  EBX
  ProcedureReturn 
EndProcedure

Procedure ClearKeyBit(ByteOffset.L, BitOffset.L)
  !MOV  EAX,DWORD[ESP+8]
  !BTR  DWORD[ESP+4],EAX
EndProcedure

Procedure SetKeyBit(ByteOffset.L, BitOffset.L)
  !MOV  EAX,[ESP+8]
  !BTS  DWORD[ESP+4],EAX
EndProcedure

Procedure.L KeyHit(KeyCode.L)
  Static KeyBuffer.S{8}

  Protected BitOffset.L = KeyCode % 32
  Protected ByteOffset.L = @KeyBuffer + KeyCode / 32

  If KeyboardPushed(KeyCode)
    If ReadKeyBit(ByteOffset, BitOffset) = 0
      SetKeyBit(ByteOffset, BitOffset)
      ProcedureReturn #True
    EndIf
  Else
    ClearKeyBit(ByteOffset, BitOffset)
    ProcedureReturn #False
  EndIf
EndProcedure
Zuletzt geändert von Shardik am 13.09.2007 12:09, insgesamt 1-mal geändert.
Kaeru Gaman
Beiträge: 17389
Registriert: 10.11.2004 03:22

Beitrag von Kaeru Gaman »

in diesem falle ja, es würde auch ein Bit genügen.

aber die Keyboard-API nutzt einen 256byte-buffer dafür.
dafür will ich es letztendlich auch kompatibel halten.

außerdem vermute ich, dass die Keyboard-Lib auch intern einen 256byte-Buffer benutzt.
ob da noch andere infos drinstecken als nur ein einzelnes Bit, muss ich noch testen...

in diesem Falle ist es nur eine zwischenlösung, um die ganzen Flags für die Tasten bequemer zu verwalten.
letztendlich aber ist es ein Ansatz, später mit den Tabellen der API und der Lib herumzuwerkeln.
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
Antworten