diff --git a/CustomKeyboard/View/KBFunctionView.m b/CustomKeyboard/View/KBFunctionView.m index 32bcfbe..28d58e1 100644 --- a/CustomKeyboard/View/KBFunctionView.m +++ b/CustomKeyboard/View/KBFunctionView.m @@ -26,6 +26,10 @@ static NSString * const kKBFunctionTagCellId = @"KBFunctionTagCellId"; // Data @property (nonatomic, strong) NSArray *itemsInternal; + +// 剪贴板自动检测 +@property (nonatomic, strong) NSTimer *pasteboardTimer; // 轮询定时器(轻量、主线程) +@property (nonatomic, assign) NSInteger lastHandledPBCount; // 上次处理过的 changeCount,避免重复弹窗 @end @implementation KBFunctionView @@ -37,10 +41,17 @@ static NSString * const kKBFunctionTagCellId = @"KBFunctionTagCellId"; [self setupUI]; [self reloadDemoData]; + + // 初始化剪贴板监控状态 + _lastHandledPBCount = [UIPasteboard generalPasteboard].changeCount; } return self; } +- (void)dealloc { + [self stopPasteboardMonitor]; +} + #pragma mark - UI - (void)setupUI { @@ -151,7 +162,76 @@ static NSString * const kKBFunctionTagCellId = @"KBFunctionTagCellId"; #pragma mark - Button Actions -- (void)onTapPaste { NSLog(@"点击:粘贴"); } +- (void)onTapPaste { + // 用户点击“粘贴”时才读取剪贴板: + // - iOS16+ 会在跨 App 首次读取时自动弹出系统权限弹窗; + // - iOS15 及以下不会弹窗,直接返回内容; + // 注意:不要在非用户触发的时机主动读取(如 viewDidLoad),否则会造成“立刻弹窗”的体验。 + UIPasteboard *pb = [UIPasteboard generalPasteboard]; + NSString *text = pb.string; // 读取纯文本(可能触发系统粘贴权限弹窗) + + if (text.length > 0) { + // 将粘贴内容展示到左侧“粘贴区”的占位文案上 + self.pasteView.placeholderLabel.text = text; + // 如果需要多行展示,可按需放开(高度由外部约束决定,默认一行会截断) + // self.pasteView.placeholderLabel.numberOfLines = 0; + } else { + // 无可用文本或用户拒绝了粘贴权限;保持占位文案不变 + NSLog(@"粘贴板无可用文本或未授权粘贴"); + } +} + +#pragma mark - 自动监控剪贴板(复制即弹窗) +// 说明: +// - 仅在视图可见时开启轮询,避免不必要的读取与打扰; +// - 当检测到 changeCount 变化,立即读 pasteboard.string: +// * iOS16+:此处会触发系统“是否允许粘贴”弹窗; +// * iOS15:不会弹窗,直接得到文本; +// - 无论允许/拒绝,都把本次 changeCount 记为已处理,避免一直重复询问。 + +- (void)startPasteboardMonitor { + if (self.pasteboardTimer) return; + __weak typeof(self) weakSelf = self; + self.pasteboardTimer = [NSTimer scheduledTimerWithTimeInterval:0.5 repeats:YES block:^(NSTimer * _Nonnull timer) { + __strong typeof(weakSelf) self = weakSelf; if (!self) return; + UIPasteboard *pb = [UIPasteboard generalPasteboard]; + NSInteger cc = pb.changeCount; + if (cc <= self.lastHandledPBCount) return; // 没有新复制 + self.lastHandledPBCount = cc; // 标记已处理,避免重复 + + // 实际读取触发系统弹窗(iOS16+) + NSString *text = pb.string; + if (text.length > 0) { + self.pasteView.placeholderLabel.text = text; + } + }]; +} + +- (void)stopPasteboardMonitor { + [self.pasteboardTimer invalidate]; + self.pasteboardTimer = nil; +} + +- (void)didMoveToWindow { + [super didMoveToWindow]; + if (self.window && !self.isHidden) { + [self startPasteboardMonitor]; + } else { + [self stopPasteboardMonitor]; + } +} + +- (void)setHidden:(BOOL)hidden { + BOOL wasHidden = self.isHidden; + [super setHidden:hidden]; + if (wasHidden != hidden) { + if (!hidden && self.window) { + [self startPasteboardMonitor]; + } else { + [self stopPasteboardMonitor]; + } + } +} - (void)onTapDelete { NSLog(@"点击:删除"); } - (void)onTapClear { NSLog(@"点击:清空"); } - (void)onTapSend { NSLog(@"点击:发送"); }