在日常 macOS 开发中经常会用到 NSTextField 控件,但是会发现一个问题,如果开发的应用没有顶栏应用菜单,编辑控件中的文本内容的时候,按下文本操作快捷键无效,而得到的是系统警告音。本文就跟十里一起看一下如何让没有应用菜单的 app 中的 NSTextField 支持常用的文本操作快捷键。

  • 复制: Command + c
  • 剪切: Command + x
  • 粘贴: Command + v
  • 全选: Command + a

实现平台

  • macOS 10.14.3
  • swift 4.2.1
  • xcode 10.1

1. 键盘事件

每个 app 都有自己的主循环线程(Main Run Loop),在这个循环中会遍历系统的事件消息队列,逐一发给对应的响应对象进行处理。具体来说就是 NSApp 的 sendAction:sendEvent:方法发送事件消息给 NSWindow,NSWindow 再分发给具体的视图对象,最后由相应的事件响应方法进行处理。其中一种事件,就是这里要说的键盘事件,NSApp 对不同的键盘事件处理方式会不同,主要是以下三种:

  • 快捷键:如果按下快捷键,系统会先向当前的活动窗口菜单发送 performKeyEquivalent: 消息,此时窗口会依次遍历所有子视图控件按照响应链传递给 performKeyEquivalent: 的响应者。
  • 控制键:NSApp 会将消息转发给键盘窗口,完成不同的控件切换控制的功能
  • 其它按键:NSApp 会将消息转发给键盘窗口,窗口对象会先定位到第一响应对象,根据响应链优先级寻找对 keyDown 键盘事件响应的视图对象,如果可以找到就由相应对象处理,否则就会按照 insertText 方法进行处理(如果是个文本控件,就会插入相应键盘文本)

很明显,我们要实现本文的主题,关注快捷键的处理流程就可以了,其实 NSTextField 有上述 performKeyEquivalent: 消息的处理,只不过是没有任何功能实现而已,所以我们只需为 NSTextField 复写一下这个消息的处理即可,这个消息的处理返回值是一个布尔类型,返回 true 则标志着按键事件消息传递的结束。

2. 新建 Demo 工程

为了更好的说明实现方法,我们还是要通过一个实际的Demo演示!新建的工程包含 storyboard ,新建完成后添加一个文本框控件,如果您对这些操作很熟悉可以跳过本小节。

  • 打开 Xcode,按下快捷键 Shift + Command + N 就会触发新建工程的导航窗口
  • 选择 macOS -> Cocoa App,点击 Next
  • 工程取名为 TextFieldKeyDemo,勾选 Use Storyboards,点击 Next 选择合适的目录,点击create 创建
  • 进入工程后,单击 Main.storyboard ,按下快捷键 Shift + Command + l 打开控件选择器,搜索 textfield ,将 Text Field 拖入 ViewController ,水平垂直居中放置:

3. 运行工程

3.1 运行结果

点击快捷键 Command + r 运行工程,在打开的窗口中可以看到刚刚添加的 Text Field,在其中输入一些文本,然后试一下快件键,比如全选、复制、粘贴、剪切,发现都支持。

此时你会不会有疑问,我们并没有为 NSTextField 类复写 performKeyEquivalent: 方法呀,为什么文本框就支持这些快捷键了,原因是最终键盘信息消息传给了应用菜单,应用菜单中有关于文本编辑的快捷键的处理,那么问题又来了,为什么应用菜单就会对 Text Field 进行操作呢?主要两点:

  • 菜单栏上编辑一组中的操作正是对应文章一开头说的几个快捷键,每个操作对应都绑定了一个对象那就是 First Responder,比如 Copy 对应的绑定 action:
  • 当前活动窗口中的 First Responder 就是文本框

3.2 试验操作

现在打开工程,打开 Main.storyboard 文件,删除 菜单栏,就是下图标注的东西:

此时再次运行工程,在文本框中尝试使用快捷键,你就会发现如我们所想失效了!

