如何在Cocoa中接收键盘输入实现文本输入框功能
纯C实现Cocoa自定义文本输入框方案
NSTextInputContext 不会独立派发输入事件,必须绑定实现了 NSTextInputClient 协议的第一响应者对象才能工作,你不用强依赖 NSText 控件,基于 NSView 自定义实现即可,所有逻辑都可以通过 Objective-C Runtime 的 C 接口完成,不需要编写 OC 源码,适配你的纯C库开发需求。
核心实现步骤
- 第一步:创建自定义 NSView 子类并实现输入协议
用objc_allocateClassPair创建继承自 NSView 的自定义输入视图类,通过class_addProtocol给类挂载NSTextInputClient协议,必须实现的核心协议方法如下:acceptsFirstResponder:重写返回YES,让视图可以获取输入焦点hasMarkedText:返回布尔值标识当前是否存在输入法组合态文本(比如中文输入时未确认的拼音片段)markedRange:返回当前组合态文本的范围,无组合态时返回{NSNotFound, 0}selectedRange:返回当前光标位置/选中文本的范围setMarkedText:selectedRange:replacementRange::接收输入法推送的组合态文本,将文本存在视图的关联对象中,标记需要重绘unmarkText:用户确认输入后清空组合态标记insertText:replacementRange::核心输入回调,用户确认输入的所有字符(英文直输、输入法选字完成、表情输入等)都会通过这个方法传入,你拿到字符后存入自己维护的文本缓冲区,触发视图重绘即可
剩余协议方法(比如获取标记文本属性、获取字符对应屏幕坐标等)做基础输入时可以返回默认值,后续需要做输入法候选框跟随光标功能时,再补全firstRectForCharacterRange:actualRange:方法返回光标所在的屏幕矩形即可。
- 第二步:绑定输入上下文并激活
自定义视图实例创建完成后,初始化NSTextInputContext并将当前视图作为 client 传入,将输入上下文实例存在视图的关联对象中。重写视图的becomeFirstResponder方法,在视图成为第一响应者时调用输入上下文的activate方法;重写resignFirstResponder方法,在视图失去焦点时调用输入上下文的deactivate方法。 - 第三步:实现文本绘制逻辑
重写视图的drawRect:方法,先绘制输入框的背景、边框,再分两部分绘制文本:- 已确认输入的文本:从你自己维护的文本缓冲区取出内容,用 NSString 的绘制接口直接画到视图对应位置
- 组合态文本:取出暂存的标记文本,加下划线样式画在当前光标位置,和已确认文本做区分
最后在文本末尾绘制竖线光标,加个定时触发器定时重绘实现光标闪烁效果即可。
- 第四步:补全特殊按键处理
不要自己在keyDown:方法里解析普通字符输入,否则会破坏输入法组合逻辑。只需要在keyDown:里判断如果输入上下文未处理当前事件(调用输入上下文的handleEvent:返回NO),再自行处理退格、回车、方向键这类编辑快捷键即可。
常见踩坑
- 不需要手动给输入上下文传入普通键盘事件,当你的视图是第一响应者时,系统会自动将输入事件路由给绑定的输入上下文,手动重复调用
handleEvent:会导致重复输入 - 纯C开发场景下,所有OC方法调用都可以通过
objc_msgSend完成,OC字符串用CFSTR宏桥接即可,不需要单独编译OC文件 - 如果只需要支持英文数字输入,可以直接重写
keyDown:从 NSEvent 的characters属性取输入字符,但这种方式完全不支持多语言输入法、系统文本替换、拼写检查等能力,正式场景不推荐使用。
内容的提问来源于stack exchange,提问作者user18791650
相关产品推荐
相关产品推荐

