Android Input和SendEvent脚本命令模拟连续滑动事件 您所在的位置:网站首页 屏幕滑动脚本怎么用 Android Input和SendEvent脚本命令模拟连续滑动事件

Android Input和SendEvent脚本命令模拟连续滑动事件

2023-09-04 00:59| 来源: 网络整理| 查看: 265

文章目录 1. Input命令滑动事件1.1 input命令使用1.2 input命令源码解析 2. SendEvent滑动事件3. shell脚本连续发送滑动事件4. python脚本连续发送滑动事件5. push shell到机器里6. 问题6.1. sendEvent命令滑动卡顿6.2. sendevent耗时太久6.3. Input缺点 7. 修改sendevent解决 adb shell sendevent慢的问题7.1 adb shell sendevent慢的原因7.2 新建命令sendeventtsp来替代脚本实现滑动7.3 sendeventtsp结果7.4 在sendevent.c添加逻辑 8. toybox sendevent源码解析

1. Input命令滑动事件 1.1 input命令使用

input --help查询使用

130|msm8996_gvmq:/ # input --help Error: Unknown command: --help Usage: input [] [...] The sources are: dpad keyboard mouse touchpad gamepad touchnavigation joystick touchscreen stylus trackball The commands and default sources are: text (Default: touchscreen) keyevent [--longpress] ... (Default: keyboard) tap (Default: touchscreen) swipe [duration(ms)] (Default: touchscreen) draganddrop [duration(ms)] (Default: touchscreen) press (Default: trackball) roll (Default: trackball) 1. keyevent指的是android对应的keycode,比如home键的keycode=3,back键的keycode=4. @frameworks/base/core/java/android/view/KeyEvent.java adb shell input keyevent 3 2. tap模拟的是touch屏幕的事件,只需给出x、y坐标即可。 此x、y坐标对应的是真实的屏幕分辨率,所以要根据具体手机具体看,比如你想点击屏幕(x, y) = (250, 250)位置: adb shell input tap 250 250 3. 关于swipe同tap是一样的,只是他是模拟滑动的事件,给出起点和终点的坐标即可。例如从屏幕(250, 250), 到屏幕(300, 300)即 adb shell input swipe 250 250 300 300 1.2 input命令源码解析

