Files
keyboard/CustomKeyboard/KeyboardViewController.m

316 lines
11 KiB
Mathematica
Raw Normal View History

2025-10-27 19:42:27 +08:00
//
// KeyboardViewController.m
// CustomKeyboard
//
// Created by Mac on 2025/10/27.
//
2026-02-24 13:38:51 +08:00
#import "KeyboardViewController+Private.h"
2025-10-28 15:10:38 +08:00
2026-01-09 19:13:35 +08:00
#import "KBBackspaceUndoManager.h"
2026-02-24 13:38:51 +08:00
#import "KBChatLimitPopView.h"
#import "KBChatPanelView.h"
2025-11-03 13:25:41 +08:00
#import "KBFullAccessManager.h"
2026-01-09 19:13:35 +08:00
#import "KBFunctionView.h"
#import "KBInputBufferManager.h"
2026-02-24 13:38:51 +08:00
#import "KBKeyBoardMainView.h"
2026-01-09 19:13:35 +08:00
#import "KBKeyboardSubscriptionView.h"
2026-02-24 13:38:51 +08:00
#import "KBLocalizationManager.h"
2026-01-09 19:13:35 +08:00
#import "KBSkinManager.h"
2026-03-02 20:20:28 +08:00
#import "KBSkinInstallBridge.h"
2025-12-22 12:54:28 +08:00
#import "KBSuggestionEngine.h"
2026-03-02 09:19:06 +08:00
#import "KBKeyboardLayoutResolver.h"
2026-01-29 19:18:38 +08:00
#import <SDWebImage/SDWebImage.h>
2026-02-24 13:38:51 +08:00
2026-02-10 13:22:19 +08:00
#if DEBUG
#import <mach/mach.h>
#endif
2026-01-09 19:13:35 +08:00
2026-02-10 13:22:19 +08:00
#if DEBUG
static NSInteger sKBKeyboardVCAliveCount = 0;
static uint64_t KBPhysFootprintBytes(void) {
task_vm_info_data_t vmInfo;
mach_msg_type_number_t count = TASK_VM_INFO_COUNT;
kern_return_t kr = task_info(mach_task_self(), TASK_VM_INFO,
(task_info_t)&vmInfo, &count);
if (kr != KERN_SUCCESS) {
return 0;
}
return (uint64_t)vmInfo.phys_footprint;
}
static NSString *KBFormatMB(uint64_t bytes) {
double mb = (double)bytes / 1024.0 / 1024.0;
return [NSString stringWithFormat:@"%.1fMB", mb];
}
#endif
2025-10-27 19:42:27 +08:00
@implementation KeyboardViewController
2025-10-30 20:23:34 +08:00
{
2026-01-09 19:13:35 +08:00
BOOL _kb_didTriggerLoginDeepLinkOnce;
2026-03-02 09:19:06 +08:00
NSString *_kb_lastLoadedProfileId; // profileId
2026-02-10 13:22:19 +08:00
#if DEBUG
BOOL _kb_debugDidCountAlive;
#endif
2025-10-30 20:23:34 +08:00
}
2025-10-27 19:42:27 +08:00
- (void)viewDidLoad {
2026-01-09 19:13:35 +08:00
[super viewDidLoad];
2026-02-10 13:22:19 +08:00
#if DEBUG
if (!_kb_debugDidCountAlive) {
_kb_debugDidCountAlive = YES;
sKBKeyboardVCAliveCount += 1;
}
NSLog(@"[Keyboard] KeyboardViewController viewDidLoad alive=%ld self=%p mem=%@",
(long)sKBKeyboardVCAliveCount, self, KBFormatMB(KBPhysFootprintBytes()));
#endif
2026-01-09 19:13:35 +08:00
// /
[[KBBackspaceUndoManager shared] registerNonClearAction];
[self setupUI];
self.suggestionEngine = [KBSuggestionEngine shared];
self.currentWord = @"";
// HUD App KeyWindow
[KBHUD setContainerView:self.view];
// 访便
[[KBFullAccessManager shared] bindInputController:self];
2026-02-10 10:21:21 +08:00
self.kb_fullAccessObserverToken = [[NSNotificationCenter defaultCenter]
2026-01-09 19:13:35 +08:00
addObserverForName:KBFullAccessChangedNotification
object:nil
queue:[NSOperationQueue mainQueue]
usingBlock:^(__unused NSNotification *_Nonnull note){
// 访 UI
}];
//
2026-02-10 10:21:21 +08:00
__weak typeof(self) weakSelf = self;
self.kb_skinObserverToken = [[NSNotificationCenter defaultCenter]
2026-01-09 19:13:35 +08:00
addObserverForName:KBSkinDidChangeNotification
object:nil
queue:[NSOperationQueue mainQueue]
usingBlock:^(__unused NSNotification *_Nonnull note) {
2026-02-10 10:21:21 +08:00
__strong typeof(weakSelf) self = weakSelf;
if (!self) {
return;
}
2026-01-09 19:13:35 +08:00
[self kb_applyTheme];
}];
[self kb_applyTheme];
2026-02-24 13:38:51 +08:00
[self kb_registerDarwinSkinInstallObserver];
2026-01-09 19:13:35 +08:00
[self kb_consumePendingShopSkin];
[self kb_applyDefaultSkinIfNeeded];
2026-03-02 09:19:06 +08:00
2026-03-02 14:39:47 +08:00
[self kb_startObservingAppGroupChanges];
2026-03-02 09:19:06 +08:00
// App Group
[self kb_checkAndApplyLayoutIfNeeded];
2026-01-09 19:13:35 +08:00
}
2025-11-04 21:01:46 +08:00
2026-02-10 13:22:19 +08:00
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
//
self.kb_cachedGradientImage = nil;
[self.kb_defaultGradientLayer removeFromSuperlayer];
self.kb_defaultGradientLayer = nil;
[[KBSkinManager shared] clearRuntimeImageCaches];
[[SDImageCache sharedImageCache] clearMemory];
}
2026-01-09 19:13:35 +08:00
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
2026-02-10 18:53:31 +08:00
// FIX: iOS 26
// setupUI 0
//
CGFloat portraitWidth = [self kb_portraitWidth];
CGFloat keyboardHeight = [self kb_keyboardHeightForWidth:portraitWidth];
if (self.kb_heightConstraint) {
self.kb_heightConstraint.constant = keyboardHeight;
}
2026-01-09 19:13:35 +08:00
// /
[[KBBackspaceUndoManager shared] registerNonClearAction];
[[KBInputBufferManager shared] resetWithText:@""];
[[KBLocalizationManager shared] reloadFromSharedStorageIfNeeded];
2026-02-10 13:22:19 +08:00
// HUD viewDidDisappear /
[KBHUD setContainerView:self.view];
[self kb_ensureKeyBoardMainViewIfNeeded];
[self kb_applyTheme];
#if DEBUG
NSLog(@"[Keyboard] viewWillAppear self=%p mem=%@",
self, KBFormatMB(KBPhysFootprintBytes()));
#endif
2026-01-09 19:13:35 +08:00
// /QQ 宿 documentContext
// liveText manualSnapshot
[[KBInputBufferManager shared]
updateFromExternalContextBefore:self.textDocumentProxy
.documentContextBeforeInput
after:self.textDocumentProxy
.documentContextAfterInput];
}
- (void)viewWillDisappear:(BOOL)animated {
2026-01-09 19:13:35 +08:00
[super viewWillDisappear:animated];
[[KBBackspaceUndoManager shared] registerNonClearAction];
2026-02-10 13:22:19 +08:00
[self kb_releaseMemoryWhenKeyboardHidden];
#if DEBUG
NSLog(@"[Keyboard] viewWillDisappear self=%p mem=%@",
self, KBFormatMB(KBPhysFootprintBytes()));
#endif
}
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
// 宿 willDisappear didDisappear
[self kb_releaseMemoryWhenKeyboardHidden];
}
2026-01-09 13:07:11 +08:00
- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection {
2026-01-09 19:13:35 +08:00
[super traitCollectionDidChange:previousTraitCollection];
if (@available(iOS 13.0, *)) {
if (previousTraitCollection.userInterfaceStyle !=
self.traitCollection.userInterfaceStyle) {
2026-02-10 10:21:21 +08:00
self.kb_cachedGradientImage = nil;
2026-01-09 19:13:35 +08:00
[self kb_applyDefaultSkinIfNeeded];
2026-01-09 13:07:11 +08:00
}
2026-01-09 19:13:35 +08:00
}
2026-01-09 13:07:11 +08:00
}
- (void)textDidChange:(id<UITextInput>)textInput {
2026-01-09 19:13:35 +08:00
[super textDidChange:textInput];
[[KBInputBufferManager shared]
updateFromExternalContextBefore:self.textDocumentProxy
.documentContextBeforeInput
after:self.textDocumentProxy
.documentContextAfterInput];
2025-11-27 15:34:33 +08:00
}
2025-10-30 20:23:34 +08:00
- (void)viewDidAppear:(BOOL)animated {
2026-01-09 19:13:35 +08:00
[super viewDidAppear:animated];
// if (!_kb_didTriggerLoginDeepLinkOnce) {
// _kb_didTriggerLoginDeepLinkOnce = YES;
// // App
// if (!KBAuthManager.shared.isLoggedIn) {
// [self kb_tryOpenContainerForLoginIfNeeded];
// }
// }
2025-10-30 20:23:34 +08:00
}
2026-01-07 13:11:23 +08:00
- (void)viewDidLayoutSubviews {
2026-01-09 19:13:35 +08:00
[super viewDidLayoutSubviews];
2026-02-24 13:38:51 +08:00
// [self kb_updateKeyboardLayoutIfNeeded];
2026-02-10 10:21:21 +08:00
//
if (self.contentView.hidden) {
self.contentView.hidden = NO;
}
2026-02-10 13:22:19 +08:00
if (self.kb_defaultGradientLayer) {
self.kb_defaultGradientLayer.frame = self.bgImageView.bounds;
}
2026-03-02 09:19:06 +08:00
//
[self kb_checkAndApplyLayoutIfNeeded];
2026-01-07 13:11:23 +08:00
}
2026-01-09 19:13:35 +08:00
- (void)viewWillTransitionToSize:(CGSize)size
withTransitionCoordinator:
(id<UIViewControllerTransitionCoordinator>)coordinator {
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
__weak typeof(self) weakSelf = self;
[coordinator
animateAlongsideTransition:^(
id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) {
2026-01-07 13:11:23 +08:00
[weakSelf kb_updateKeyboardLayoutIfNeeded];
2026-01-09 19:13:35 +08:00
}
completion:^(
__unused id<
UIViewControllerTransitionCoordinatorContext> _Nonnull context) {
2026-01-07 13:11:23 +08:00
[weakSelf kb_updateKeyboardLayoutIfNeeded];
2026-01-09 19:13:35 +08:00
}];
2026-01-07 13:11:23 +08:00
}
2026-02-24 13:38:51 +08:00
- (void)dealloc {
if (self.kb_fullAccessObserverToken) {
[[NSNotificationCenter defaultCenter]
removeObserver:self.kb_fullAccessObserverToken];
self.kb_fullAccessObserverToken = nil;
2026-02-10 10:21:21 +08:00
}
2026-02-24 13:38:51 +08:00
if (self.kb_skinObserverToken) {
[[NSNotificationCenter defaultCenter]
removeObserver:self.kb_skinObserverToken];
self.kb_skinObserverToken = nil;
2026-01-09 19:13:35 +08:00
}
2026-03-02 14:39:47 +08:00
[self kb_stopObservingAppGroupChanges];
2026-02-24 13:38:51 +08:00
[self kb_unregisterDarwinSkinInstallObserver];
2026-01-08 18:57:17 +08:00
#if DEBUG
2026-02-24 13:38:51 +08:00
if (_kb_debugDidCountAlive) {
sKBKeyboardVCAliveCount -= 1;
2026-01-09 19:13:35 +08:00
}
2026-02-24 13:38:51 +08:00
NSLog(@"[Keyboard] KeyboardViewController dealloc alive=%ld self=%p mem=%@",
(long)sKBKeyboardVCAliveCount, self, KBFormatMB(KBPhysFootprintBytes()));
2026-01-08 18:57:17 +08:00
#endif
}
2026-03-02 09:19:06 +08:00
#pragma mark - Layout Switching
- (void)kb_checkAndApplyLayoutIfNeeded {
NSString *currentProfileId = [[KBKeyboardLayoutResolver sharedResolver] currentProfileId];
if (currentProfileId.length == 0) {
2026-03-02 20:20:28 +08:00
currentProfileId = @"en_US_qwerty";
2026-03-02 09:19:06 +08:00
}
if ([currentProfileId isEqualToString:_kb_lastLoadedProfileId]) {
return;
}
NSLog(@"[KeyboardViewController] Detected profileId change: %@ -> %@", _kb_lastLoadedProfileId, currentProfileId);
_kb_lastLoadedProfileId = currentProfileId;
if (self.keyBoardMainView && [self.keyBoardMainView respondsToSelector:@selector(reloadLayoutWithProfileId:)]) {
[self.keyBoardMainView performSelector:@selector(reloadLayoutWithProfileId:) withObject:currentProfileId];
}
NSString *suggestionEngine = [[KBKeyboardLayoutResolver sharedResolver] suggestionEngineForProfileId:currentProfileId];
if (suggestionEngine.length > 0) {
[self kb_updateSuggestionEngineType:suggestionEngine];
}
2026-03-02 20:20:28 +08:00
NSString *languageCode = [[KBKeyboardLayoutResolver sharedResolver] currentLanguageCode];
if (languageCode.length > 0) {
NSLog(@"[KeyboardViewController] Reloading skin icon map for language: %@", languageCode);
[KBSkinInstallBridge reloadCurrentSkinIconMapForLanguageCode:languageCode];
}
2026-03-02 09:19:06 +08:00
}
- (void)kb_updateSuggestionEngineType:(NSString *)engineType {
NSLog(@"[KeyboardViewController] Switching suggestion engine to: %@", engineType);
[[KBSuggestionEngine shared] setEngineTypeFromString:engineType];
}
2026-03-02 14:39:47 +08:00
#pragma mark - App Group KVO
- (void)kb_startObservingAppGroupChanges {
NSUserDefaults *appGroup = [[NSUserDefaults alloc] initWithSuiteName:AppGroup];
__weak typeof(self) weakSelf = self;
self.kb_appGroupObserverToken = [[NSNotificationCenter defaultCenter]
addObserverForName:NSUserDefaultsDidChangeNotification
object:appGroup
queue:[NSOperationQueue mainQueue]
usingBlock:^(__unused NSNotification *_Nonnull note) {
__strong typeof(weakSelf) strongSelf = weakSelf;
if (!strongSelf) { return; }
[strongSelf kb_checkAndApplyLayoutIfNeeded];
}];
NSLog(@"[KeyboardViewController] Started observing App Group changes");
}
- (void)kb_stopObservingAppGroupChanges {
if (self.kb_appGroupObserverToken) {
[[NSNotificationCenter defaultCenter] removeObserver:self.kb_appGroupObserverToken];
self.kb_appGroupObserverToken = nil;
}
}
2025-10-28 15:18:12 +08:00
@end