8种机械键盘轴体对比
本人程序员,要买一个写代码的键盘,请问红轴和茶轴怎么选?
最近项目中对usb进行使用的场景比较多,了解到libusb是比较出名的usb跨平台方案,学习libusb可以对android/linux底层的外设usb直接进行操作,理论上可以绕开android的弹窗授权限制.另外如果以后进行业务的移植会比较迅速.网上看了一些例子,有说修改源码的,增加方法然后android列出usb节点之后进行操作的.其实demo不需要那么复杂,这个库本来就能列出节点,也不需要usb授权之类的操作.另外使用android自带的可能还会导致没法搜索到usb节点,需要在/system/etc/permissions下添加android.hardware.usb.host.xml文件之后重启设备.
下载源码编译,方法一–ndk-build先编译libusb,然后导入so库和头文件使用
首先我们去官网的Downloads下载Latest Sources.解压之后进去android-jni目录.这个时候我们可以看到README文件,已经有编译方案了.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31Building:
---------
To build libusb for Android do the following:
1. Download the latest NDK from:
http://developer.android.com/tools/sdk/ndk/index.html
2. Extract the NDK.
3. Open a shell and make sure there exist an NDK global variable
set to the directory where you extracted the NDK.
4. Change directory to libusb's "android/jni"
5. Run "$NDK/ndk-build".
The libusb library, examples and tests can then be found in:
"android/libs/$ARCH"
Where $ARCH is one of:
armeabi
armeabi-v7a
mips
mips64
x86
x86_64
Installing
-----------
.......
..........
因为我要直接在app里面使用,所以我只是进行编译,Installing部分我直接忽略.编译我们可以参考这篇文章android开发ndk调用第三方so库,下面我会把我的android.mk文件释放出来.
几个坑找不到”libusb.h”`
我由于没这样使用过,头文件一直提示找不到,如:fatal error: 'libusb.h' file not found #include "libusb.h" ,这个我们时候的时候需要在添加头文件的路径LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/../libusb/libusb.这样就能搜索到头文件,不然没法使用.
libusb.so: incompatible target error: undefined reference to ‘libusb_init’
这个bug浪费了我很多时间,是由于我一开始拷贝的so文件仅仅是arm64-v8a类型的LOCAL_SRC_FILES := libusb.so,但是我编译的时候没留意到,所以一直报错,一直找不到libusb_init,我都怀疑是头文件导入不合理,google了很久,有一次突然发现arm64-v8a目录下的so文件生成了(也可能编译不出来,arm64-v8a是碰巧第一执行,如果armeabi-v7a先编译那么直接就中断编译了),在后来在stackoverflow上居然也找到了这个bug的解释.后来我把所有的lib包都添加到lib目录下,修改LOCAL_SRC_FILES := libs/arm64-v8a/libusb.so,Application.mk也修改APP_ABI := armeabi-v7a成对应的cup类型那个.每修改一次cpu类型就编译一次,应该也可以直接添加多个cpu类型的so,然后一次编译,不过我试过不行,后面可以继续尝试.
testlibusb的jni的目录结构1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38jni
├── Android.mk
├── Application.mk
├── libusb
│ ├── aclocal.m4
│ ├── android
│ ├── AUTHORS
│ ├── ChangeLog
│ ├── compile
│ ├── config.guess
│ ├── config.h.in
│ ├── config.sub
│ ├── configure
│ ├── configure.ac
│ ├── COPYING
│ ├── depcomp
│ ├── doc
│ ├── examples
│ ├── INSTALL
│ ├── install-sh
│ ├── libusb
│ ├── libusb-1.0.pc.in
│ ├── ltmain.sh
│ ├── m4
│ ├── Makefile.am
│ ├── Makefile.in
│ ├── missing
│ ├── msvc
│ ├── NEWS
│ ├── PORTING
│ ├── README
│ ├── tests
│ ├── TODO
│ └── Xcode
└── testlibusb
├── Android.mk
├── libs
└── testlibusb.cpp
/TestLibusb/app/src/main/jni/Application.mk文件内容1
2
3
4
5
6# APP_ABI := all
APP_ABI := armeabi-v7a
# Workaround for MIPS toolchain linker being unable to find liblog dependency
# of shared object in NDK versions at least up to r9.
#
APP_LDFLAGS := -llog
TestLibusb/app/src/main/jni/Android.mk 文件内容1
2
3
4LOCAL_PATH2:= $(call my-dir)
include $(CLEAR_VARS)
# include $(LOCAL_PATH2)/libusb/android/jni/Android.mk
include $(LOCAL_PATH2)/testlibusb/Android.mk
/TestLibusb/app/src/main/jni/testlibusb/Android.mk 文件内容1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
######################################################################
# Make shared library libUVCCamera.so
######################################################################
CFLAGS := -Werror
LOCAL_LDLIBS := -llog
##LOCAL_SHARED_LIBRARIES += libusb
#------test-------------
include $(CLEAR_VARS)
LOCAL_MODULE := myusb
#LOCAL_SRC_FILES := libs/arm64-v8a/libusb.so
LOCAL_SRC_FILES := libs/armeabi-v7a/libusb.so
#LOCAL_SRC_FILES := libs/x86/libusb.so
# LOCAL_SRC_FILES := libs/x86_64/libusb.so
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/../libusb/libusb
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
#-------end----------------
LOCAL_SHARED_LIBRARIES += myusb
LOCAL_SRC_FILES :=
./testlibusb.cpp
LOCAL_MODULE := testlibusb
include $(BUILD_SHARED_LIBRARY)
编译过程1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19➜ jni ndk-build
Android NDK: APP_PLATFORM not set. Defaulting to minimum supported version android-16.
Android NDK: WARNING: APP_PLATFORM android-16 is higher than android:minSdkVersion 1 in /home/steve/work/android/AndroidStudioProjects/TestLibusb/app/src/main/AndroidManifest.xml. NDK binaries will *not* be compatible with devices older than android-16. See https://android.googlesource.com/platform/ndk/+/master/docs/user/common_problems.md for more information.
[armeabi-v7a] Compile++ thumb: testlibusb <= testlibusb.cpp
[armeabi-v7a] Compile thumb : usb <= core.c
[armeabi-v7a] Compile thumb : usb <= descriptor.c
[armeabi-v7a] Compile thumb : usb <= hotplug.c
[armeabi-v7a] Compile thumb : usb <= io.c
[armeabi-v7a] Compile thumb : usb <= sync.c
[armeabi-v7a] Compile thumb : usb <= strerror.c
[armeabi-v7a] Compile thumb : usb <= linux_usbfs.c
[armeabi-v7a] Compile thumb : usb <= poll_posix.c
[armeabi-v7a] Compile thumb : usb <= threads_posix.c
[armeabi-v7a] Compile thumb : usb <= linux_netlink.c
[armeabi-v7a] SharedLibrary : libusb.so
[armeabi-v7a] StaticLibrary : libstdc++.a
[armeabi-v7a] SharedLibrary : libtestlibusb.so
[armeabi-v7a] Install : libtestlibusb.so => libs/armeabi-v7a/libtestlibusb.so
[armeabi-v7a] Install : libusb.so => libs/armeabi-v7a/libusb.so
下载源码编译,方法二–ndk-build编译adnrod.mk文件直接使用
其实我一开始不是按照方法一使用的,是先参考的UVCCamera的使用方式,也是爬了一些坑,把mk文件贴出来先.
/TestLibusb/app/src/main/jni/Application.mk文件内容1
2
3
4
5APP_ABI := all
# Workaround for MIPS toolchain linker being unable to find liblog dependency
# of shared object in NDK versions at least up to r9.
#
APP_LDFLAGS := -llog
TestLibusb/app/src/main/jni/Android.mk 文件内容1
2
3
4LOCAL_PATH2:= $(call my-dir)
include $(CLEAR_VARS)
include $(LOCAL_PATH2)/libusb/android/jni/Android.mk
include $(LOCAL_PATH2)/testlibusb/Android.mk
/TestLibusb/app/src/main/jni/testlibusb/Android.mk 文件内容1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
######################################################################
# Make shared library libUVCCamera.so
######################################################################
CFLAGS := -Werror
LOCAL_LDLIBS := -llog
LOCAL_SHARED_LIBRARIES += libusb
LOCAL_SRC_FILES :=
./testlibusb.cpp
LOCAL_MODULE := testlibusb
include $(BUILD_SHARED_LIBRARY)
编译过程
这个方案不需要进行so的导入,很方便,各个cpu也直接能编译出来了.这也是我方案一在多个so同时导入编译不成功之后不继续的原因,因为有更好的方案了1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67➜ jni ndk-build
Android NDK: APP_PLATFORM not set. Defaulting to minimum supported version android-16.
Android NDK: WARNING: APP_PLATFORM android-16 is higher than android:minSdkVersion 1 in /home/steve/work/android/AndroidStudioProjects/TestLibusb/app/src/main/AndroidManifest.xml. NDK binaries will *not* be compatible with devices older than android-16. See https://android.googlesource.com/platform/ndk/+/master/docs/user/common_problems.md for more information.
[arm64-v8a] Compile++ : testlibusb <= testlibusb.cpp
[arm64-v8a] Compile : usb <= core.c
[arm64-v8a] Compile : usb <= descriptor.c
[arm64-v8a] Compile : usb <= hotplug.c
[arm64-v8a] Compile : usb <= io.c
[arm64-v8a] Compile : usb <= sync.c
[arm64-v8a] Compile : usb <= strerror.c
[arm64-v8a] Compile : usb <= linux_usbfs.c
[arm64-v8a] Compile : usb <= poll_posix.c
[arm64-v8a] Compile : usb <= threads_posix.c
[arm64-v8a] Compile : usb <= linux_netlink.c
[arm64-v8a] SharedLibrary : libusb.so
[arm64-v8a] StaticLibrary : libstdc++.a
[arm64-v8a] SharedLibrary : libtestlibusb.so
[arm64-v8a] Install : libtestlibusb.so => libs/arm64-v8a/libtestlibusb.so
[arm64-v8a] Install : libusb.so => libs/arm64-v8a/libusb.so
[x86_64] Compile++ : testlibusb <= testlibusb.cpp
[x86_64] Compile : usb <= core.c
[x86_64] Compile : usb <= descriptor.c
[x86_64] Compile : usb <= hotplug.c
[x86_64] Compile : usb <= io.c
[x86_64] Compile : usb <= sync.c
[x86_64] Compile : usb <= strerror.c
[x86_64] Compile : usb <= linux_usbfs.c
[x86_64] Compile : usb <= poll_posix.c
[x86_64] Compile : usb <= threads_posix.c
[x86_64] Compile : usb <= linux_netlink.c
[x86_64] SharedLibrary : libusb.so
[x86_64] StaticLibrary : libstdc++.a
[x86_64] SharedLibrary : libtestlibusb.so
[x86_64] Install : libtestlibusb.so => libs/x86_64/libtestlibusb.so
[x86_64] Install : libusb.so => libs/x86_64/libusb.so
[armeabi-v7a] Compile++ thumb: testlibusb <= testlibusb.cpp
[armeabi-v7a] Compile thumb : usb <= core.c
[armeabi-v7a] Compile thumb : usb <= descriptor.c
[armeabi-v7a] Compile thumb : usb <= hotplug.c
[armeabi-v7a] Compile thumb : usb <= io.c
[armeabi-v7a] Compile thumb : usb <= sync.c
[armeabi-v7a] Compile thumb : usb <= strerror.c
[armeabi-v7a] Compile thumb : usb <= linux_usbfs.c
[armeabi-v7a] Compile thumb : usb <= poll_posix.c
[armeabi-v7a] Compile thumb : usb <= threads_posix.c
[armeabi-v7a] Compile thumb : usb <= linux_netlink.c
[armeabi-v7a] SharedLibrary : libusb.so
[armeabi-v7a] StaticLibrary : libstdc++.a
[armeabi-v7a] SharedLibrary : libtestlibusb.so
[armeabi-v7a] Install : libtestlibusb.so => libs/armeabi-v7a/libtestlibusb.so
[armeabi-v7a] Install : libusb.so => libs/armeabi-v7a/libusb.so
[x86] Compile++ : testlibusb <= testlibusb.cpp
[x86] Compile : usb <= core.c
[x86] Compile : usb <= descriptor.c
[x86] Compile : usb <= hotplug.c
[x86] Compile : usb <= io.c
[x86] Compile : usb <= sync.c
[x86] Compile : usb <= strerror.c
[x86] Compile : usb <= linux_usbfs.c
[x86] Compile : usb <= poll_posix.c
[x86] Compile : usb <= threads_posix.c
[x86] Compile : usb <= linux_netlink.c
[x86] SharedLibrary : libusb.so
[x86] StaticLibrary : libstdc++.a
[x86] SharedLibrary : libtestlibusb.so
[x86] Install : libtestlibusb.so => libs/x86/libtestlibusb.so
[x86] Install : libusb.so => libs/x86/libusb.so
总结
方案二很适合我们有源码的情况,这样能快速的编译使用,配置也更加简单.由于现在android studio都使用cmake编译,所以接下来就是用尝试直接配置CMakeLists.txt文件进行编译.这部分实现了再更新.
使用libusb的例子打印usb设备
我看了下app/src/main/jni/libusb/examples下的例子,listdevs.c比较简单,那么我们就进行藏这个demo的尝试.
MainActivity文件
这个文件很简单,导入** System.loadLibrary(“testlibusb”);,定义jni方法public native String getubs();**.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28public class MainActivity extends AppCompatActivity {
// Used to load the 'native-lib' library on application startup.
static {
// System.loadLibrary("usb");
System.loadLibrary("testlibusb");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.buttonPlay).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Log.e("device","call getubs ");
getubs();
}
});
}
/**
* A native method that is implemented by the 'native-lib' native library,
* which is packaged with this application.
*/
public native String getubs();
}
app/src/main/jni/testlibusb/testlibusb.cpp文件
print_devs内容从listdevs.c中拷贝修改过来1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65//
// Created by steve on 19-7-23.
//
#include
#include
#include "libusb.h"
#include
#include "libusb.h"
#include
#define TAG "libusb" // 这个是自定义的LOG的标识
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,TAG,__VA_ARGS__) // 定义LOGD类型
static void print_devs()
{
libusb_device **devs;
int r;
ssize_t cnt;
LOGD("print_devs");
r = libusb_init(NULL);
LOGD("libusb_init");
cnt = libusb_get_device_list(NULL, &devs);
LOGD("libusb_get_device_list");
libusb_device *dev;
int i = 0, j = 0;
uint8_t path[8];
while ((dev = devs[i++]) != NULL) {
struct libusb_device_descriptor desc;
int r = libusb_get_device_descriptor(dev, &desc);
if (r < 0) {
LOGD("failed to get device descriptor");
}
LOGD("%04x:%04x (bus %d, device %d)",
desc.idVendor, desc.idProduct,
libusb_get_bus_number(dev), libusb_get_device_address(dev));
r = libusb_get_port_numbers(dev, path, sizeof(path));
if (r > 0) {
LOGD(" path: %d", path[0]);
for (j = 1; j < r; j++)
printf(".%d", path[j]);
}
printf("n");
}
libusb_free_device_list(devs, 1);
libusb_exit(NULL);
}
extern "C"
JNIEXPORT jstring JNICALL
Java_com_example_testlibusb_MainActivity_getubs
(JNIEnv *env, jobject obj){
print_devs();
//test();
return env->NewStringUTF("111");
}
执行
点击button,执行getubs方法就可以打印出系统的usb设备,日志如下:1
2
3
4
5
607-25 00:00:54.963 23280-23280/com.example.testlibusb D/libusb: print_devs
07-25 00:00:54.965 23280-23280/com.example.testlibusb D/libusb: libusb_init
07-25 00:00:54.965 23280-23280/com.example.testlibusb D/libusb: libusb_get_device_list
07-25 00:00:54.966 23280-23280/com.example.testlibusb D/libusb: 1c4f:0065 (bus 1, device 18)
07-25 00:00:54.966 23280-23280/com.example.testlibusb D/libusb: path: 1
07-25 00:00:54.966 23280-23280/com.example.testlibusb D/libusb: 1d6b:0002 (bus 1, device 1)
1c4f就是VendorId,0065就是ProductId,有了这2个就可以过滤出你想要的设备,之后就能进行数据的读取和发送了,这块后面有时间再研究.
总结
这个使用需要先ndk编译后使用,整个编译和使用已经可以完整走通,之后还需要研究使用cmake编译,和设备信息的读取.