IPB
ЛогинПароль:

> Внимание!

1. Пользуйтесь тегами кода. - [code] ... [/code]
2. Точно указывайте язык, название и версию компилятора (интерпретатора).
3. Название темы должно быть информативным.
В описании темы указываем язык!!!

Наладить общение поможет, если вы подпишитесь по почте на новые темы в этом форуме.

 
 Ответить  Открыть новую тему 
> работа с клавиатурой, C#, MSVS08
сообщение
Сообщение #1


Пионер
**

Группа: Пользователи
Сообщений: 104
Пол: Мужской
Реальное имя: Евгений

Репутация: -  0  +


Подскажите, пожалуйста, как научить программу отлавливать факт нажатия кнопок клавиатуры в окне другого приложения?
В общем нужно что-то типа клавиатурного шпиона написать...


--------------------
go ask Alice
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #2


Гость






Глобальный хук на клавиатуру?

Вот тут есть пример на C#: Processing Global Mouse and Keyboard Hooks in C#
 К началу страницы 
+ Ответить 
сообщение
Сообщение #3


Пионер
**

Группа: Пользователи
Сообщений: 104
Пол: Мужской
Реальное имя: Евгений

Репутация: -  0  +


Спасибо! Теперь другой вопрос: как в окно другого приложения (например, Word'а) записать какой-то текст, который был отловлен моей программой?


--------------------
go ask Alice
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #4


Гость






А оно тебе надо писать это в окно Word-а? Создать DOC-файл и открыть его Word-ом будет недостаточно?
 К началу страницы 
+ Ответить 
сообщение
Сообщение #5


Пионер
**

Группа: Пользователи
Сообщений: 104
Пол: Мужской
Реальное имя: Евгений

Репутация: -  0  +


да, мне это нужно smile.gif
Мне нужно написать прогу наподобие PuntoSwitcher.


--------------------
go ask Alice
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #6


Гость






Ну, тогда смотри, как работать с Word-ом: Word Automation, больше помочь ничем не могу, .NET - это не мое smile.gif
 К началу страницы 
+ Ответить 
сообщение
Сообщение #7


Пионер
**

Группа: Пользователи
Сообщений: 104
Пол: Мужской
Реальное имя: Евгений

Репутация: -  0  +


Word - это я просто в качестве примера привел. А вообще мне нужно: отловить ввод текста, определить последнее окно, в котором клавиши нажимались, стереть введенный текст и заменить транслитированным.
Сейчас я хочу узнать, как обратиться к окну другого приложения. Или хотя бы как это правильно сформулировать, чтобы поискать можно было. Я правильно понимаю, что мне нужен хэндл окна? еще нужно определить текстовое поле на этом окне...
В общем, если кто подскажет, будет здорово smile.gif


--------------------
go ask Alice
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #8


Пионер
**

Группа: Пользователи
Сообщений: 104
Пол: Мужской
Реальное имя: Евгений

Репутация: -  0  +


определять хэндл окна по его названию научился - findwindow, но это не совсем то, что нужно...


--------------------
go ask Alice
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #9


Гость






Цитата
Я правильно понимаю, что мне нужен хэндл окна? еще нужно определить текстовое поле на этом окне...
Ты правильно понимаешь... На WinAPI это делается через FindWindow/FindWindowEx, в Шарпе - насколько я знаю - через вызов этих же функций с использованием механизма pInvoke. Последнее окно - это то, которое имеет фокус ввода? API-шная GetFocus Function тебе поможет (вызывать - через тот же pInvoke)... Вот и все собственно...
 К началу страницы 
+ Ответить 
сообщение
Сообщение #10


Пионер
**

Группа: Пользователи
Сообщений: 104
Пол: Мужской
Реальное имя: Евгений

Репутация: -  0  +


Вот спасибо! оказывается есть полно полезных функций! smile.gif


--------------------
go ask Alice
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #11


Пионер
**

Группа: Пользователи
Сообщений: 104
Пол: Мужской
Реальное имя: Евгений

Репутация: -  0  +


Гмм... GetFocus все время возвращает 0... в чем может быть дело?

Код
if (winH != GetFocus())
            {
                buf = new List<int>();
                winH = GetFocus();
            }
            buf.Add(e.KeyValue);
            textBox1.Text += e.KeyCode;


Добавлено через 18 мин.
Вроде бы GetForegroundWindow - то, что нужно! )


--------------------
go ask Alice
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #12


Гость






