|
Вопрос # 1 861/ вопрос решён / |
|
Здравствуйте, уважаемые эксперты!
Такая вот у меня проблема. Есть функция для имитации нажатия клавиш.
1. Хотелось бы чтобы эта функция посылала нажатие клавиш только в определенное окно.
2. Если легче написать новую чем переделывать старую то прошу.
3. Хотелось бы также получить список всех окон (handle).
Приложение: Переключить в обычный режим-
- function SendKeys(SendKeysString: PChar; Wait: Boolean): Boolean;
- type
- WBytes = array[0..pred(SizeOf(Word))] of Byte;
- TSendKey = record
- Name: ShortString;
- VKey: Byte;
- end;
- const
- MaxSendKeyRecs = 41;
- SendKeyRecs: array[1..MaxSendKeyRecs] of TSendKey =
- (
- (Name: 'BKSP'; VKey: VK_BACK),
- (Name: 'BS'; VKey: VK_BACK),
- (Name: 'BACKSPACE'; VKey: VK_BACK),
- (Name: 'BREAK'; VKey: VK_CANCEL),
- (Name: 'CAPSLOCK'; VKey: VK_CAPITAL),
- (Name: 'CLEAR'; VKey: VK_CLEAR),
- (Name: 'DEL'; VKey: VK_DELETE),
- (Name: 'DELETE'; VKey: VK_DELETE),
- (Name: 'DOWN'; VKey: VK_DOWN),
- (Name: 'END'; VKey: VK_END),
- (Name: 'ENTER'; VKey: VK_RETURN),
- (Name: 'ESC'; VKey: VK_ESCAPE),
- (Name: 'ESCAPE'; VKey: VK_ESCAPE),
- (Name: 'F1'; VKey: VK_F1),
- (Name: 'F10'; VKey: VK_F10),
- (Name: 'F11'; VKey: VK_F11),
- (Name: 'F12'; VKey: VK_F12),
- (Name: 'F13'; VKey: VK_F13),
- (Name: 'F14'; VKey: VK_F14),
- (Name: 'F15'; VKey: VK_F15),
- (Name: 'F16'; VKey: VK_F16),
- (Name: 'F2'; VKey: VK_F2),
- (Name: 'F3'; VKey: VK_F3),
- (Name: 'F4'; VKey: VK_F4),
- (Name: 'F5'; VKey: VK_F5),
- (Name: 'F6'; VKey: VK_F6),
- (Name: 'F7'; VKey: VK_F7),
- (Name: 'F8'; VKey: VK_F8),
- (Name: 'F9'; VKey: VK_F9),
- (Name: 'HELP'; VKey: VK_HELP),
- (Name: 'HOME'; VKey: VK_HOME),
- (Name: 'INS'; VKey: VK_INSERT),
- (Name: 'LEFT'; VKey: VK_LEFT),
- (Name: 'NUMLOCK'; VKey: VK_NUMLOCK),
- (Name: 'PGDN'; VKey: VK_NEXT),
- (Name: 'PGUP'; VKey: VK_PRIOR),
- (Name: 'PRTSC'; VKey: VK_PRINT),
- (Name: 'RIGHT'; VKey: VK_RIGHT),
- (Name: 'SCROLLLOCK'; VKey: VK_SCROLL),
- (Name: 'TAB'; VKey: VK_TAB),
- (Name: 'UP'; VKey: VK_UP)
- );
- VK_NULL = 0;
- VK_SemiColon = 186;
- VK_Equal = 187;
- VK_Comma = 188;
- VK_Minus = 189;
- VK_Period = 190;
- VK_Slash = 191;
- VK_BackQuote = 192;
- VK_LeftBracket = 219;
- VK_BackSlash = 220;
- VK_RightBracket = 221;
- VK_Quote = 222;
- VK_Last = VK_Quote;
-
- ExtendedVKeys: set of byte =
- [VK_Up,
- VK_Down,
- VK_Left,
- VK_Right,
- VK_Home,
- VK_End,
- VK_Prior,
- VK_Next,
- VK_Insert,
- VK_Delete];
-
- const
- INVALIDKEY = $FFFF
- VKKEYSCANSHIFTON = $01;
- VKKEYSCANCTRLON = $02;
- VKKEYSCANALTON = $04;
- UNITNAME = 'SendKeys';
- var
- UsingParens, ShiftDown, ControlDown, AltDown, FoundClose: Boolean;
- PosSpace: Byte;
- I, L: Integer;
- NumTimes, MKey: Word;
- KeyString: string[20];
-
- procedure DisplayMessage(Message: PChar);
- begin
- MessageBox(0, Message, UNITNAME, 0);
- end;
-
- function BitSet(BitTable, BitMask: Byte): Boolean;
- begin
- Result := ByteBool(BitTable and BitMask);
- end;
-
- procedure SetBit(var BitTable: Byte; BitMask: Byte);
- begin
- BitTable := BitTable or Bitmask;
- end;
-
- procedure KeyboardEvent(VKey, ScanCode: Byte; Flags: Longint);
- var
- KeyboardMsg: TMsg;
- begin
- keybd_event(VKey, ScanCode, Flags, 0);
- if (Wait) then
- while (PeekMessage(KeyboardMsg, 0, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE)) do
- begin
- TranslateMessage(KeyboardMsg);
- DispatchMessage(KeyboardMsg);
- end;
- end;
-
- procedure SendKeyDown(VKey: Byte; NumTimes: Word; GenUpMsg: Boolean);
- var
- Cnt: Word;
- ScanCode: Byte;
- NumState: Boolean;
- KeyBoardState: TKeyboardState;
- begin
- if (VKey = VK_NUMLOCK) then
- begin
- NumState := ByteBool(GetKeyState(VK_NUMLOCK) and 1);
- GetKeyBoardState(KeyBoardState);
- if NumState then
- KeyBoardState[VK_NUMLOCK] := (KeyBoardState[VK_NUMLOCK] and not 1)
- else
- KeyBoardState[VK_NUMLOCK] := (KeyBoardState[VK_NUMLOCK] or 1);
- SetKeyBoardState(KeyBoardState);
- exit;
- end;
-
- ScanCode := Lo(MapVirtualKey(VKey, 0));
- for Cnt := 1 to NumTimes do
- if (VKey in ExtendedVKeys) then
- begin
- KeyboardEvent(VKey, ScanCode, KEYEVENTF_EXTENDEDKEY);
- if (GenUpMsg) then
- KeyboardEvent(VKey, ScanCode, KEYEVENTF_EXTENDEDKEY or KEYEVENTF_KEYUP)
- end
- else
- begin
- KeyboardEvent(VKey, ScanCode, 0);
- if (GenUpMsg) then
- KeyboardEvent(VKey, ScanCode, KEYEVENTF_KEYUP);
- end;
- end;
-
- procedure SendKeyUp(VKey: Byte);
- var
- ScanCode: Byte;
- begin
- ScanCode := Lo(MapVirtualKey(VKey, 0));
- if (VKey in ExtendedVKeys) then
- KeyboardEvent(VKey, ScanCode, KEYEVENTF_EXTENDEDKEY and KEYEVENTF_KEYUP)
- else
- KeyboardEvent(VKey, ScanCode, KEYEVENTF_KEYUP);
- end;
-
- procedure SendKey(MKey: Word; NumTimes: Word; GenDownMsg: Boolean);
- begin
- if (BitSet(Hi(MKey), VKKEYSCANSHIFTON)) then
- SendKeyDown(VK_SHIFT, 1, False);
- if (BitSet(Hi(MKey), VKKEYSCANCTRLON)) then
- SendKeyDown(VK_CONTROL, 1, False);
- if (BitSet(Hi(MKey), VKKEYSCANALTON)) then
- SendKeyDown(VK_MENU, 1, False);
- SendKeyDown(Lo(MKey), NumTimes, GenDownMsg);
- if (BitSet(Hi(MKey), VKKEYSCANSHIFTON)) then
- SendKeyUp(VK_SHIFT);
- if (BitSet(Hi(MKey), VKKEYSCANCTRLON)) then
- SendKeyUp(VK_CONTROL);
- if (BitSet(Hi(MKey), VKKEYSCANALTON)) then
- SendKeyUp(VK_MENU);
- end;
-
- function StringToVKey(KeyString: ShortString): Word;
- var
- Found, Collided: Boolean;
- Bottom, Top, Middle: Byte;
- begin
- Result := INVALIDKEY;
- Bottom := 1;
- Top := MaxSendKeyRecs;
- Found := false;
- Middle := (Bottom + Top) div 2;
- repeat
- Collided := ((Bottom = Middle) or (Top = Middle));
- if (KeyString = SendKeyRecs[Middle].Name) then
- begin
- Found := True;
- Result := SendKeyRecs[Middle].VKey;
- end
- else
- begin
- if (KeyString > SendKeyRecs[Middle].Name) then
- Bottom := Middle
- else
- Top := Middle;
- Middle := (Succ(Bottom + Top)) div 2;
- end;
- until (Found or Collided);
- if (Result = INVALIDKEY) then
- DisplayMessage('Invalid Key Name');
- end;
-
- procedure PopUpShiftKeys;
- begin
- if (not UsingParens) then
- begin
- if ShiftDown then
- SendKeyUp(VK_SHIFT);
- if ControlDown then
- SendKeyUp(VK_CONTROL);
- if AltDown then
- SendKeyUp(VK_MENU);
- ShiftDown := false;
- ControlDown := false;
- AltDown := false;
- end;
- end;
-
- begin
- AllocationSize := MaxInt;
- Result := false;
- UsingParens := false;
- ShiftDown := false;
- ControlDown := false;
- AltDown := false;
- I := 0;
- L := StrLen(SendKeysString);
- if (L > AllocationSize) then
- L := AllocationSize;
- if (L = 0) then
- Exit;
-
- case SendKeysString[I] of
- '(':
- begin
- UsingParens := True;
- Inc(I);
- end;
- ')':
- begin
- UsingParens := False;
- PopUpShiftKeys;
- Inc(I);
- end;
- '%':
- begin
- AltDown := True;
- SendKeyDown(VK_MENU, 1, False);
- Inc(I);
- end;
- '+':
- begin
- ShiftDown := True;
- SendKeyDown(VK_SHIFT, 1, False);
- Inc(I);
- end;
- '^':
- begin
- ControlDown := True;
- SendKeyDown(VK_CONTROL, 1, False);
- Inc(I);
- end;
- '{':
- begin
- NumTimes := 1;
- if (SendKeysString[Succ(I)] = '{') then
- begin
- MKey := VK_LEFTBRACKET;
- SetBit(Wbytes(MKey)[1], VKKEYSCANSHIFTON);
- SendKey(MKey, 1, True);
- PopUpShiftKeys;
- Inc(I, 3);
- end;
- KeyString := '';
- FoundClose := False;
- while (I <= L) do
- begin
- Inc(I);
- if (SendKeysString[I] = '}') then
- begin
- FoundClose := True;
- Inc(I);
- Break;
- end;
- KeyString := KeyString + Upcase(SendKeysString[I]);
- end;
- if (not FoundClose) then
- begin
- DisplayMessage('No Close');
- Exit;
- end;
- if (SendKeysString[I] = '}') then
- begin
- MKey := VK_RIGHTBRACKET;
- SetBit(Wbytes(MKey)[1], VKKEYSCANSHIFTON);
- SendKey(MKey, 1, True);
- PopUpShiftKeys;
- Inc(I);
- end;
- PosSpace := Pos(' ', KeyString);
- if (PosSpace <> 0) then
- begin
- NumTimes := StrToInt(Copy(KeyString, Succ(PosSpace), Length(KeyString)
- - PosSpace));
- KeyString := Copy(KeyString, 1, Pred(PosSpace));
- end;
- if (Length(KeyString) = 1) then
- MKey := vkKeyScan(KeyString[1])
- else
- MKey := StringToVKey(KeyString);
- if (MKey <> INVALIDKEY) then
- begin
- SendKey(MKey, NumTimes, True);
- PopUpShiftKeys;
- end;
- end;
- '~':
- begin
- SendKeyDown(VK_RETURN, 1, True);
- PopUpShiftKeys;
- Inc(I);
- end;
- else
- begin
- MKey := vkKeyScan(SendKeysString[I]);
- if (MKey <> INVALIDKEY) then
- begin
- SendKey(MKey, 1, True);
- PopUpShiftKeys;
- end
- else
- DisplayMessage('Invalid KeyName');
- Inc(I);
- end;
- end;
-
- Result := true;
- PopUpShiftKeys;
- end;
 |