input命令最终是调用 InputManager.getInstance().injectInputEvent(event来发送事件

@frameworks/base/cmds/input/src/com/android/commands/input/Input.java private void sendSwipe(int inputSource, float x1, float y1, float x2, float y2, int duration) { if (duration long elapsedTime = now - startTime; float alpha = (float) elapsedTime / duration; injectMotionEvent(inputSource, MotionEvent.ACTION_MOVE, now, lerp(x1, x2, alpha), lerp(y1, y2, alpha), 1.0f); now = SystemClock.uptimeMillis(); } injectMotionEvent(inputSource, MotionEvent.ACTION_UP, now, x2, y2, 0.0f); } /** * Builds a MotionEvent and injects it into the event stream. * * @param inputSource the InputDevice.SOURCE_* sending the input event * @param action the MotionEvent.ACTION_* for the event * @param when the value of SystemClock.uptimeMillis() at which the event happened * @param x x coordinate of event * @param y y coordinate of event * @param pressure pressure of event */ private void injectMotionEvent(int inputSource, int action, long when, float x, float y, float pressure) { final float DEFAULT_SIZE = 1.0f; final int DEFAULT_META_STATE = 0; final float DEFAULT_PRECISION_X = 1.0f; final float DEFAULT_PRECISION_Y = 1.0f; final int DEFAULT_EDGE_FLAGS = 0; MotionEvent event = MotionEvent.obtain(when, when, action, x, y, pressure, DEFAULT_SIZE, DEFAULT_META_STATE, DEFAULT_PRECISION_X, DEFAULT_PRECISION_Y, getInputDeviceId(inputSource), DEFAULT_EDGE_FLAGS); event.setSource(inputSource); Log.i(TAG, "injectMotionEvent: " + event); InputManager.getInstance().injectInputEvent(event, InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH); }

IInputManager没有displayID接口的调用,因此无法发送事件到其他屏

@frameworks/base/core/java/android/hardware/input/IInputManager.aidl boolean injectInputEvent(in InputEvent ev, int mode); @Override // Binder call public boolean injectInputEvent(InputEvent event, int mode) { return injectInputEventInternal(event, Display.DEFAULT_DISPLAY, mode); } private boolean injectInputEventInternal(InputEvent event, int displayId, int mode) { if (event == null) { throw new IllegalArgumentException("event must not be null"); } if (mode != InputManager.INJECT_INPUT_EVENT_MODE_ASYNC && mode != InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH && mode != InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT) { throw new IllegalArgumentException("mode is invalid"); } final int pid = Binder.getCallingPid(); final int uid = Binder.getCallingUid(); final long ident = Binder.clearCallingIdentity(); final int result; try { result = nativeInjectInputEvent(mPtr, event, displayId, pid, uid, mode, INJECTION_TIMEOUT_MILLIS, WindowManagerPolicy.FLAG_DISABLE_KEY_REPEAT); } finally { Binder.restoreCallingIdentity(ident); } switch (result) { case INPUT_EVENT_INJECTION_PERMISSION_DENIED: Slog.w(TAG, "Input event injection from pid " + pid + " permission denied."); throw new SecurityException( "Injecting to another application requires INJECT_EVENTS permission"); case INPUT_EVENT_INJECTION_SUCCEEDED: return true; case INPUT_EVENT_INJECTION_TIMED_OUT: Slog.w(TAG, "Input event injection from pid " + pid + " timed out."); return false; case INPUT_EVENT_INJECTION_FAILED: default: Slog.w(TAG, "Input event injection from pid " + pid + " failed."); return false; } }

JNI最终还是调用InputDispatcher来完成事件发送

@frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp static jint nativeInjectInputEvent(JNIEnv* env, jclass /* clazz */, jlong ptr, jobject inputEventObj, jint displayId, jint injectorPid, jint injectorUid, jint syncMode, jint timeoutMillis, jint policyFlags) { NativeInputManager* im = reinterpret_cast(ptr); if (env->IsInstanceOf(inputEventObj, gKeyEventClassInfo.clazz)) { KeyEvent keyEvent; status_t status = android_view_KeyEvent_toNative(env, inputEventObj, & keyEvent); if (status) { jniThrowRuntimeException(env, "Could not read contents of KeyEvent object."); return INPUT_EVENT_INJECTION_FAILED; } return (jint) im->getInputManager()->getDispatcher()->injectInputEvent( & keyEvent, displayId, injectorPid, injectorUid, syncMode, timeoutMillis, uint32_t(policyFlags)); } else if (env->IsInstanceOf(inputEventObj, gMotionEventClassInfo.clazz)) { const MotionEvent* motionEvent = android_view_MotionEvent_getNativePtr(env, inputEventObj); if (!motionEvent) { jniThrowRuntimeException(env, "Could not read contents of MotionEvent object."); return INPUT_EVENT_INJECTION_FAILED; } return (jint) im->getInputManager()->getDispatcher()->injectInputEvent( motionEvent, displayId, injectorPid, injectorUid, syncMode, timeoutMillis, uint32_t(policyFlags)); } else { jniThrowRuntimeException(env, "Invalid input event type."); return INPUT_EVENT_INJECTION_FAILED; } } 2. SendEvent滑动事件

通过getevent 观察滑动事件,发现滑动事件就是一个down事件,加上很多move事件,在最后加一个up事件,因此是否通过sendevent发送这样的事件就可以了

//getevent -l /dev/input/event0: EV_ABS ABS_MT_TRACKING_ID 0000001a /dev/input/event0: EV_ABS ABS_MT_POSITION_X 0000057b /dev/input/event0: EV_ABS ABS_MT_POSITION_Y 000000b7 /dev/input/event0: EV_KEY BTN_TOUCH DOWN /dev/input/event0: EV_SYN SYN_REPORT 00000000 /dev/input/event0: EV_ABS ABS_MT_POSITION_X 0000056f /dev/input/event0: EV_ABS ABS_MT_POSITION_Y 000000b8 /dev/input/event0: EV_SYN SYN_REPORT 00000000 /dev/input/event0: EV_ABS ABS_MT_POSITION_X 0000027b /dev/input/event0: EV_SYN SYN_REPORT 00000000 /dev/input/event0: EV_ABS ABS_MT_POSITION_X 00000273 /dev/input/event0: EV_SYN SYN_REPORT 00000000 /dev/input/event0: EV_ABS ABS_MT_POSITION_X 00000272 /dev/input/event0: EV_SYN SYN_REPORT 00000000 /dev/input/event0: EV_ABS ABS_MT_POSITION_X 00000271 /dev/input/event0: EV_SYN SYN_REPORT 00000000 /dev/input/event0: EV_ABS ABS_MT_TRACKING_ID ffffffff /dev/input/event0: EV_KEY BTN_TOUCH UP /dev/input/event0: EV_SYN SYN_REPORT 00000000 ### getevent /dev/input/event0 0003 0039 00000021 /dev/input/event0 0003 0035 00000770 //ABS_MT_POSITION_X 0035 /dev/input/event0 0003 0036 00000087 //ABS_MT_POSITION_Y 0036 /dev/input/event0 0001 014a 00000001 //down /dev/input/event0 0000 0000 00000000 /dev/input/event0 0000 0000 00000000 /dev/input/event0 0003 0035 0000054c /dev/input/event0 0003 0036 00000072 /dev/input/event0 0000 0000 00000000 /dev/input/event0 0003 0039 ffffffff /dev/input/event0 0001 014a 00000000 //up /dev/input/event0 0000 0000 00000000 //SYN_REPORT 3. shell脚本连续发送滑动事件

shell脚本可用于linux客户端测试

和5最主要差别就是此shell是放在电脑上运行,5是push在机器上运行

#!/bin/bash echo "test....Pid: $$" Display1Event=/dev/input/event0 Display2Event=/dev/input/event1 Display3Event=/dev/input/event2 #swipe from rigint to left swipeRightToLeft(){ XstartCoord=1900 YstartCoord=300 interval=200 XendCoord=800 adb shell sendevent $Display1Event 3 57 33 adb shell sendevent $Display1Event 3 53 $XstartCoord adb shell sendevent $Display1Event 3 54 $YstartCoord adb shell sendevent $Display1Event 1 330 1 adb shell sendevent $Display1Event 0 0 0 echo "swipeRightToLeft....down" while [ `expr $XstartCoord - $interval` -gt $XendCoord ]; do echo "swipeRightToLeft...move" XstartCoord=`expr $XstartCoord - $interval` adb shell sendevent $Display1Event 3 53 $XstartCoord adb shell sendevent $Display1Event 3 54 $YstartCoord adb shell sendevent $Display1Event 0 0 0 done echo "swipeRightToLeft....up" adb shell sendevent $Display1Event 3 57 ffffffff #adb shell sendevent $Display1Event 3 57 0 adb shell sendevent $Display1Event 1 330 0 adb shell sendevent $Display1Event 0 0 0 } #swipe from rigint to left swipeLeftToRight(){ XstartCoord=10 #down的x坐标 YstartCoord=300 interval=200 XendCoord=1000 #结束时坐标 adb shell sendevent $Display1Event 3 57 33 adb shell sendevent $Display1Event 3 53 $XstartCoord adb shell sendevent $Display1Event 3 54 $YstartCoord adb shell sendevent $Display1Event 1 330 1 adb shell sendevent $Display1Event 0 0 0 echo "swipeRightToLeft....down" while [ `expr $XstartCoord + $interval` -lt $XendCoord ]; do echo "swipeRightToLeft...move" XstartCoord=`expr $XstartCoord + $interval` adb shell sendevent $Display1Event 3 53 $XstartCoord adb shell sendevent $Display1Event 3 54 $YstartCoord adb shell sendevent $Display1Event 0 0 0 done echo "swipeRightToLeft....up" adb shell sendevent $Display1Event 3 57 ffffffff #adb shell sendevent $Display1Event 3 57 0 adb shell sendevent $Display1Event 1 330 0 adb shell sendevent $Display1Event 0 0 0 } adb root adb remount echo $Display1Event while true; do echo "while...." swipeRightToLeft sleep 1 swipeLeftToRight sleep 1 done echo "test finish...." 4. python脚本连续发送滑动事件

电脑端python脚本可用于window和linux测试

import sys import os import time import datetime print ('usage: test.py path [excel path]') # 1. adb shell命令方法有好几种,可以google def adb_shell(cmd): exit_code = os.system(cmd) return exit_code>>8 # 2. 添加了adb shell sendevent而已 def adb_shell_sendevent(cmd): exit_code = os.system("adb shell sendevent " + cmd) return exit_code>>8 # 3. 滑动的方法 def swipeRightToLeft(displayEvent) : begin = datetime.datetime.now() DisplayEvent=displayEvent XstartCoord=1900 YstartCoord=300 interval=200 XendCoord=800 # 3.1 发送xy坐标 + down事件 adb_shell_sendevent(DisplayEvent + " 3 57 33 ") adb_shell_sendevent(DisplayEvent + " 3 53 " + str(XstartCoord)) adb_shell_sendevent(DisplayEvent + " 3 54 " + str(YstartCoord)) adb_shell_sendevent(DisplayEvent + " 1 330 1") adb_shell_sendevent(DisplayEvent + " 0 0 0") # 3.2 发送move xy坐标 #print ("swipeRightToLeft....down") while ( XstartCoord - interval > XendCoord ) : XstartCoord=XstartCoord - interval adb_shell_sendevent(DisplayEvent + " 3 53 " + str(XstartCoord)) adb_shell_sendevent(DisplayEvent + " 3 54 " + str(YstartCoord)) adb_shell_sendevent(DisplayEvent + " 0 0 0") # 3.3 发送up #print ("swipeRightToLeft....up") adb_shell_sendevent(DisplayEvent + " 3 57 ffffffff") adb_shell_sendevent(DisplayEvent + " 1 330 0 ") adb_shell_sendevent(DisplayEvent + " 0 0 0") end = datetime.datetime.now() print("swipeRightToLeft Time: ",end-begin) def swipeLeftToRight(displayEvent) : begin = datetime.datetime.now() DisplayEvent=displayEvent XstartCoord=10 #down的x坐标 YstartCoord=300 interval=200 XendCoord=1000 #结束时坐标 adb_shell_sendevent(DisplayEvent + " 3 57 33 ") adb_shell_sendevent(DisplayEvent + " 3 53 " + str(XstartCoord)) adb_shell_sendevent(DisplayEvent + " 3 54 " + str(YstartCoord)) adb_shell_sendevent(DisplayEvent + " 1 330 1") adb_shell_sendevent(DisplayEvent + " 0 0 0") #print ("swipeLeftToRight....down") while ( XstartCoord + interval < XendCoord ) : XstartCoord=XstartCoord + interval adb_shell_sendevent(DisplayEvent + " 3 53 " + str(XstartCoord)) adb_shell_sendevent(DisplayEvent + " 3 54 " + str(YstartCoord)) adb_shell_sendevent(DisplayEvent + " 0 0 0") #print ("swipeLeftToRight....up") adb_shell_sendevent(DisplayEvent + " 3 57 ffffffff") adb_shell_sendevent(DisplayEvent + " 1 330 0 ") adb_shell_sendevent(DisplayEvent + " 0 0 0") end = datetime.datetime.now() print("swipeRightToLeft Time: ",end-begin) #main函数 def main(argv): adb_shell("adb root && adb remount") Display0Event="/dev/input/event0" Display1Event="/dev/input/event1" Display2Event="/dev/input/event2" #adb_shell(cmd) while 0: #0-->1 swipeLeftToRight(Display0Event) time.sleep(0.8) #1-->2 swipeLeftToRight(Display1Event) time.sleep(0.8) #2-->1 swipeRightToLeft(Display2Event) time.sleep(0.8) #1-->0 swipeRightToLeft(Display1Event) time.sleep(0.8) while 1: swipeLeftToRight(Display0Event) time.sleep(0.8) swipeRightToLeft(Display0Event) time.sleep(0.8) #函数主入口,其他Module导入不会走main if __name__ == "__main__": main(sys.argv[1:]) 5. push shell到机器里

sendEvent在adb shell里面发,需要push到机器,避免电脑操作系统影响

#!/bin/bash #获取pid进程号 echo "test....Pid: $$" Display0Event=/dev/input/event0 Display1Event=/dev/input/event1 Display2Event=/dev/input/event2 #swipe from rigint to left swipeRightToLeft(){ DisplayEvent=$1 XstartCoord=1900 YstartCoord=300 interval=200 XendCoord=800 start=$(date +%s) #1. 发送down事件,和初始xy坐标,最后report sendevent $DisplayEvent 3 57 33 sendevent $DisplayEvent 3 53 $XstartCoord sendevent $DisplayEvent 3 54 $YstartCoord sendevent $DisplayEvent 1 330 1 sendevent $DisplayEvent 0 0 0 echo "swipeRightToLeft....down" while [ `expr $XstartCoord - $interval` -gt $XendCoord ]; do echo "swipeRightToLeft...move" # 2. while循环发送move事件,发送x,y坐标加report就可以。这里是把y值每次减$interval XstartCoord=`expr $XstartCoord - $interval` sendevent $DisplayEvent 3 53 $XstartCoord sendevent $DisplayEvent 3 54 $YstartCoord sendevent $DisplayEvent 0 0 0 done # 3. 最后发送up事件并report,完成一次提交 echo "swipeRightToLeft....up" sendevent $DisplayEvent 3 57 ffffffff #sendevent $DisplayEvent 3 57 0 sendevent $DisplayEvent 1 330 0 sendevent $DisplayEvent 0 0 0 # 4. 最后判断此次滑动事件,adb shell sendEvent耗时很久,大概2秒钟 end=$(date +%s) take=$(( end - start )) echo Time taken is ${take} seconds. } #swipe from rigint to left swipeLeftToRight(){ DisplayEvent=$1 XstartCoord=10 #down的x坐标 YstartCoord=300 interval=200 XendCoord=1000 #结束时坐标 sendevent $DisplayEvent 3 57 33 sendevent $DisplayEvent 3 53 $XstartCoord sendevent $DisplayEvent 3 54 $YstartCoord sendevent $DisplayEvent 1 330 1 sendevent $DisplayEvent 0 0 0 echo "swipeRightToLeft....down" while [ `expr $XstartCoord + $interval` -lt $XendCoord ]; do echo "swipeRightToLeft...move" XstartCoord=`expr $XstartCoord + $interval` sendevent $DisplayEvent 3 53 $XstartCoord sendevent $DisplayEvent 3 54 $YstartCoord sendevent $DisplayEvent 0 0 0 done echo "swipeRightToLeft....up" sendevent $DisplayEvent 3 57 ffffffff #sendevent $DisplayEvent 3 57 0 sendevent $DisplayEvent 1 330 0 sendevent $DisplayEvent 0 0 0 } adb root adb remount echo $Display1Event while false; do echo "while...." #0-->1 swipeLeftToRight Display0Event sleep 1 #1-->2 swipeLeftToRight Display1Event sleep 1 #2-->1 swipeRightToLeft Display2Event sleep 1 #1-->0 swipeRightToLeft Display1Event sleep 1 done #左滑,右滑依次判断 while true; do echo "while...." swipeLeftToRight $Display0Event sleep 1 swipeRightToLeft $Display0Event sleep 1 done echo "test finish...." 6. 问题 6.1. sendEvent命令滑动卡顿

因为我这里,设置的间隔坐标很大,同时sendevent到inputdispacher又到界面,太慢了,耗时太久

6.2. sendevent耗时太久

sendEvetn是软件模拟,input命令是调用inputdispatcher感觉也有点慢

6.3. Input缺点

input默认是0的DisplayID,在多屏中好像没法使用,但是又不想去看binder接口,如果可以,建议改inputManagerService的injectInputEvent看效果

7. 修改sendevent解决 adb shell sendevent慢的问题 7.1 adb shell sendevent慢的原因

adb shell sendevent是通过toybox里面的sendevent来完成event的发送 每次调用sendevent都会走main开启一个进程,从getpid log就可以看出来。没fork一个进程是很耗费时间的,同时main函数是先open,再read,重复的open也是很耗时的

@sendevent.c void sendevent_main(void) { error_msg("william sendevent_main pid: %d ", getpid()); int fd = xopen(*toys.optargs, O_RDWR); int version; struct input_event ev; if (ioctl(fd, EVIOCGVERSION, &version)) perror_exit("EVIOCGVERSION failed for %s", *toys.optargs); memset(&ev, 0, sizeof(ev)); // TODO: error checking and support for named constants. ev.type = atoi(toys.optargs[1]); ev.code = atoi(toys.optargs[2]); ev.value = atoi(toys.optargs[3]); xwrite(fd, &ev, sizeof(ev)); } 7.2 新建命令sendeventtsp来替代脚本实现滑动

external/toybox 目录中修改和添加的文件如下

@external/toybox$ 修改: Android.mk 修改: generated/config.h 修改: generated/flags.h 修改: generated/help.h 修改: generated/newtoys.h 修改: toys/android/sendevent.c 未跟踪的文件: (使用 "git add ..." 以包含要提交的内容) toys/android/sendeventtsp.c

编译后需要push的文件如下

adb root adb remount adb push ./system/bin/toybox /system/bin/toybox adb push ./vendor/bin/toybox_vendor /vendor/bin/toybox_vendor adb push ./vendor/bin/sendeventtsp /vendor/bin/sendeventtsp adb push ./system/bin/sendeventtsp /system/bin/sendeventtsp

git diff修改后的patch如下。里面主要是需要配置tsp,需要toybox把sendeventtsp_main()z注册到命令里面去

diff --git a/Android.mk b/Android.mk index a2cfe5f..50d7a1b 100644 --- a/Android.mk +++ b/Android.mk @@ -64,6 +64,7 @@ common_SRC_FILES := \ toys/android/restorecon.c \ toys/android/runcon.c \ toys/android/sendevent.c \ + toys/android/sendeventtsp.c \ toys/android/setenforce.c \ toys/android/setprop.c \ toys/android/start.c \ @@ -339,6 +340,7 @@ ALL_TOOLS := \ runcon \ sed \ sendevent \ + sendeventtsp \ seq \ setenforce \ setprop \ diff --git a/generated/config.h b/generated/config.h index e6f9354..d59d913 100644 --- a/generated/config.h +++ b/generated/config.h @@ -456,6 +456,8 @@ #define USE_SED(...) __VA_ARGS__ #define CFG_SENDEVENT 1 #define USE_SENDEVENT(...) __VA_ARGS__ +#define CFG_SENDEVENTTSP 1 +#define USE_SENDEVENTTSP(...) __VA_ARGS__ #define CFG_SEQ 1 #define USE_SEQ(...) __VA_ARGS__ #define CFG_SETENFORCE 1 diff --git a/generated/flags.h b/generated/flags.h index 431b924..4a937ff 100644 --- a/generated/flags.h +++ b/generated/flags.h @@ -2227,6 +2227,14 @@ #undef FOR_sendevent #endif +// sendeventtsp 4 4 +#undef OPTSTR_sendeventtsp +#define OPTSTR_sendeventtsp "4" +#ifdef CLEANUP_sendeventtsp +#undef CLEANUP_sendeventtsp +#undef FOR_sendeventtsp +#endif + // seq 3?f:s:w[!fw] 3?f:s:w[!fw] #undef OPTSTR_seq #define OPTSTR_seq "3?f:s:w[!fw]" @@ -5091,6 +5099,13 @@ #endif #endif +#ifdef FOR_sendeventtsp +#ifndef TT +#define TT this.sendeventtsp +#endif +#endif + + #ifdef FOR_seq #ifndef TT #define TT this.seq diff --git a/generated/help.h b/generated/help.h index 811b534..145a96e 100644 --- a/generated/help.h +++ b/generated/help.h @@ -44,6 +44,8 @@ #define HELP_sendevent "usage: sendevent DEVICE TYPE CODE VALUE\n\nSends a Linux input event.\n\n" +#define HELP_sendeventtsp "usage: sendeventtsp DEVICE TYPE CODE VALUE\n\nSends a Linux input event.\n\n" + #define HELP_runcon "usage: runcon CONTEXT COMMAND [ARGS...]\n\nRun a command in a specified security context.\n\n" #define HELP_restorecon "usage: restorecon [-D] [-F] [-R] [-n] [-v] FILE...\n\nRestores the default security contexts for the given files.\n\n-D apply to /data/data too\n-F force reset\n-R recurse into directories\n-n don't make any changes; useful with -v to see what would change\n-v verbose: show any changes\n\n" diff --git a/generated/newtoys.h b/generated/newtoys.h index 46cc2db..5b7920f 100644 --- a/generated/newtoys.h +++ b/generated/newtoys.h @@ -197,6 +197,7 @@ USE_ROUTE(NEWTOY(route, "?neA:", TOYFLAG_BIN)) USE_RUNCON(NEWTOY(runcon, "


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有