2
votes

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

2

2 Answers

1
votes

You could do this using Quartz Event Taps, which provides a:

...C API for event taps, which are filters used to observe and alter the stream of low-level user input events in Mac OS X

0
votes

On the Mac, there is the keyboard view. Why can't you use that?