Question

I have developed a custom input method and now would like to develop a tweak that would register it as a keyboard in iOS.

There are many different keyboards in Cydia (mainly from Chinese developers) such as TouchPal and Baidu Input that appear in settings as a keyboard, so it is definitely possible.

I have tried looking into the following options (barely 4 days in IDA, Xcode with theos and console):

  • Text Input bundles located in /System/Library/TextInput — seems to have nothing to deal with the keyboards themselves? Some superclass headers are missing (i.e. TIZephyr... classes) so I couldn't quite figure it out. However a native integration would be awesome.
  • TextInput private framework — also seems to be just for dictionary and so on
  • UIKit's UIKB.. and UIKeyboard.. classes — UIKeyboardImpl seems to be something related with the keyboard functioning and UIKeyboardLayout is the thing you build upon.

I tried hooking UIKeyboardDictationLayout to just give a plain instance of a UIKeyboardLayout upon initialization — and when I tapped the mic button on the keyboard, the keyboard went blank! That kind of implementation would be nice too (even though killing dictation functionality is undesired). However, I can't find where do I send typing events as well.

So the points are:

  • What is responsible for registering a class as an input method?
  • What is responsible for receiving typing events?

I am asking this in hope that there are developers who had to do something similar already, because I couldn't find any articles nor anything that would give me a hint in the header files and bundles.

Thanks in advance.

Was it helpful?

Solution

I got it right this february even though didn't have the time to respond and it's not quite necessary now that iOS 8 has come. Still, this is how you load your own keyboard:

%hook UIKeyboardInputMode

+ (id)keyboardInputModeWithIdentifier:(id)arg1 {
    id o = %orig;
    return o;
}
- (id)primaryLanguage {
    if([TegakiLayout isTegaki:[self identifier]]) return @"Tegaki";
    return %orig;
}
%end

%hook UIKeyboardImpl
/* This is where the magic is! */
+ (Class)layoutClassForInputMode:(NSString*)arg1 keyboardType:(int)arg2 {
    Class sass = %orig;
    if ([TegakiLayout isTegaki: arg1]) {
        return [TegakiLayout class];
    }
    return sass;
}
%end



extern "C" NSArray*UIKeyboardGetSupportedInputModes();
extern "C" NSArray*UIKeyboardGetActiveInputModes();
static NSArray* (*orig_modes)();
NSArray* rep_modes() {
    NSArray* res = [orig_modes() arrayByAddingObjectsFromArray:@[@"TEGAKI", @"TEGAKI_Graffiti"]];
    return res;
}

static NSArray* (*orig_active_modes)();
NSArray* rep_active_modes() {
    NSArray* res = orig_active_modes();
    return res;
}



%ctor {
    %init;
    MSHookFunction(UIKeyboardGetSupportedInputModes, rep_modes, &orig_modes);
    MSHookFunction(UIKeyboardGetActiveInputModes, rep_active_modes, &orig_active_modes);
}

where TegakiLayout is a subclass of UIKeyboardLayout.

You then implement - (BOOL)isAlphabeticPlane for returning whether it's a traditional keyboard thing and do the custom view creation in showKeyboardWithInputTraits:screenTraits:splitTraits:.

To type in you then use [[UIKeyboardImpl activeInstance]insertText:@"\n"];.

To create a 'globe' button you use this:

Class sw = NSClassFromString(@"UIInputSwitcherView");
[[sw sharedInstance]selectNextInputMode];

Don't forget to implement -keyboardName and -keyplaneName as well! I'll post the whole project one day probably, but for now it's too large to describe here. This should be enough to get you up and running, though.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top