Есть USB-клавиатура. Требуется программно зажигать индикаторы Caps Lock, Scroll Lock и/или Num Lock. Нагуглил когда-то одно решение, но так понял, что оно только для PS/2 клавиатур. Программно эмулировать нажатие соответствующих клавиш, думаю, не подойдёт, потому что нажатие, например, Caps Lock всегда будет перехвачено системой и сами понимаете что будет. В какую сторону копать?
А>Есть USB-клавиатура. Требуется программно зажигать индикаторы Caps Lock, Scroll Lock и/или Num Lock. Нагуглил когда-то одно решение, но так понял, что оно только для PS/2 клавиатур. Программно эмулировать нажатие соответствующих клавиш, думаю, не подойдёт, потому что нажатие, например, Caps Lock всегда будет перехвачено системой и сами понимаете что будет. В какую сторону копать?
Здравствуйте, Andrew S, Вы писали:
А>>Есть USB-клавиатура. Требуется программно зажигать индикаторы Caps Lock, Scroll Lock и/или Num Lock. Нагуглил когда-то одно решение, но так понял, что оно только для PS/2 клавиатур. Программно эмулировать нажатие соответствующих клавиш, думаю, не подойдёт, потому что нажатие, например, Caps Lock всегда будет перехвачено системой и сами понимаете что будет. В какую сторону копать?
AS>Это? http://www.rsdn.ru/Forum/Message.aspx?mid=1357795&only=1
А>>>Есть USB-клавиатура. Требуется программно зажигать индикаторы Caps Lock, Scroll Lock и/или Num Lock. Нагуглил когда-то одно решение, но так понял, что оно только для PS/2 клавиатур. Программно эмулировать нажатие соответствующих клавиш, думаю, не подойдёт, потому что нажатие, например, Caps Lock всегда будет перехвачено системой и сами понимаете что будет. В какую сторону копать?
AS>>Это? http://www.rsdn.ru/Forum/Message.aspx?mid=1357795&only=1
Здравствуйте, Andrew S, Вы писали:
А>>>>Есть USB-клавиатура. Требуется программно зажигать индикаторы Caps Lock, Scroll Lock и/или Num Lock. Нагуглил когда-то одно решение, но так понял, что оно только для PS/2 клавиатур. Программно эмулировать нажатие соответствующих клавиш, думаю, не подойдёт, потому что нажатие, например, Caps Lock всегда будет перехвачено системой и сами понимаете что будет. В какую сторону копать?
AS>>>Это? http://www.rsdn.ru/Forum/Message.aspx?mid=1357795&only=1
А>>Да, вот это решение на моей USB-клавиатуре не работает
AS>Скорее всего, другое название устройства. Я думаю, самый правильный вариант — попробовать получить хендл устройства клавиатуры при помощи SetupApi.
Ты не мог бы рассказать о SetupApi чуть поподробнее, какие функции смотреть, например. Я с ним совсем не знаком.
А>>>>>Есть USB-клавиатура. Требуется программно зажигать индикаторы Caps Lock, Scroll Lock и/или Num Lock. Нагуглил когда-то одно решение, но так понял, что оно только для PS/2 клавиатур. Программно эмулировать нажатие соответствующих клавиш, думаю, не подойдёт, потому что нажатие, например, Caps Lock всегда будет перехвачено системой и сами понимаете что будет. В какую сторону копать?
AS>>>>Это? http://www.rsdn.ru/Forum/Message.aspx?mid=1357795&only=1
А>>>Да, вот это решение на моей USB-клавиатуре не работает
AS>>Скорее всего, другое название устройства. Я думаю, самый правильный вариант — попробовать получить хендл устройства клавиатуры при помощи SetupApi.
А>Ты не мог бы рассказать о SetupApi чуть поподробнее, какие функции смотреть, например. Я с ним совсем не знаком.
Попродробнее — в MSDN.
Вкратце — надо пронумерить устройства нужного класса (в данном случае — клавиатура), затем для каждого устройства попробовать получить нужный интерфейс (SetupDiEnumDeviceInterfaces), ну и наконец, получить искомый путь к устройству (SetupDiGetDeviceInterfaceDetail). Получится или нет — в данном случае неизвестно, но попробуйте, вероятность есть.
А для начала я бы просто посмотрел, какие нативные имена зарегистрированы, если нашлось бы подходящее — попробовал бы его. Если заработает код, указанный в предыдущих сообщениях — тогда бы уже и стал ковырять, как это имя правильно получить. Тем более, что клавиатура может быть не одна.
Здравствуйте, Andrew S, Вы писали:
А>>>>>>Есть USB-клавиатура. Требуется программно зажигать индикаторы Caps Lock, Scroll Lock и/или Num Lock. Нагуглил когда-то одно решение, но так понял, что оно только для PS/2 клавиатур. Программно эмулировать нажатие соответствующих клавиш, думаю, не подойдёт, потому что нажатие, например, Caps Lock всегда будет перехвачено системой и сами понимаете что будет. В какую сторону копать?
AS>>>>>Это? http://www.rsdn.ru/Forum/Message.aspx?mid=1357795&only=1
А>>>>Да, вот это решение на моей USB-клавиатуре не работает
AS>>>Скорее всего, другое название устройства. Я думаю, самый правильный вариант — попробовать получить хендл устройства клавиатуры при помощи SetupApi.
А>>Ты не мог бы рассказать о SetupApi чуть поподробнее, какие функции смотреть, например. Я с ним совсем не знаком.
AS>Попродробнее — в MSDN. AS>Вкратце — надо пронумерить устройства нужного класса (в данном случае — клавиатура), затем для каждого устройства попробовать получить нужный интерфейс (SetupDiEnumDeviceInterfaces), ну и наконец, получить искомый путь к устройству (SetupDiGetDeviceInterfaceDetail). Получится или нет — в данном случае неизвестно, но попробуйте, вероятность есть. AS>А для начала я бы просто посмотрел, какие нативные имена зарегистрированы, если нашлось бы подходящее — попробовал бы его. Если заработает код, указанный в предыдущих сообщениях — тогда бы уже и стал ковырять, как это имя правильно получить. Тем более, что клавиатура может быть не одна.
Спасибо за подсказку. Я попробовал, но никаких устройств мой код не находит (SetupDiEnumDeviceInterfaces постоянно возвращает FALSE, в GetLastError() — ERROR_NO_MORE_ITEMS).
#include <windows.h>
#include <setupapi.h>
#pragma comment(lib, "setupapi")
#include <vector>
using namespace std;
/*
Здесь константы, которые взял из того кода, и те, которые сам отыскал в Google.
Кто знает, может дело в них?
*/
vector<HANDLE> g_devices;
void collectDevicesByInterface(HDEVINFO di, const GUID * guid_devinterface) {
SP_DEVICE_INTERFACE_DATA did = { sizeof(did) };
for (DWORD i = 0; SetupDiEnumDeviceInterfaces(di, NULL, guid_devinterface, i, &did); ++i) {
DWORD detailsSize;
if (!SetupDiGetDeviceInterfaceDetail(di, &did, NULL, 0, &detailsSize, NULL))
continue;
vector<BYTE> details_(detailsSize);
SP_DEVICE_INTERFACE_DETAIL_DATA * details = reinterpret_cast<SP_DEVICE_INTERFACE_DETAIL_DATA *>(&details_[0]);
details->cbSize = sizeof(*details);
if (!SetupDiGetDeviceInterfaceDetail(di, &did, details, detailsSize, &detailsSize, NULL))
continue;
HANDLE h = CreateFile(details->DevicePath, GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
if (h == INVALID_HANDLE_VALUE)
continue;
g_devices.push_back(h);
}
}
void collectDevices(const GUID * guid_devclass) {
HDEVINFO di = SetupDiGetClassDevs(guid_devclass, NULL, NULL, DIGCF_PRESENT | DIGCF_INTERFACEDEVICE);
if (di == INVALID_HANDLE_VALUE)
return;
collectDevicesByInterface(di, &GUID_DEVINTERFACE_HID);
collectDevicesByInterface(di, &GUID_DEVINTERFACE_KEYBOARD);
SetupDiDestroyDeviceInfoList(di);
}
int main() {
collectDevices(&GUID_DEVCLASS_HIDCLASS);
collectDevices(&GUID_DEVCLASS_KEYBOARD);
if (g_devices.empty())
return 0;
KEYBOARD_INDICATOR_PARAMETERS InputBuffer = {1};
for (int i = 1; ; ++i) {
InputBuffer.LedFlags = i & 7;
DWORD xx;
for (size_t i = 0; i < g_devices.size(); ++i)
DeviceIoControl(g_devices[i], IOCTL_KEYBOARD_SET_INDICATORS, &InputBuffer, sizeof(KEYBOARD_INDICATOR_PARAMETERS), 0, 0, &xx, 0);
Sleep(500);
}
for (size_t i = 0; i < g_devices.size(); ++i)
CloseHandle(g_devices[i]);
return 0;
}
Подозрение падает на константы GUID_*, которые я нашёл в поисковике... Но может что-нибудь ещё не так?
AS>>Попродробнее — в MSDN. AS>>Вкратце — надо пронумерить устройства нужного класса (в данном случае — клавиатура), затем для каждого устройства попробовать получить нужный интерфейс (SetupDiEnumDeviceInterfaces), ну и наконец, получить искомый путь к устройству (SetupDiGetDeviceInterfaceDetail). Получится или нет — в данном случае неизвестно, но попробуйте, вероятность есть. AS>>А для начала я бы просто посмотрел, какие нативные имена зарегистрированы, если нашлось бы подходящее — попробовал бы его. Если заработает код, указанный в предыдущих сообщениях — тогда бы уже и стал ковырять, как это имя правильно получить. Тем более, что клавиатура может быть не одна.
А>Спасибо за подсказку. Я попробовал, но никаких устройств мой код не находит (SetupDiEnumDeviceInterfaces постоянно возвращает FALSE, в GetLastError() — ERROR_NO_MORE_ITEMS).
А>Подозрение падает на константы GUID_*, которые я нашёл в поисковике... Но может что-нибудь ещё не так?
Вроде все нормально. Единственно, можно попробовать перечислить все интерфейсы (передать в guid InterfaceClassGuid енума NULL).
В любом случае — возьмите WinObj и посмотрите — может, есть какие подозрительные символьные имена.
Здравствуйте, Andrew S, Вы писали:
AS>>>Попродробнее — в MSDN. AS>>>Вкратце — надо пронумерить устройства нужного класса (в данном случае — клавиатура), затем для каждого устройства попробовать получить нужный интерфейс (SetupDiEnumDeviceInterfaces), ну и наконец, получить искомый путь к устройству (SetupDiGetDeviceInterfaceDetail). Получится или нет — в данном случае неизвестно, но попробуйте, вероятность есть. AS>>>А для начала я бы просто посмотрел, какие нативные имена зарегистрированы, если нашлось бы подходящее — попробовал бы его. Если заработает код, указанный в предыдущих сообщениях — тогда бы уже и стал ковырять, как это имя правильно получить. Тем более, что клавиатура может быть не одна.
А>>Спасибо за подсказку. Я попробовал, но никаких устройств мой код не находит (SetupDiEnumDeviceInterfaces постоянно возвращает FALSE, в GetLastError() — ERROR_NO_MORE_ITEMS).
А>>Подозрение падает на константы GUID_*, которые я нашёл в поисковике... Но может что-нибудь ещё не так?
AS>Вроде все нормально. Единственно, можно попробовать перечислить все интерфейсы (передать в guid InterfaceClassGuid енума NULL). AS>В любом случае — возьмите WinObj и посмотрите — может, есть какие подозрительные символьные имена.
С NULL абсолютно то же самое...
Опробовал WinObj. Присутствуют устройства KeyboardClass0 и KeyboardClass1... Выходит, все попытки использовать SetupApi были для меня напрасны...
Я тут ещё поэкспериментировал на клавиатурах знакомых. Похоже, что виноват DeviceIoControl и IOCTL_KEYBOARD_SET_INDICATORS, который видимо работает только для PS/2 клавиатур. На самом деле, мне несколько месяцев назад приходилось уже обращать внимание на управление клавиатурными индикаторами, я даже нашёл ссылку, но не уделил ей достаточно внимания. Пришлось найти её снова:
Не зря же они для USB и PS/2 используют разные способы! Способ с посылкой нажатия клавиш мне очень мало подходит, но видимо всё-таки придётся использовать его для USB-клавиатур...
А>Опробовал WinObj. Присутствуют устройства KeyboardClass0 и KeyboardClass1... Выходит, все попытки использовать SetupApi были для меня напрасны...
Ну, я ж предупреждал — посмотрите сначала уже известные объекты
А>Я тут ещё поэкспериментировал на клавиатурах знакомых. Похоже, что виноват DeviceIoControl и IOCTL_KEYBOARD_SET_INDICATORS, который видимо работает только для PS/2 клавиатур. На самом деле, мне несколько месяцев назад приходилось уже обращать внимание на управление клавиатурными индикаторами, я даже нашёл ссылку, но не уделил ей достаточно внимания. Пришлось найти её снова:
А>http://mamedev.org/source/src/osd/windows/ledutil.c.html
А>Не зря же они для USB и PS/2 используют разные способы! Способ с посылкой нажатия клавиш мне очень мало подходит, но видимо всё-таки придётся использовать его для USB-клавиатур...
Ну, просто не нашли способа управлять по-другому. Но это не значит, что его нет... Может, кроме KeyboardClass есть еще какие подозрительные имена?
А>Вам огромное спасибо за помощь!
Да не за что, жаль, что ничего нового не обнаружилось.
Здравствуйте, Andrew S, Вы писали:
AS>Ну, просто не нашли способа управлять по-другому. Но это не значит, что его нет... Может, кроме KeyboardClass есть еще какие подозрительные имена?