// // KBKeyboardKeyFactory.m // CustomKeyboard // #import "KBKeyboardKeyFactory.h" #import "KBKeyboardLayoutConfig.h" #import "KBKey.h" @interface KBKeyboardKeyFactory () @property (nonatomic, strong) KBKeyboardLayoutConfig *layoutConfig; @end @implementation KBKeyboardKeyFactory - (instancetype)initWithLayoutConfig:(KBKeyboardLayoutConfig *)layoutConfig { self = [super init]; if (self) { _layoutConfig = layoutConfig; } return self; } - (KBKey *)keyForItemId:(NSString *)itemId shiftOn:(BOOL)shiftOn { if (itemId.length == 0) { return nil; } KBKeyboardKeyDef *def = [self.layoutConfig keyDefForIdentifier:itemId]; if (def) { return [self keyFromDef:def identifier:itemId shiftOn:shiftOn]; } NSRange range = [itemId rangeOfString:@":"]; if (range.location != NSNotFound) { NSString *prefix = [itemId substringToIndex:range.location]; NSString *value = [itemId substringFromIndex:range.location + 1]; if ([prefix isEqualToString:@"letter"]) { if (value.length >= 1) { return [self letterKeyWithChar:value shiftOn:shiftOn]; } return nil; } if ([prefix isEqualToString:@"digit"]) { NSString *identifier = [NSString stringWithFormat:@"digit_%@", value]; KBKey *k = [KBKey keyWithIdentifier:identifier title:value output:value type:KBKeyTypeCharacter]; k.caseVariant = KBKeyCaseVariantNone; return k; } if ([prefix isEqualToString:@"sym"]) { NSString *identifier = [self kb_identifierForSymbol:value]; KBKey *k = [KBKey keyWithIdentifier:identifier title:value output:value type:KBKeyTypeCharacter]; k.caseVariant = KBKeyCaseVariantNone; return k; } } return nil; } - (KBKey *)keyFromDef:(KBKeyboardKeyDef *)def identifier:(NSString *)identifier shiftOn:(BOOL)shiftOn { KBKeyType type = [self kb_keyTypeForDef:def]; NSString *title = def.title ?: @""; if (type == KBKeyTypeShift && shiftOn && def.selectedTitle.length > 0) { title = def.selectedTitle; } NSString *output = @""; switch (type) { case KBKeyTypeSpace: output = @" "; break; case KBKeyTypeReturn: output = @"\n"; break; default: output = @""; break; } NSString *finalId = identifier; if ([identifier isEqualToString:@"emoji"]) { finalId = KBKeyIdentifierEmojiPanel; } else if ([identifier isEqualToString:@"send"]) { finalId = @"return"; } KBKey *k = [KBKey keyWithIdentifier:finalId title:title output:output type:type]; if (type == KBKeyTypeShift) { k.caseVariant = shiftOn ? KBKeyCaseVariantUpper : KBKeyCaseVariantLower; } else { k.caseVariant = KBKeyCaseVariantNone; } return k; } - (KBKey *)letterKeyWithChar:(NSString *)charString shiftOn:(BOOL)shiftOn { if (charString.length == 0) { return nil; } NSString *lower = charString.lowercaseString; NSString *upper = charString.uppercaseString; NSString *shown = shiftOn ? upper : lower; NSString *identifier = [NSString stringWithFormat:@"letter_%@", lower]; KBKey *k = [KBKey keyWithIdentifier:identifier title:shown output:shown type:KBKeyTypeCharacter]; k.caseVariant = shiftOn ? KBKeyCaseVariantUpper : KBKeyCaseVariantLower; return k; } #pragma mark - Private - (KBKeyType)kb_keyTypeForDef:(KBKeyboardKeyDef *)def { NSString *type = def.type.lowercaseString; if ([type isEqualToString:@"shift"]) return KBKeyTypeShift; if ([type isEqualToString:@"backspace"]) return KBKeyTypeBackspace; if ([type isEqualToString:@"mode"]) return KBKeyTypeModeChange; if ([type isEqualToString:@"symbolstoggle"]) return KBKeyTypeSymbolsToggle; if ([type isEqualToString:@"space"]) return KBKeyTypeSpace; if ([type isEqualToString:@"return"]) return KBKeyTypeReturn; if ([type isEqualToString:@"globe"]) return KBKeyTypeGlobe; return KBKeyTypeCustom; } - (NSString *)kb_identifierForSymbol:(NSString *)symbol { if (symbol.length == 0) { return nil; } static NSDictionary *map = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ map = @{ @"-": @"sym_minus", @"/": @"sym_slash", @":": @"sym_colon", @";": @"sym_semicolon", @"(": @"sym_paren_l", @")": @"sym_paren_r", @"¥": @"sym_money", @"¥": @"sym_money", @"&": @"sym_amp", @"@": @"sym_at", @"\"": @"sym_quote_double", @"“": @"sym_quote_double", @"”": @"sym_quote_double", @".": @"sym_dot", @"。": @"sym_chinese_dot", @",": @"sym_comma", @"、": @"sym_dun", @"?": @"sym_question", @"!": @"sym_exclam", @"'": @"sym_quote_single", @"‘": @"sym_quote_single", @"’": @"sym_quote_single", @"[": @"sym_bracket_l", @"]": @"sym_bracket_r", @"{": @"sym_brace_l", @"}": @"sym_brace_r", @"「": @"sym_corner_l", @"」": @"sym_corner_r", @"#": @"sym_hash", @"%": @"sym_percent", @"^": @"sym_caret", @"*": @"sym_asterisk", @"+": @"sym_plus", @"=": @"sym_equal", @"_": @"sym_underscore", @"\\": @"sym_backslash", @"|": @"sym_pipe", @"~": @"sym_tilde", @"<": @"sym_lt", @">": @"sym_gt", @"€": @"sym_euro", @"$": @"sym_dollar", @"£": @"sym_pound", @"·": @"sym_bullet", @"^_^": @"sym_face", @"—": @"sym_emdash", @"«": @"sym_guillemet_l", @"»": @"sym_guillemet_r", @"《": @"sym_book_title_l", @"》": @"sym_book_title_r", @"...": @"sym_ellipsis" }; }); return map[symbol]; } @end