I want to create a virtual keyboard in osx. Is it possible? I mean can I make a program that gives same signals than real keyboard. Example of this kind of keyboard would be onscreen keyboard, or keybord viewer (does it have necessary interface btw).
How low should I start? Should I make a device driver e.g. virtual (wireless) keyboard? Or does cocoa etc. have the necessary stuff?
The requirements I have are:
- a list of tuples (time, key_down/key_up, key_code) corresponds to person typing
- virtual keyboard should work side by side with the real one (like touchpad and bluetooh mouse)
- this should work with every program. Hardest examples I can find are: Terminal+vim, remote desktop, games like starcraft
Sample code and links are more than welcome.
edit: The main point is to have programmatic access to keystrokes. There are similar programs but they are with closed source (e.g. http://www.assistiveware.com/keystrokes.php). I want to know what is the best way to make this kind of program.
edit 2: Now I got this party started. Below is a copy-edit-paste-try-something-else code that basically includes all necessary parts to make a virtual keyboard. In this case, every time I press 'a' the virtual keyboard presses 'z'. There is a bug, that there is multiple 'z's added...
#import <ApplicationServices/ApplicationServices.h>
CGEventRef myCGEventCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon) {
UniChar unicodeString[101];
UniCharCount unicharCount;
char chars[2];
int i,j,charsLen;
CGEventRef zDown;
CGEventRef zUp;
zDown = CGEventCreateKeyboardEvent (NULL, (CGKeyCode)6, true);
zUp = CGEventCreateKeyboardEvent (NULL, (CGKeyCode)6, false);
//printf("%u %u\n", (uint32_t)type, (uint32_t) event);
CGEventKeyboardGetUnicodeString(event, 100, &unicharCount, unicodeString);
for (i=0; i < unicharCount; i++)
{
if (unicodeString[i] > 127) {
chars[0] = (unicodeString[i] >> 8) & (1 << 8) - 1;
chars[1] = unicodeString[i] & (1 << 8) - 1;
charsLen = 2;
} else {
charsLen = 1;
chars[0] = unicodeString[i];
}
//for (j = 0; j < charsLen; j++) printf("%c", chars[j]);
}
if (chars[0] == 'a')
{
CGEventPost(kCGHIDEventTap, zDown);
CGEventPost(kCGHIDEventTap, zUp);
}
return event;
}
int main (int argc, const char * argv[]) {
CFMachPortRef eventTap;
CFRunLoopSourceRef runLoopSource;
eventTap = CGEventTapCreate(kCGSessionEventTap, kCGHeadInsertEventTap, 0, kCGEventMaskForAllEvents, myCGEventCallback, NULL);
runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0);
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes);
CGEventTapEnable(eventTap, true);
CFRunLoopRun();
return 0;
}
br,
Juha