Symulowanie klawisza w pętli - problem

0

Dopiero co uporałem się z jedynym problemem odnośnie hook na klawisz ALT to teraz mam problem z symulowaniem klawisza od momentu zajścia zdarzenia OnKeyDown i wykonywania go aż do OnKeyUp.

Mam zapisaną w gridzie instrukcję w taki sposób:

Lp | Nazwa | Czekaj [ms]
1 | [BACKSPACE DOWN] | 0
2 | [BACKSPACE UP] | 1591

To znaczy: wykonuj pozycję numer 1 aż przez 1591 ms

Mam taką oto ciekawą funkcję w której sprawdzam powyższe ustawienie:

// dane podstawiłem specjalnie dla forum
while not dataset.eof do
begin
  Action_SpecialKey: // Klawisze specjalne
  begin
     SendSpecialKey(dataset.fieldbyname('nazwa').value); // podstawiam nazwę pozycji
  end;

  dataset.next;
end;

no i magiczna procedurka, która niestety wykonuje się tylko raz:

procedure SendSpecialKey(Key: string);
begin
  if Key = '[ENTER DOWN]' then
    keybd_event(Ord(VK_RETURN),0,0,0);

  if Key = '[ENTER UP]' then
    keybd_event(Ord(VK_RETURN),0,KEYEVENTF_KEYUP,0);

  if Key = '[BACKSPACE DOWN]' then
    keybd_event(Ord(VK_BACK),0,0,0);

  if Key = '[BACKSPACE UP]' then
    keybd_event(Ord(VK_BACK),0,KEYEVENTF_KEYUP,0);

  if Key = '[ESC DOWN]' then
    keybd_event(Ord(VK_ESCAPE),0,0,0);

  if Key = '[ESC UP]' then
    keybd_event(Ord(VK_ESCAPE),0,KEYEVENTF_KEYUP,0);

  if Key = '[TAB DOWN]' then
    keybd_event(Ord(VK_TAB),0,0,0);

  if Key = '[TAB UP]' then
    keybd_event(Ord(VK_TAB),0,KEYEVENTF_KEYUP,0);
end;

Nie wiem czy dobrze kombinuję, ale wydaje mi się, że powinienem wykonać procedurę SendSpecialKey w pętli WHILE korzystając wewnątrz z funkcji GetTickCount i sprawdzać:

wynik := 0;
start := GetTickCount;
while wynik < 1591 do
begin
  stop := GetTickCount;

  wynik := stop - start;

  /// instrukcje wciskania klawiszy
end;

Dobrze kombinuję?

0

Lepiej chyba w wątku zrobić Sleep z żądaną ilością milisekund przed symulacją klawisza. Do tego symulowania polecił bym Tobie zobaczyć na procedurę KeyDownUp w module useful_winapi.pas, która znajduje się w archiwum z kodami, ktore Ci wcześniej pobrać z mojej odpowiedzi z innego tematu. Unikniesz problemu z symulowaniem na przykład controla w grach pod DirectX. Poza tym funkcja, którą użyłeś jest przestarzała, zaleca się używać SendInput zamiast niej, tak jak zrobiłem w swoim kodzie.

0

Nie mogę sobie z tym poradzić.

Opiszę o co mi chodzi:

Mam otwarty notatnik, klikam skrót F1 żeby rozpocząć zapamiętywanie klawiszy. Naciskam ENTER i trzymam przez 2 sekundy. Przez ten czas w notatniku zrobiło mi się sporo enterów. Wciskam F1 żeby zakończyć zapamiętywanie i w tym momencie do programu zapisuję kod w takiej postaci jak w tabelce powyżej.

Problem występuje podczas symulowania tej samej akcji co użytkownik czyli trzymania ENTER i robienia tyle samo nowych linii przez ile trzymaliśmy ENTER wciśnięty.

Klawisz Ile wciśnięty [ms]
ENTER DÓŁ 0
ENTER GÓRA 2000

Chciałbym, aby program wykonywał enter przez określony czas czyli 2000 ms.

Tak wygląda moja symulacja:

procedure SendSpecialKey(Key: string; Delay: integer);
var
  start, stop, equals : cardinal;
