Подскажите, пожалуйста, как научить программу отлавливать факт нажатия кнопок клавиатуры в окне другого приложения?
В общем нужно что-то типа клавиатурного шпиона написать...
Глобальный хук на клавиатуру?
Вот тут есть пример на C#: http://www.codeproject.com/KB/cs/globalhook.aspx
Спасибо! Теперь другой вопрос: как в окно другого приложения (например, Word'а) записать какой-то текст, который был отловлен моей программой?
А оно тебе надо писать это в окно Word-а? Создать DOC-файл и открыть его Word-ом будет недостаточно?
да, мне это нужно
Мне нужно написать прогу наподобие PuntoSwitcher.
Ну, тогда смотри, как работать с Word-ом: http://www.codeproject.com/KB/cs/Word_Automation.aspx?display=Print, больше помочь ничем не могу, .NET - это не мое
Word - это я просто в качестве примера привел. А вообще мне нужно: отловить ввод текста, определить последнее окно, в котором клавиши нажимались, стереть введенный текст и заменить транслитированным.
Сейчас я хочу узнать, как обратиться к окну другого приложения. Или хотя бы как это правильно сформулировать, чтобы поискать можно было. Я правильно понимаю, что мне нужен хэндл окна? еще нужно определить текстовое поле на этом окне...
В общем, если кто подскажет, будет здорово
определять хэндл окна по его названию научился - findwindow, но это не совсем то, что нужно...
Вот спасибо! оказывается есть полно полезных функций!
Гмм... GetFocus все время возвращает 0... в чем может быть дело?
Ну и чего ты творишь? Я ж тебе дал ссылку на MSDN, там явно сказано:
// Получаем хэндл активного приложенияВозможно, .NET позволяет сделать это же самое и проще...
HWND hWnd = ::GetForegroundWindow();
DWORD myProcessId, otherProcessId;
DWORD otherThread=::GetWindowThreadProcessId(hWnd, &otherProcessId);
DWORD myThread = ::GetWindowThreadProcessId(mуWnd, &myProcessId);
// Подключаемся к другому потоку
::AttachThreadInput(myThread, otherThread, true);
// Получаем в его контексте дочернее окно с фокусом, обрабатываем его как нужно
HWND hWndOfFocused = ::GetFocus();
// И отсоединяемся от чужого процесса
::AttachThreadInput(myThread, otherThread, false);
спасибо, попробовал сделать по шагам - споткнулся на GetFocus - возвращает ноль.
winH = GetForegroundWindow();
int otherThread = GetWindowThreadProcessId(winH, out otherProcessId);
int myThread = GetWindowThreadProcessId(this.Handle, out myProcessId);
AttachThreadInput(myThread, otherThread, true);
IntPtr n = GetFocus();
for (int i = 0; i < buf.Count; i++)
SendKeys.Send("{BACKSPACE}");
LoadKeyboardLayout(LANG_EN_US, KLF_ACTIVATE);
foreach (int i in buf)
SendKeys.Send(abc[1, i - 'а']);
LoadKeyboardLayout(LANG_Ru_RU, KLF_ACTIVATE);
SendMessage(txtbox, WM_SETFOCUS, nul, nul);
SendMessage(txtbox, WM_KEYDOWN, (IntPtr) 'х', nul);
SendMessage(txtbox, WM_CHAR, (IntPtr) 'х', nul);
SendMessage(txtbox, WM_KEYUP, (IntPtr) 'х', nul);
txtbox = FindWindowEx(winH, IntPtr.Zero, "Edit", null);
::SendMessage(hWndOfFocused, WM_SETTEXT, 0,(long int)"Just a test\0");, приводит к появлению этого текста в чужом приложении... НО!!! Не везде, естественно. Универсального способа нет и вряд ли он будет, потому что это сработает только тогда, когда контрол является оконным, то есть, если у него вообще есть HWND. А если нет? А если чужое приложение рисует на канве (как это делал ICQ, например, в форме быстрого ответа. Не знаю, может сейчас уже изменили, и там тоже используются оконные компоненты?), что тогда делать будешь?
Update: ответ на вопрос
Установил себе наконец-то SharpDevelop, написал так:
void getActControl(IntPtr myWnd), ни в случае активного NotePad-а, ни в случае активного Word-а не получаю нулей в myFocused...
{
while(myWnd != IntPtr.Zero)
{
uint otherPID = 0;
uint otherTID = NativeMethods.GetWindowThreadProcessId(myWnd, out otherPID);
NativeMethods.AttachThreadInput(NativeMethods.GetCurrentThreadId(), otherTID, true);
IntPtr myFocused = NativeMethods.GetFocus();
NativeMethods.AttachThreadInput(NativeMethods.GetCurrentThreadId(), otherTID, false);
st += "Handle = " + myWnd.ToString() + " (Focused: " + myFocused.ToString() + ") \n";
getActControl(NativeMethods.GetWindow(myWnd, 5)); // 5 = GW_CHILD
myWnd = NativeMethods.GetWindow(myWnd, 2); // 2 = GW_HWNDNEXT
}
}
// Вызываю так:
string st = "";
IntPtr actWin = NativeMethods.GetForegroundWindow();
st += "** Handle: " + actWin.ToString() + "\n";
getActControl(NativeMethods.GetWindow(actWin, 5)); // 5 = GW_CHILD
foreach(string ss in st.Split('\n')) {
listBox1.Items.Add(ss);
}
Если я не ошибаюсь, я пробовал на ICQ...
Спасибо за помощь, программу написал - с помощью SendKeys )