Вопрос задал: Gooddy (статус: 3-ий класс)
Вопрос отправлен: 28 августа 2008, 20:40
Состояние вопроса: решён, ответов: 2.
|
Ответ #1. Отвечает эксперт: Вадим К
Здравствуйте, Failure!
Отсылать "нажатия клавиш" можно разными способами. Тот код, который Вы привели симулирует обычную клавиатуру. То есть типа как бы Вы нажимали кнопки на клавиатуре. Естественно, их перехватит то приложение, которое в данный момент на переднем фоне (активно) или "ждёт их нажатия" - некоторые приложения могут перехватывать нажатия кнопок. Понятно, что бы этот код работал, надо сделать, что бы окно-получатель было активно. Раньше работала функция SetForeGroundWindow, но многие плохие программы любят выкидывать свои окна "на верх" и Майкрософт прикрыла лавочку:).
Если надо просто отправлять нажатия, то можно делать так. Вначале с помощью FindWindow('заголовок окна','тип'); нужно получить хендл окна. если надо не конкретному окну, а какому то дочернему окну это окна (кнопки, эдиты...), то с помощью FindWindowEx ищем нужное дочернее окно.
После того, как хендл будет найден, ему можно с помощью SendMessage(хендл, WM_CHAR, ord('A'), 0); послать нажатие кнопки А. Иногда надо симулировать нажатие-отпускание. Для этого есть свои события (WM_KEYUP, WM_KEYDOWN). Можно и нажатие мышки симулировать. Надо только сообщения нужные найти.
Составить список всех хендлов - сложноватая задача. Не забываем, что все кнопки тоже есть окнами.
начните с этой статьистатьи.
А потом, естественно возникнут вопросы. И когда они конкретизируются - задавайте, будем разбираться.
 |
Ответ отправил: Вадим К (статус: Академик)
Время отправки: 29 августа 2008, 00:15
Оценка за ответ: 5
Комментарий к оценке: жалко без примера но ответ исчерпывающий
|
Ответ #2. Отвечает эксперт: Feniks
Здравствуйте, Failure!
Вот вам примерчик, что бы получить список запущенных приложения/окон:
procedure TForm1.Button1Click(Sender: TObject);
VAR
Wnd : hWnd;
buff: ARRAY [0..127] OF Char;
begin
ListBox1.Clear;
Wnd := GetWindow(Handle, gw_HWndFirst);
WHILE Wnd <> 0 DO
BEGIN {Не показываем:}
IF (Wnd <> Application.Handle) AND {-Собственное окно}
IsWindowVisible(Wnd) AND {-Невидимые окна}
(GetWindow(Wnd, gw_Owner) = 0) AND {-Дочернии окна}
(GetWindowText(Wnd, buff, sizeof(buff)) <> 0) {-Окна без заголовков}
THEN BEGIN
GetWindowText(Wnd, buff, sizeof(buff));
ListBox1.Items.Add(StrPas(buff));
END;
Wnd := GetWindow(Wnd, gw_hWndNext);
END;
ListBox1.ItemIndex := 0;
end;
А в Приложении смотрите компонент SendKeys для отправки любых комбинаций нажатия клавиш в чужие окна.
P.S. Желаю удачи.
Приложение: Переключить в обычный режим- unit SendKeys;
-
- interface
-
- uses
- Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;
-
- type
- TSendKeys = class(TComponent)
- private
- fhandle:HWND;
- L:Longint;
- fchild: boolean;
- fChildText: string;
- procedure SetIsChildWindow(const Value: boolean);
- procedure SetChildText(const Value: string);
- procedure SetWindowHandle(const Value: HWND);
- protected
-
- public
-
- published
- Procedure GetWindowHandle(Text:String);
- Procedure SendKeys(buffer:string);
- Property WindowHandle:HWND read fhandle write SetWindowHandle;
- Property IsChildWindow:boolean read fchild write SetIsChildWindow;
- Property ChildWindowText:string read fChildText write SetChildText;
- end;
-
- procedure Register;
-
- implementation
-
-
- utilizadas como callbacks}
- HTemp:Hwnd;
- ChildText:string;
- ChildWindow:boolean;
-
- procedure Register;
- begin
- RegisterComponents('Standard', [TSendKeys]);
- end;
-
- { TSendKeys }
-
-
- function PRVGetChildHandle(H:HWND; L: Integer): LongBool;
- var p:pchar;
- I:integer;
- s:string;
- begin
- I:=length(ChildText)+2;
- GetMem(p,i+1);
- SendMessage(H,WM_GetText,i,integer(p));
- s:=strpcopy(p,s);
- if pos(ChildText,s)<>0 then
- begin
- HTemp:=H;
- Result:=False
- end else
- Result:=True;
- FreeMem(p);
- end;
-
- function PRVSendKeys(H: HWND; L: Integer): LongBool;stdcall;
- var s:string;
- i:integer;
- begin
- i:=length(temps);
- if i<>0 then
- begin
- SetLength(s,i+2);
- GetWindowText(H, pchar(s),i+2);
- if Pos(temps,string(s))<>0 then
- begin
- Result:=false;
- if ChildWindow then
- EnumChildWindows(H,@PRVGetChildHandle,L)
- else
- HTemp:=H;
- end
- else
- Result:=True;
- end else
- Result:=False;
- end;
-
- procedure TSendKeys.GetWindowHandle(Text: String);
- begin
- temps:=Text;
- ChildText:=fChildText;
- ChildWindow:=fChild;
- EnumWindows(@PRVSendKeys,L);
- fHandle:=HTemp;
- end;
-
-
- procedure TSendKeys.SendKeys(buffer: string);
- var i:integer;
- w:word;
- D:DWORD;
- P:^DWORD;
- begin
- P:=@D;
- SystemParametersInfo( //get flashing timeout on win98
- SPI_GETFOREGROUNDLOCKTIMEOUT,
- 0,
- P,
- 0);
- SetForeGroundWindow(fHandle);
- for i:=1 to length(buffer) do
- begin
- w:=VkKeyScan(buffer[i]);
- keybd_event(w,0,0,0);
- keybd_event(w,0,KEYEVENTF_KEYUP,0);
- end;
- SystemParametersInfo( //set flashing TimeOut=0
- SPI_SETFOREGROUNDLOCKTIMEOUT,
- 0,
- nil,
- 0);
- SetForegroundWindow(TWinControl(TComponent(Self).Owner).Handle);
- //->typecast working...
- SystemParametersInfo( //set flashing TimeOut=previous value
- SPI_SETFOREGROUNDLOCKTIMEOUT,
- D,
- nil,
- 0);
- end;
-
- procedure TSendKeys.SetChildText(const Value: string);
- begin
- fChildText := Value;
- end;
-
- procedure TSendKeys.SetIsChildWindow(const Value: boolean);
- begin
- fchild := Value;
- end;
-
- procedure TSendKeys.SetWindowHandle(const Value:HWND);
- begin
- fHandle:=WindowHandle;
- end;
- end.
-
-
-
-
-
-
-
-
- procedure TForm1.Button1Click(Sender: TObject);
- begin
-
- WinExec('NotePad.exe', SW_SHOW);
-
-
- SendKeys1.GetWindowHandle('Untitled - Notepad');
-
- if SendKeys1.WindowHandle <> 0 then
- SendKeys1.SendKeys('This is a test');
-
-
- // SendKeys1.SendKeys(Chr(13));
- end;
 |
