1 移动自动化简介
移动自动化就是通过代码来控制手机, 模拟人的动作, 对手机进行一些点击, 输入等操作, 那 python 代码如何能控制到手机呢? 目前的思路应该是 python 代码 ->Appium-python 库 ->Appium 服务 -> 手机. 也就是通过 appium 的库来调用 appium 服务, 让 appium 服务对手机进行操作.
基于上面的思路, 我们环境安装好之后, 运行代码之前, 需要先将环境开起来, appium 服务开启, 安卓模拟器开启, 就可以运行安卓自动化代码了. 如果运行报错没有找到安卓设备的话, 试试看在 cmd 里面输入 adb connect 设备名, 比如 adb connect 127.0.0.1:62001
1.1 连接手机的代码
写自动化代码之前, 首先写一段下面的代码, 用来连接上手机, 并且连接上你需要测试的 App, 如果报错没有找到设备的话, 按照上面说的运行 adb connect 设备名试试看.
- # encoding=utf-8
- from appium import webdriver
- server = r'http://localhost:4723/wd/hub' # Appium Server, 端口默认为 4723
- desired_capabilities = {
- 'platformName': 'Android', # 平台
- # 需替换成你的 driverName, 如果不知 道自己的设备名, 用 adb 命令去查看一下
- 'driverName': '127.0.0.1:62001',
- 'platformVersion': '5.1.1', # 安卓版本
- 'appPackage': 'com.android.settings', #App 包名
- 'appActivity': '.Settings' # App 启动名
- 'unicodeKeyboard': True # 这句和下面那句是避免中文问题的
- 'resetKeyboard': True
- }
- driver = webdriver.Remote(server, desired_capabilities) # 连接手机和 App
- driver.find_element_by_id("com.android.settings:id/title").click() # 后面讲
- driver.quit() # 退出 driver
在上面的代码 driver.quit() 之前加入下面的代码, 获取当前 App 的包名和启动名
- # 获取 App 的包名
- print(driver.current_package)
- # 获取 App 的启动名
- print(driver.current_activity)
打印的结果:
- com.Android.settings
- .SubSettings
2 UIAutomatorViewer 使用
在讲元素定位之前, 首先说一个很有用的工具 UIAutomatorViewer, 这个工具在 \ Android-sdk-Windows\tools 文件夹下面, uiautomatorviewer.bat 这个文件, 双击打开.
第一步: 打开之后看到的界面应该是:
- (这里提示一下: 如果打开的时候报错了,"Error obtaining UI hierarchy" 错误, 不能找到 ui, 一般就是因为 adb 被占用了, 那么可以试着关闭 adb, 去 cmd 里面输入 adb kill-server, 再输入 adb start-server, 重启后等会再去点, 如果还是不行, 多等会, 再不行就把 appium 的服务关掉)
- (再提示: 打开 uiantomatorviewer 的时候还会打开一个黑框, 这个黑框别关)
第二步, 打开你的虚拟器或者真机中的需要测试的 App, 比如我现在测试设置, 我就打开设置, 如图:
第三步: 点击第一步图示的圈红按钮, 点击后等待一会, 会出来如下图:
第四步, 出来上图后, 想要哪个按钮的 id 或者 name, 就用鼠标点到哪个按钮上, 比如我想要看更多按钮的信息, 点击 "更多", 就在右面界面中出来了 text,id,class 等信息, 其中的 resourse-id 就是 id 名.
第五步: 这个工具还可以保存当前页面, 这样方便以后多次查看当前页面的控件内容, 而不用每次去打开 App, 操作步骤, 点击保存按钮, 工具栏里面的第四个按钮, 保存后, 会同时保存两个文件, 一个 PNG 文件, 一个 uix 文件. 保存后怎么打开呢? 点击工具上的第一个按钮, open, 点击后会弹出一个框, 如图:
上面那个路径是刚才保存的 PNG 路径, 下面是 uix 路径, 原来保存的名字可能是 dump 开头的, 改一下名字, PNG 和 uix 可以改成一样的, 这样再次打开的时候比较容易找. 这样打开跟之前的方法打开出来的结果一样.
3 appium 自动化测试代码编写
3.1 定位元素
做自动化测试最重要的是要先定位到元素, appium 定位元素和 selenium 类似, 准确的说 appium 也是继承了 selenium 的方法.
3.1.1 通过 id 定位元素
driver.find_element_by_id("com.android.settings:id/title")
这个方法的参数写的是 id 名, 也就是 resourse-id 的值. 这样就找到 id 为 "com.android.settings:id/title" 的控件了, 可以对它进行 click 等操作.
3.1.2 通过 class 定位元素
接着上面的代码: driver.find_element_by_id("com.android.settings:id/title").click(), 再写一句:
driver.find_element_by_class_name("android.widget.ImageButton").click()
参数为 "class" 的值.
通过 class name 找到返回按钮, 点击返回按钮.
3.1.3 通过 xpath 定位元素
- driver.find_element_by_xpath("//*[contains(@text,'更多')]").click()
- driver.find_element_by_xpath("//*[contains(@content-desc,'向上')]").click()
全部的测试代码为:
- # encoding=utf-8
- from appium import webdriver
- import time
- server = r'http://localhost:4723/wd/hub' # Appium Server, 端口默认为 4723
- desired_capabilities = {
- 'platformName': 'Android',
- 'driverName': '127.0.0.1:62001', # 需替换成你的 driverName
- 'platformVersion': '5.1.1',
- 'appPackage': 'com.android.settings',
- 'appActivity': '.Settings'
- }
- driver = webdriver.Remote(server, desired_capabilities) # 连接手机和 App
- driver.find_element_by_id("com.android.settings:id/title").click() # 点击 wlan
- #time.sleep(2)
- driver.find_element_by_class_name("android.widget.ImageButton").click() # 点击返回
- #time.sleep(2)
- driver.find_element_by_xpath("//*[contains(@text,'更多')]").click() # 点击更多
- #time.sleep(2)
- driver.find_element_by_xpath("//*[contains(@content-desc,'向上')]").click() # 点击返回
- #time.sleep(2)
- driver.quit()
3.2 定位多个元素
上面那些方法可以定位到一个元素, 那么 find_elements_by_XXX 可以找到多个元素, 然后通过下标找你需要的元素.
比如上面那段代码中的这句话:
driver.find_element_by_id("com.android.settings:id/title").click()
这里的 id 其实并不是唯一的, 仔细看看设置页面的其他的元素 id,id 值也都是这些.
所以可以像下面这样写:
- eles = driver.find_elements_by_id("com.android.settings:id/title")
- print(type(eles))
- eles[0].click() # 点击 eles 这个列表的第一个元素
eles 的类型是 list.
3.3 WebDriverWait 显示等待
在一个超时时间范围内, 每隔一段时间去搜索一次元素是否存在, 一旦找到, 就返回, 没有找到就每隔一段时间找一次, 直到超时后报错.
代码编写如下:
- # 创建一个 WebDriverWait 类的对象, 传三个参数, 第一个参数为 driver, 第二个参数是总共查找的时间, 单位秒, 第三个参数为每隔 1 秒的时间查找一次, 如果查找时间超过 10 秒还没找到, 就报超时错误.
- wdw = WebDriverWait(driver, 10, 1)
- # wdw 对象的方法有一个 until() 方法, 这个方法的参数是一个匿名函数, 这里的匿名函数, 形参 x 传入的是 driver, 后面的表达式就是通过 xpath 找到更多这个按钮.
- ele = wdw.until(lambda x:x.find_element_by_xpath("//*[contains(@text,'更多')]"))
- ele.click()
使用前需要导入包:
from selenium.webdriver.support.ui import WebDriverWait
3.4 元素操作
3.4.1 点击元素
click() # 上面已经使用过
3.4.2 发送数据到输入框
- send_keys(value):
- ele.send_keys("test")
3.4.3 清空输入框的元素
clear():
ele.clear
代码示例:
- # encoding=utf-8
- from appium import webdriver
- from selenium.webdriver.support.ui import WebDriverWait
- import time
- server = r'http://localhost:4723/wd/hub' # Appium Server, 端口默认为 4723
- desired_capabilities = {
- 'platformName': 'Android',
- 'driverName': '127.0.0.1:62001', # 需替换成你的 driverName
- 'platformVersion': '5.1.1',
- 'appPackage': 'com.android.settings',
- 'appActivity': '.Settings'
- }
- driver = webdriver.Remote(server, desired_capabilities)
- wdw = WebDriverWait(driver, 10, 1)
- # 点击搜索
- serach = wdw.until(lambda x:x.find_element_by_xpath("//*[contains(@content-desc,'搜索')]"))
- serach.click()
- # 输入搜索内容
- serach_text = wdw.until(lambda x : x.find_element_by_id("android:id/search_src_text"))
- serach_text.send_keys("设置")
- # 清空搜索内容
- serach_text.clear()
- time.sleep(3)
- driver.quit()
3.4.4 获取元素的文本内容
- text:
- wlan_button = driver.find_element_by_id("com.android.settings:id/title")
- print(wlan_button.text)
3.4.5 获取元素的属性值
get_attribute("属性名称"):
value 的值可以是 name,text,className,resourceId
name: 首先返回 content-desc 的值, 如果没有 content-desc, 就返回 text 属性
text: 返回 text 的属性值
className: 返回 class 属性值, 只有 API 在 18 版本以上才支持
resourceId: 返回 resource-id 属性值, 只有 API 在 18 版本以上才支持
- wdw = WebDriverWait(driver, 10, 1)
- serach = wdw.until(lambda x:x.find_element_by_xpath("//*[contains(@content-desc,'搜索')]"))
- print("className:%s"%serach.get_attribute("className"))
- print("resourceId:%s"%serach.get_attribute("resourceId"))
- print("name:%s"%serach.get_attribute("content-desc")) # 上面那段写的是输入 "name", 首先返回 content-desc 的值, 但是现在新版本输入 "name" 就只返回 text 的值, 所以如果输入 name 没有得到想要的, 就试试看这样写 get_attribute("content-desc")
- print("name:%s"%serach.get_attribute("checked")) # 返回 True 或者 Flase, 还有别的属性也类似使用即可.
3.4.6 获取元素的位置
location:
想要获取元素的位置, 首先理解一下坐标点, App 的每个控件元素都有一个坐标点, 比如下面的左上角的设置控件, 左上角的坐标点是 (24,59), 右下角的坐标点是 (84,100).
越往右, x 坐标点越大, 越往下, y 坐标点值越大.
- wdw = WebDriverWait(driver, 10, 1)
- serach = wdw.until(lambda x:x.find_element_by_xpath("//*[contains(@content-desc,'搜索')]"))
- print(serach.location) # 返回一个字典:{
- 'x': 648, 'y': 44
- }
3.4.7 获取控件的 class
- tag_name:
- driver.find_element_by_name(u"菜单").tag_name
3.4.8 判断该控件是否对用户可见
is_displayed:
driver.find_element_by_id("xxx").is_displayed() 返回 True 或 False
3.4.9 获取控件的大小
- size:
- driver.find_element_by_id("xxx").size
3.5 滑动和拖拽
3.5.1 swipe
: 从 A 点滑动至 B 点, 滑动时间为毫秒
driver.swipe(279,1081,320,354)
前面两个值是 A 点的 x,y 坐标, 后面两个值是 B 点的 x,y 坐标, 上面那个意思就是从下面的某个点滑动到上面某个点, 模拟手机从下往上滑, 第五个参数也可以写, 是个可选参数, 意思是滑动总共花费的时间, 单位是毫秒, 有一个默认时间大约 0.8s 左右, 比如:
driver.swipe(279,1081,320,354,5000) 意思就是说从 A 点滑动到 B 点总共花费 5s, 可以和上面的比较一下, 可以看出 5s 滑动的速度慢了, 惯性小了.
还有一个类似的方法, 按住 A 点后快速滑动至 B 点:
driver.flick(start_x, start_y, end_x, end_y): 传入的也是 AB 点的坐标,
3.5.2 scroll 滑动事件: 从一个元素滑动到另一个元素
- # 找到应用元素
- ying_yong = driver.find_element_by_xpath("//*[contains(@text,'应用')]")
- # 找到蓝牙元素
- lan_ya = driver.find_element_by_xpath("//*[contains(@text,'蓝牙')]")
从应用元素滑动到蓝牙元素
driver.scroll(ying_yong, lan_ya)
3.5.3 drag 拖拽事件
- ying_yong = driver.find_element_by_xpath("//*[contains(@text,'应用')]")
- lan_ya = driver.find_element_by_xpath("//*[contains(@text,'蓝牙')]")
- driver.drag_and_drop(ying_yong, lan_ya)
drag 和 scroll 的区别: drag 是没有惯性的, 所谓没有惯性的意思是每次滑动, 滑动停止的位置都是一样的, scroll 从同一个元素滑动到另一个元素, 多次运行的结果可能会不一样. swipe
方法的最后一个参数时间设置的长一些, 效果会等同于 drag, 如果不设置时间, 那效果就等同于 scroll.
多次滑动, 可以参考下面的代码, 要注意的是, find_element_by_xxx 这个方法只找显示在当前页面的元素, 不会找没有显示在当前页面的元素.
- ying_yong = driver.find_element_by_xpath("//*[contains(@text,'应用')]")
- lan_ya = driver.find_element_by_xpath("//*[contains(@text,'蓝牙')]")
- driver.drag_and_drop(ying_yong, lan_ya)
- # 下面这个按钮不可以放到上面去, 因为上句话是滑动, 备份和重置按钮只有在滑动后才能看到
- bei_fen = driver.find_element_by_xpath("//*[contains(@text,'备份')]")
- driver.drag_and_drop(bei_fen, ying_yong)
3.5.4 综合应用 1
如果页面上有 "关于手机" 元素, 就点击, 否则就向下翻页, 直到找到 "关于手机" 元素, 点击它,, 再判断关于手机页面是否有 "5.1.1".
- # encoding=utf-8
- from appium import webdriver
- from selenium.webdriver.support.ui import WebDriverWait
- import time
- server = r'http://localhost:4723/wd/hub' # Appium Server, 端口默认为 4723
- desired_capabilities = {
- 'platformName': 'Android',
- 'deviceName': '127.0.0.1:62001', # 需替换成你的 deviceName
- 'platformVersion': '5.1.1',
- 'appPackage': 'com.android.settings',
- 'appActivity': '.Settings'
- }
- driver = webdriver.Remote(server, desired_capabilities)
- while True:
- try:
- about_button = driver.find_element_by_xpath("//*[contains(@text,'关于')]")
- about_button.click()
- time.sleep(2)
- break
- except Exception:
- # 向下翻页
- # 这里还要注意, 翻完页之后, 上一页的最下面的元素还应该在页面上, 以免丢失元素
- driver.swipe(320,1081,320,500,3000)
- # 判断关于我们页面是否有 5.1.1
- eles = driver.find_elements_by_id("android:id/summary")
- for i in eles:
- # if "5.1" in i.text: # 判断只要包含 5.1 就可以
- if i.text == "5.1.1": # 判断 i.text 必须等于 5.1.1
- print("有 5.1.1")
- break
- else:
- print("没有")
- driver.quit()
for...else... 语法: for 循环正常执行完毕的情况下 (没有执行 break 语句), 继续执行 else 语法, 如果不是正常执行完毕的, 即执行了 break 语言, 就不执行 else 语句了.
3.6 高级手势 TouchAction
TouchAction 是 AppiumDriver 的辅助类, 主要针对手势操作, 比如滑动, 长按, 拖动等, 原理是将一系列动作放在一个链条中发送到服务器, 服务器接收到该链条后, 解析各个动作, 逐个执行.
3.6.1 手指轻敲
模拟手机轻轻点击一下屏幕的操作方法为:
tap(element=None, x=None, y=None, count=1)
其中 element 是被定位到的元素, x,y 是敲击的坐标点
然后使用 perform() 方法发送命令到服务器执行
- from appium import webdriver
- from appium.webdriver.common.touch_action import TouchAction # 导包
- server = r'http://localhost:4723/wd/hub' # Appium Server, 端口默认为 4723
- desired_capabilities = {
- 'platformName': 'Android',
- 'deviceName': '127.0.0.1:62001', # 需替换成你的 deviceName
- 'platformVersion': '5.1.1',
- 'appPackage': 'com.android.settings',
- 'appActivity': '.Settings'
- }
- driver = webdriver.Remote(server, desired_capabilities)
- tc = TouchAction(driver) # 创建 TouchAction 类对象
- # more_button = driver.find_element_by_xpath("//*[contains(@text,'更多')]")
- # tc.tap(more_button).perform() # 可以直接传入找到的元素
- tc.tap(x=108, y=445).perform() # 也可以不找元素, 直接传入坐标
3.6.2 手指按下和抬起
- # 前面的代码都一样
- driver = webdriver.Remote(server, desired_capabilities)
- more_button = driver.find_element_by_xpath("//*[contains(@text,'更多')]")
- tc = TouchAction(driver)
- tc.tap(more_button).perform()
- # tc.press(x=24, y=478).perform() # 按下某个点, 不松开
- tc.press(x=24, y=478).wait(5000).release().perform() # 按下某个点, 等待 5 秒钟后, 松开. 可以理解为长按
用到的方法:
press(element=None, x=None, y=None, count=1): 长按
wait(time): 等待多少毫秒
release(): 释放
3.6.3 长按 long_press
方法:
TouchAction(driver).long_presss(el=None, x=None, y=None, duration=1000)
el 意思是可以传入一个查找到的元素,
x,y 意思是传入坐标点
duration, 是长按的时间, 单位毫秒, 默认 1s
- driver = webdriver.Remote(server, desired_capabilities)
- tc = TouchAction(driver)
- driver.find_element_by_xpath("//*[contains(@text,'WLAN')]").click()
- time.sleep(2)
- tc.long_press(driver.find_element_by_xpath("//*[contains(@text,'SSID')]")).perform()
3.6.4 移动 move_to() 方法
move_to(el=None, x=None, y=None):
这个方法跟前面的方法类似, 第一个参数可以传入一个找到的元素, 第二个和第三个元素可以传入坐标点, 选择哪种方法都可以.
假如想要更改解锁图案为如图的样子:
代码可以如下:
- # encoding=utf-8
- from appium import webdriver
- from appium.webdriver.common.touch_action import TouchAction
- from selenium.webdriver.support.wait import WebDriverWait
- server = r'http://localhost:4723/wd/hub' # Appium Server, 端口默认为 4723
- desired_capabilities = {
- 'platformName': 'Android',
- 'deviceName': '127.0.0.1:62001', # 需替换成你的 deviceName
- 'platformVersion': '5.1.1',
- 'appPackage': 'com.android.settings',
- 'appActivity':'.ChooseLockPattern' # 活动名, 解锁图案的页面
- }
- driver = webdriver.Remote(server, desired_capabilities)
- wdw = WebDriverWait(driver, 10, 1)
- tc = TouchAction(driver)
- tc.press(x=120, y=418)\
- .move_to(x=360, y=418)\
- .move_to(x=601, y=418)\
- .move_to(x=600, y=656)\
- .move_to(x=360, y=665)\
- .move_to(x=360, y=895)\
- .move_to(x=120, y=650)\
- .release()\
- .perform()
ps: 这里需要注意一点, 用 UIAutomatorViewer 工具找各个点的坐标找不到, 这时候要用什么找呢? 可以打开手机的开发者模式, 用手机自带的指针位置功能.
打开方式:
进入设置 -> 关于手机 -> 多次点击版本号, 就打开了开发者模式, 找到 "开发者选项", 按照图示打开:
move_to 需要注意:
- tc.press(x=120, y=418).wait(1000).move_to(x=360, y=418).release().perform()
- tc.press(x=120, y=418).move_to(x=360, y=418).wait(1000).release().perform()
上面这两种写法, wait 放置的地方不同, move_to 出来的结果有可能不一样, 上面这种写法就可以, 下面那个就会滑偏, 原因: 第一个写法是因为脚本直接转换成了 swipe 的操作, 认为是从哪里滑动到哪里, 坐标点都是绝对坐标.
第二种写法会被认为是相对坐标, 第二个坐标点就被 appium 改成相对于前面的坐标点的坐标了.
appium1.8 版本以上的应该就不会这样了, 两种写法都是按照绝对坐标去滑动.
3.7 针对手机操作的 API
3.7.1 获取手机时间
- device_time:
- print(driver.device_time)
返回时间: 2020-01-31T22:04:54+08:00
3.7.2 获取手机分辨率
- get_window_size():
- print(driver.get_window_size())
返回一个字典:{'width': 720, 'height': 1280}
3.7.3 打开通知栏
- open_notifications():
- driver.open_notifications()
关闭的话点击手机的返回就可以
3.7.4 返回网络的连接类型
network_connection:
'''返回一个指定网络连接类型的整数位掩码 (android)''', 即下面的方法里面提到的数字
用法: driver.network_connection
3.7.5 设置网络的连接 (Android)
set_network_connection(connectionType):
这个方法的参数可以直接写, 0,1,2,4,6 这几个数字, 也可以写具体名如下:
- NO_CONNECTION = 0
- AIRPLANE_MODE = 1
- WIFI_ONLY = 2
- DATA_ONLY = 4
- ALL_NETWORK_ON = 6
比如:
driver.set_network_connection(1)
等同于
driver.set_network_connection(ConnectionType.ALL_NETWORK_ON)
3.7.6 截图
get_screenshot_as_file(路径):
把当前的页面截图放到对应路径中.
截图的方法:
driver.get_screenshot_as_file("../xxx.png")
比如出现 bug 的时候可以截图, 或者有一些输入需要确认是否输入正确等都可以截图等 case 执行完毕后确认.
3.7.7 检查 App 是否已安装
- is_app_installed:
- driver.is_app_installed("com.android.xxx")
3.7.8 安装 App
- install_app:
- driver.install_app(app_path)
3.7.9 删除 App
- remove_app:
- driver.remove_app(app_path)
3.7.10 关掉 App
- close_app:
- driver.close_app ()
3.7.11 keyevent() 方法, 通过 keycode 操作手机
- keyevent(keycode):
- driver.keyevent(24) # 音量加
如果在连接手机的代码里面, 有 automationName='Uiautomator2'这样的配置, 则应该使用下面这个指令:
- press_keycode(keycode)
- driver.press_keycode(24) # 音量加
3.7.12 keycode 列表
基本按键
KEYCODE 名称 | 按键 | keycode |
KEYCODE_0 | 按键'0' | 7 |
KEYCODE_1 | 按键'1' | 8 |
KEYCODE_2 | 按键'2' | 9 |
KEYCODE_3 | 按键'3' | 10 |
KEYCODE_4 | 按键'4' | 11 |
KEYCODE_5 | 按键'5' | 12 |
KEYCODE_6 | 按键'6' | 13 |
KEYCODE_7 | 按键'7' | 14 |
KEYCODE_8 | 按键'8' | 15 |
KEYCODE_9 | 按键'9' | 16 |
KEYCODE_A | 按键'A' | 29 |
KEYCODE_B | 按键'B' | 30 |
KEYCODE_C | 按键'C' | 31 |
KEYCODE_D | 按键'D' | 32 |
KEYCODE_E | 按键'E' | 33 |
KEYCODE_F | 按键'F' | 34 |
KEYCODE_G | 按键'G' | 35 |
KEYCODE_H | 按键'H' | 36 |
KEYCODE_I | 按键'I' | 37 |
KEYCODE_J | 按键'J' | 38 |
KEYCODE_K | 按键'K' | 39 |
KEYCODE_L | 按键'L' | 40 |
KEYCODE_M | 按键'M' | 41 |
KEYCODE_N | 按键'N' | 42 |
KEYCODE_O | 按键'O' | 43 |
KEYCODE_P | 按键'P' | 44 |
KEYCODE_Q | 按键'Q' | 45 |
KEYCODE_R | 按键'R' | 46 |
KEYCODE_S | 按键'S' | 47 |
KEYCODE_T | 按键'T' | 48 |
KEYCODE_U | 按键'U' | 49 |
KEYCODE_V | 按键'V' | 50 |
KEYCODE_W | 按键'W' | 51 |
KEYCODE_X | 按键'X' | 52 |
KEYCODE_Y | 按键'Y' | 53 |
KEYCODE_Z | 按键'Z' | 54 |
手柄按键
KEYCODE_BUTTON_1 | 通用游戏手柄按钮 #1 | 188 |
KEYCODE_BUTTON_2 | 通用游戏手柄按钮 & nbsp;#2 | 189 |
KEYCODE_BUTTON_3 | 通用游戏手柄按钮 & nbsp;#3 | 190 |
KEYCODE_BUTTON_4 | 通用游戏手柄按钮 & nbsp;#4 | 191 |
KEYCODE_BUTTON_5 | 通用游戏手柄按钮 & nbsp;#5 | 192 |
KEYCODE_BUTTON_6 | 通用游戏手柄按钮 & nbsp;#6 | 193 |
KEYCODE_BUTTON_7 | 通用游戏手柄按钮 & nbsp;#7 | 194 |
KEYCODE_BUTTON_8 | 通用游戏手柄按钮 & nbsp;#8 | 195 |
KEYCODE_BUTTON_9 | 通用游戏手柄按钮 & nbsp;#9 | 196 |
KEYCODE_BUTTON_10 | 通用游戏手柄按钮 & nbsp;#10 | 197 |
KEYCODE_BUTTON_11 | 通用游戏手柄按钮 & nbsp;#11 | 198 |
KEYCODE_BUTTON_12 | 通用游戏手柄按钮 & nbsp;#12 | 199 |
KEYCODE_BUTTON_13 | 通用游戏手柄按钮 & nbsp;#13 | 200 |
KEYCODE_BUTTON_14 | 通用游戏手柄按钮 & nbsp;#14 | 201 |
KEYCODE_BUTTON_15 | 通用游戏手柄按钮 & nbsp;#15 | 202 |
KEYCODE_BUTTON_16 | 通用游戏手柄按钮 & nbsp;#16 | 203 |
KEYCODE_BUTTON_A | 游戏手柄按钮 & nbsp;A | 96 |
KEYCODE_BUTTON_B | 游戏手柄按钮 & nbsp;B | 97 |
KEYCODE_BUTTON_C | 游戏手柄按钮 & nbsp;C | 98 |
KEYCODE_BUTTON_X | 游戏手柄按钮 & nbsp;X | 99 |
KEYCODE_BUTTON_Y | 游戏手柄按钮 & nbsp;Y | 100 |
KEYCODE_BUTTON_Z | 游戏手柄按钮 & nbsp;Z | 101 |
KEYCODE_BUTTON_L1 | 游戏手柄按钮 & nbsp;L1 | 102 |
KEYCODE_BUTTON_L2 | 游戏手柄按钮 & nbsp;L2 | 104 |
KEYCODE_BUTTON_R1 | 游戏手柄按钮 & nbsp;R1 | 103 |
KEYCODE_BUTTON_R2 | 游戏手柄按钮 & nbsp;R2 | 105 |
KEYCODE_BUTTON_MODE | 游戏手柄按钮 & nbsp;Mode | 110 |
KEYCODE_BUTTON_SELECT | 游戏手柄按钮 & nbsp;Select | 109 |
KEYCODE_BUTTON_START | 游戏手柄按钮 & nbsp;Start | 108 |
KEYCODE_BUTTON_THUMBL | Left Thumb Button | 106 |
KEYCODE_BUTTON_THUMBR | Right Thumb Button | 107 |
电话按键
KEYCODE_CALL | 拨号键 | 5 |
KEYCODE_ENDCALL | 挂机键 | 6 |
KEYCODE_HOME | 按键 Home | 3 |
KEYCODE_MENU | 菜单键 | 82 |
KEYCODE_BACK | 返回键 | 4 |
KEYCODE_SEARCH | 搜索键 | 84 |
KEYCODE_CAMERA | 拍照键 | 27 |
KEYCODE_FOCUS | 拍照对焦键 | 80 |
KEYCODE_POWER | 电源键 | 26 |
KEYCODE_NOTIFICATION | 通知键 | 83 |
KEYCODE_MUTE | 话筒静音键 | 91 |
KEYCODE_VOLUME_MUTE | 扬声器静音键 | 164 |
KEYCODE_VOLUME_UP | 音量增加键 | 24 |
KEYCODE_VOLUME_DOWN | 音量减小键 | 25 |
控制按键
KEYCODE_ENTER | 回车键 | 66 |
KEYCODE_ESCAPE | ESC 键 | 111 |
KEYCODE_DPAD_CENTER | 导航键 & nbsp; 确定键 | 23 |
KEYCODE_DPAD_UP | 导航键 & nbsp; 向上 | 19 |
KEYCODE_DPAD_DOWN | 导航键 & nbsp; 向下 | 20 |
KEYCODE_DPAD_LEFT | 导航键 & nbsp; 向左 | 21 |
KEYCODE_DPAD_RIGHT | 导航键 & nbsp; 向右 | 22 |
KEYCODE_MOVE_HOME | 光标移动到开始键 | 122 |
KEYCODE_MOVE_END | 光标移动到末尾键 | 123 |
KEYCODE_PAGE_UP | 向上翻页键 | 92 |
KEYCODE_PAGE_DOWN | 向下翻页键 | 93 |
KEYCODE_DEL | 退格键 | 67 |
KEYCODE_FORWARD_DEL | 删除键 | 112 |
KEYCODE_INSERT | 插入键 | 124 |
KEYCODE_TAB | Tab 键 | 61 |
KEYCODE_NUM_LOCK | 小键盘锁 | 143 |
KEYCODE_CAPS_LOCK | 大写锁定键 | 115 |
KEYCODE_BREAK | Break/Pause 键 | 121 |
KEYCODE_SCROLL_LOCK | 滚动锁定键 | 116 |
KEYCODE_ZOOM_IN | 放大键 | 168 |
KEYCODE_ZOOM_OUT | 缩小键 | 169 |
组合键
KEYCODE_ALT_LEFT | Alt+Left | 57 |
KEYCODE_ALT_RIGHT | Alt+Right | 58 |
KEYCODE_CTRL_LEFT | Control+Left | 113 |
KEYCODE_CTRL_RIGHT | Control+Right | 114 |
KEYCODE_SHIFT_LEFT | Shift+Left | 59 |
KEYCODE_SHIFT_RIGHT | Shift+Right | 60 |
符号
KEYCODE_PLUS | 按键'+' | 81 |
KEYCODE_MINUS | 按键'-' | 69 |
KEYCODE_STAR | 按键'*' | 17 |
KEYCODE_SLASH | 按键'/' | 76 |
KEYCODE_EQUALS | 按键'=' | 70 |
KEYCODE_AT | 按键'@' | 77 |
KEYCODE_POUND | 按键'#' | 18 |
KEYCODE_APOSTROPHE | 按键''' (单引号) | 75 |
KEYCODE_BACKSLASH | 按键'\' | 73 |
KEYCODE_COMMA | 按键',' | 55 |
KEYCODE_PERIOD | 按键'.' | 56 |
KEYCODE_LEFT_BRACKET | 按键'[' | 71 |
KEYCODE_RIGHT_BRACKET | 按键']' | 72 |
KEYCODE_SEMICOLON | 按键';' | 74 |
KEYCODE_GRAVE | 按键'`' | 68 |
KEYCODE_SPACE | 空格键 | 62 |
小键盘
KEYCODE_NUMPAD_0 | 小键盘按键'0' | 144 |
KEYCODE_NUMPAD_1 | 小键盘按键'1' | 145 |
KEYCODE_NUMPAD_2 | 小键盘按键'2' | 146 |
KEYCODE_NUMPAD_3 | 小键盘按键'3' | 147 |
KEYCODE_NUMPAD_4 | 小键盘按键'4' | 148 |
KEYCODE_NUMPAD_5 | 小键盘按键'5' | 149 |
KEYCODE_NUMPAD_6 | 小键盘按键'6' | 150 |
KEYCODE_NUMPAD_7 | 小键盘按键'7' | 151 |
KEYCODE_NUMPAD_8 | 小键盘按键'8' | 152 |
KEYCODE_NUMPAD_9 | 小键盘按键'9' | 153 |
KEYCODE_NUMPAD_ADD | 小键盘按键'+' | 157 |
KEYCODE_NUMPAD_SUBTRACT | 小键盘按键'-' | 156 |
KEYCODE_NUMPAD_MULTIPLY | 小键盘按键'*' | 155 |
KEYCODE_NUMPAD_DIVIDE | 小键盘按键'/' | 154 |
KEYCODE_NUMPAD_EQUALS | 小键盘按键'=' | 161 |
KEYCODE_NUMPAD_COMMA | 小键盘按键',' | 159 |
KEYCODE_NUMPAD_DOT | 小键盘按键'.' | 158 |
KEYCODE_NUMPAD_LEFT_PAREN | 小键盘按键'(' | 162 |
KEYCODE_NUMPAD_RIGHT_PAREN | 小键盘按键')' | 163 |
KEYCODE_NUMPAD_ENTER | 小键盘按键回车 | 160 |
功能键
KEYCODE_F1 | 按键 F1 | 131 |
KEYCODE_F2 | 按键 F2 | 132 |
KEYCODE_F3 | 按键 F3 | 133 |
KEYCODE_F4 | 按键 F4 | 134 |
KEYCODE_F5 | 按键 F5 | 135 |
KEYCODE_F6 | 按键 F6 | 136 |
KEYCODE_F7 | 按键 F7 | 137 |
KEYCODE_F8 | 按键 F8 | 138 |
KEYCODE_F9 | 按键 F9 | 139 |
KEYCODE_F10 | 按键 F10 | 140 |
KEYCODE_F11 | 按键 F11 | 141 |
KEYCODE_F12 | 按键 F12 | 142 |
多媒体键
KEYCODE_MEDIA_PLAY | 多媒体键 & nbsp; 播放 | 126 |
KEYCODE_MEDIA_STOP | 多媒体键 & nbsp; 停止 | 86 |
KEYCODE_MEDIA_PAUSE | 多媒体键 & nbsp; 暂停 | 127 |
KEYCODE_MEDIA_PLAY_PAUSE | 多媒体键 & nbsp; 播放 / 暂停 | 85 |
KEYCODE_MEDIA_FAST_FORWARD | 多媒体键 & nbsp; 快进 | 90 |
KEYCODE_MEDIA_REWIND | 多媒体键 & nbsp; 快退 | 89 |
KEYCODE_MEDIA_NEXT | 多媒体键 & nbsp; 下一首 | 87 |
KEYCODE_MEDIA_PREVIOUS | 多媒体键 & nbsp; 上一首 | 88 |
KEYCODE_MEDIA_CLOSE | 多媒体键 & nbsp; 关闭 | 128 |
KEYCODE_MEDIA_EJECT | 多媒体键 & nbsp; 弹出 | 129 |
KEYCODE_MEDIA_RECORD | 多媒体键 & nbsp; 录音 | 130 |
其他
KEYCODE_NUM | 按键 Number modifier | 78 |
KEYCODE_INFO | 按键 Info | 165 |
KEYCODE_APP_SWITCH | 按键 App switch | 187 |
KEYCODE_BOOKMARK | 按键 Bookmark | 174 |
KEYCODE_AVR_INPUT | 按键 A/V Receiver input | 182 |
KEYCODE_AVR_POWER | 按键 A/V Receiver power | 181 |
KEYCODE_CAPTIONS | 按键 Toggle captions | 175 |
KEYCODE_CHANNEL_DOWN | 按键 Channel down | 167 |
KEYCODE_CHANNEL_UP | 按键 Channel up | 166 |
KEYCODE_CLEAR | 按键 Clear | 28 |
KEYCODE_DVR | 按键 DVR | 173 |
KEYCODE_ENVELOPE | 按键 Envelope special function | 65 |
KEYCODE_EXPLORER | 按键 Explorer special function | 64 |
KEYCODE_FORWARD | 按键 Forward | 125 |
KEYCODE_FORWARD_DEL | 按键 Forward Delete | 112 |
KEYCODE_FUNCTION | 按键 Function modifier | 119 |
KEYCODE_GUIDE | 按键 Guide | 172 |
KEYCODE_HEADSETHOOK | 按键 Headset Hook | 79 |
KEYCODE_META_LEFT | 按键 Left Meta modifier | 117 |
KEYCODE_META_RIGHT | 按键 Right Meta modifier | 118 |
KEYCODE_PICTSYMBOLS | 按键 Picture Symbols modifier | 94 |
KEYCODE_PROG_BLUE | 按键 Blue “programmable” | 186 |
KEYCODE_PROG_GREEN | 按键 Green “programmable” | 184 |
KEYCODE_PROG_RED | 按键 Red “programmable” | 183 |
KEYCODE_PROG_YELLOW | 按键 Yellow “programmable” | 185 |
KEYCODE_SETTINGS | 按键 Settings | 176 |
KEYCODE_SOFT_LEFT | 按键 Soft Left | 1 |
KEYCODE_SOFT_RIGHT | 按键 Soft Right | 2 |
KEYCODE_STB_INPUT | 按键 Set-top-box input | 180 |
KEYCODE_STB_POWER | 按键 Set-top-box power | 179 |
KEYCODE_SWITCH_CHARSET | 按键 Switch Charset modifier | 95 |
KEYCODE_SYM | 按键 Symbol modifier | 63 |
KEYCODE_SYSRQ | 按键 System Request / Print Screen | 120 |
KEYCODE_TV | 按键 TV | 170 |
KEYCODE_TV_INPUT | 按键 TV input | 178 |
KEYCODE_TV_POWER | 按键 TV power | 177 |
KEYCODE_WINDOW | 按键 Window | 171 |
KEYCODE_UNKNOWN | 未知按键 | 0 |
来源: https://www.cnblogs.com/sy_test/p/12546400.html