begin
  start := GetTickCount;
  stop := GetTickCount;
  equals := stop - start;
  while stop - start < Delay do
  begin
    equals := stop - start;
    stop := GetTickCount;

    if Key = '[ENTER DOWN]' then
      KeyDownUp(VK_RETURN, False); //keybd_event(Ord(VK_RETURN),0,0,0);

    if Key = '[ENTER UP]' then
      KeyDownUp(VK_RETURN, True); //keybd_event(Ord(VK_RETURN),0,KEYEVENTF_KEYUP,0);

    if Key = '[BACKSPACE DOWN]' then
      KeyDownUp(VK_BACK, False); //keybd_event(Ord(VK_BACK),0,0,0);

    if Key = '[BACKSPACE UP]' then
      KeyDownUp(VK_BACK, True); //keybd_event(Ord(VK_BACK),0,KEYEVENTF_KEYUP,0);

    if Key = '[ESC DOWN]' then
      KeyDownUp(VK_ESCAPE, False); //keybd_event(Ord(VK_ESCAPE),0,0,0);

    if Key = '[ESC UP]' then
      KeyDownUp(VK_ESCAPE, True); //keybd_event(Ord(VK_ESCAPE),0,KEYEVENTF_KEYUP,0);

    if Key = '[TAB DOWN]' then
      KeyDownUp(VK_TAB, False); //keybd_event(Ord(VK_TAB),0,0,0);

    if Key = '[TAB UP]' then
      KeyDownUp(VK_TAB, True); //keybd_event(Ord(VK_TAB),0,KEYEVENTF_KEYUP,0);

    if Key = '[ALT DOWN]' then
      KeyDownUp(VK_MENU, False);

    if Key = '[ALT UP]' then
      KeyDownUp(VK_MENU, True);
  end;
end;

procedure KeyDownUp(KeyToSend : Byte; KeyDown : boolean);
const
  DownUp_Flags_Arr : array[boolean] of DWORD = (0, KEYEVENTF_KEYUP);
  Extended_Flags_Arr : array[boolean] of DWORD = (0, KEYEVENTF_EXTENDEDKEY);
var
  Input : TagINPUT;
  KeyExtended : boolean;
begin
  Input.Itype := INPUT_KEYBOARD;
  Input.ki.wVK := KeyToSend;
  Input.ki.wScan := MapVirtualKey(KeyToSend, 0);
  KeyExtended := KeyToSend in
    [VK_CONTROL, VK_LCONTROL, VK_RCONTROL,
    VK_UP, VK_DOWN, VK_LEFT, VK_RIGHT,
    VK_HOME, VK_END, VK_PRIOR, VK_NEXT,
    VK_INSERT, VK_DELETE, VK_MENU];
  Input.ki.dwFlags := DownUp_Flags_Arr[not KeyDown] or Extended_Flags_Arr[KeyExtended];
  Input.ki.time := 0;
  SendInput(1, Input, SizeOf(Input));
end;

Tyle, że podczas tej symulacji enter wciskany jest o milion razy za dużo. Jeżeli zastosuję sleep to chyba też nie zrobię tyle samo enterów co przy zapamiętywaniu.
Masz może jakiś pomysł, albo ktoś jeszcze zna jakieś rozwiązanie?

0

Za pewne dzieje się tak dlatego, ponieważ fizyczna reakcja klawiatury jest wolniejsza niż wykonanie tego przez kod. Tutaj jednak chyba przyda się kod, który jest oparty o Hook (bo nie wiem jak z tym wczytywaniu w wątku przez GetAsyncKeyState, ponieważ tam jest sleep 100 ms domyślnie w moim kodzie). A zamieszczałem go w załączniku o nazwie keys_hook_global.rar w innym temacie. Lepiej tutaj niż czas trwania wciskania klawisza, sprawdzi się według mnie odczytanie ilości jego naciśnięć.

0

@olesio zaraz mnie coś tu trafi ;/

Wciskam ALT + SHIFT w programie dostaję

ALT DOWN, SHIFT DOWN
puszczam ALT i SHIFT
ALT DOWN, ???????

nie dostaję shift down z kolei jeżeli puszczę tylko ALT to program wykonuje non stop SHIFT UP dopóty go nie puszczę....

próbuje na różne sposoby:

          KeyDown := lParam and $80000000 <> $80000000; (* key is not being released *)
          KeyUp := ((GetKeyState(VK_SHIFT) and (1 shl 15)) <> 0);

         WM_KEYDOWN, WM_KEYUP

Nie działa... help !!

function KeyboardHookProc(nCode : Integer; wParam : integer; lParam : integer) : Integer; stdcall; export;
var
  Hook : PKBDLLHOOKSTRUCT;
  NewChar: array [0..1] of Char;
  s: String;