Ну и чего ты творишь? Я ж тебе дал ссылку на MSDN, там явно сказано:
Цитата
Return Value
The return value is the handle to the window with the keyboard focus. If the calling thread's message queue does not have an associated window with the keyboard focus, the return value is NULL.
...
Use the GetForegroundWindow function to retrieve the handle to the window with which the user is currently working. You can associate your thread's message queue with the windows owned by another thread by using the AttachThreadInput function.


Вот так это приблизительно делается на WinAPI:
// Получаем хэндл активного приложения
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);
Возможно, .NET позволяет сделать это же самое и проще...
 К началу страницы 
+ Ответить 
сообщение
Сообщение #13


Пионер
**

Группа: Пользователи
Сообщений: 104
Пол: Мужской
Реальное имя: Евгений

Репутация: -  0  +


спасибо, попробовал сделать по шагам - споткнулся на GetFocus - возвращает ноль.
winH = GetForegroundWindow();
int otherThread = GetWindowThreadProcessId(winH, out otherProcessId);
int myThread = GetWindowThreadProcessId(this.Handle, out myProcessId);
AttachThreadInput(myThread, otherThread, true);
IntPtr n = GetFocus();

В чем может быть дело?

Пробовал сделать по-другому: через SendKeys.Send, но возникла проблема с раскладками - чтобы вывести транслитированный текст с помощью Send, нужно сменить раскладку в окне активного приложения - никак не могу разобраться, как это сделать!
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);

Но, видимо, LoadKeyboardLayout меняет раскладку только в моей программе... пробовал подключиться к потоку другого приложения - не помогло.

Обойтись без раскладок, в принципе, можно - используя SendMessage:
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.
txtbox = FindWindowEx(winH, IntPtr.Zero, "Edit", null);

Это работает для NotePad'а, а универсальный способ есть?


--------------------
go ask Alice
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #14


Гость






Цитата
попробовал сделать по шагам - споткнулся на GetFocus - возвращает ноль.
Хм... Надо будет установить себе хотя бы SharpDevelop, посмотреть, что творится в C#, потому как приведенный мной код в C++ отрабатывает прекрасно, GetFocus получает дескриптор активного контрола, и посылка в него, скажем,
::SendMessage(hWndOfFocused, WM_SETTEXT, 0,(long int)"Just a test\0");
, приводит к появлению этого текста в чужом приложении... НО!!! Не везде, естественно. Универсального способа нет и вряд ли он будет, потому что это сработает только тогда, когда контрол является оконным, то есть, если у него вообще есть HWND. А если нет? А если чужое приложение рисует на канве (как это делал ICQ, например, в форме быстрого ответа. Не знаю, может сейчас уже изменили, и там тоже используются оконные компоненты?), что тогда делать будешь?

Кстати, еще один способ (опять же, только для оконных контролов) - получить активное приложение через GetForegroundWindow, а потом пройтись по каждому из его дочерних окон, то есть, перебрать все суб-контролы этого приложения (удобно делается через EnumChildWindows), для каждого получать GetWindowInfo, и проверять в полученной структуре поле dwWindowStatus. Если оно == WS_ACTIVECAPTION, значит, нашел контрол, на котором фокус ввода.
 К началу страницы 
+ Ответить 
сообщение
Сообщение #15


Гость






Update: ответ на вопрос
Цитата
GetFocus - возвращает ноль. <...> В чем может быть дело?

WinForms FAQ - "// Note that if the focused Control is not a .Net control, then this will return null."
 К началу страницы 
+ Ответить 
сообщение
Сообщение #16


Гость






Цитата
WinForms FAQ - "// Note that if the focused Control is not a .Net control, then this will return null."

т.е., к примеру, поле мемо программы, написанной в билдере, я не смогу определить как выделенное?
 К началу страницы 
+ Ответить 
сообщение
Сообщение #17


Гость






Установил себе наконец-то SharpDevelop, написал так:

      void getActControl(IntPtr myWnd)
{
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);
}
, ни в случае активного NotePad-а, ни в случае активного Word-а не получаю нулей в myFocused...
 К началу страницы 
+ Ответить 
сообщение
Сообщение #18


Пионер
**

Группа: Пользователи
Сообщений: 104
Пол: Мужской
Реальное имя: Евгений

Репутация: -  0  +


Если я не ошибаюсь, я пробовал на ICQ...
Спасибо за помощь, программу написал - с помощью SendKeys )


--------------------
go ask Alice
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 

 Ответить  Открыть новую тему 
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 





- Текстовая версия 26.04.2024 7:36
500Gb HDD, 6Gb RAM, 2 Cores, 7 EUR в месяц — такие хостинги правда бывают
Связь с администрацией: bu_gen в домене octagram.name