Emulowanie klawiatury - problem z wielkimi literami

0

Witam,

mam taki oto kod, który odpowiada za symulowanie wciskanych klawiszy podanych w zmiennej value:

procedure Keyboard_SendText(const value: WideString);
var i:integer;
    j:integer;
    ch:byte;
    str:string;
begin
  i:=1;
  while i<=Length(value) do
  begin
    ch:=byte(value[i]);
    if Windows.IsDBCSLeadByte(ch) then
    begin
      Inc(i);
      str:=inttostr(MakeWord(byte(value[i]), ch));
      keybd_event(VK_MENU, MapVirtualKey(VK_MENU, 0), 0, 0);
      j:=1;
      while j<=Length(str) do
      begin
        keybd_event(96+strtoint(str[j]), MapVirtualKey(96+strtoint(str[j]), 0), 0, 0);
        keybd_event(96+strtoint(str[j]), MapVirtualKey(96+strtoint(str[j]), 0), 2, 0);
        j:=j+1;
      end;
      keybd_event(VK_MENU, MapVirtualKey(VK_MENU, 0), KEYEVENTF_KEYUP, 0);
    end else
    begin
      keybd_event(VkKeyScan(value[i]),0,0,0);
      keybd_event(VkKeyScan(value[i]),0,2,0);
    end;
    Inc(i);
  end;
end;

Problem jest taki, że nie emuluje mi WIELKICH liter. Wiem, że trzeba obsłużyć w jakiś sposób SHIFT ale szczerze powiedziawszy to nie wiem w jaki sposób to zrobić. Może ma ktoś jakiś przykład, gdzie obsługuje małe i duże litery oraz znaki?

0

wielka litera to - początek magii - SHIFT + mała litera - koniec magii

0

Nie jestem pewien, ale nie wystarczy po prostu zrobić:

keybd_event(ord('A')+strtoint(str[j])-1, MapVirtualKey(ord('A')+strtoint(str[j])-1, 0), 0, 0);
0

Pokombinowałem z Twoim kodem, ale nie zadziałało. Nie bardzo wiem jak to ugryźć.

2

Do symulowania klawiatury polecam używać następujących procedur:

Procedure SymulujKeyDown(Key: Cardinal);
  Var
  Input: tagINPUT;
 Begin
  Input.Itype:=INPUT_KEYBOARD;
  Input.ki.wVK:=Key;
  Input.ki.wScan:=MapVirtualKey(Key, 0);

  If Key in [VK_UP, VK_DOWN, VK_LEFT, VK_RIGHT, VK_HOME,
             VK_END, VK_PRIOR, VK_NEXT, VK_INSERT, VK_DELETE]
    then Input.ki.dwFlags:=KEYEVENTF_EXTENDEDKEY
    else Input.ki.dwFlags:=0;
  Input.ki.time:=0;
  SendInput(1, Input, SizeOf(Input));
 end;

Procedure SymulujKeyUp(Key: Cardinal);
  Var
  Input: tagINPUT;
 Begin
   Input.Itype:=INPUT_KEYBOARD;
   Input.ki.wVK:=Key;
   Input.ki.wScan:=MapVirtualKey(Key, 0);

   If Key in [VK_UP, VK_DOWN, VK_LEFT, VK_RIGHT, VK_HOME,
              VK_END, VK_PRIOR, VK_NEXT, VK_INSERT, VK_DELETE]
     then Input.ki.dwFlags:=KEYEVENTF_KEYUP or KEYEVENTF_EXTENDEDKEY
     else Input.ki.dwFlags:=KEYEVENTF_KEYUP;
   Input.ki.time:=0;
   SendInput(1, Input, SizeOf(Input));
 end; 

Przykład użycia (symulacja 'A'):

SymulujKeyDown(VK_LSHIFT); //lewy shift wciśnięty
SymulujKeyDown(Ord('A')); // symulacja wciśnięcia 'a'
SymulujKeyUp(Ord('A')); //symulacja zwolnienia 'a'
SymulujKeyUp(VK_LSHIFT); //lewy shift zwolniony

Oczywiście, jak wspomniał @Patryk27, wciśnięty CapsLock wpływa na odwrócenie wielkości liter, tak więc @user322 jako zadanie domowe wyszpera w Helpie, jak sprawdzić stan CapsLock-a, żeby w sytuacji, gdy jest wciśnięty pomijać symulowane wciśnięcie i zwolnienie Shifta (dotyczy symulowania wielkich liter) lub użyć symulacji Shifta (dotyczy symulowania małych liter).

Dodatkowo powyższe procedury symulacji klawiszy rozwiązują problem nie zwalniania prawego Shifta przy użyciu funkcji Keybd_event, np:

keybd_event(VK_RSHIFT,0,0,0);
keybd_event(Ord(VK_HOME),0,0,0);
keybd_event(Ord(VK_HOME),0,KEYEVENTF_KEYUP,0);
keybd_event(VK_RSHIFT,0,KEYEVENTF_KEYUP,0); 

można porównać z poprawnie działającą sekwencją:

SymulujKeyDown(VK_RSHIFT);
SymulujKeyDown(VK_HOME);
SymulujKeyUp(VK_HOME);
SymulujKeyUp(VK_RSHIFT)
1

Aby odpowiednio zareagować na duże litery musisz sprawdzić czy litera jest faktycznie duża i jeśli tak - zasymulować wciśnięcie Shift; To samo tyczy się znaków specjalnych, które wpisuje się z Shift;

W załączniku masz przykładową aplikację, która przepisuje w Timer tekst z pola Edit do Memo symulując wciskanie klawiszy dla kolejnych liter/znaków; Źródła z projektu testowanego na szybko w Delphi7;

Na zadanie domowe będziesz miał dodanie polskich znaków diakrytycznych lub jeśli chcesz znaków kodowanych w Unicode; Inne dodatki także możesz doimplementować - jeśli chcesz.;


Widzę, że @marogo podał inne rozwiązanie; Bazuje ono na podaniu stałej odzwierciedlającej dany klawisz; Aby go wykorzystać musisz znać wartość klawisza i wywołać tak, jak pokazał w przykładzie; Jest to lepsze rozwiązanie od standardowego wykorzystania keybd_event.

0

Super!
Wielkie dzięki za pomoc i już zabieram się za robotę.

0

Od siebie polecę sprawdzoną procedurę, która również prawidłowo wysyła na przykład sam lewy/prawy Control jeżeli zaszła by taka potrzeba. Natomiast wielkie litery wysyłamy tak, jak napisali poprzednicy. Wciskamy Shift, Wciskamy literę (na przykład Ord('A') - koniecznie jako parametr podając wielką literę), puszczamy literę, poszczamy Shift. Dla polskich znaków diakrytycznych przed wciśnięciem Shifta - wciskamy Control, a po wciśnięciu Shifta dodatkowo wciskamy klawisz VK_MENU. Oczywiście po zwolnieniu klawisza litery, zwalniamy VK_MENU, później Shift i na końcu "zwalniamy również VK_CONTROL. Więcej opisano na MSDNie.

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;

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