Как отправить виртуальные ключи в другое приложение с помощью delphi 2010?

Мне нужно отправить несколько виртуальных ключей (VK_RETURN) из моего приложения delphi (myapp.exe) в другое приложение (target.exe). Eg : Send VK_RETURN twice , from myapp.exe , into target.exe

ОС, которые я использую, это Windows 7 64 бит и Windows XP.

Я прочитал: Как отправить нажатие клавиши ENTER другому приложение? , Отправить Ctrl+Key в стороннее приложение (у меня не сработало) и другие ранее заданные вопросы. Но все же я путаюсь.

Как установить фокус на целевое приложение?

Как отправить виртуальные ключи целевому приложению?

Простой пример: я хочу дважды отправить VK_RETURN в notepad.exe или calc.exe (уже загруженный) или любую другую программу из моего приложения Delphi. Как это сделать ?

Самый простой способ сделать это в Delphi 2010, пожалуйста...

PS: я попробовал SndKey32.pass с http://delphi.about.com/od/adptips2004/a/bltip1104_3.htm И получил ошибку: [Ошибка DCC] SndKey32.pas(420): E2010 Несовместимые типы: 'Char' и 'AnsiChar'

  If (Length(KeyString)=1) then MKey:=vkKeyScan(KeyString[1])

person Galvion    schedule 10.08.2013    source источник
comment
Что вы имеете в виду под фокусом. Окно или определенный элемент управления на нем?   -  person Tony Hopkinson    schedule 10.08.2013
comment
@Tony: фокус означает прямую отправку виртуальных ключей в target.exe   -  person Galvion    schedule 10.08.2013
comment
@ Кен Уайт: я уже прочитал эту одну и все предложенные ссылки, прежде чем задать этот вопрос. Но как отправить виртуальные ключи только в target.exe?   -  person Galvion    schedule 10.08.2013
comment
Если это трудно понять для моего вопроса, просто я хочу дважды отправить VK_RETURN в notepad.exe (уже загруженный) из моего приложения Delphi. Как это сделать ?   -  person Galvion    schedule 10.08.2013
comment
И допустим, что в Блокноте фокус направлен в главное меню, а не в текстовую область. Вы хотите, чтобы VK_RETURN вошел в этот текст, где находится курсор, или просто отправил нажатие клавиши туда, где находится фокус?   -  person Jerry Dodge    schedule 10.08.2013
comment
Сначала мне нужно знать, как отправить только нажатие клавиши? Но если не возражаете, подскажите, пожалуйста, еще как зайти в тест, где курсор в меню. Спасибо :)   -  person Galvion    schedule 10.08.2013
comment
Я показал, как это сделать (за исключением того, что я отправил Enter только один раз).   -  person Ken White    schedule 10.08.2013
comment
Вместо подделки ввода, не проще ли использовать автоматизацию?   -  person David Heffernan    schedule 10.08.2013
comment
@david: что ты имеешь в виду под автоматизацией?   -  person Galvion    schedule 11.08.2013
comment
Например, UIAutomation   -  person David Heffernan    schedule 11.08.2013
comment
Приложения @SidhiCiang не имеют фокуса, элемент управления в приложении имеет..   -  person Tony Hopkinson    schedule 11.08.2013


Ответы (1)


Если ваше целевое приложение не является окном переднего плана, вам необходимо использовать PostMessage для отправки нажатий клавиш дескриптору окна. Вы можете получить этот дескриптор окна, используя FindWindow. Приведенный ниже код отправляет клавишу Enter в текстовую область запущенного экземпляра Блокнота (обратите внимание, что он использует дополнительный FindWindowEx, чтобы сначала найти область заметок). Он был протестирован с использованием Delphi 2007 и Delphi XE4 (32-разрядная цель) в Windows 7 64.

uses Windows;
    
procedure TForm1.Button1Click(Sender: TObject);
var
  NpWnd, NpEdit: HWnd;
begin
  NpWnd := FindWindow('Notepad', nil);
  if NpWnd <> 0 then
  begin
    NpEdit := FindWindowEx(NpWnd, 0, 'Edit', nil);
    if NpEdit <> 0 then
    begin
      PostMessage(NpEdit, WM_KEYDOWN, VK_RETURN, 0);
      PostMessage(NpEdit, WM_KEYUP, VK_RETURN, 0); 
    end;
  end;
end;

Чтобы найти окно по заголовку (заголовку), вы можете просто использовать второй параметр FindWindow. Это находит новый экземпляр Блокнота с открытым файлом «Без названия» по умолчанию:

NpWnd := FindWindow(nil, 'Untitled - Notepad');

Обратите внимание, что для этого требуется точное совпадение с заголовком окна. Дополнительный пробел перед или после -, например, приведет к сбою сопоставления и невозможности получения дескриптора окна.

Вы можете использовать как класс окна, так и заголовок, если у вас запущено несколько экземпляров. Чтобы найти копию Блокнота, работающую с загруженным Readme.txt, вы должны использовать

NpWnd := FindWindow('Notepad', 'Readme.txt - Notepad');

Чтобы найти другие приложения, вам нужно будет использовать что-то вроде WinSpy или WinSight, чтобы найти имена оконных классов. (Есть и другие, такие как Wspawn или WinDowse (оба написаны на Delphi).)