Ответ отправил: Feniks (статус: Бакалавр)
Время отправки: 29 августа 2008, 11:27
Оценка за ответ: 5
Комментарий к оценке: супер
|
Мини-форум вопроса
Всего сообщений: 5; последнее сообщение — 30 августа 2008, 12:40; участников в обсуждении: 4.
|
Gooddy (статус: 3-ий класс), 29 августа 2008, 17:13 [#1]:
FindWindow('заголовок окна','тип') типы какие есть?
Чисти код! Чисти код! Чисти код!
|
|
Вадим К (статус: Академик), 29 августа 2008, 17:39 [#3]:
я постоянно их путаю. когда есть делфи - можно всегда подсмотреть в списке параметов.
Но оставить на английском, Феникс, это немного жестоко .
строка FindWindow(nil, 'Блокнот') найдет хендл первого окна, которое имеет заголовок "Блокнот". А вот что такое первое окно - оставте на совесть windows.
Один с параметров можно всегда поставить nil = это значит, что вы не хотите его заполнять или не знаете. Но оба - нельзя.
Галочка "подтверждения прочтения" - вселенское зло.
|
|
Паровоз (статус: 10-ый класс), 29 августа 2008, 18:41 [#4]:
"Но оставить на английском, Феникс, это немного жестоко"
Тяжело в учении, легко в бою.
|
|
Gooddy (статус: 3-ий класс), 30 августа 2008, 12:40 [#5]:
"Но оставить на английском, Феникс, это немного жестоко"
я знаю английский, спасибо
Чисти код! Чисти код! Чисти код!
|
31 января 2011, 19:31: Статус вопроса изменён на решённый (изменил модератор Ерёмин А.А.): Автоматическая обработка (2 и более ответов с оценкой 5)
Чтобы оставлять сообщения в мини-форумах, Вы должны авторизироваться на сайте.
|