4. 快捷键加持

有时我们开发 app 就是不想保留菜单栏,比如状态栏小工具。所以继续研究怎么在没有菜单栏的情况下让 Text Field 支持快捷键是有必要的!很自然的我们就会想到上面说的为 NSTextField 复写 performKeyEquivalent: 方法的方式来解决!

这里直接贴出代码:

// NSTextField 自身支持快捷键
extension NSTextField {open override func performKeyEquivalent(with event: NSEvent) -> Bool {switch event.charactersIgnoringModifiers {case "a":return NSApp.sendAction(#selector(NSText.selectAll(_:)), to: self.window?.firstResponder, from: self)case "c":return NSApp.sendAction(#selector(NSText.copy(_:)), to: self.window?.firstResponder, from: self)case "v":return NSApp.sendAction(#selector(NSText.paste(_:)), to: self.window?.firstResponder, from: self)case "x":return NSApp.sendAction(#selector(NSText.cut(_:)), to: self.window?.firstResponder, from: self)default:return super.performKeyEquivalent(with: event)}}
}

上面的代码贴到合适位置即可,比如 AppDelegate.swift 文件 AppDelegate 类的后面。

可以看到上面的方法实现了四个快捷键的功能,分别是:全选、复制、粘贴和剪切,都是通过 NSApp 向文本框所在窗口的 First Responder(也就是文本框自己) 发起相应行为,而这些行为是 NStext 类的基本方法。另外:

  • event.charactersIgnoringModifiers: 除去修饰键剩余的按键

charactersIgnoringModifiers: The characters generated by a key event as if no modifier key (except for Shift) applies

  • 修饰键类型为 NSevent:ModifierFlags 类型,是一个集合,有 capsLock、shift、control、option、command、numericPad、help、function 和 deviceIndependentFlagsMask

运行工程,窗口中的 Text Field 支持四个快捷键了!但是此时有一个问题,将 Command 键替换为 Ctrl 按下快捷键也能实现相应文本操作,所以在 switch 语句之前加一个判断,如果修饰键不包含 Command 就按照正常响应:

if event.modifierFlags.isDisjoint(with: .command) {return super.performKeyEquivalent(with: event)
}

  • event.modifierFlags.isDisjoint(with: .command): 判断快捷键中的修饰键(modifier)是不是不包含 Command 键,不包含就返回 true

isDisjoint: Returns a Boolean value that indicates whether the set has no members in common with the given set.

此时,还是不完美的,如果按下文本操作快捷键的同时按下了其它有效修饰键(比如 Ctrl) 同样可以完成文本操作,目前还没想到其他更好的处理方式!后面有所发现就会更新这里!

不知道您会不会有疑问:怎么不支持撤销和重做两个快捷键?不是不做,撤销重做 操作实现是挺大的一块内容,所以放到这个主题的第二篇文章介绍。

本文工程下载:

TextFieldKeyDemo​pichome-1254392422.cos.ap-chengdu.myqcloud.com

参考

NSTextField支持Cmd+C/V快捷键复制、粘贴 - Kaymin - 博客园​www.cnblogs.com


博客原文:

macOS 开发之 NSTextField 支持文本操作快捷键(一)​www.smslit.top

kali怎么新建文本_macOS 开发之 NSTextField 支持文本快捷键(一): 基本操作相关推荐

  1. Revit二次开发之“为Ribbon设置快捷键”

    目前不支持使用代码为Ribbon设置快捷键. 以下是帮助文档: 单击"视图"选项卡 "窗口"面板 "用户界面"下拉列表 "快捷键& ...

  2. 苹果开发之Cocoa编程(原书第4版)

