Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 2006.06.04;
Скачать: [xml.tar.bz2];

Вниз

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

 
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;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.51 MB
Время: 0.058 c
15-1147551749
alex-drob
2006-05-14 00:22
2006.06.04
Сохранить/загрузить динамический массив


15-1146945909
ArtemESC
2006-05-07 00:05
2006.06.04
Поменять язык WINXP по умолчанию...


2-1148119883
Glex
2006-05-20 14:11
2006.06.04
Как получить имена всех подпапок, находящихся в данной папке?


1-1145976859
Radistka Cat
2006-04-25 18:54
2006.06.04
подсветка отдельных слов в RichEdit


15-1147070109
Nic
2006-05-08 10:35
2006.06.04
Задача со строками





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский