мои коллеги разработчики! Я очень надеюсь, что, по крайней мере, некоторые из вас не будут напуганы количеством текста, содержащегося в этом вопросе (я просто сделал все возможное, чтобы описательный текст был настолько гуманным, насколько это возможно). :)
Тем, кто думает, что я задал этот вопрос, чтобы написать вредоносную программу или что-то в этом роде. Я хочу написать приложение, которое позволит пользователям выбирать приложения для запуска после того, как ОС завершит запуск. Основная идея заключается в том, чтобы позволить пользователю выбирать эти приложения ДО завершения загрузки ОС, нажимая горячие клавиши, ранее привязанные к приложениям. Например, пользователь включает свой Mac, набирает SMTV и уходит, когда система заканчивает запуск, мое приложение восстанавливает ввод и запускает Safari, Mail, Tweetie и Vuze. Я новичок в SO, но я делаю все возможное, чтобы помочь другим, отвечая на их вопросы - я думаю, что могу ожидать того же в ответ. Проверьте мой профиль и мою активность, и после этого начните кричать о вредоносных программах.
Этот вопрос является продолжением вопроса Можно ли восстановить ввод с клавиатуры, выполненный во время загрузки Mac OS? .
Руководствуясь советом Пекки , я наткнулся на статью Перехват событий клавиатуры Кристиана Старкджоханна, в которой описывается, как ему и команде объективного развития удалось переназначение клавиши извлечения CDROM iBook с F12 на Shift + F12. Основная часть в том, что они на самом деле перехватили события клавиатуры, что мне и нужно. В конце Кристиан написал эту статью именно для таких разработчиков, как я, чтобы использовать идею iJect в качестве прототипа для аналогичной функциональности.
Для начала я решил создать простое расширение ядра, чтобы просто записывать ввод с клавиатуры пользователя на /var/log/kernel.log
. Я запустил новый проект Generic Kernel Extension в XCode, следуя инструкциям Hello Kernel: создание расширения ядра с помощью Xcode , которое можно найти в Концепции расширения ядра Центра разработки Mac для создания проект Hello World, а затем наполнил его кодом, взятым из исходников iJect. Вот результаты:
TestKEXT.c
#include <sys/systm.h>
#include <mach/mach_types.h>
extern int HidHackLoad(void);
extern int HidHackUnload(void);
kern_return_t MacOSSCKEXT_start (kmod_info_t * ki, void * d) {
return HidHackLoad() == 0 ? KERN_SUCCESS : KERN_FAILURE;
}
kern_return_t MacOSSCKEXT_stop (kmod_info_t * ki, void * d) {
return HidHackUnload() == 0 ? KERN_SUCCESS : KERN_FAILURE;
}
HIDHack.h
#ifdef __cplusplus
extern "C" {
#endif
#include <mach/mach_types.h>
#include <sys/systm.h>
extern int HidHackLoad(void);
extern int HidHackUnload(void);
#ifdef __cplusplus
}
#endif
#include <IOKit/system.h>
#include <IOKit/assert.h>
#include <IOKit/hidsystem/IOHIDSystem.h>
class HIDHack : public IOHIDSystem {
public:
virtual void keyboardEvent(unsigned eventType,
/* flags */ unsigned flags,
/* keyCode */ unsigned key,
/* charCode */ unsigned charCode,
/* charSet */ unsigned charSet,
/* originalCharCode */ unsigned origCharCode,
/* originalCharSet */ unsigned origCharSet,
/* keyboardType */ unsigned keyboardType,
/* repeat */ bool repeat,
/* atTime */ AbsoluteTime ts);
virtual void keyboardSpecialEvent(unsigned eventType,
/* flags */ unsigned flags,
/* keyCode */ unsigned key,
/* specialty */ unsigned flavor,
/* guid */ UInt64 guid,
/* repeat */ bool repeat,
/* atTime */ AbsoluteTime ts);
};
HIDHack.cpp
#include "HIDHack.h"
static void *oldVtable = NULL;
static void *myVtable = NULL;
int HidHackLoad(void) {
IOHIDSystem *p;
HIDHack *sub;
if (oldVtable != NULL) {
printf("###0 KEXT is already loaded\n");
return 1;
}
if (myVtable == NULL) {
sub = new HIDHack();
myVtable = *(void **)sub;
sub->free();
}
p = IOHIDSystem::instance();
oldVtable = *(void **)p;
*(void **)p = myVtable;
printf("###1 KEXT has been successfully loaded\n");
return 0;
}
int HidHackUnload(void) {
IOHIDSystem *p;
if (oldVtable != NULL) {
p = IOHIDSystem::instance();
if (*(void **)p != myVtable) {
printf("###2 KEXT is not loaded\n");
return 1;
}
*(void **)p = oldVtable;
oldVtable = NULL;
}
printf("###3 KEXT has been successfully unloaded\n");
return 0;
}
void HIDHack::keyboardEvent(unsigned eventType, unsigned flags, unsigned key, unsigned charCode, unsigned charSet, unsigned origCharCode, unsigned origCharSet, unsigned keyboardType, bool repeat,
AbsoluteTime ts) {
printf("###4 hid event type %d flags 0x%x key %d kbdType %d\n", eventType, flags, key, keyboardType);
IOHIDSystem::keyboardEvent(eventType, flags, key, charCode, charSet, origCharCode, origCharSet, keyboardType, repeat, ts);
}
void HIDHack::keyboardSpecialEvent( unsigned eventType,
/* flags */ unsigned flags,
/* keyCode */ unsigned key,
/* specialty */ unsigned flavor,
/* guid */ UInt64 guid,
/* repeat */ bool repeat,
/* atTime */ AbsoluteTime ts) {
printf("###5 special event type %d flags 0x%x key %d flavor %d\n", eventType, flags, key, flavor);
IOHIDSystem::keyboardSpecialEvent(eventType, flags, key, flavor, guid, repeat, ts);
}
Полученное расширение ядра успешно загружается / выгружается программами kextload / kextunload, но фактически не перехватывает ни одно из событий клавиатуры. Я пытался сделать много вещей, чтобы заставить его работать, но без каких-либо ошибок или других проблем с ним, так что я не могу гуглить что-нибудь полезное и прошу вашей помощи.