    <苹果开发之Cocoa编程(原书第4版)> 基本信息 原书名:Cocoa Programming for Mac OS X: Fourth Edition 作者: (美)希莱加斯(Hill ...

  3. 安卓开发之Handler、HandlerThread学习篇

    安卓开发之Handler.HandlerThread学习心得篇           开篇说明:本文采用的都是最基础最简单的例子,目的只有一个:希望大家将学习的焦点放在Handler的理解和使用上,我不 ...

  4. Windows8 Metro应用开发之C#(1)- 项目模板(Project Templates)

    Windows8 Metro应用开发之C#(1)- 项目模板(Project Templates) 新建模板 打开Visual Studio 11,新建项目 -> 展开Visual C# -&g ...

  5. 测试开发之Django实战示例 第十章 创建在线教育平台

    第十章 创建在线教育平台 在上一章,我们为电商网站项目添加了国际化功能,还创建了优惠码和商品推荐系统.在本章,会建立一个新的项目:一个在线教育平台,并创内容管理系统CMS(Content Manage ...

  6. [整理]Unity3D游戏开发之Lua

    原文1:[Unity3D]Unity3D游戏开发之Lua与游戏的不解之缘(上) 各位朋友,大家好,我是秦元培,欢迎大家关注我的博客,我地博客地址是blog.csdn.net/qinyuanpei.如果 ...

  7. SpringBoot开发之Spring Boot入门

    SpringBoot开发之SpringBoot入门 一.Spring Boot概述 1.什么是Spring Boot 2.Spring Boot的优点 二.第一个Spring Boot应用 1.创建S ...

  8. 3G应用开发之Android 传智播客 基础知识总结

    3G应用开发之Android Android应用开发之3G  3G应用开发之Android 3G应用开发之Android 应用开发之 讲师: 讲师:黎活明 北京传智 播客教育 www.itcast.c ...

  9. 前端开发之html超链接

    前端开发之html字体属性和超链接 前言 前端开发之html超链接 1.超链接的三种形式 1.外部链接:链接到外部文件 举例: <a href="02页面.html"> ...

最新文章

  1. 熔断的意义和适用场景,你真的清楚吗?
  2. java biginterger_Java BigInteger类知识点总结
  3. 《好未来编程题》求和
  4. 解决“第一次偶然出现的异常”问题
  5. leetcode306 2022.1.10
  6. 【Win10 应用开发】实现数据的增量加载
  7. 《金字塔原理》学习笔记 | 第4篇—演示的逻辑
  8. 笔试占比近40%,中国人民大学高瓴人工智能学院2022年夏令营来袭
  9. 【STM32】【HAL库】【实用制作】数控收音机(软件设计)
  10. cpp设计并实现大整数
  11. APS究竟是什么系统呢?看完文章你就知道了
  12. 一起来学Kotlin:概念:7. Kotlin 函数介绍:扩展函数,中缀函数,运算符函数,带有varrag输入的函数
  13. 坚持一件事比决定一件事难多了
  14. app与后台通信完整流程
  15. 面向对象程序设计c++版董正言张聪课本课后习题答案第四章
  16. gcms基峰有什么用_请收下!来自前辈的“气质联用”经验分享
  17. Installing OpenCV 2.4.9 in Ubuntu 14.04 LTS(好文章)
  18. 华为od统一考试B卷【敏感字段加密】JavaScript 实现
  19. 新代系统反向间隙参数_新代系统参数
  20. 2021年焊工(技师)考试总结及焊工(技师)试题及答案

热门文章

  1. 大数据Hadoop原理学习(HDFS,MAPREDUCE,YARN)
  2. yoga11rt系统刷linux,【攻略贴】联想Yoga“一秒”变身安卓平板,Win8 Andriod双系统刷机攻略出炉!...
  3. asp系统转换php系统时间函数,window_Asp常用通用函数之生成时间的整数,'函数名:GetMyTimeNumber()' - phpStudy...
  4. Python3爬虫入门之pyquery库的使用
  5. 使用DataWorks调度DLA循环任务
  6. [转]magento2项目上线注意事项 切换到产品模式
  7. 第十四:Pytest进阶之html测试报告
  8. (四)Java中的多线程之间实现同步+多线程并发同步
  9. java api es_ES 常用java api
  10. 程序员值得思考的问题