begin
  Hook := Pointer(lParam);

  case nCode of
    HC_ACTION :
      begin
        If not iMoveIt.getConfig.Hook_Paused Then
        begin
          FillChar(NewChar,2,#0);
          GetKeyboardState(KeyState);
          iMoveIt.GetDataFromCursor;

          KeyDown := lParam and $80000000 <> $80000000; (* key is not being released *)
          KeyUp := ((GetKeyState(VK_SHIFT) and (1 shl 15)) <> 0);

          case Hook.vkCode of
            VK_LSHIFT, VK_RSHIFT, VK_SHIFT:
              begin
                if FBuffer <> '' then
                begin
                  iMoveIt.AddAction(iMoveIt.getConfig.Action_TypeText, '', 0, 0, FBuffer + '1');
                  FBuffer := '';
                end;

                if (wParam = WM_KEYDOWN) then
                begin
                  if not SHIFT_WaitForUp then
                  begin
                    Start := GetTickCount;
                    iMoveIt.AddAction(iMoveIt.getConfig.Action_SpecialKey, '', 0, 0, '[SHIFT DOWN]');
                    SHIFT_WaitForUp := True;
                  end;
                end else
                begin
                  stop := GetTickCount;
                  iMoveIt.AddAction(iMoveIt.getConfig.Action_SpecialKey, '', 0, stop - start, '[SHIFT UP]');
                  SHIFT_WaitForUp := False;
                end;
              end;
          

            VK_LMENU, VK_RMENU, VK_MENU:
              begin
                if FBuffer <> '' then
                begin
                  iMoveIt.AddAction(iMoveIt.getConfig.Action_TypeText, '', 0, 0, FBuffer + '1');
                  FBuffer := '';
                end;

                if KeyDown{(wParam = WM_KEYDOWN)} then
                begin
                  if not ALT_WaitForUp then
                  begin
                    Start := GetTickCount;
                    iMoveIt.AddAction(iMoveIt.getConfig.Action_SpecialKey, '', 0, 0, '[ALT DOWN]');
                    ALT_WaitForUp := True;
                  end;
                end;
                if wParam = WM_KEYUP then
                begin
                  stop := GetTickCount;
                  iMoveIt.AddAction(iMoveIt.getConfig.Action_SpecialKey, '', 0, stop - start, '[ALT UP]');
                  ALT_WaitForUp := False;
                end;
              end;
          end;

        end;
      end;
  end;
  Result := CallNextHookEx(KeyboardHookHandle, nCode, wParam, lParam);
end;
0

Masakra, udało mi się w końcu.

Teraz mam pytanie odnośnie symulacji wciśnięcia klawisza ALT.

procedure KeyDownUp(KeyToSend : Byte; KeyDown : boolean);
const
  DownUp_Flags_Arr : array[boolean] of DWORD = (0, KEYEVENTF_KEYUP);
  Extended_Flags_Arr : array[boolean] of DWORD = (0, KEYEVENTF_EXTENDEDKEY);
var
  Input : TagINPUT;
  KeyExtended : boolean;
begin
  Input.Itype := INPUT_KEYBOARD;
  Input.ki.wVK := KeyToSend;
  Input.ki.wScan := MapVirtualKey(KeyToSend, 0);
  KeyExtended := KeyToSend in
    [VK_CONTROL, VK_LCONTROL, VK_RCONTROL,
    VK_UP, VK_DOWN, VK_LEFT, VK_RIGHT,
    VK_HOME, VK_END, VK_PRIOR, VK_NEXT,
    VK_INSERT, VK_DELETE, VK_MENU];
  Input.ki.dwFlags := DownUp_Flags_Arr[not KeyDown] or Extended_Flags_Arr[KeyExtended];
  Input.ki.time := 0;
  SendInput(1, Input, SizeOf(Input));
end;

// Wywołanie klawisza
if Key = '[ALT DOWN]' then
   KeyDownUp(VK_MENU, False);

if Key = '[ALT UP]' then
   KeyDownUp(VK_MENU, True);

Problem polega na tym, że po wykonaniu obydwu procedur nie mogę pisać na klawiaturze.... tak jak by ALT był wciśnięty i nie da rady go normalnie puścić a na 100% wykonuję ALT DOWN i ALT UP, muszę wylogować się z systemu :P coś robię źle ale nie wiem co?

2

Zobacz jak nazywa się drugi parametr procedury KeyDownUp :-)

1 użytkowników online, w tym zalogowanych: 0, gości: 1