Як включити великі букви в чужому процесі
Як включити великі букви в чужому процесі?
допустимо на формі є кілька кнопок і таймер 100мс.
ось код таймера який буде переміщати фокус по кнопках:
procedure Tmform.Timer1Timer (Sender: TObject);
begin
PostMessage (Handle, WM_KEYDOWN, VK_TAB, 0);
PostMessage (Handle, WM_KEYUP, VK_TAB, 0);
end;
Використання WM_CHAR при цьому нічого не робить.
А ось такий код, успішно переміщує курсор в початок тексту в блокноті:
var h, hm, tid, ctid: THandle;
# XA0; # XA0; ks: TKeyboardstate;
begin
hm: = GetForegroundWindow;
ctid: = GetCurrentThreadId ();
tid: = GetWindowThreadProcessId (hm);
if tid <> ctid then AttachThreadInput (ctid, tid, true);
h: = GetFocus;
fillchar (ks, sizeof (TKeyboardState), 0);
ks [VK_CONTROL]: = $ 80;
SetKeyboardState (ks);
SendMessage (h, WM_KEYDOWN, VK_HOME, 0);
SendMessage (h, WM_KEYUP, VK_HOME, 0);
ks [VK_CONTROL]: = $ 00;
SetKeyboardState (ks);
if tid <> ctid then AttachThreadInput (ctid, tid, false);
end;
Можна і SendMessage - на notepad діє (див. [42]). Головне що при цьому чомусь працює і SetKeyboardState, і відповідно можна адже будь-яку комбінацію зробити.
Обмеження SetKeyboardState:
Changes made to this table do not affect keyboard input to any other thread.
.
Because the SetKeyboardState function alters the input state of the calling thread and not the global input state of the system, an application can not use SetKeyboardState to set the NUM LOCK, CAPS LOCK, or SCROLL LOCK (or the Japanese KANA) indicator lights on the keyboard .
.
Тобто він не призведе до змін клавирного введення, в іншому потоці. # XA0; Для цього і викликати AttachInput. Крім цього - він не змінює стану клавіш, загального для всієї системи (типу * Lock).
> Крім цього - він не змінює стану клавіш, загального для
> Всієї системи (типу * Lock).
спробуй. Якщо правда програма реагує тільки на PostMessage (а таке дуже навіть може бути) - між викликами SetKeyboardState треба давати їй відпрацювати надійшли повідомлення (найпростіше - через Sleep). Оскільки PostMessage відправить повідомлення в чергу потоку відразу, а обробити вони швидше за все після завершення роботи твого коду (включаючи всі виклики SetKeyboardState).
Ай # 9786 ;. Знову помилки на уважність?
В сенсі? SetKeyboardState натисне CAPS LOCK в поточному процесі. Так само як і будь-яку іншу клавішу.
> Взагалі то я перевів це, що він лампочки на цих кнопках
> Включати не вміє.
> Можна як нибудь змусити його в іншому процесі працювати?
Я б спробував потрапити.
> Чи не натисне, це програмно не можна реалізувати (в сенсі фізичне
> Натискання).
А що, прямо-таки незрозуміло було, про що я говорив?
> Функція може встановити стан цієї клавіші для викликав
> потоку
І я про це ж. Тому незрозуміло, чим поведінка SetKeyboardState в сенсі установки стану CAPS LOCK відрізняється від випадків з іншими клавішами.
Справа не в аттаче, а синхронізації введення, і його обробки потоком Magic "a.
ks [VK_CONTROL]: = $ 80;
SetKeyboardState (ks);
PostMessage (. VK_HOME);
Sleep (200); // Magic must handle Ctrl-Home combination
ks [VK_CONTROL]: = $ 00;
SetKeyboardState (ks);
Тема дуже цікава. Хоча я ні коли на працював з клавіатурою на пряму вирішив спробувати включити / вимкнути лампочку КАПСЛОКУ. За годину випробувань отримав такий код:
keybd_event (VK_CAPITAL, 0,0,0);
keybd_event (VK_CAPITAL, 0, KEYEVENTF_KEYUP, 0);
змінює стан КАПСЛОКУ на протилежне.
А зприводу комбінації, припустимо Ctrl + A, на форумі писали:
Натиснути (Емулювати) Ctrl
натиснути А
відпустити А
відпустити Ctrl
або через keybd_event (для активної програми), або через PostMessage (для певної програми).
Вибачте, якщо повідомлення не в тему.
Я так давно Новомосковськ цю гілку, що забув про що питається.
Схоже, що моя відповідь в тему, а Ctrl + A зайве.
AttachThreadInput необхідний, як же без нього буде працювати SetKeyboardState
майже. замість $ FF # XA0; треба використовувати $ 81 або $ 80. При цьому старший біт відповідає стану клавіші - натиснута / не було натиснуто, а молодший - стан в попередній раз (тобто швидше використовується для GetKeyboardState).
Спробуй обійтися без Sleep:
begin
hm: = GetForegroundWindow;
ctid: = GetCurrentThreadId ();
tid: = GetWindowThreadProcessId (hm, pid);
if tid <> ctid then AttachThreadInput (ctid, tid, true);
hProcess: = OpenProcess (SYNCHRONIZE, false, pid);
h: = GetFocus;
GetKeyboardState (ks);
ks [VK_CONTROL]: = $ 81;
SetKeyboardState (ks);
PostMessage (h, WM_KEYDOWN, VK_HOME, 0);
PostMessage (h, WM_KEYUP, VK_HOME, 0);
if hProcess <> 0 then WaitForInputIdle (hProcess, 500)
# XA0; else sleep (500);
ks [VK_CONTROL]: = $ 00;
SetKeyboardState (ks);
if tid <> ctid then AttachThreadInput (ctid, tid, false);
CloseHandle (hProcess);
end;
Для більшої оптимізації hProcess можна отримувати при запуску програми, наприклад якщо запускати magic через CreateProcess.
Перевірив ще раз - перший варіант навіть регістр не зберігається.
Перед відправкою українських букв треба дійсно перемикати расскладку, але можна обійтися без keybd_event:
PostMessage (hWnd, WM_INPUTLANGCHANGEREQUEST, 0, $ 419); // switch to ru
PostMessage (hWnd, WM_INPUTLANGCHANGEREQUEST, 0, $ 409); // switch to eng
Щодо WaitForInputIdle - який результат функція повертає? Якщо помилку спробуй процес відкривати PROCESS_ALL_ACCESS.
З приводу регістра:
ks [VK_SHIFT]: = $ 81;
SetKeyboardState (ks);
PostMessage (hWnd, WM_CHAR, Ord ( "A"), 0);
Sleep (500);
ks [VK_SHIFT]: = $ 00;
SetKeyboardState (ks);
PostMessage (hWnd, WM_CHAR, Ord ( "b"), 0);
Sleep (500);
SendMessage (hWindow, WM_INPUTLANGCHANGE, $ CC, KBD);
Причому KBD можна будь-яку передавати. Головне - $ CC - на мові включити і всюди печататает і по російськи і по англійськи.
Вельми працездатний і слід. код. Треба тільки символи в верхньому регістрі передавати. Паузу я зазвичай ставлю в 5 - вистачає як правило для notepad.
d: = 5;
ks [vk_shift]: = ks [vk_shift] or $ 80;
SetKeyboardState (ks);
PostMessage (h, WM_KEYDOWN, Ord ( "A"), 0);
Sleep (d);
ks [vk_shift]: = ks [vk_shift] and $ 7F;
SetKeyboardState (ks);
Sleep (d);
PostMessage (h, WM_KEYDOWN, Ord ( "Q"), 0);
Sleep (d);
Якщо вставити в обробник таймера, друкувати: "AqAqAqAq"
Пам'ять: 0.8 MB
Час: 0.097 c