Skip to content

Instantly share code, notes, and snippets.

@edvakf
Created September 21, 2012 15:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save edvakf/3762129 to your computer and use it in GitHub Desktop.
Save edvakf/3762129 to your computer and use it in GitHub Desktop.
#import <Cocoa/Cocoa.h>
#include <stdio.h>
#include <time.h>
#include <dispatch/dispatch.h>
#include <curl/curl.h>
#define MAXLINE 512
CFMachPortRef eventTap;
time_t prev_time = 0;
int count_key = 0;
int count_mouse = 0;
size_t curl_write_callback_func(char* ptr, size_t size, size_t nmemb, void* nothing) {
return 0;
}
int post(char *name, int num) {
char url[MAXLINE];
sprintf(url, "http://localhost:5126/api/me/log/%s", name);
char postdata[MAXLINE];
sprintf(postdata, "number=%d", num);
printf("%s: %d\n", name, num);
CURL *curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postdata);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_write_callback_func);
CURLcode res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
return res == CURLE_OK;
}
void postEventsAsync(int num_key, int num_mouse) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{
post("key", num_key);
post("mouse", num_mouse);
});
}
CGEventRef catchEventCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void* nothing) {
// http://stackoverflow.com/questions/4727149/application-randomly-stops-receiving-key-presses-cgeventtaps
if (type == kCGEventTapDisabledByTimeout) {
CGEventTapEnable(eventTap, true);
}
if (type == kCGEventKeyDown) { /* to listen for key events, run this program as root */
int key = CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode);
printf("%d\n", key);
count_key++;
}
else if (type == kCGEventMouseMoved || type == kCGEventScrollWheel) {
count_mouse++;
}
return event;
}
void recordCountsCallback(CFRunLoopTimerRef timer, void* nothing) {
time_t this_time;
struct tm * timeinfo;
time(&this_time);
timeinfo = localtime(&this_time);
timeinfo->tm_sec = 0;
this_time = mktime(timeinfo);
if (this_time == prev_time) {
// within less than 60 sec (do nothing)
return;
} else if (prev_time == 0) {
// first time (set prev_time to this_time)
} else if (difftime(this_time, prev_time) >= 120.0) {
// come back from sleep (discard)
count_key = 0;
count_mouse = 0;
postEventsAsync(count_key, count_mouse);
} else {
// more than 60 sec (record)
postEventsAsync(count_key, count_mouse);
count_key = 0;
count_mouse = 0;
}
prev_time = this_time;
}
int main() {
CFRunLoopSourceRef runLoopSource;
eventTap = CGEventTapCreate(kCGHIDEventTap, kCGHeadInsertEventTap, 0, kCGEventMaskForAllEvents, catchEventCallback, NULL);
runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0);
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes);
CGEventTapEnable(eventTap, true);
CFRunLoopTimerRef timer = CFRunLoopTimerCreate(kCFAllocatorDefault, 0, 1.0, 0, 0, recordCountsCallback, NULL);
CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopDefaultMode);
CFRunLoopRun();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment