Files
keyboard/CustomKeyboard/Model/KBKeyboardLayoutConfig.m
2026-01-08 16:54:38 +08:00

188 lines
5.9 KiB
Objective-C

//
// KBKeyboardLayoutConfig.m
// CustomKeyboard
//
#import "KBKeyboardLayoutConfig.h"
#import <MJExtension/MJExtension.h>
#import "KBConfig.h"
static NSString * const kKBKeyboardLayoutConfigFileName = @"kb_keyboard_layout_config";
@implementation KBKeyboardLayoutMetrics
@end
@implementation KBKeyboardLayoutFonts
@end
@implementation KBKeyboardKeyDef
@end
@implementation KBKeyboardRowItem
+ (NSDictionary *)mj_replacedKeyFromPropertyName {
return @{ @"itemId": @"id" };
}
+ (NSArray<KBKeyboardRowItem *> *)itemsFromRawArray:(NSArray *)raw {
if (![raw isKindOfClass:[NSArray class]] || raw.count == 0) {
return @[];
}
NSMutableArray<KBKeyboardRowItem *> *items = [NSMutableArray arrayWithCapacity:raw.count];
for (id obj in raw) {
if ([obj isKindOfClass:[NSString class]]) {
KBKeyboardRowItem *item = [KBKeyboardRowItem new];
item.itemId = (NSString *)obj;
[items addObject:item];
continue;
}
if ([obj isKindOfClass:[NSDictionary class]]) {
KBKeyboardRowItem *item = [KBKeyboardRowItem mj_objectWithKeyValues:obj];
if (item.itemId.length == 0) {
NSString *fallback = ((NSDictionary *)obj)[@"id"];
if ([fallback isKindOfClass:[NSString class]]) {
item.itemId = fallback;
}
}
if (item.itemId.length > 0) {
[items addObject:item];
}
}
}
return items.copy;
}
@end
@implementation KBKeyboardRowSegments
- (NSArray<KBKeyboardRowItem *> *)leftItems {
return [KBKeyboardRowItem itemsFromRawArray:self.left ?: @[]];
}
- (NSArray<KBKeyboardRowItem *> *)centerItems {
return [KBKeyboardRowItem itemsFromRawArray:self.center ?: @[]];
}
- (NSArray<KBKeyboardRowItem *> *)rightItems {
return [KBKeyboardRowItem itemsFromRawArray:self.right ?: @[]];
}
@end
@implementation KBKeyboardRowConfig
- (NSArray<KBKeyboardRowItem *> *)resolvedItems {
return [KBKeyboardRowItem itemsFromRawArray:self.items ?: @[]];
}
@end
@implementation KBKeyboardLayout
+ (NSDictionary *)mj_objectClassInArray {
return @{ @"rows": [KBKeyboardRowConfig class] };
}
@end
@implementation KBKeyboardLayoutConfig
+ (instancetype)sharedConfig {
static KBKeyboardLayoutConfig *config = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSString *path = [[NSBundle mainBundle] pathForResource:kKBKeyboardLayoutConfigFileName ofType:@"json"];
NSData *data = path.length ? [NSData dataWithContentsOfFile:path] : nil;
config = data ? [KBKeyboardLayoutConfig configFromJSONData:data] : nil;
});
return config;
}
+ (instancetype)configFromJSONData:(NSData *)data {
if (data.length == 0) { return nil; }
NSError *error = nil;
id json = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
if (error || ![json isKindOfClass:[NSDictionary class]]) {
return nil;
}
NSDictionary *dict = (NSDictionary *)json;
KBKeyboardLayoutConfig *config = [KBKeyboardLayoutConfig mj_objectWithKeyValues:dict];
NSDictionary *keyDefsRaw = dict[@"keyDefs"];
if ([keyDefsRaw isKindOfClass:[NSDictionary class]]) {
NSMutableDictionary<NSString *, KBKeyboardKeyDef *> *defs = [NSMutableDictionary dictionaryWithCapacity:keyDefsRaw.count];
[keyDefsRaw enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
if (![key isKindOfClass:[NSString class]] || ![obj isKindOfClass:[NSDictionary class]]) {
return;
}
KBKeyboardKeyDef *def = [KBKeyboardKeyDef mj_objectWithKeyValues:obj];
if (def) {
defs[key] = def;
}
}];
config.keyDefs = defs.copy;
}
NSDictionary *layoutsRaw = dict[@"layouts"];
if ([layoutsRaw isKindOfClass:[NSDictionary class]]) {
NSMutableDictionary<NSString *, KBKeyboardLayout *> *layouts = [NSMutableDictionary dictionaryWithCapacity:layoutsRaw.count];
[layoutsRaw enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
if (![key isKindOfClass:[NSString class]] || ![obj isKindOfClass:[NSDictionary class]]) {
return;
}
KBKeyboardLayout *layout = [KBKeyboardLayout mj_objectWithKeyValues:obj];
if (layout) {
layouts[key] = layout;
}
}];
config.layouts = layouts.copy;
}
return config;
}
- (CGFloat)scaledValue:(CGFloat)designValue {
CGFloat baseWidth = (self.designWidth > 0.0) ? self.designWidth : KB_DESIGN_WIDTH;
CGFloat scale = KBScreenWidth() / baseWidth;
return designValue * scale;
}
- (CGFloat)keyboardAreaDesignHeight {
KBKeyboardLayout *layout = [self layoutForName:@"letters"] ?: self.layouts.allValues.firstObject;
NSUInteger rowCount = layout.rows.count;
if (rowCount == 0) { return 0.0; }
CGFloat rowSpacing = self.metrics.rowSpacing.doubleValue;
CGFloat topInset = self.metrics.topInset.doubleValue;
CGFloat bottomInset = self.metrics.bottomInset.doubleValue;
CGFloat total = topInset + bottomInset + rowSpacing * (rowCount - 1);
for (KBKeyboardRowConfig *row in layout.rows) {
CGFloat height = row.height.doubleValue;
if (height <= 0.0) {
height = self.metrics.keyHeight.doubleValue;
}
if (height <= 0.0) { height = 40.0; }
total += height;
}
return total;
}
- (CGFloat)keyboardAreaScaledHeight {
CGFloat designHeight = [self keyboardAreaDesignHeight];
return designHeight > 0.0 ? [self scaledValue:designHeight] : 0.0;
}
- (KBKeyboardLayout *)layoutForName:(NSString *)name {
if (name.length == 0) { return nil; }
return self.layouts[name];
}
- (KBKeyboardKeyDef *)keyDefForIdentifier:(NSString *)identifier {
if (identifier.length == 0) { return nil; }
return self.keyDefs[identifier];
}
@end