Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2006.06.04;
Скачать: CL | DM;

Вниз

Как сделать окно активным и послать клавиши?   Найти похожие ветки 

 
TStas ©   (2006-04-24 14:51) [0]

Через FindWindow(nil, "Имя окна") нахожу окно и получаю на него handel.
А вот дальше... Ни Windows.SetFocus(handel) ни т.п. не помогает - окно как
было не активным, так активным и не стало.
Выход-то я нашел: почему-то через сервер сценариев все изумительно работает,
только вот мне вполне рабочий способ кажется слишком кривым, хотелось бы все
дельфями сделать, тем более, что точно так можно. Примеры скаченные с форума
почему-то тоже не работают. Послать надо Ctrl+V и Ctrl+Enter


 
SuperBug ©   (2006-04-24 15:59) [1]

После некоторых поисков по 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


 
SuperBug ©   (2006-04-24 16:29) [2]

да,сразу извинюсь, из-за невнимательного прочтения MSDN вкралась досадная ошибка: после эмуляции нажатия необходимо сразу же эмулировать и отжатие,а то такая фигня будет....
код отжатия:
   keybd_event( VK_RETURN,
                    13,
                    KEYEVENTF_EXTENDEDKEY or KEYEVENTF_KEYUP,0 );


 
SuperBug ©   (2006-04-24 17:20) [3]

чего-то в процессе исследования данного вопроса меня взял живой интерес,поэтому доведу уж этот пост до конца :)
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 вроде может и неиспользваться.

Вроде все,если будут уточнения и дополнения-пишите :)))


 
TStas ©   (2006-04-24 19:01) [4]

Вечером попробую. Только я пробовал посылать через PostMessage коды клавиш получал очень просто: положил ApplicationEvent и смотрел, что он мне покажет при нажатиях. Так он msg.wParam возвращал 17 для Ctrl и 13 для Enter.


 
TStas ©   (2006-04-24 19:22) [5]

А вот в lParam какие-то длинные числа. Уж не знаю что это и учитываются ли они где


 
SuperBug ©   (2006-04-24 19:39) [6]

1.Что касается "каких-то длинных чисел" - то про них хорошо описано в  справке по дельфи для WM_KEYDOWN как раз в пункте про lParam %)
2.те самые 13 для Enter и 17 для Ctrl - это и есть виртуальные коды клавиш, их помимо MSDN можно найти и в файле Windows.pas
3.а вот насчет посылки кодов через PostMessage меня гложут определенные сомнения,будут ли отрабатываться посланные нажатия совместно или по очереди....что-то мучают предположения,что второе ближе к истине


 
TStas ©   (2006-04-25 17:45) [7]

Так 17 и 13 вещи известные, просто у тебя указаны были другие числа, что меня и удивило


 
SuperBUG ©   (2006-04-25 17:52) [8]

ну так есть же заразница виртуал-кей и скан-код....


 
TStas ©   (2006-04-25 23:38) [9]

Чего-то с посылкой клавиш не получается. Мне кажется, надо послать нажатие CTrl, потом V, Enter и отпускание Ctrl. PostMessage почему-то не срабатывает, а код
keybd_event( VK_RETURN,
                    13,
                    KEYEVENTF_EXTENDEDKEY or 0,0 ); я не понял. Enter при этом посылается, но вот как послать сочетание. Если можно, поподробнее.
И еще, не нужно ли вставлять задержку, все-таки это аська, пробами в скрипте я подобрал 2000 мс. Проверял пока код на блокнотике. Окно активным делается и строка переводится.


 
TStas ©   (2006-04-26 00:56) [10]

С посылкой клавиш все получилось, только во что странно: ни Activate, ни Show, ни SetFocus ни даже SetActiveWindow(handle);
   ShowWindow(handle,SW_SHOWNORMAL); не возвращают фокус моей программе, почему - непонятно. Скрипт возвращал.


 
Царев Евгений ©   (2006-04-26 08:31) [11]


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.



 
ANB ©   (2006-04-26 09:58) [12]

Добавлю от себя имхо.

Иммитация нажатий через keybd_event работает неустойчиво.
SetForegroundWindow MS постоянно подрезает, то что работало в 98, не факт, что отработает в XP. Плюс любой случайный клик мышкой может все сломать.

Намного надежнее работает способ через сообщения (WM_KEYDOWN, WM_CHAR, WM_KEYUP). Причем можно не заботится о раскладке и регистре.


 
Cash ©   (2006-04-26 13:26) [13]

ANB ©   (26.04.06 09:58) [12]:
А чему должен быть равен LParam для этих сообщений?
(для: WM_KEYDOWN, WM_CHAR, WM_KEYUP).


 
SuperBUG ©   (2006-04-26 16:24) [14]

TStas © ,
а где ты сказал что фокус обратно должен вернуться????
Что касается предложенной <Царев Евгений © > функцией SetForegroundWindow,то все очень здорово работает,если только приложение ,которому все засылается не свернуто,иначе все теряется,т.е. первый вывод-если приложение свернуто-неплохо бы его в таком вырианте развернуть!!! А вот для возвращения фокуса своему приложению действительно неплохо подходит.


 
TStas ©   (2006-04-26 19:30) [15]

Все теперь хорошо работает, прямо сейчас пользуюсь.
>ANB PostMessage пробовал, в lParam писал 0 совсем не работало


 
Acidlex   (2006-04-27 13:47) [16]

Когда то у меня была подобная задача, но
мне надо было посылать комбинации клавиш без активизации окна.
К сожалению я ее не решил, может кто нибуть поможет :)

Плюс ко всему, некоторые программы, кроме обработки сообщения, сканируют клавиатуру на нажатие клавиш.

был пример через JournalPlaybackProc (точно непомню), но работал с глюками :( , а сам я неразобрался.


 
TStas ©   (2006-04-27 14:53) [17]

>Acidlex  А разьве можно посылать комбинацию клавишь в неактивное окно?


 
Leonid Troyanovsky ©   (2006-04-28 02:11) [18]


> 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.


 
Leonid Troyanovsky ©   (2006-04-28 02:14) [19]


> 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.



Страницы: 1 вся ветка

Текущий архив: 2006.06.04;
Скачать: CL | DM;

Наверх




Память: 0.53 MB
Время: 0.032 c
9-1131153824
апвапв
2005-11-05 04:23
2006.06.04
opengl+шейдеры


15-1147291233
Victor_new
2006-05-11 00:00
2006.06.04
Wi-Fi


2-1147855038
aleshap
2006-05-17 12:37
2006.06.04
Метод


2-1147682133
Hitkliff
2006-05-15 12:35
2006.06.04
Опять WebBrowser


2-1148039229
kitti
2006-05-19 15:47
2006.06.04
Microsoft SQL Server