![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Как сделать окно активным и послать клавиши?
TStas © (2006-04-24 14:51:00)Через FindWindow(nil, 'Имя окна') нахожу окно и получаю на него handel.
А вот дальше... Ни Windows.SetFocus(handel) ни т.п. не помогает - окно как
было не активным, так активным и не стало.
Выход-то я нашел: почему-то через сервер сценариев все изумительно работает,
только вот мне вполне рабочий способ кажется слишком кривым, хотелось бы все
дельфями сделать, тем более, что точно так можно. Примеры скаченные с форума
почему-то тоже не работают. Послать надо Ctrl+V и Ctrl+Enter
Leonid Troyanovsky (2006-04-28 02:14:00) [1]
> Leonid Troyanovsky © (28.04.06 02:11) [18]
> tid := GetWindowThreadProcessID(h, nil);
..
> h := FindWindowEx(h, 0, 'EDIT', nil);
Имелось ввиду
h := FindWindowEx(h, 0, 'EDIT', nil);
tid := GetWindowThreadProcessID(h, nil);
Sorry.
--
Regards, LVT.
Leonid Troyanovsky (2006-04-28 02:11:00) [2]
> TStas © (27.04.06 14:53) [17]
> >Acidlex А разьве можно посылать комбинацию клавишь в неактивное
> окно?
Скорее всего, в общем случае, корректно сделать это не удастся.
Рассмотрим другой пример by Peter Below
http://groups.google.com/group/borland.public.delphi.nativeapi/msg/69c29080f4913c2b
И попробуем применить его к блокноту, посылая нажатие Сtrl+V,
т.е., вставка из буфера.
На моей w2k вставка происходит лишь так:
procedure TForm1.Button1Click(Sender: TObject);
var
tid: DWORD;
h: HWND;
begin
tid := GetWindowThreadProcessID(h, nil);
h := FindWindow('Notepad', nil);
h := FindWindowEx(h, 0, 'EDIT', nil);
AttachThreadInput(GetCurrentThreadId, tid, True);
Windows.SetFocus(h); // необходимо передать фокус Блокноту
PostKeyEx(h, Ord('V'), [ssCtrl], false);
Windows.SetFocus(Handle);
AttachThreadInput(GetCurrentThreadId, tid, false);
end;
если, кроме того,
PostMessage( hWindow, WM_KEYUP, key, lparam or $C0000000);
заменить на
SendMessage( hWindow, WM_KEYUP, key, lparam or $C0000000);
(Вместо Application.ProcessMessages использован Sleep(100))
Понятно, что в данном конкретном случае добиться желаемого
можно было б проще, послав окну WM_CHAR ^C, или WM_PASTE,
но, комбинация клавиш выглядит именно так.
Т.е., из-за того, что фокус, все равно, необходимо переместить
на целевое окно, способ с посылкой сообщений никаких
преимуществ по сравнению с keybd_event не имеет.
--
Regards, LVT.
TStas (2006-04-27 14:53:00) [3]>Acidlex А разьве можно посылать комбинацию клавишь в неактивное окно?
Acidlex (2006-04-27 13:47:00) [4]Когда то у меня была подобная задача, но
мне надо было посылать комбинации клавиш без активизации окна.
К сожалению я ее не решил, может кто нибуть поможет :)
Плюс ко всему, некоторые программы, кроме обработки сообщения, сканируют клавиатуру на нажатие клавиш.
был пример через JournalPlaybackProc (точно непомню), но работал с глюками :( , а сам я неразобрался.
TStas (2006-04-26 19:30:00) [5]Все теперь хорошо работает, прямо сейчас пользуюсь.
>ANB PostMessage пробовал, в lParam писал 0 совсем не работало
SuperBUG (2006-04-26 16:24:00) [6]TStas © ,
а где ты сказал что фокус обратно должен вернуться????
Что касается предложенной <Царев Евгений © > функцией SetForegroundWindow,то все очень здорово работает,если только приложение ,которому все засылается не свернуто,иначе все теряется,т.е. первый вывод-если приложение свернуто-неплохо бы его в таком вырианте развернуть!!! А вот для возвращения фокуса своему приложению действительно неплохо подходит.
Cash (2006-04-26 13:26:00) [7]ANB © (26.04.06 09:58) [12]:
А чему должен быть равен LParam для этих сообщений?
(для: WM_KEYDOWN, WM_CHAR, WM_KEYUP).
ANB (2006-04-26 09:58:00) [8]Добавлю от себя имхо.
Иммитация нажатий через keybd_event работает неустойчиво.
SetForegroundWindow MS постоянно подрезает, то что работало в 98, не факт, что отработает в XP. Плюс любой случайный клик мышкой может все сломать.
Намного надежнее работает способ через сообщения (WM_KEYDOWN, WM_CHAR, WM_KEYUP). Причем можно не заботится о раскладке и регистре.
Царев Евгений (2006-04-26 08:31:00) [9]
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
{****************************PostKeyEx32**************************************** **********}
procedure PostKeyEx32(Key: Word; const Shift: TShiftState; SpecialKey: Boolean);
{************************************************************
* Procedure PostKeyEx32
*
* Parameters:
* key : virtual keycode of the key to send. For printable
* keys this is simply the ANSI code (Ord(character)).
* shift : state of the modifier keys. This is a set, so you
* can set several of these keys (shift, control, alt,
* mouse buttons) in tandem. The TShiftState type is
* declared in the Classes Unit.
* specialkey: normally this should be False. Set it to True to
* specify a key on the numeric keypad, for example.
* Description:
* Uses keybd_event to manufacture a series of key events matching
* the passed parameters. The events go to the control with focus.
* Note that for characters key is always the upper-case version of
* the character. Sending without any modifier keys will result in
* a lower-case character, sending it with [ssShift] will result
* in an upper-case character!
*Created: 17.7.98 by P. Below
************************************************************}
type
TShiftKeyInfo = record
Shift: Byte;
Vkey : Byte;
end;
ByteSet = set of 0..7;
const
ShiftKeys: array [1..3] of TShiftKeyInfo =
((Shift: Ord(ssCtrl); Vkey: VK_CONTROL),
(Shift: Ord(ssShift); Vkey: VK_SHIFT),
(Shift: Ord(ssAlt); Vkey: VK_MENU));
var
Flag: DWORD;
bShift: ByteSet absolute Shift;
I: Integer;
begin
for I := 1 to 3 do begin
if ShiftKeys[I].Shift In bShift Then
keybd_event(ShiftKeys[I].Vkey,MapVirtualKey(ShiftKeys[I].Vkey,0),0,0);
end;
if SpecialKey then
Flag := KEYEVENTF_EXTENDEDKEY
else
Flag := 0;
keybd_event(Key,MapvirtualKey(Key,0),Flag,0);
Flag := Flag or KEYEVENTF_KEYUP;
keybd_event(Key, MapvirtualKey(Key,0),Flag,0);
for i := 3 downto 1 do begin
if ShiftKeys[I].Shift In bShift then
keybd_event(ShiftKeys[I].Vkey,MapVirtualKey(ShiftKeys[I].Vkey,0),KEYEVENTF_KEYUP ,0);
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
var h:THandle;
begin
H := FindWindow('Notepad',nil);
if H > 0 then
if SetForegroundWindow(H) then
begin
// Извиняюсь что не Ord но что то с функцией(ORD) не получается на XP, в 2k все работало
PostKeyEx32(65,[ssShift],False);// A
PostKeyEx32(66,[],False);// b
PostKeyEx32(67,[],False);// c
PostKeyEx32(VK_RETURN,[],False);// Enter
PostKeyEx32(VK_F4,[ssAlt],False); // Закрываем блокнот Alt+F4
Sleep(5000); // ждем 5 секунд "Сохранять не сохранять" :)
//Application.Restore;// Если свернуто
SetForegroundWindow(Handle);// Активизируем форму
end;
end;
end.
TStas (2006-04-26 00:56:00) [10]С посылкой клавиш все получилось, только во что странно: ни Activate, ни Show, ни SetFocus ни даже SetActiveWindow(handle);
ShowWindow(handle,SW_SHOWNORMAL); не возвращают фокус моей программе, почему - непонятно. Скрипт возвращал.
TStas (2006-04-25 23:38:00) [11]Чего-то с посылкой клавиш не получается. Мне кажется, надо послать нажатие CTrl, потом V, Enter и отпускание Ctrl. PostMessage почему-то не срабатывает, а код
keybd_event( VK_RETURN,
13,
KEYEVENTF_EXTENDEDKEY or 0,0 ); я не понял. Enter при этом посылается, но вот как послать сочетание. Если можно, поподробнее.
И еще, не нужно ли вставлять задержку, все-таки это аська, пробами в скрипте я подобрал 2000 мс. Проверял пока код на блокнотике. Окно активным делается и строка переводится.
SuperBUG (2006-04-25 17:52:00) [12]ну так есть же заразница виртуал-кей и скан-код....
TStas (2006-04-25 17:45:00) [13]Так 17 и 13 вещи известные, просто у тебя указаны были другие числа, что меня и удивило
SuperBug (2006-04-24 19:39:00) [14]1.Что касается "каких-то длинных чисел" - то про них хорошо описано в справке по дельфи для WM_KEYDOWN как раз в пункте про lParam %)
2.те самые 13 для Enter и 17 для Ctrl - это и есть виртуальные коды клавиш, их помимо MSDN можно найти и в файле Windows.pas
3.а вот насчет посылки кодов через PostMessage меня гложут определенные сомнения,будут ли отрабатываться посланные нажатия совместно или по очереди....что-то мучают предположения,что второе ближе к истине
TStas (2006-04-24 19:22:00) [15]А вот в lParam какие-то длинные числа. Уж не знаю что это и учитываются ли они где
TStas (2006-04-24 19:01:00) [16]Вечером попробую. Только я пробовал посылать через PostMessage коды клавиш получал очень просто: положил ApplicationEvent и смотрел, что он мне покажет при нажатиях. Так он msg.wParam возвращал 17 для Ctrl и 13 для Enter.
SuperBug (2006-04-24 17:20:00) [17]чего-то в процессе исследования данного вопроса меня взял живой интерес,поэтому доведу уж этот пост до конца :)
1.в предыдущих постах есть маленький баг,в качестве скэн-кода должео стоять не 13 а 28,эти цифры получаются с использование функции MapVirtualKey, таблицу VK легко найти в MSDN
2. Чтобы иммитировать двойное нажатие клавиш типа Ctrl+V и Ctrl+Enter надо поочередно вызвать нажатие Ctrl (VK_CONTROL,scan 29) и V($56,scan 47), а затем вызвать отжатие этих клавиш, сначала V потом Ctrl, порядок вроде без разницы, но так красивше :)))))
3.флаг KEYEVENTF_EXTENDEDKEY вроде может и неиспользваться.
Вроде все,если будут уточнения и дополнения-пишите :)))
SuperBug (2006-04-24 16:29:00) [18]да,сразу извинюсь, из-за невнимательного прочтения MSDN вкралась досадная ошибка: после эмуляции нажатия необходимо сразу же эмулировать и отжатие,а то такая фигня будет....
код отжатия:
keybd_event( VK_RETURN,
13,
KEYEVENTF_EXTENDEDKEY or KEYEVENTF_KEYUP,0 );
SuperBug (2006-04-24 15:59:00) [19]После некоторых поисков по MSDN и прочим хэлпам удалось сконструировать следующий код, сразу хочу сказать что он не идеален,но поставленную задачу похоже решает
var Hndl:HWND;
ThrId:HWND;
begin
hndl:=FindWindow(nil,'Безымянный - Блокнот');
ThrID:=GetWindowThreadProcessId(hndl,nil);
if ThrID<>0 then
if AttachThreadInput(ThrID, GetCurrentThreadId,true) then
begin
SetActiveWindow(hndl);
ShowWindow(hndl,SW_SHOWNORMAL);
keybd_event( VK_RETURN,
13,
KEYEVENTF_EXTENDEDKEY or 0,0 );
AttachThreadInput(ThrID, GetCurrentThreadId,false);
end;
end;
единственно что, мне было лениво искать виртуальные коды для Ctrl+V и Ctrl+Enter поэтому этот примерчик делает активным окно блокнота и посылает туда просто Enter