В вашем комментарии упоминается Calculator; Согласно Wинспекции, главное окно Calculator относится к классу окна, называемому CalcFrame в Windows 7, а область, в которой отображаются числа, представляет собой окно Static (это означает, что оно, похоже, не получает нажатия клавиш напрямую). Кнопки называются просто Button, поэтому вам придется перебирать их, используя EnumChildWindows ищет отдельные кнопки, чтобы идентифицировать их, чтобы получить их дескрипторы.

(Как перечислить дочерние окна — это отдельный вопрос; вы, вероятно, можете найти пример, выполнив поиск здесь или через Google. Если вы не можете, опубликуйте новый отдельный вопрос об этом, и мы можем попытаться дать вам ответ.)

Вот краткий пример отправки ключей в Калькулятор после его нахождения по классу окна. Он не делает ничего полезного, потому что ему нужно некоторое время, чтобы определить различные кнопки и клавиши, на которые каждая из них реагирует (и правильную комбинацию сообщений). Этот код просто отправляет 11Numpad+22 в окно калькулятора (a быстрый тест показал, что они правильно принимаются и отображаются, и это примерно все время, которое я хотел потратить на процесс).

uses Windows;

procedure TForm1.Button1Click(Sender: TObject);
var
  NpWnd: HWnd;
begin
  NpWnd := FindWindow('CalcFrame',  nil);
  if NpWnd <> 0 then
  begin
    PostMessage(NpWnd, WM_KEYDOWN, VK_NUMPAD1, 0);
    PostMessage(NpWnd, WM_KEYDOWN, VK_ADD, 0);
    PostMessage(NpWnd, WM_KEYDOWN, VK_NUMPAD2, 0);
  end;
end;
person Ken White    schedule 10.08.2013
comment
да, в блокноте работает. А как быть с другим приложением? У меня есть приложение с именами DKQC.EXE и DKQG.EXE, которому я хочу отправить двойное нажатие клавиши Enter (VK_Return) внутри DKQG.EXE для кнопки и ее подтверждающего сообщения, чтобы заменить щелчок мышью. - person Galvion; 11.08.2013
comment
а может можно протестировать скрипт с acdess12.exe, где для открытия папки нажимаем return/enter. и чтобы открыть файл внутри, мы нажимаем еще один ввод (дважды ввод). как заставить его работать в ACDSee12.exe? потому что ваш скрипт работает только в блокноте. - person Galvion; 11.08.2013
comment
Мой скрипт (это не скрипт, это код) работает в Блокноте, потому что именно это он ищет (и что вы просили). Если вам нужно, чтобы он работал для другого приложения, вам нужно выяснить, какой класс окна вам нужно искать - я не устанавливаю программное обеспечение, которое мне не нужно, на свой компьютер, чтобы понять это для вас. :-) Найдите WinSpy или WinSight, которые помогут вам найти эту информацию (так же, как я сделал для Блокнота). - person Ken White; 11.08.2013
comment
Это работает для всех случаев? Я думаю, что UIPI в Vista+ будет блокировать подобный код в случае, если целевое приложение запускается с повышенными привилегиями по отношению к приведенному выше коду (т. е. отправка пользовательского кода чему-либо, запускаемому от имени администратора и т. д.). - person J...; 12.08.2013
comment
@J: Вероятно, нет, но в вопросе не говорилось о том, что что-то работает за пределами привилегий. Он специально спрашивал об отправке двух клавиш ввода, а в комментариях говорил о notepad.exe. Я почти уверен, что почти ничего не работает во всех случаях; Я уверен, что у большинства вещей может быть крайний случай, когда что-то не работает. :-) Почти ничего не работает вне границ привилегий, переходя от более низких привилегий к более высоким; если бы они это сделали, это было бы серьезной дырой в безопасности. - person Ken White; 12.08.2013
comment
@ken: Спасибо за исходный код блокнота. Вам не нужно устанавливать приложения. Потому что ваш код работает в блокноте, но когда я пробую его в calc.exe (калькулятор Windows), он не работает. Это больше похоже на то, что FindWindow и FindWindowEx не могут найти calc.exe, но могут найти notepad.exe (я использую Process Explorer. И у меня есть контроль администратора в моем логине). - person Galvion; 15.08.2013
comment
Или, может быть, есть какой-нибудь код для поиска приложения на основе заголовка Windows, а не только класса окна? Потому что я пытаюсь заменить «Блокнот» на «SciCalc», и я работаю или могу отправить нажатие клавиши в calc.exe. Но когда я заменяю его на «TDkForm», он может распознать TDkForm, но не может отправить нажатие клавиши в нужное мне приложение. Любая идея найти приложение на основе класса Windows и заголовка Windows? - person Galvion; 15.08.2013
comment
Я связал вас с документацией и дал вам информацию о WinSpy и WinSight (есть также WInspector и WinDowse). Если вы собираетесь использовать WinAPI для каких-либо действий, иногда вам нужно прочитать документацию и разобраться во всем. Я обновлю свой код, чтобы также отправить пару цифровых ключей в Calc (и найти его по имени), но после этого вам нужно использовать инструменты, которые я вам дал, и потратить некоторое время, пытаясь понять это самостоятельно. :-) - person Ken White; 15.08.2013
comment
@ShaunRoselt: Windows отправляет их на основе ввода пользователя. - person Ken White; 10.10.2020
comment
@KenWhite Да, но я спрашивал, в какой единице содержатся WM_KEYDOWN и WM_KEYUP. Итак, что вы должны использовать в своем списке использования, чтобы использовать их. - person Shaun Roselt; 12.10.2020
comment
@ShaunRoselt: они определены в Windows.pas. - person Ken White; 12.10.2020