Исходный код, отвечающий за обработку скан-кодов и кодов клавиш, входит в состав многих программ, распространяемых согласно свободной лицензии. К ним относятся kbd (мы будем рассматривать версию 1.15.3) и console-tools (версия 0.2.3, например). Архивы с исходными текстами и kbd и console-tools содержат файл showkey.c , в котором реализуется механизм вывода скан-кодов и кодов (keycodes) клавиш, генерируемых когда пользователь нажимает кнопки на клавиатуре.
И kbd и console-tools являются приложениями с текстовым интерфейсом. В среде GNU/Linux такие программы почти всегда включают в свой состав стандартную функцию getopt_long() , осуществляющую синтаксический анализ аргументов командной строки. Достаточно подробные пояснения по поводу использования этой функции даны в работе [МитчеллОулдемСамьюэл2003, С. 31-34].
Применяется ли getopt_long() в kbd и console-tools ? Да. Код в файле src/showkey.c (из набора программ kbd-1.15.3 ) служит наглядным примером того, как это делается.
Уроки C# – Нажатие клавиш в программе, событие на нажимаемые кнопки, KeyDown, KeyPreview – C#
Версию пакета kbd , используемую в вашей системе, можно узнать, например, выполнив команду showkey —version . В ответ будет выведено сообщение, похожее на «showkey from kbd 1.15» .
Исходя из того, что одним из основных недостатков современной литературы о программировании является почти полное отсутствие примеров кода, решающего реальные, а не учебные задачи, остановимся на src/showkey.c подробнее.
/*— Начало файла src/showkey.c с комментариями —*/
/* Директивы препроцессора, начинающиеся со слова #include (в переводе с английского — «включить в состав») подключают заголовочные файлы (header files). Препроцессор — это один из элементов компилятора языка Си, осуществляющий предварительную обработку кода программы (с его помощью можно включать в состав программы внешние файлы, осуществлять макроподстановки и условные включения). Подробные сведения о препроцессоре Си указаны в отличной книге [КерниганРитчи2006, С. 101-104]. */
#include #include #include #include #include #include #include #include #include
/* Имена заголовочных файлов, находящихся в каталоге /usr/include (или его аналоге), заключаются в угловые скобки. В свою очередь, двойные кавычки применяются для выделения имён заголовочных файлов, расположенных в одном каталоге с кодом программы, которую предстоит компилировать (переводить с языка высокого уровня на язык понятный компьютеру, то есть — в машинный код). */
#include «getfd.h» #include «nls.h» #include «version.h»
/* Имена переменных tmp , fd и oldkbmode говорят сами за себя. Tmp — сокращение от слова temporary (временный); fd — сокращение от file descriptor (дескриптор файла, являющийся ссылкой на «объект» открытого файла; подробнее см. [Вахалия2003, С. 338-340]); oldkbmode (old keyboard mode) служит для хранения названия режима, в котором находится драйвер клавиатуры (об этих режимах мы ещё поговорим). Сокращение int указывает на тип переменной (см. [КерниганРитчи2006, С. 50-54]). */
AutoHotKey — Узнать код клавиши, Цикл, Сторонняя программа
int tmp; /* for debugging (для отладки программы) */ int fd; int oldkbmode;
/* Структура termios используется функциями управления терминалом в Unix-подобных системах. Подробнее см. [Рочкинд2005, С. 226-228]. Структура — это совокупность нескольких переменных, часто различных типов, сгруппированных под единым именем для удобства обращения. [КернигаРитчи2006, с. 139] */
struct termios old; /* Данная строка создаёт копию (old) текущей структуры termios */ /* version 0.81 of showkey would restore kbmode unconditially to XLATE, thus making the console unusable when it was called under X. Здесь авторы обращают внимание на сбои в обработке сигналов с клавиатуры, которые могут появиться если запустить программу showkey версии 0.81 в среде X Window. */
/* Область действия функции get_mode() ограничивается данным файлом исходного кода: от точки объявления до конца (на это указывает слово static перед именем функции). Иными словами, к функции get_mode() нельзя обращаться за пределами файла, в котором она объявлена. */
/* В свою очередь, тип void (в переводе с английского — «пустой») обозначает пустое множество значений. Он используется для указания типа возвращаемого функцией значения в случае если функция ничего не возвращает. */
static void get_mode(void)
/* Предшествующая строка кода указывает, что функция get_mode() не только не возвращает, но и не получает никаких значений на вход. */
/* *m является указателем и представляет из себя группу ячеек памяти, которые могут содержать адрес переменной типа char . */
char *m;
/* KDGKMODE (Get Keyboard Mode) объявляется в файле /usr/include/kd.h и хранит название текущего режима работы драйвера клавиатуры. Нам не удалось найти документации, где пояснялось бы как расшифровывается «KD» . Вероятнее всего, «KD» — это Keyboard Driver . */
if (ioctl(fd, KDGKBMODE, perror(«KDGKBMODE»);
/* Функция perror() входит в стандартную библиотеку языка Си и определяется в заголовочном файле stdio.h . Она выводит содержимое своего аргумента, а также сообщение об ошибке. */
exit(1); >
/* ioctl — системный вызов общего назначения, служащий для управления символьными устройствами всех типов. Его синтаксис описывается следующим образом: ioctl(fd, cmd, arg) , где fd — дескриптор файла; cmd — целое число, указывающее вызываемую команду; arg — дополнительный аргумент команды (обычно — адрес блока параметров). */
/* KDGKBMODE — это имя, которое в результате макроподстановки, осуществляемой препроцессором (подробнее см. [КерниганРитчи2006, С. 102-103]), заменяется на число, указывающее на команду, результатом которой является получение информации о текущем режиме работы драйвера клавиатуры. Упомянутая макроподстановка происходит благодаря содержимому файла /usr/include/linux/kd.h . */
/* Аргумент case K_RAW: m = «RAW»; break; case K_XLATE: m = «XLATE»; break; case K_MEDIUMRAW: m = «MEDIUMRAW»; break; case K_UNICODE: m = «UNICODE»; break; default: m = _(«?UNKNOWN?»); break; >printf(_(«kb mode was %sn»), m); if (oldkbmode != K_XLATE) < printf(_(«[ if you are trying this under X, it might not workn» «since the X server is also reading /dev/console ]n»)); >printf(«n»); > static void clean_up(void)
/* KDSKBMODE (Set Keyboard Mode) содержит число, указывающее на команду установки режима работы драйвера клавиатуры. */
if (ioctl(fd, KDSKBMODE, oldkbmode)) < perror(«KDSKBMODE»);
/* Конструкция еxit(выражение) эквивалентна конструкции return . Обычно она возравщает 0 если всё идёт хорошо, а 1 — когда произошла ошибка. */
exit(1); >
/* Системный вызов tcsetattr задаёт атрибуты терминала, предварительно сохранённые в структуре old (копия структуры termios ). */
if (tcsetattr(fd, 0, tcsetattr»); close(fd); >
/* Атрибут attr_noreturn указывает на то, что функция никогда не возвращает значений. */
static void attr_noreturn die(int x) < printf(_(«caught signal %d, cleaning up. n»), x);
/* Функция clean_up() восстанавливает режим работы драйвера клавиатуры, исходя из данных, полученных с помощью системного вызова ioctl . */
clean_up(); exit(1); >
/* Атрибут attr_unused указывает на то, что аргумент функции никак не обрабатывается. */
static void attr_noreturn watch_dog(attr_unused int x)
/* Функция usage() , выводящая информацию об аргументах, которые принимает программа, не нуждается в особых пояснениях. */
static void attr_noreturn usage(void) < fprintf(stderr, _( «showkey version %snn» «usage: showkey [options. ]n» «n» «valid options are:n» «n» » -h —help display this help textn» » -a —ascii display the decimal/octal/hex values of the keysn» » -s —scancodes display only the raw scan-codesn» » -k —keycodes display only the interpreted keycodes (default)n» ), PACKAGE_VERSION); exit(1); >int main (int argc, char *argv[])
/* *short_opts — это указатель. Значение записанное в адрес, на который ссылается этот указатель, впоследствии не меняется, так как в начале строки с его объявлением стоит модификатор const . Строка, хранимая по адресу *short_opts , содержит возможные короткие опции, каждая из которых представлена одной буквой. */
const char *short_opts = «haskV»;
/* long_opts[] (в переводе — «длинные опции», то есть содержащие более одной буквы в своём имени) представляет из себя массив структур. Каждая структура массива имеет следующие элементы:
< «имя опции», наличие_аргумента, флаг, значение>. */
/* Крайняя структура в массиве должна содержать только нули. */
/* Элемент «наличие_аргумента» может содержать либо числа (0, 1 ,2), либо имена имена для макроподстановки, указанные в файле /usr/include/getopt.h и соответствующие этим числам ( no_argument соответствует нулю; required_argument соответствует единице; optional_argument соответствует двойке). */
/* Если элемент «значение» содержит короткую опцию из строки, на которую указывает *short_opts , то элемент «флаг» , будучи установленным в NULL , позволяет обеспечить соответствие между короткой и длинной опцией (например, как показано ниже, короткая опция -h соответствует длинной опции —help ). Если же заменить элемент «флаг» на указатель, то он будет указывать на переменную, имя которой находится в элементе «значение» . */
const struct option long_opts[] = < < «help», no_argument, NULL, ‘h’ >, < «ascii», no_argument, NULL, ‘a’ >, < «scancodes», no_argument, NULL, ‘s’ >, < «keycodes», no_argument, NULL, ‘k’ >, < «version», no_argument, NULL, ‘V’ >, < NULL, 0, NULL, 0 >>; int c; int show_keycodes = 1; int print_ascii = 0; struct termios new; unsigned char buf[18]; /* divisible by 3 */ int i, n; set_progname(argv[0]);
/* Следующие три строки кода отвечают за локализацию интерфейса программы средствами GNU gettext . */
setlocale(LC_ALL, «»); bindtextdomain(PACKAGE_NAME, LOCALEDIR); textdomain(PACKAGE_NAME);
/* Пятый арумент функции getopt_long может содержать указатель на структуру в массиве long_opts[] . Подробнее см. man getopt_long (данная страница справочного руководства, помимо всего прочего, содержит пример исходного кода, где пятый аргумент является указателем, а не нулём, как в рассматриваемом нами файле). */
while ((c = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) < switch (c) < case ‘s’: show_keycodes = 0; break; case ‘k’: show_keycodes = 1; break; case ‘a’: print_ascii = 1; break; case ‘V’: print_version_and_exit(); case ‘h’: case ‘?’: usage(); >> if (optind < argc) usage(); if (print_ascii) < /* no mode and signal and timer stuff — just read stdin */ fd = 0; if (tcgetattr(fd, tcgetattr»); if (tcgetattr(fd, tcgetattr»);
/* Как уже отмечалось выше, структура new — это копия структуры termios . */
/* Две строки кода, представленные далее, иллюстрируют приёмы работы с элементами структуры (локальными флагами копии структуры termios ). Флаги ICANON и ISIG устанавливаются в нуль, ECHO и ECHOCTL — в единицу (подробнее см. [КерниганРитчи2006, с. 160]). */
/* При флаге ICANON равном нулю, вводимые символы не составляются в строки вплоть до чтения (выполнения системного вызова read ). ISIG , будучи обнулённым, блокирует обработку управляющих символов (терминал перестаёт реагировать на управляющие последовательности, вызывающие появление сигналов). К этим символам относятся: INTR (Ctrl+C), QUIT (Ctrl+), SUSP (Ctrl+z) и DSUSP (Ctrl+y) . Подробнее см. [ТаненбаумВудхалл2006, С. 270-277].*/
/* Обратите внимание, что рассматриваемый блок кода выполняется только при условии если установлена в 1 опция -a (print_ascii). Согласно документации ( man 3 termios ), при ECHOCTL == 1 и ECHO == 1 вводимые пользователем управляющие символы ASCII (за исключением TAB, NL, START и STOP) отображаются в виде ^X , где вместо X размещается символ из таблицы ASCII с кодом на 0x40 больше, чем у управляющего символа. Например, в ответ на символ возврата каретки (клавиша с надписью Enter) появляется ^M (шестнадцатеричный код M в таблице ASCII равен 0x4D , a «Enter» соответствует коду 0xD ). Также следует отметить, что ECHOCTL требует, чтобы в коде программы было определено (через #define в файле /usr/include/features.h) имя _BSD_SOURCE или _SVID_SOURCE (подробнее об этих именах см. http://www.aquaphoenix.com/ref/gnu_c_library/libc_12.html ). */
new.c_lflag new.c_lflag |= (ECHO | ECHOCTL);
/* Следующая строка устанавливает все флаги ввода (IGNBRK, BRKINT, IGNPAR, PARMRK, INPCK, ISTRIP, INLCR, IGNCR, ICRNL, IUCLC, IXON, IXANY, IXOFF, IMAXBEL, IUTF8) в нуль. Подробнее см. /usr/include/bits/termios.h , а также комментарии по флагам режимов . */
new.c_iflag = 0;
/* Когда число символов в очереди будет равно значению, записанному в new.c_cc[VMIN] , или когда пройдёт количество десятых долей секунды, указанное в new.c_cc[VTIME] (код рассматриваемого файла отключает таймер так как в new.c_cc[VTIME] заносится нуль) будет выполнен системный вызов read . Подробнее см. [Рочкинд2005, С. 233-236]. */
new.c_cc[VMIN] = 1; new.c_cc[VTIME] = 0;
/* Изменения в структуре termios , хранимые в структуре new , применяются системным вызовом tcsetattr() . Аргумент TCSAFLUSH говорит о том, что помимо применения изменений должны быть очищены буферы ввода/вывода терминала (подробнее см. раздел 3.1 документа Serial Programming Guide for POSIX Operating Systems и его не самый качественный, но всё же перевод на русский язык . */
if (tcsetattr(fd, TCSAFLUSH, tcgetattr»); printf(_(«nPress any keys — » «Ctrl-D will terminate this programnn»)); while (1) < n = read(fd, buf, 1); if (n == 1) printf(» t%3d 0%03o 0x%02xn», buf[0], buf[0], buf[0]); if (n != 1 || buf[0] == 04) break; >if (tcsetattr(fd, 0, tcsetattr»); exit(0); >
/* Функция getfd() определена в файле getfd.c . */
fd = getfd(NULL);
/* По умолчанию showkey прекращает работу при отсутствии активности пользователя (нажатых клавиш) в течение 10 секунд. */
/* the program terminates when there is no input for 10 secs */ signal(SIGALRM, watch_dog);
/* Системный вызов signal устанавливает реакцию программы showkey на сигналы (запросы на прерывание, осуществляемые на уровне процессов), имена которых определены в файле /usr/include/bits/signum.h (см. /usr/include/signal.h ). По сути речь идёт о назначении подпрограмм обработки для каждого из сигналов. Разработчики showkey сделали всё достаточно прямолинейно, назначив функцию die() обрабатывать все возможные сигналы, кроме того, что генерируется по истечении времени, заданного в качестве аргумента функции alarm() (см. выше). */
/* Очень подробные и наглядные материалы о сигналах Unix представлены в книге [НеметСнайдерСибассХейн2003, С. 68-71]. */
/* if we receive a signal, we want to exit nicely, in order not to leave the keyboard in an unusable mode (единообразная обработка сигналов позволяет быть уверенным в том, что драйвер клавиатуры находится в нужном режиме). */ signal(SIGHUP, die); signal(SIGINT, die); signal(SIGQUIT, die); signal(SIGILL, die); signal(SIGTRAP, die); signal(SIGABRT, die); signal(SIGIOT, die); signal(SIGFPE, die); signal(SIGKILL, die); signal(SIGUSR1, die); signal(SIGSEGV, die); signal(SIGUSR2, die); signal(SIGPIPE, die); signal(SIGTERM, die); #ifdef SIGSTKFLT signal(SIGSTKFLT, die); #endif signal(SIGCHLD, die); signal(SIGCONT, die); signal(SIGSTOP, die); signal(SIGTSTP, die); signal(SIGTTIN, die); signal(SIGTTOU, die); get_mode(); /* Вызов функции get_mode(), определённой выше по тексту. */ if (tcgetattr(fd, tcgetattr»); if (tcgetattr(fd, tcgetattr»); new.c_lflag new.c_iflag = 0; new.c_cc[VMIN] = sizeof(buf); new.c_cc[VTIME] = 1; /* 0.1 sec intercharacter timeout */ if (tcsetattr(fd, TCSAFLUSH, tcsetattr»); if (ioctl(fd, KDSKBMODE, show_keycodes ? K_MEDIUMRAW : K_RAW)) < perror(«KDSKBMODE»); exit(1); >printf(_(«press any key (program terminates 10s after last keypress). n»));
/* Как видно, чтение скан-кодов осуществляется с помощью системного вызова read , считывающего в бесконечном цикле байты из файла, представленного дескриптором fd (не забывайте, что в GNU/Linux устройства также являются файлами). */
/* show scancodes */ if (!show_keycodes) < while (1) < alarm(10); n = read(fd, buf, sizeof(buf)); for (i = 0; i < n; i++) printf(«0x%02x «, buf[i]); printf(«n»); >clean_up(); exit(0); > /* show keycodes — 2.6 allows 3-byte reports */ while (1) < alarm(10); n = read(fd, buf, sizeof(buf)); i = 0; while (i < n) < int kc; char *s;
/* Как отмечалось ранее (при обсуждении вывода программы getkeycodes ), отпускание клавиши результируется в скан-коде, старший бит которого равен единице (напомним, что речь идёт об особенностях набора скан-кодов Set 1 ). Иными словами, к скан-коду нажатой клавиши прибавляется шестнадцатеричное число 80 , которое в программах на языке Си записывается как 0x80 . */
s = (buf[i] release») : _(«press»); if (i+2 < n (buf[i] 0x80) != 0 (buf[i+2] kc = ((buf[i+1] 7) | (buf[i+2] i += 3; >else < kc = (buf[i] i++; >printf(_(«keycode %3d %sn»), kc, s); > > clean_up(); exit(0); >
/*— Конец файла src/showkey.c с комментариями —*/
Компилирировать представленный выше исходный код нужно вместе с файлом src/getfd.c , содержащем определение функции getfd() .
gcc showkey.c getfd.c
Проверить работоспособность получившегося исполняемого файла ( a.out ) лучше всего вне X сессии. Например, в виртуальном терминале, доступном по нажатию ++.
Разумеется, для удобства, было бы хорошо иметь возможность управлять длительностью временного промежутка, который программа showkey ожидает ввода пользователя перед тем, как завершить свою работу (в kbd-1.15.3 этот промежуток времени равен 10 секундам). В рамках проекта console-tools данное пожелание реализовано (см. файл kbdtools/showkey.c в архиве). Комментарии по поводу использования некоторых приложений, входящих в состав console-tools см. в статье «VGA console basics and Linux console-tools» .
Предыдущий раздел: | Оглавление | Следующий раздел: |
Взаимодействие с клавиатурой. Общие замечания | Режимы работы драйвера клавиатуры |
Источник: rus-linux.net
Предыстория
Всю свою жизнь был фанатом бесшумных, тонких, и красивых клавиатур и к моему удивлению обнаружил что таковых не так уж и много, из доступных в свободной продаже, — их единицы. Пришлось пользоваться «Genius SlimStar Pro», и все равно она меня угнетала, как и мысль о том, что я никогда не найду клавиатуру которая бы удовлетворяла меня на все 100%. Я такую нашел и по рекомендации товарища Boomburum, приобрел «Illuminated Keyboard», которая стала достойной подругой моей «MX Revolution», и я окончательно порвал отношения с Genius, а последние рассказы о поддержке пользователей со стороны Logitech, убедили меня, что вложенные (не малые деньги) себя оправдают за 3 гарантийных года.
Но есть небольшая беда в клавиатурах этой компании, — «Не стандартные, не удобные, или не нужные расположения некоторых кнопок». В случае с Illuminated, это две одинаковые кнопки «», левая из которых пошла в ущерб клавише «LShift», Кстати на картинке вы можете заметить что раньше эти клавиатуры имели стандартный размер «LShift». Под катом, я расскажу как вернуть «стандартную длину» этой кнопки, так как в слепой печати и в силу привычки, я нажимаю именно / вместо шифта. А заодно расскажу как без дополнительного установленного ПО, на примере, вы сможете менять назначения любых клавиш ваших клавиатур (в том числе и функциональных/медийных) при помощи Реестра и Скан-кода клавиш.
Что такое Скан-код
Спецификация для Windows.
При нажатии любой клавиши контроллер клавиатуры вырабатывает скан-код, соответствующей позиции клавиши, который передаются в компьютер. Служебные коды, которые может вырабатывать контроллер клавиатуры, передаются для обработки подпрограммам BIOS. В буфере клавиатуры для кода клавиши отводится по 2 байта, т. е. он рассчитан на 16 символов.
Как определить Скан-код клавиши
Узнать Скан-код необходимой для ремаппинга клавиши вы можете здесь, а если у вас супер новая клавиатура с кнопками космического происхождения, то отловить скан-код вы можете используя программу «KeyboardTest» от разработчика Passmark Software. Программка платная, но бесплатным триалом. Или OpenSource Программу SharpKeys. Она потребовалась для определения скан-кода левой «», так как многие наивно полагали что сигналы у обеих одинаковые, а значит и не подлежат ремаппингу. На деле оказалось не так.
Правый «» имеет скан-код: 2b.00
Левый нижний «» имеет скан-код: 56.00
И так, мы определили скан-код нашей незадачливой кнопки, теперь нам нужно найти скан-код «LShift». Его можно найти по данной выше ссылке и он равен: 2A.00
Ремаппинг клавиш
Есть куча приложений которые делают этот ремаппинг, многие за базу принимают существующие скан-коды, многие не имеют сканера, что бы определить скан-код клавиши которой нет в базе. Да и устанавливать лишнее приложение очень не хотелось. По-гуглив я остановился на возможностях Windows. а точнее редактора реестра (Пуск-Выполнить: regedit). Или вышеупомянутую программу SharpKeys, которая имеет GUI и выполняет такую же замену в реестре
1. В ветке
HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControlKeyboard Layout
создайте бинарный параметр с именем «Scancode Map»
2. В параметр «Scancode Map» записываем следующие значения:
00.00.00.00.00.00.00.00.02 — девятый байт (02) в этой записи означает количество клавиш которое мы будем менять (и равен количеству клавиш +1) в нашем случае это 02, так как мы меняем значения одной клавиши. После этого вписываем еще три «пустых» байта, и теперь наш параметр выглядит так:
00.00.00.00.00.00.00.00.02.00.00.00.
Поскольку мы уже определили все Скан-коды, то продолжая наш параметр, нам следует указать скан-код значения новой кнопки (в нашем случае это 2A.00), а затем скан-код старой (заменяемой) кнопки 56.00. Теперь необходимо закрыть эту функцию четырьмя «пустыми» байтами, то есть 00.00.00.00:
3. Перезагружаем компьютер и пользуемся нашими новыми кнопками.
PS: Если нужно сделать ремаппинг не на всем ПК, а только в вашем сеансе, то значения необходимо менять в HKEY_CURRENT_USERSYSTEMCurrentControlSetControlKeyboard Layout
UPD: Если вы боитесь работать в реесте, то создайте текстовый файл с расширением *.reg, и впишите туда следующее:
[HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControlKeyboard Layout]
«Scancode Map»=hex:00,00,00,00,00,00,00,00,02,00,00,00,2a,00,56,00,00,00,00,00
затем сохраните, запустите, и перезагрузите ПК.
UPD2: Перенос Скриншотов на
1. Левый Win-key выглядит так:
[HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControlKeyboard Layout]
«Scancode Map»=hex:00,00,00,00,00,00,00,00,02,00,00,00,37,E0,5B,E0,00,00,00,00
Правый Win-key выглядит так:
[HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControlKeyboard Layout]
«Scancode Map»=hex:00,00,00,00,00,00,00,00,02,00,00,00,37,E0,5C,E0,00,00,00,00
Источник: habr.com
Код нажатой клавиши программа
Обработка и эмуляция мультимедийных кнопок клавиатуры
Практически все современные клавиатуры имеют несколько специальных, так называемых мультимедийных кнопок для управления громкостью звука, навигацией браузера, плеером, запуска почтовой программы или калькулятора и так далее. Их количество и функционал зависит от производителя и модели клавиатуры. Особенностью этих кнопок является то, что при нажатии они не генерируют скан-кодов, не порождают события типа WM_KEYDOWN, не отслеживаются в полях ввода типа msctls_hotkey32.
Но оказывается, что работать с ними очень просто. В процедуре обработки окна надо отслеживать сообщение WM_APPCOMMAND, оно приходит, когда окно активно и нажата какая-либо мультимедийная кнопка.
Code (Assembler) : Убрать нумерациюВыделить код
- WM_APPCOMMAND = 0x319
- . . .
- ; Пришло сообщение от мультимедийной кнопки?
- cmp [ msg ] , WM_APPCOMMAND
- je wm_mmkey
Код нажатой кнопки приходит в младшем слове значения lParam сообщения. Полный список кодов мультимедийных клавиш и их назначение можно посмотреть здесь.
Code (Assembler) : Убрать нумерациюВыделить код
- wm_mmkey :
- ; Код нажатой кнопки приходит в lParam
- moveax , [ lparam ]
- shreax , 16
- ; EAX = код кнопки
- . . .
Если ваше приложение должно обрабатывать только часть мультимедийных кнопок, то ваш обработчик сообщения WM_APPCOMMAND должен пропускать его дальше по цепочке системных обработчиков. Для установки глобального обработчика этого сообщения, который будет работать не только когда окно активно, придется воспользоваться инжектом dll во все активные процессы.
От обработки переходим к эмуляции нажатий мультимедийных кнопок. Эмуляцию можно использовать не только для имеющихся кнопок, но и в том случае, когда на клавиатуре какие-либо кнопки отсутствуют или даже вообще нет ни одной мультимедийной кнопки. Использовать эмуляцию нажатий на мультимедийные кнопки гораздо проще и удобнее, чем, например, регулировать громкость или отключать звук средствами WinAPI, так что этот способ может оказаться весьма полезным.
Code (Assembler) : Убрать нумерациюВыделить код
- WM_APPCOMMAND = 0x319
- . . .
- ; Получить хэндл рабочего стола
- invoke GetShellWindow
- ; Отправить ему сообщение о нажатии кнопки «Calculator»
- invoke SendMessage , eax , WM_APPCOMMAND , 0 , ( 12h shl 16 )
- . . .
Функции некоторых кнопок можно переопределить. Описание, какая кнопка за что отвечает, хранится в реестре. Название ветки соответствует коду кнопки, а ключ определяет ассоциацию действия или имя исполняемого файла, который будет запущен при нажатии. Вместо стандартного калькулятора или окна «Мой компьютер», например, можно определить запуск другой программы.
[HKLMSOFTWAREMicrosoftWindowsCurrentVersionexplorerAppKey7]
«Association»=»http»
В приложении примеры программ с исходными текстами, одна из которых при активном окне обрабатывает нажатия мультимедийных кнопок и показывает их код, а вторая эмулирует нажатие на кнопку запуска калькулятора.
Примеры программ с исходными текстами (FASM)
Источник: www.manhunter.ru