DIO様「今までに打ち込んだキーの数を覚えているのか?」
俺氏「ログあります!✧\\٩(‘ω’)و //✧」
DIO様「URYYYYYYYYY!!!!!!!!」
という事をしたかったので調査した。ライフログの一環です。
ポイント
- ApplicationServicesを使う。
- イベントハンドラを書く。
- イベントログをハンドルするには管理者権限が必要っぽい。
- (脱線: ちなみにLinuxでは
/dev/input/
あたりで取れるらしい。)
サンプルコード
- 動作: キー押下イベントをハンドルして標準出力にタイムスタンプと共にキーコードを出力する。
keylogger.c
// This program is a simple implementation of a key logger for OS X.
// This key loggger requires sudo and outputs key codes and a time stamp to standard output.
//
// build: cc keylogger.c -o keylogger -framework ApplicationServices
// usage: sudo keylogger > keylogger.log
// author: Masayuki Higashino
#include <stdio.h>
#include <time.h>
#include <ApplicationServices/ApplicationServices.h>
CGEventRef on_tap(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon) {
CGKeyCode key = CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode);
time_t now; time(&now);
printf("%d %d\n", (int)now, key); fflush(stdout);
return event;
}
int main(int argc, const char * argv[]) {
CGEventFlags flags = CGEventSourceFlagsState(kCGEventSourceStateCombinedSessionState);
CGEventMask mask = CGEventMaskBit(kCGEventKeyDown);
CFMachPortRef tap = CGEventTapCreate(kCGSessionEventTap, kCGHeadInsertEventTap, 0, mask, on_tap, &flags);
if (!tap) {
fprintf(stderr, "This program requires sudo.");
return -1;
}
CFRunLoopSourceRef runloop = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, tap, 0);
CFRunLoopAddSource(CFRunLoopGetCurrent(), runloop, kCFRunLoopCommonModes);
CGEventTapEnable(tap, true);
CFRunLoopRun();
return 0;
}
コンパイル
-
-framwork
オプションを付ける。
cc keylogger.c -o keylogger -framework ApplicationServices
実行
-
sudo
を付ける。
sudo keylogger > keylogger.log
CGKeyCodeの値と意味の対応表
下記ヘッダファイルのenumに定義されている。
/System/Library/Frameworks/Carbon.framework/Frameworks/HIToolbox.framework/Headers/Events.h
enum {
kVK_ANSI_A = 0x00,
kVK_ANSI_S = 0x01,
kVK_ANSI_D = 0x02,
// 以下略
};
プログラム内で使うにはCarbonをインクルードして使う。
keylogger.c
#include <Carbon/Carbon.h>
コンパイル。
cc keylogger.c -o keylogger -framework ApplicationServices -framework Carbon