@@ -9,6 +9,7 @@
# import "KBSkinManager.h"
# import "KBKeyPreviewView.h"
# import "KBBackspaceLongPressHandler.h"
# import "KBKeyboardLayoutConfig.h"
// UI 常 量 统 一 管 理 , 方 便 后 续 调 试 样 式 ( 以 375 宽 设 计 稿 为 基 准 , 通 过 KBFit 做 等 比 缩 放 )
# define kKBRowVerticalSpacing KBFit ( 8.0 f )
@@ -33,6 +34,7 @@ static const CGFloat kKBLettersRow2EdgeSpacerMultiplier = 0.5;
@ property ( nonatomic , strong ) NSArray < NSArray < KBKey * > * > * keysForRows ;
@ property ( nonatomic , strong ) KBBackspaceLongPressHandler * backspaceHandler ;
@ property ( nonatomic , strong ) KBKeyPreviewView * previewView ;
@ property ( nonatomic , strong ) KBKeyboardLayoutConfig * layoutConfig ;
@ end
@ implementation KBKeyboardView
@@ -44,6 +46,7 @@ static const CGFloat kKBLettersRow2EdgeSpacerMultiplier = 0.5;
// 默 认 小 写 : 与 需 求 一 致 , 初 始 不 开 启 Shift
_shiftOn = NO ;
_symbolsMoreOn = NO ; // 数 字 面 板 默 认 第 一 页 ( 123 )
self . layoutConfig = [ KBKeyboardLayoutConfig sharedConfig ] ;
self . backspaceHandler = [ [ KBBackspaceLongPressHandler alloc ] initWithContainerView : self ] ;
[ self buildBase ] ;
[ self reloadKeys ] ;
@@ -67,26 +70,39 @@ static const CGFloat kKBLettersRow2EdgeSpacerMultiplier = 0.5;
[ self addSubview : self . row3 ] ;
[ self addSubview : self . row4 ] ;
KBKeyboardLayoutConfig * config = [ self kb_layoutConfig ] ;
KBKeyboardLayout * layout = [ self kb_layoutForName : @ "letters" ] ;
NSArray < KBKeyboardRowConfig * > * rows = layout . rows ? : @ [ ] ;
CGFloat rowSpacing = [ self kb_metricValue : config . metrics . rowSpacing fallback : nil defaultValue : 8.0 ] ;
CGFloat topInset = [ self kb_metricValue : config . metrics . topInset fallback : nil defaultValue : 8.0 ] ;
CGFloat bottomInset = [ self kb_metricValue : config . metrics . bottomInset fallback : nil defaultValue : 6.0 ] ;
CGFloat row1Height = [ self kb_rowHeightForRow : ( rows . count > 0 ? rows [ 0 ] : nil ) ] ;
CGFloat row2Height = [ self kb_rowHeightForRow : ( rows . count > 1 ? rows [ 1 ] : nil ) ] ;
CGFloat row3Height = [ self kb_rowHeightForRow : ( rows . count > 2 ? rows [ 2 ] : nil ) ] ;
CGFloat row4Height = [ self kb_rowHeightForRow : ( rows . count > 3 ? rows [ 3 ] : nil ) ] ;
[ self . row1 mas_makeConstraints : ^ ( MASConstraintMaker * make ) {
make . top . equalTo ( self . mas_top ) . offset ( kKBRowVerticalSpacing ) ;
make . top . equalTo ( self . mas_top ) . offset ( topInset ) ;
make . left . right . equalTo ( self ) ;
make . height . mas_equalTo ( kKBR owHeight) ;
make . height . mas_equalTo ( r ow1 Height) ;
} ] ;
[ self . row2 mas_makeConstraints : ^ ( MASConstraintMaker * make ) {
make . top . equalTo ( self . row1 . mas_bottom ) . offset ( kKBRowVertical Spacing) ;
make . top . equalTo ( self . row1 . mas_bottom ) . offset ( row Spacing) ;
make . left . right . equalTo ( self ) ;
make . height . equalTo( self . row1 ) ;
make . height . mas_ equalTo( row2Height ) ;
} ] ;
[ self . row3 mas_makeConstraints : ^ ( MASConstraintMaker * make ) {
make . top . equalTo ( self . row2 . mas_bottom ) . offset ( kKBRowVertical Spacing) ;
make . top . equalTo ( self . row2 . mas_bottom ) . offset ( row Spacing) ;
make . left . right . equalTo ( self ) ;
make . height . equalTo( self . row1 ) ;
make . height . mas_ equalTo( row3Height ) ;
} ] ;
[ self . row4 mas_makeConstraints : ^ ( MASConstraintMaker * make ) {
make . top . equalTo ( self . row3 . mas_bottom ) . offset ( kKBRowVertical Spacing) ;
make . top . equalTo ( self . row3 . mas_bottom ) . offset ( row Spacing) ;
make . left . right . equalTo ( self ) ;
make . height . equalTo( self . row1 ) ;
make . bottom . equalTo ( self . mas_bottom ) . offset ( -6 ) ;
make . height . mas_ equalTo( row4Height ) ;
make . bottom . equalTo ( self . mas_bottom ) . offset ( - bottomInset ) ;
} ] ;
}
@@ -99,18 +115,17 @@ static const CGFloat kKBLettersRow2EdgeSpacerMultiplier = 0.5;
[ row . subviews makeObjectsPerformSelector : @ selector ( removeFromSuperview ) ] ;
}
self . keysForRows = [ self buildKeysForC urrentLayout] ;
if ( self . keysForRows . count < 4 ) return ;
KBKeyboardLayout * layout = [ self kb_c urrentLayout] ;
NSArray < KBKeyboardRowConfig * > * rows = layout . rows ? : @ [ ] ;
if ( rows . count < 4 ) {
[ self kb_buildLegacyLayout ] ;
return ;
}
[ self buildRow : self . row1 withKeys : self . keysForR ows [ 0 ] ] ;
// 第 二 行 : 字 母 布 局 时 通 过 左 右 等 宽 占 位 让 整 行 居 中
CGFloat row2Spacer = ( self . layoutStyle = = KBKeyboardLayoutStyleLetters )
? kKBLettersRow2EdgeSpacerMultiplier : 0.0 ;
[ self buildRow : self . row2 withKeys : self . keysForRows [ 1 ] edgeSpacerMultiplier : row2Spacer ] ;
[ self buildRow : self . row3 withKeys : self . keysForRows [ 2 ] ] ;
[ self buildRow : self . row4 withKeys : self . keysForRows [ 3 ] ] ;
[ self buildRow : self . row1 withRowConfig : r ows [ 0 ] ] ;
[ self buildRow : self . row2 withRowConfig : rows [ 1 ] ] ;
[ self buildRow : self . row3 withRowConfig : rows [ 2 ] ] ;
[ self buildRow : self . row4 withRowConfig : rows [ 3 ] ] ;
}
# pragma mark - Key Model Construction
@@ -315,6 +330,152 @@ static const CGFloat kKBLettersRow2EdgeSpacerMultiplier = 0.5;
# pragma mark - Row Building
- ( void ) buildRow : ( UIView * ) row withRowConfig : ( KBKeyboardRowConfig * ) rowConfig {
if ( ! row || ! rowConfig ) { return ; }
CGFloat gap = [ self kb_gapForRow : rowConfig ] ;
CGFloat insetLeft = [ self kb_insetLeftForRow : rowConfig ] ;
CGFloat insetRight = [ self kb_insetRightForRow : rowConfig ] ;
if ( rowConfig . segments ) {
KBKeyboardRowSegments * segments = rowConfig . segments ;
NSArray < KBKeyboardRowItem * > * leftItems = [ segments leftItems ] ;
NSArray < KBKeyboardRowItem * > * centerItems = [ segments centerItems ] ;
NSArray < KBKeyboardRowItem * > * rightItems = [ segments rightItems ] ;
UIView * leftContainer = [ UIView new ] ;
UIView * centerContainer = [ UIView new ] ;
UIView * rightContainer = [ UIView new ] ;
[ row addSubview : leftContainer ] ;
[ row addSubview : centerContainer ] ;
[ row addSubview : rightContainer ] ;
[ leftContainer mas_makeConstraints : ^ ( MASConstraintMaker * make ) {
make . left . equalTo ( row . mas_left ) . offset ( insetLeft ) ;
make . top . bottom . equalTo ( row ) ;
} ] ;
[ rightContainer mas_makeConstraints : ^ ( MASConstraintMaker * make ) {
make . right . equalTo ( row . mas_right ) . offset ( - insetRight ) ;
make . top . bottom . equalTo ( row ) ;
} ] ;
[ centerContainer mas_makeConstraints : ^ ( MASConstraintMaker * make ) {
make . centerX . equalTo ( row ) ;
make . top . bottom . equalTo ( row ) ;
make . left . greaterThanOrEqualTo ( leftContainer . mas_right ) . offset ( gap ) ;
make . right . lessThanOrEqualTo ( rightContainer . mas_left ) . offset ( - gap ) ;
} ] ;
if ( leftItems . count = = 0 ) {
[ leftContainer mas_makeConstraints : ^ ( MASConstraintMaker * make ) {
make . width . mas_equalTo ( 0 ) ;
} ] ;
}
if ( centerItems . count = = 0 ) {
[ centerContainer mas_makeConstraints : ^ ( MASConstraintMaker * make ) {
make . width . mas_equalTo ( 0 ) ;
} ] ;
}
if ( rightItems . count = = 0 ) {
[ rightContainer mas_makeConstraints : ^ ( MASConstraintMaker * make ) {
make . width . mas_equalTo ( 0 ) ;
} ] ;
}
[ self kb_buildButtonsInContainer : leftContainer
items : leftItems
gap : gap
insetLeft : 0
insetRight : 0
alignCenter : NO ] ;
[ self kb_buildButtonsInContainer : centerContainer
items : centerItems
gap : gap
insetLeft : 0
insetRight : 0
alignCenter : NO ] ;
[ self kb_buildButtonsInContainer : rightContainer
items : rightItems
gap : gap
insetLeft : 0
insetRight : 0
alignCenter : NO ] ;
return ;
}
BOOL alignCenter = [ rowConfig . align . lowercaseString isEqualToString : @ "center" ] ;
[ self kb_buildButtonsInContainer : row
items : [ rowConfig resolvedItems ]
gap : gap
insetLeft : insetLeft
insetRight : insetRight
alignCenter : alignCenter ] ;
}
- ( void ) kb_buildButtonsInContainer : ( UIView * ) container
items : ( NSArray < KBKeyboardRowItem * > * ) items
gap : ( CGFloat ) gap
insetLeft : ( CGFloat ) insetLeft
insetRight : ( CGFloat ) insetRight
alignCenter : ( BOOL ) alignCenter {
if ( items . count = = 0 ) { return ; }
UIView * leftSpacer = nil ;
UIView * rightSpacer = nil ;
if ( alignCenter ) {
leftSpacer = [ UIView new ] ;
rightSpacer = [ UIView new ] ;
[ container addSubview : leftSpacer ] ;
[ container addSubview : rightSpacer ] ;
[ leftSpacer mas_makeConstraints : ^ ( MASConstraintMaker * make ) {
make . left . equalTo ( container . mas_left ) . offset ( insetLeft ) ;
make . top . bottom . equalTo ( container ) ;
} ] ;
[ rightSpacer mas_makeConstraints : ^ ( MASConstraintMaker * make ) {
make . right . equalTo ( container . mas_right ) . offset ( - insetRight ) ;
make . top . bottom . equalTo ( container ) ;
} ] ;
[ leftSpacer mas_makeConstraints : ^ ( MASConstraintMaker * make ) {
make . width . equalTo ( rightSpacer ) ;
} ] ;
}
KBKeyButton * previous = nil ;
for ( KBKeyboardRowItem * item in items ) {
KBKeyButton * btn = [ self kb_buttonForItem : item ] ;
if ( ! btn ) { continue ; }
[ container addSubview : btn ] ;
[ btn mas_makeConstraints : ^ ( MASConstraintMaker * make ) {
make . top . bottom . equalTo ( container ) ;
if ( previous ) {
make . left . equalTo ( previous . mas_right ) . offset ( gap ) ;
} else {
if ( leftSpacer ) {
make . left . equalTo ( leftSpacer . mas_right ) . offset ( gap ) ;
} else {
make . left . equalTo ( container . mas_left ) . offset ( insetLeft ) ;
}
}
} ] ;
CGFloat width = [ self kb_widthForItem : item key : btn . key ] ;
if ( width > 0.0 ) {
[ btn mas_makeConstraints : ^ ( MASConstraintMaker * make ) {
make . width . mas_equalTo ( width ) ;
} ] ;
}
previous = btn ;
}
if ( ! previous ) { return ; }
[ previous mas_makeConstraints : ^ ( MASConstraintMaker * make ) {
if ( rightSpacer ) {
make . right . equalTo ( rightSpacer . mas_left ) . offset ( - gap ) ;
} else {
make . right . equalTo ( container . mas_right ) . offset ( - insetRight ) ;
}
} ] ;
}
- ( void ) buildRow : ( UIView * ) row withKeys : ( NSArray < KBKey * > * ) keys {
[ self buildRow : row withKeys : keys edgeSpacerMultiplier : 0.0 ] ;
}
@@ -581,6 +742,382 @@ edgeSpacerMultiplier:(CGFloat)edgeSpacerMultiplier {
// Space 不 设 置 宽 度 ; 通 过 此 前 已 建 立 的 左 右 约 束 自 动 占 满 剩 余 宽 度 。
}
# pragma mark - Config Helpers
- ( KBKeyboardLayoutConfig * ) kb_layoutConfig {
if ( ! self . layoutConfig ) {
self . layoutConfig = [ KBKeyboardLayoutConfig sharedConfig ] ;
}
return self . layoutConfig ;
}
- ( KBKeyboardLayout * ) kb_layoutForName : ( NSString * ) name {
return [ [ self kb_layoutConfig ] layoutForName : name ] ;
}
- ( KBKeyboardLayout * ) kb_currentLayout {
if ( self . layoutStyle = = KBKeyboardLayoutStyleNumbers ) {
return [ self kb_layoutForName : ( self . symbolsMoreOn ? @ "symbolsMore" : @ "numbers" ) ] ;
}
return [ self kb_layoutForName : @ "letters" ] ;
}
- ( void ) kb_buildLegacyLayout {
self . keysForRows = [ self buildKeysForCurrentLayout ] ;
if ( self . keysForRows . count < 4 ) { return ; }
[ self buildRow : self . row1 withKeys : self . keysForRows [ 0 ] ] ;
CGFloat row2Spacer = ( self . layoutStyle = = KBKeyboardLayoutStyleLetters )
? kKBLettersRow2EdgeSpacerMultiplier : 0.0 ;
[ self buildRow : self . row2 withKeys : self . keysForRows [ 1 ] edgeSpacerMultiplier : row2Spacer ] ;
[ self buildRow : self . row3 withKeys : self . keysForRows [ 2 ] ] ;
[ self buildRow : self . row4 withKeys : self . keysForRows [ 3 ] ] ;
}
- ( CGFloat ) kb_scaledValue : ( CGFloat ) designValue {
KBKeyboardLayoutConfig * config = [ self kb_layoutConfig ] ;
if ( config ) {
return [ config scaledValue : designValue ] ;
}
return KBFit ( designValue ) ;
}
- ( CGFloat ) kb_numberValue : ( NSNumber * ) value defaultValue : ( CGFloat ) defaultValue {
if ( [ value isKindOfClass : [ NSNumber class ] ] ) {
return value . doubleValue ;
}
return defaultValue ;
}
- ( CGFloat ) kb_metricValue : ( NSNumber * ) value fallback : ( NSNumber * ) fallback defaultValue : ( CGFloat ) defaultValue {
CGFloat v = [ self kb_numberValue : value defaultValue : -1.0 ] ;
if ( v < 0.0 ) {
v = [ self kb_numberValue : fallback defaultValue : defaultValue ] ;
}
if ( v < 0.0 ) {
v = defaultValue ;
}
return [ self kb_scaledValue : v ] ;
}
- ( CGFloat ) kb_rowHeightForRow : ( KBKeyboardRowConfig * ) row {
KBKeyboardLayoutConfig * config = [ self kb_layoutConfig ] ;
NSNumber * height = row . height ? : config . metrics . keyHeight ;
CGFloat value = [ self kb_numberValue : height defaultValue : 40.0 ] ;
return [ self kb_scaledValue : value ] ;
}
- ( CGFloat ) kb_gapForRow : ( KBKeyboardRowConfig * ) row {
KBKeyboardLayoutConfig * config = [ self kb_layoutConfig ] ;
return [ self kb_metricValue : row . gap fallback : config . metrics . gap defaultValue : 5.0 ] ;
}
- ( CGFloat ) kb_insetLeftForRow : ( KBKeyboardRowConfig * ) row {
KBKeyboardLayoutConfig * config = [ self kb_layoutConfig ] ;
return [ self kb_metricValue : row . insetLeft fallback : config . metrics . edgeInset defaultValue : 0.0 ] ;
}
- ( CGFloat ) kb_insetRightForRow : ( KBKeyboardRowConfig * ) row {
KBKeyboardLayoutConfig * config = [ self kb_layoutConfig ] ;
return [ self kb_metricValue : row . insetRight fallback : config . metrics . edgeInset defaultValue : 0.0 ] ;
}
- ( KBKeyButton * ) kb_buttonForItem : ( KBKeyboardRowItem * ) item {
if ( item . itemId . length = = 0 ) { return nil ; }
KBKeyboardKeyDef * def = [ [ self kb_layoutConfig ] keyDefForIdentifier : item . itemId ] ;
KBKey * key = [ self kb_keyForItemId : item . itemId ] ;
if ( ! key ) { return nil ; }
KBKeyButton * btn = [ [ KBKeyButton alloc ] init ] ;
btn . key = key ;
[ btn setTitle : key . title forState : UIControlStateNormal ] ;
UIColor * bgColor = [ self kb_backgroundColorForItem : item keyDef : def ] ;
if ( bgColor ) {
btn . customBackgroundColor = bgColor ;
}
CGFloat fontSize = [ self kb_fontSizeForItem : item key : key ] ;
if ( fontSize > 0.0 ) {
btn . titleLabel . font = [ UIFont systemFontOfSize : fontSize weight : UIFontWeightSemibold ] ;
}
[ btn applyThemeForCurrentKey ] ;
[ self kb_applySymbolIfNeededForButton : btn keyDef : def fontSize : fontSize ] ;
[ btn addTarget : self action : @ selector ( onKeyTapped : ) forControlEvents : UIControlEventTouchUpInside ] ;
if ( key . type = = KBKeyTypeBackspace ) {
[ self . backspaceHandler bindDeleteButton : btn showClearLabel : YES ] ;
}
if ( key . type = = KBKeyTypeShift ) {
btn . selected = self . shiftOn ;
}
return btn ;
}
- ( void ) kb_applySymbolIfNeededForButton : ( KBKeyButton * ) button
keyDef : ( KBKeyboardKeyDef * ) def
fontSize : ( CGFloat ) fontSize {
if ( ! button || ! def ) { return ; }
if ( button . iconView . image ! = nil ) { return ; }
NSString * symbolName = button . isSelected ? def . selectedSymbolName : def . symbolName ;
if ( symbolName . length = = 0 ) { return ; }
UIImage * image = [ UIImage systemImageNamed : symbolName ] ;
if ( ! image ) { return ; }
UIImageSymbolConfiguration * config = [ UIImageSymbolConfiguration configurationWithPointSize : fontSize weight : UIFontWeightSemibold ] ;
image = [ image imageWithConfiguration : config ] ;
button . iconView . image = image ;
button . iconView . hidden = NO ;
button . iconView . contentMode = UIViewContentModeCenter ;
button . titleLabel . hidden = YES ;
UIColor * textColor = [ KBSkinManager shared ] . current . keyTextColor ? : [ UIColor blackColor ] ;
button . iconView . tintColor = button . isSelected ? [ UIColor blackColor ] : textColor ;
}
- ( UIColor * ) kb_backgroundColorForItem : ( KBKeyboardRowItem * ) item keyDef : ( KBKeyboardKeyDef * ) def {
NSString * hex = def . backgroundColor ;
if ( hex . length = = 0 ) {
hex = [ self kb_layoutConfig ] . defaultKeyBackground ;
}
if ( hex . length = = 0 ) { return nil ; }
return [ KBSkinManager colorFromHexString : hex defaultColor : nil ] ;
}
- ( CGFloat ) kb_metricWidthForKey : ( NSString * ) key {
KBKeyboardLayoutMetrics * m = [ self kb_layoutConfig ] . metrics ;
if ( [ key isEqualToString : @ "letterWidth" ] ) { return m . letterWidth . doubleValue ; }
if ( [ key isEqualToString : @ "controlWidth" ] ) { return m . controlWidth . doubleValue ; }
if ( [ key isEqualToString : @ "sendWidth" ] ) { return m . sendWidth . doubleValue ; }
if ( [ key isEqualToString : @ "symbolsWideWidth" ] ) { return m . symbolsWideWidth . doubleValue ; }
if ( [ key isEqualToString : @ "symbolsSideWidth" ] ) { return m . symbolsSideWidth . doubleValue ; }
return 0.0 ;
}
- ( CGFloat ) kb_widthForItem : ( KBKeyboardRowItem * ) item key : ( KBKey * ) key {
CGFloat width = 0.0 ;
if ( item . widthValue . doubleValue > 0.0 ) {
width = item . widthValue . doubleValue ;
} else if ( item . width . length > 0 ) {
if ( [ item . width . lowercaseString isEqualToString : @ "flex" ] ) {
return 0.0 ;
}
width = [ self kb_metricWidthForKey : item . width ] ;
if ( width <= 0.0 ) {
width = item . width . doubleValue ;
}
}
if ( width <= 0.0 ) {
KBKeyboardLayoutMetrics * m = [ self kb_layoutConfig ] . metrics ;
if ( [ item . itemId hasPrefix : @ "letter:" ] ||
[ item . itemId hasPrefix : @ "digit:" ] ||
[ item . itemId hasPrefix : @ "sym:" ] ) {
width = m . letterWidth . doubleValue ;
} else if ( key . type = = KBKeyTypeReturn ) {
width = m . sendWidth . doubleValue ;
} else if ( key . type = = KBKeyTypeSpace ) {
return 0.0 ;
} else {
width = m . controlWidth . doubleValue ;
}
}
if ( width <= 0.0 ) {
if ( [ item . itemId hasPrefix : @ "letter:" ] ||
[ item . itemId hasPrefix : @ "digit:" ] ||
[ item . itemId hasPrefix : @ "sym:" ] ) {
width = 32.0 ;
} else if ( key . type = = KBKeyTypeReturn ) {
width = 88.0 ;
} else if ( key . type = = KBKeyTypeSpace ) {
return 0.0 ;
} else {
width = 41.0 ;
}
}
return width > 0.0 ? [ self kb_scaledValue : width ] : 0.0 ;
}
- ( CGFloat ) kb_fontSizeForItem : ( KBKeyboardRowItem * ) item key : ( KBKey * ) key {
NSString * fontKey = nil ;
if ( [ item . itemId hasPrefix : @ "letter:" ] ) {
fontKey = @ "letter" ;
} else if ( [ item . itemId hasPrefix : @ "digit:" ] ) {
fontKey = @ "digit" ;
} else if ( [ item . itemId hasPrefix : @ "sym:" ] ) {
fontKey = @ "symbol" ;
} else {
KBKeyboardKeyDef * def = [ [ self kb_layoutConfig ] keyDefForIdentifier : item . itemId ] ;
fontKey = def . font ;
}
if ( fontKey . length = = 0 ) {
switch ( key . type ) {
case KBKeyTypeModeChange :
case KBKeyTypeSymbolsToggle :
fontKey = @ "mode" ;
break ;
case KBKeyTypeSpace :
fontKey = @ "space" ;
break ;
case KBKeyTypeReturn :
fontKey = @ "send" ;
break ;
default :
fontKey = @ "symbol" ;
break ;
}
}
return [ self kb_fontSizeForFontKey : fontKey ] ;
}
- ( CGFloat ) kb_fontSizeForFontKey : ( NSString * ) fontKey {
KBKeyboardLayoutFonts * fonts = [ self kb_layoutConfig ] . fonts ;
CGFloat size = 0.0 ;
if ( [ fontKey isEqualToString : @ "letter" ] ) { size = fonts . letter . doubleValue ; }
else if ( [ fontKey isEqualToString : @ "digit" ] ) { size = fonts . digit . doubleValue ; }
else if ( [ fontKey isEqualToString : @ "symbol" ] ) { size = fonts . symbol . doubleValue ; }
else if ( [ fontKey isEqualToString : @ "mode" ] ) { size = fonts . mode . doubleValue ; }
else if ( [ fontKey isEqualToString : @ "space" ] ) { size = fonts . space . doubleValue ; }
else if ( [ fontKey isEqualToString : @ "send" ] ) { size = fonts . send . doubleValue ; }
if ( size <= 0.0 ) { size = 18.0 ; }
return [ self kb_scaledValue : size ] ;
}
- ( KBKey * ) kb_keyForItemId : ( NSString * ) itemId {
if ( itemId . length = = 0 ) { return nil ; }
KBKeyboardKeyDef * def = [ [ self kb_layoutConfig ] keyDefForIdentifier : itemId ] ;
if ( def ) {
return [ self kb_keyFromDef : def identifier : itemId ] ;
}
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 kb_letterKeyWithChar : value ] ;
}
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 * ) kb_keyFromDef : ( KBKeyboardKeyDef * ) def identifier : ( NSString * ) identifier {
KBKeyType type = [ self kb_keyTypeForDef : def ] ;
NSString * title = def . title ? : @ "" ;
if ( type = = KBKeyTypeShift && self . 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 ] ;
k . caseVariant = KBKeyCaseVariantNone ;
return k ;
}
- ( 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 < NSString * , NSString * > * 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_comma" ,
@ "?" : @ "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_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_bullet"
} ;
} ) ;
return map [ symbol ] ;
}
# pragma mark - Actions
- ( void ) onKeyTapped : ( KBKeyButton * ) sender {