Unity 如何在 iOS 新增键盘 KeyCode 响应事件
1.定位到文件UnityView+Keyboard.mm同如下路径:

2.打开该Objective-C脚本进行编辑,找到关键函数: createKeyboard:
- (void)createKeyboard
{// only English keyboard layout is supportedNSString* baseLayout = @"1234567890-=qwertyuiop[]asdfghjkl;'\\`zxcvbnm,./!@#$%^&*()_+{}:\"|<>?~ \t\r\b\\";NSString* numpadLayout = @"1234567890-=*+/.\r";NSString* upperCaseLetters = @"QWERTYUIOPASDFGHJKLZXCVBNM";size_t sizeOfKeyboardCommands = baseLayout.length + numpadLayout.length + upperCaseLetters.length + 11;NSMutableArray* commands = [NSMutableArray arrayWithCapacity: sizeOfKeyboardCommands];void (^addKey)(NSString *keyName, UIKeyModifierFlags modifierFlags) = ^(NSString *keyName, UIKeyModifierFlags modifierFlags){UIKeyCommand* command = [UIKeyCommand keyCommandWithInput: keyName modifierFlags: modifierFlags action: @selector(handleCommand:)];
#if UNITY_HAS_IOSSDK_15_0if (@available(iOS 15.0, tvOS 15.0, *))command.wantsPriorityOverSystemBehavior = YES;
#endif[commands addObject:command];};for (NSInteger i = 0; i < baseLayout.length; ++i){NSString* input = [baseLayout substringWithRange: NSMakeRange(i, 1)];NSLog(@"%@ !!!",input);addKey(input, kNilOptions);}for (NSInteger i = 0; i < numpadLayout.length; ++i){NSString* input = [numpadLayout substringWithRange: NSMakeRange(i, 1)];addKey(input, UIKeyModifierNumericPad);}for (NSInteger i = 0; i < upperCaseLetters.length; ++i){NSString* input = [upperCaseLetters substringWithRange: NSMakeRange(i, 1)];addKey(input, UIKeyModifierShift);}// pageUp, pageDownaddKey(@"UIKeyInputPageUp", kNilOptions);addKey(@"UIKeyInputPageDown", kNilOptions);// up, down, left, right, escaddKey(UIKeyInputUpArrow, kNilOptions);addKey(UIKeyInputDownArrow, kNilOptions);addKey(UIKeyInputLeftArrow, kNilOptions);addKey(UIKeyInputRightArrow, kNilOptions);addKey(UIKeyInputEscape, kNilOptions);// caps Lock, shift, control, option, commandaddKey(@"", UIKeyModifierAlphaShift);addKey(@"", UIKeyModifierShift);addKey(@"", UIKeyModifierControl);addKey(@"", UIKeyModifierAlternate);addKey(@"", UIKeyModifierCommand);keyboardCommands = commands.copy;
}
此函数由Unity定义,通过addKey函数负责初始化注册所有需要响应的按键.
void (^addKey)(NSString *keyName, UIKeyModifierFlags modifierFlags) = ^(NSString *keyName, UIKeyModifierFlags modifierFlags){UIKeyCommand* command = [UIKeyCommand keyCommandWithInput: keyName modifierFlags: modifierFlags action: @selector(handleCommand:)];
#if UNITY_HAS_IOSSDK_15_0if (@available(iOS 15.0, tvOS 15.0, *))command.wantsPriorityOverSystemBehavior = YES;
#endif[commands addObject:command];};
函数接受两个参数第一个是keyName表示接收的按键名称例如键盘上的a-z,第二个参数为UIKeyModifierFlags表示作为Modifier的按键种类如下:
typedef NS_OPTIONS(NSInteger, UIKeyModifierFlags) {UIKeyModifierAlphaShift = 1 << 16, // This bit indicates CapsLockUIKeyModifierShift = 1 << 17,UIKeyModifierControl = 1 << 18,UIKeyModifierAlternate = 1 << 19,UIKeyModifierCommand = 1 << 20,UIKeyModifierNumericPad = 1 << 21,} API_AVAILABLE(ios(7.0));
使用时例如用户需要接收处理command a,需调用addKey(@"a", UIKeyModifierCommand); 针对于特殊按键对应的NSString存储于UIResponder.h中:
// These are pre-defined constants for use with the input property of UIKeyCommand objects.
UIKIT_EXTERN NSString *const UIKeyInputUpArrow API_AVAILABLE(ios(7.0));
UIKIT_EXTERN NSString *const UIKeyInputDownArrow API_AVAILABLE(ios(7.0));
UIKIT_EXTERN NSString *const UIKeyInputLeftArrow API_AVAILABLE(ios(7.0));
UIKIT_EXTERN NSString *const UIKeyInputRightArrow API_AVAILABLE(ios(7.0));
UIKIT_EXTERN NSString *const UIKeyInputEscape API_AVAILABLE(ios(7.0));
UIKIT_EXTERN NSString *const UIKeyInputPageUp API_AVAILABLE(ios(8.0));
UIKIT_EXTERN NSString *const UIKeyInputPageDown API_AVAILABLE(ios(8.0));
UIKIT_EXTERN NSString *const UIKeyInputHome API_AVAILABLE(ios(13.4), tvos(13.4)) API_UNAVAILABLE(watchos);
UIKIT_EXTERN NSString *const UIKeyInputEnd API_AVAILABLE(ios(13.4), tvos(13.4)) API_UNAVAILABLE(watchos);
UIKIT_EXTERN NSString *const UIKeyInputF1 API_AVAILABLE(ios(13.4), tvos(13.4)) API_UNAVAILABLE(watchos);
UIKIT_EXTERN NSString *const UIKeyInputF1 API_AVAILABLE(ios(13.4), tvos(13.4)) API_UNAVAILABLE(watchos);
UIKIT_EXTERN NSString *const UIKeyInputF2 API_AVAILABLE(ios(13.4), tvos(13.4)) API_UNAVAILABLE(watchos);
UIKIT_EXTERN NSString *const UIKeyInputF3 API_AVAILABLE(ios(13.4), tvos(13.4)) API_UNAVAILABLE(watchos);
UIKIT_EXTERN NSString *const UIKeyInputF4 API_AVAILABLE(ios(13.4), tvos(13.4)) API_UNAVAILABLE(watchos);
UIKIT_EXTERN NSString *const UIKeyInputF5 API_AVAILABLE(ios(13.4), tvos(13.4)) API_UNAVAILABLE(watchos);
UIKIT_EXTERN NSString *const UIKeyInputF6 API_AVAILABLE(ios(13.4), tvos(13.4)) API_UNAVAILABLE(watchos);
UIKIT_EXTERN NSString *const UIKeyInputF7 API_AVAILABLE(ios(13.4), tvos(13.4)) API_UNAVAILABLE(watchos);
UIKIT_EXTERN NSString *const UIKeyInputF8 API_AVAILABLE(ios(13.4), tvos(13.4)) API_UNAVAILABLE(watchos);
UIKIT_EXTERN NSString *const UIKeyInputF9 API_AVAILABLE(ios(13.4), tvos(13.4)) API_UNAVAILABLE(watchos);
UIKIT_EXTERN NSString *const UIKeyInputF10 API_AVAILABLE(ios(13.4), tvos(13.4)) API_UNAVAILABLE(watchos);
UIKIT_EXTERN NSString *const UIKeyInputF11 API_AVAILABLE(ios(13.4), tvos(13.4)) API_UNAVAILABLE(watchos);
UIKIT_EXTERN NSString *const UIKeyInputF12 API_AVAILABLE(ios(13.4), tvos(13.4)) API_UNAVAILABLE(watchos);
UIKIT_EXTERN NSString *const UIKeyInputDelete API_AVAILABLE(ios(15.0), tvos(15.0)) API_UNAVAILABLE(watchos);
此文档以F1-F12按键添加为例:使用addKey(UIKeyInputF4, kNilOptions);
addKey(UIKeyInputF1, kNilOptions);addKey(UIKeyInputF2, kNilOptions);addKey(UIKeyInputF3, kNilOptions);addKey(UIKeyInputF4, kNilOptions);
-
注册好按键后还需要在handleCommand函数中进行响应处理:
- (void)handleCommand:(UIKeyCommand *)command
{NSString* input = command.input;UIKeyModifierFlags modifierFlags = command.modifierFlags;char inputChar = ([input length] > 0) ? [input characterAtIndex: 0] : 0;int code = (int)inputChar; // ASCII codeUnitySendKeyboardCommand(command);if (![self isValidCodeForButton: code]){code = 0;}if ((modifierFlags & UIKeyModifierAlphaShift) != 0)code = UnityStringToKey("caps lock");if ((modifierFlags & UIKeyModifierShift) != 0)code = UnityStringToKey("left shift");if ((modifierFlags & UIKeyModifierControl) != 0)code = UnityStringToKey("left ctrl");if ((modifierFlags & UIKeyModifierAlternate) != 0)code = UnityStringToKey("left alt");if ((modifierFlags & UIKeyModifierCommand) != 0)code = UnityStringToKey("left cmd");if ((modifierFlags & UIKeyModifierNumericPad) != 0){switch (inputChar){case '0':code = UnityStringToKey("[0]");break;case '1':code = UnityStringToKey("[1]");break;case '2':code = UnityStringToKey("[2]");break;case '3':code = UnityStringToKey("[3]");break;case '4':code = UnityStringToKey("[4]");break;case '5':code = UnityStringToKey("[5]");break;case '6':code = UnityStringToKey("[6]");break;case '7':code = UnityStringToKey("[7]");break;case '8':code = UnityStringToKey("[8]");break;case '9':code = UnityStringToKey("[9]");break;case '-':code = UnityStringToKey("[-]");break;case '=':code = UnityStringToKey("equals");break;case '*':code = UnityStringToKey("[*]");break;case '+':code = UnityStringToKey("[+]");break;case '/':code = UnityStringToKey("[/]");break;case '.':code = UnityStringToKey("[.]");break;case '\r':code = UnityStringToKey("enter");break;default:break;}}if (input == UIKeyInputUpArrow)code = UnityStringToKey("up");else if (input == UIKeyInputDownArrow)code = UnityStringToKey("down");else if (input == UIKeyInputRightArrow)code = UnityStringToKey("right");else if (input == UIKeyInputLeftArrow)code = UnityStringToKey("left");else if (input == UIKeyInputEscape)code = UnityStringToKey("escape");else if ([input isEqualToString: @"UIKeyInputPageUp"])code = UnityStringToKey("page up");else if ([input isEqualToString: @"UIKeyInputPageDown"])code = UnityStringToKey("page down");KeyMap::iterator item = GetKeyMap().find(code);if (item == GetKeyMap().end()){// New key is down, register it and its timeUnitySetKeyboardKeyState(code, true);GetKeyMap()[code] = GetTimeInSeconds();}else{// Still holding the key, update its timeitem->second = GetTimeInSeconds();}
}
函数中input表示createKeyboard函数注册对应的keyName,modifierFlags表示注册时传入的modifierFlags.函数中的Code对应Unity的KeyCodeEnum:
using System;namespace UnityEngine
{// Key codes returned by Event.keyCode. These map directly to a physical key on the keyboard.public enum KeyCode{// Not assigned (never returned as the result of a keystroke)None = 0,// The backspace keyBackspace = 8,// The forward delete keyDelete = 127,// The tab keyTab = 9,// The Clear keyClear = 12,// Return keyReturn = 13,// Pause on PC machinesPause = 19,// Escape keyEscape = 27,// Space keySpace = 32,// Numeric keypad 0Keypad0 = 256,// Numeric keypad 1Keypad1 = 257,
前添加判断并给code进行赋值即可,F1-F12对应282-294以此为例代码如下:
if (input == UIKeyInputF1)code = 282;else if (input == UIKeyInputF2)code = 283;else if (input == UIKeyInputF3)code = 284;
-
测试结果如下:

相关文章:
Unity 如何在 iOS 新增键盘 KeyCode 响应事件
1.定位到文件UnityViewKeyboard.mm同如下路径: 2.打开该Objective-C脚本进行编辑,找到关键函数: createKeyboard: - (void)createKeyboard {// only English keyboard layout is supportedNSString* baseLayout "1234567890-qwertyuiop[]asdfghjkl;\\zxcvbnm,./!#$%^&am…...
pytorh学习笔记——波士顿房价预测
机器学习的“hello world”:波士顿房价预测 波士顿房价预测的背景不用提了,简单了解一下数据集的结构。 波士顿房价的数据集,共有506组数据,每组数据共14项,前13项是影响房价的各种因素,比如&…...
让AI像人一样思考和使用工具,reAct机制详解
reAct机制详解 reAct是什么reAct的关键要素reAct的思维过程reAct的代码实现查看效果引入依赖,定义模型定义相关工具集合工具创建代理启动测试完整代码 思考 reAct是什么 reAct的核心思想是将**推理(Reasoning)和行动(Acting&…...
Linux系列-常见的指令(二)
🌈个人主页: 羽晨同学 💫个人格言:“成为自己未来的主人~” mv 剪切文件,目录 重命名 比如说,我们在最开始创建一个新的文件hello.txt 然后我们将这个文件改一个名字,改成world.txt 所以,…...
Leecode刷题之路第17天之电话号码的字母组合
题目出处 17-电话号码的字母组合-题目出处 题目描述 个人解法 思路: todo 代码示例:(Java) todo复杂度分析 todo 官方解法 17-电话号码的字母组合-官方解法 方法1:回溯 思路: 代码示例:&a…...
2023牛客暑期多校训练营3(题解)
今天下午也是小小的做了一下,OI,也是感觉手感火热啊,之前无意间看到的那个哥德巴赫定理今天就用到了,我以为根本用不到的,当时也只是感兴趣看了一眼,还是比较激动啊 话不多说,直接开始看题 Wo…...
Magnum IO
NVIDIA Magnum IO 文章目录 前言加速数据中心 IO 性能,随时随地助力 AINVIDIA Magnum IO 优化堆栈1. 存储 IO2. 网络 IO3. 网内计算4. IO 管理跨数据中心应用加速 IO1. 数据分析Magnum IO 库和数据分析工具2. 高性能计算Magnum IO 库和 HPC 应用3. 深度学习Magnum IO 库和深度…...
Flink job的提交流程
在Flink中,作业(Job)的提交流程是一个复杂的过程,涉及多个组件和模块,包括作业的编译、优化、序列化、任务分发、任务调度、资源分配等。Flink通过分布式架构来管理作业的生命周期,确保作业在不同节点上以高…...
git操作pull的时候出现冲突怎么解决
问: PS C:\Users\fury_123\Desktop\consumptionforecast> git branch * dev main PS C:\Users\fury_123\Desktop\consumptionforecast> git add . PS C:\Users\fury_123\Desktop\consumptionforecast> git commit -m 修改部分样式 [dev 74693e0] 修改部分样…...
Sentinel 1.80(CVE-2021-44139)
Sentinel 是面向分布式、多语言异构化服务架构的流量治理组件,主要以流量为切入点,从流量路由、流量控制、流量整形、熔断降级、系统自适应过载保护、热点流量防护等多个维度来帮助开发者保障微服务的稳定性 Report a Sentinel Security Vulnerability …...
黑马程序员C++提高编程学习笔记
黑马程序员C提高编程 提高阶段主要针对泛型编程和STL技术 文章目录 黑马程序员C提高编程一、模板1.1 函数模板1.1.1 函数模板基础知识 案例一: 数组排序1.2.1 普通函数与函数模板1.2.2 函数模板的局限性 1.2 类模板1.2.1 类模板的基础知识1.2.2 类模板与函数模板1.…...
力扣第1题:两数之和(图解版)
Golang版本 func twoSum(nums []int, target int) []int {m : make(map[int]int)for i : range nums {if _, ok : m[target - nums[i]]; ok {return []int{i, m[target - nums[i]]}} m[nums[i]] i}return nil }...
aws(学习笔记第三课) AWS CloudFormation
aws(学习笔记第三课) 使用AWS CloudFormation 学习内容: AWS CloudFormation的模板解析使用AWS CloudFormation启动ec2 server 1. AWS CloudFormation 的模版解析 CloudFormation模板结构 CloudFormation是AWS的配置管理工具,属于Infrastructure as Co…...
浅学React和JSX
往期推荐 一文搞懂大数据流式计算引擎Flink【万字详解,史上最全】-CSDN博客 数仓架构:离线数仓、实时数仓Lambda和Kappa、湖仓一体数据湖-CSDN博客 一文入门大数据准流式计算引擎Spark【万字详解,全网最新】_大数据 spark-CSDN博客 浅谈维度建…...
React 为什么 “虚拟 DOM 顶部有很多 provider“?
1、介绍React中的Context Provider 在 React 中,虚拟 DOM(Virtual DOM)是 React 用来高效更新 UI 的核心机制,它通过对比前后两次虚拟 DOM 树,确定哪些部分需要更新,以减少直接操作真实 DOM 的开销。而 “…...
忘记了 MySQL 8.0 的 root 密码,应该怎么办?
如果你忘记了 MySQL 8.0 的 root 密码,可以通过以下步骤来重置密码。请注意,这些步骤需要你有对 MySQL 服务器的物理或命令行访问权限。 步骤 1: 停止 MySQL 服务 首先,你需要停止正在运行的 MySQL 服务。你可以使用以下命令来停止 MySQL 服…...
Promise.reject()
Promise.reject() 静态方法返回一个已拒绝(rejected)的 Promise 对象,拒绝原因为给定的参数。 语法 Promise.reject(reason)参数 reason 该 Promise 对象被拒绝的原因。 返回值 返回一个已拒绝(rejected)的 Promi…...
大数据-163 Apache Kylin 全量增量Cube的构建 手动触发合并 JDBC 操作 Scala
点一下关注吧!!!非常感谢!!持续更新!!! 目前已经更新到了: Hadoop(已更完)HDFS(已更完)MapReduce(已更完&am…...
云手机与传统手机的区别是什么?
随着科技的快速进步,云手机逐渐成为手机市场的热门选择。与传统的智能手机相比,云手机具有许多独特的功能和优势,尤其在多账号管理和高效操作方面备受关注。那么,云手机究竟与普通手机有哪些区别呢? 1. 更灵活的操作与…...
微知-Bluefield DPU命名规则各字段作用?BF2 BF3全系列命名大全
文章目录 背景字段命名C是bmc的意思NOT的N是是否加密S表示不加密但是secureboot enable倒数第四个都是E倒数第五个是速率 V和H是200GM表示E serials,H表示P serials(区别参考兄弟篇:[more](https://blog.csdn.net/essencelite/article/detail…...
QDKTAI实战面试题50问之41-50
一、逐题详细解析(41-50题)第41题:如何设计一个有效的AI内容审核系统?1. 考察重点对大模型“生成式而非判别式”核心特性的理解识别AI审核场景中的关键冲突点(长文本处理、语气/风格干扰)针对性解决方案的设…...
【实战指南】Spirent TCL 并发与新建连接测试全流程解析
1. Spirent TCL测试基础与环境搭建 第一次接触Spirent TestCenter时,我也被它强大的功能和复杂的界面吓到过。但实际用下来发现,只要掌握几个核心模块,就能完成大多数性能测试任务。这里先带大家快速搭建测试环境,为后续的并发和新…...
Excel动态甘特图制作指南:利用条件格式实现进度可视化
1. 为什么需要动态甘特图 项目管理中最让人头疼的就是进度跟踪。传统的静态表格需要手动更新颜色标注,每次进度变化都得重新调整,费时费力还容易出错。我在带团队做软件版本迭代时,就经常遇到这样的困扰:明明任务进度已经更新了&a…...
实现网页动态交互:Live2D模型嵌入与换装功能详解
1. Live2D技术入门:从零开始认识动态模型 第一次接触Live2D时,我被它流畅的动画效果惊艳到了。这种技术能在二维平面上呈现出近乎三维的立体感,让静态角色"活"起来。Live2D最初确实是为游戏开发的,但现在越来越多地被用…...
会Python可以找什么工作?
Python凭借简洁易用、功能强大的特点,成为当下就业面极广的编程语言。不少人学会后却不清楚可以找什么工作,其实从开发、数据分析到自动化运维都有大量机会,接下来为大家详细讲解一下。会Python后,可以找的工作有很多,…...
手把手教你理解永磁同步电机的Clark与Park变换(附MATLAB仿真代码)
手把手教你理解永磁同步电机的Clark与Park变换(附MATLAB仿真代码) 在工业自动化与电动汽车驱动领域,永磁同步电机(PMSM)凭借其高功率密度和卓越的动态性能,已成为现代运动控制系统的核心部件。然而…...
Qwen3-0.6B-FP8效果展示:用‘把这篇技术博客改写成适合小学生理解的版本’实测简化能力
Qwen3-0.6B-FP8效果展示:用‘把这篇技术博客改写成适合小学生理解的版本’实测简化能力 1. 引言:当大模型遇上“小学生”挑战 想象一下,你面前有一篇满是专业术语、复杂逻辑的技术文章,现在需要把它讲给一个小学三年级的孩子听&…...
开源模型运维实践:雯雯的后宫Z-Image-瑜伽女孩Xinference日志监控与告警配置
开源模型运维实践:雯雯的后宫Z-Image-瑜伽女孩Xinference日志监控与告警配置 1. 引言:当你的AI画师“罢工”了怎么办? 想象一下这个场景:你刚部署好一个能生成精美瑜伽女孩图片的AI模型,兴致勃勃地准备创作。你输入了…...
OpenClaw+Qwen3.5-4B-Claude:3类逻辑任务自动化实测对比
OpenClawQwen3.5-4B-Claude:3类逻辑任务自动化实测对比 1. 测试背景与实验设计 去年在尝试用OpenClaw自动化处理技术文档时,我发现原生大模型虽然能完成基础任务,但在需要多步推理的场景中经常出现"跳步"或"逻辑断层"。…...
OpenClaw+nanobot智能客服:个人网站问答机器人搭建
OpenClawnanobot智能客服:个人网站问答机器人搭建 1. 为什么选择OpenClawnanobot组合 去年运营个人技术博客时,我经常收到读者在非工作时间发来的技术咨询。作为独立开发者,很难做到7x24小时在线回复,但让用户等待又会影响体验。…...
