從 API 16 開始, InputManager就成了一個公開的類別了, 可以通過如下方法獲得 InputManager:
InputManager im = (InputManager) getSystemService(Context.INPUT_SERVICE);
... private synchronized void injectKeyEvent(KeyEvent event) { Class[] paramTypes = new Class[2]; paramTypes[0] = InputEvent.class; paramTypes[1] = Integer.TYPE; InputManager im = (InputManager) getSystemService(Context.INPUT_SERVICE); Object[] params = new Object[2]; params[0] = event; params[1] = 0; try { Method injectKeyEvent = im.getClass().getMethod("injectInputEvent", paramTypes); injectKeyEvent.invoke(im, params); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } ...
INJECT_EVENTS
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.androidservice" android:versionCode="1" android:versionName="1.0" android:sharedUserId="android.uid.system"> .... <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INJECT_EVENTS" /> <uses-permission android:name="android.permission.INSTALL_PACKAGES" /> <uses-permission android:name="android.permission.SHUTDOWN" /> .... <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="20" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="com.example.androidservice.MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> <meta-data android:name="android.app.lib_name" android:value="RkGpio" /> </activity> <receiver android:name="com.example.androidservice.OnBoot"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED"/> <!-- <action android:name="android.intent.action.QUICKBOOT_POWERON" /> --> </intent-filter> </receiver> <service android:enabled="true" android:name=".MyService" /> </application> </manifest>
注意, 使用 injectInputEvent() 需要申明
android:name="android.permission.INJECT_EVENTS" 權限.
你可能還需要 system uid
android:sharedUserId="android.uid.system"
簽名
java -jar signapk.jar platform.x509.pem platform.pk8 app-release.apk app-release-signed.apk
java -jar signapk.jar platform.x509.pem platform.pk8 app-release.apk app-release-signed.apk
可以得到具有對應權限的 APK
優化 APK
zipalign -fv 4 app-release-signed.apk app-release-signed-aligned.apk
Fire Positive or Negative KeyCodes
... public void onNative(int action, int keycode) { event = new KeyEvent(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(), action, keycode, 0); injectKeyEvent(event); } ...
Android 可以發射 (fire) 負的 KeyCodes; 它的 KeyCodes 是 32-bit integer (注意: 非 unsigned integer) ; 如果以 KeyCode MSB (Most Significant Bit) set/reset 來區分第1組與第2組設備, 以 KEYCODE_BUTTON_Z 為例, 則:
第1組: KEYCODE_BUTTON_Z
第2組: (KEYCODE_BUTTON_Z - 0x7fffffff - 1)
// JNI .cpp ... if ((events & (1ULL <<codes[i].index)) != (lastEvents & (1ULL <<codes[i].index))) { if ((events & (1ULL <<codes[i].index)) == (1ULL <<codes[i].index)) { PortTwoEnv->CallVoidMethod(nativeObj, cachedmethodID, ACTION_UP, codes[i].code); } else { PortTwoEnv->CallVoidMethod(nativeObj, cachedmethodID, ACTION_DOWN, codes[i].code); }; } ...
... // ACTIVITY .java public class MainActivity extends Activity { ... public boolean onKeyDown(int KeyCode, KeyEvent E) { ... switch (KeyCode) { case (KEYCODE_BUTTON_Z - 0x7fffffff - 1): ... //第2組 return true; case KeyEvent.KEYCODE_BUTTON_Z: ... //第1組 return true; } return false; } ... } ...
Keyboard Input Information
# cat /proc/bus/input/devices ... I: Bus=0011 Vendor=0001 Product=0001 Version=ab41 N: Name="AT Translated Set 2 keyboard" P: Phys=isa0060/serio0/input0 S: Sysfs=/devices/platform/i8042/serio0/input/input2 U: Uniq= H: Handlers=sysrq kbd event2 leds B: PROP=0 B: EV=120013 B: KEY=402000000 3803078f800d001 feffffdfffefffff fffffffffffffffe B: MSC=10 B: LED=7 ...
Keyboard Input Data
以 a 為例: Down / UP
# cat /dev/input/event2 | od -t x1 -w3 ... 0000000 68 d1 38 0000003 5a 00 00 0000006 00 00 a2 0000011 1c 01 00 0000014 00 00 00 0000017 00 04 00 0000022 04 00 1c 0000025 00 00 00 0000030 68 d1 38 0000033 5a 00 00 0000036 00 00 a2 0000041 1c 01 00 0000044 00 00 00 0000047 00 01 00 0000052 1c 00 01 0000055 00 00 00 0000060 68 d1 38 0000063 5a 00 00 0000066 00 00 a2 0000071 1c 01 00 0000074 00 00 00 * 0000110 68 d1 38 0000113 5a 00 00 0000116 00 00 c0 0000121 74 03 00 0000124 00 00 00 0000127 00 04 00 0000132 04 00 1c 0000135 00 00 00 0000140 68 d1 38 0000143 5a 00 00 0000146 00 00 c0 0000151 74 03 00 0000154 00 00 00 0000157 00 01 00 0000162 1c 00 00 0000165 00 00 00 0000170 68 d1 38 0000173 5a 00 00 0000176 00 00 c0 0000201 74 03 00 0000204 00 00 00 ...
C++ Example to Process EV_KEY
C++ example to process EV_KEY
#include <stdio.h> #include <linux/input.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #define DEV_PATH "/dev/input/event2" int main (int argc, char **argv) { int keys_fd; char ret[2]; struct input_event t; keys_fd=open(DEV_PATH, O_RDONLY); if(keys_fd <= 0) { printf("open /dev/input/event2 device error!\n"); return -1; } for(;;) { if(read(keys_fd, &t, sizeof(t)) == sizeof(t)) { if(t.type==EV_KEY) if(t.value==0 || t.value==1) { printf("key %d %s\n", t.code, (t.value) ? "Pressed" : "Released"); if(t.code == KEY_ESC) break; } } } close(keys_fd); return 0; }
C++ example to Fire KeyStrokes
可以參考這個 https://www.kernel.org/doc/html/v4.16/input/uinput.html 範例.
- http://www.jollen.org/blog/2009/04/linux_input_device_apis.html
- https://github.com/torvalds/linux/blob/master/include/uapi/linux/input.h
- https://github.com/torvalds/linux/blob/master/include/uapi/linux/input-event-codes.h
以下是我自己的範例:
範例 I:
#include <stdio.h> #include <unistd.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <errno.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> #include <stdarg.h> #include <stdlib.h> #include <time.h> #include <sys/mount.h> // for mount #include <fcntl.h> #include <signal.h> #include <netinet/tcp.h> #include <inttypes.h> #include <sched.h> #include <assert.h> #include <sys/ioctl.h> #include <ctype.h> #include <termios.h> #include <poll.h> #include <linux/uinput.h> #include <linux/input-event-codes.h> #define TTY_SERIAL "/dev/ttyMK0" #define SELECT_EXPIRY_NINISECONDS 100ULL #define ACTION_DOWN 1 #define ACTION_UP 0 #define _u1_ 0 #define _d1_ 1 #define _l1_ 2 #define _r1_ 3 #define _s1_ 4 #define _x1_ 5 #define _y1_ 6 #define _z1_ 7 #define _a1_ 8 #define _b1_ 9 #define _c1_ 10 #define _u2_ 11 #define _d2_ 12 #define _l2_ 13 #define _r2_ 14 #define _s2_ 15 #define _x2_ 16 #define _y2_ 17 #define _z2_ 18 #define _a2_ 19 #define _b2_ 20 #define _c2_ 21 #define _m_ 22 #define _w_ 23 #define _U1_ (1 << _u1_) #define _D1_ (1 << _d1_) #define _L1_ (1 << _l1_) #define _R1_ (1 << _r1_) #define _S1_ (1 << _s1_) #define _X1_ (1 << _x1_) #define _Y1_ (1 << _y1_) #define _Z1_ (1 << _z1_) #define _A1_ (1 << _a1_) #define _B1_ (1 << _b1_) #define _C1_ (1 << _c1_) #define _U2_ (1 << _u2_) #define _D2_ (1 << _d2_) #define _L2_ (1 << _l2_) #define _R2_ (1 << _r2_) #define _S2_ (1 << _s2_) #define _X2_ (1 << _x2_) #define _Y2_ (1 << _y2_) #define _Z2_ (1 << _z2_) #define _A2_ (1 << _a2_) #define _B2_ (1 << _b2_) #define _C2_ (1 << _c2_) #define _M_ (1 << _m_) #define _W_ (1 << _w_) struct code_t { int index; int code; const char *name; }; static struct code_t keypad_codes[] = { {_u1_, KEY_UP, "P1_UP"}, {_d1_, KEY_DOWN, "P1_DW"}, {_l1_, KEY_LEFT, "P1_LF"}, {_r1_, KEY_RIGHT, "P1_RG"}, {_s1_, KEY_ENTER, "P1_ST"}, {_x1_, KEY_X, "P1_X "}, {_y1_, KEY_Y, "P1_Y "}, {_z1_, KEY_Z, "P1_Z "}, {_a1_, KEY_A, "P1_A "}, {_b1_, KEY_B, "P1_B "}, {_c1_, KEY_C, "P1_C "}, {_u2_, KEY_KP8, "P2_UP"}, {_d2_, KEY_KP2, "P2_DW"}, {_l2_, KEY_KP4, "P2_LF"}, {_r2_, KEY_KP6, "P2_RG"}, {_s2_, KEY_SPACE, "P2_ST"}, {_x2_, KEY_F4, "P2_X "}, {_y2_, KEY_F5, "P2_Y "}, {_z2_, KEY_F6, "P2_Z "}, {_a2_, KEY_F1, "P2_A "}, {_b2_, KEY_F8, "P2_B "}, {_c2_, KEY_F3, "P2_C "}, {_m_, KEY_M, "MD"}, {_w_, KEY_R, "RW"}, }; #define KEYPAD_KEYNUMBER (sizeof(keypad_codes)/sizeof(struct code_t)) static int uinputfd = -1; static int ttyfd = -1; static char ttyLine[1024] = {0}; static int ttyLineLength = 0; #define PRINTF(f_, ...) \ sprintf(ttyLine, f_, ##__VA_ARGS__), \ ttyLineLength = strlen(ttyLine), \ ttyLine[ttyLineLength] = 0, \ write(ttyfd, (void *)ttyLine, ttyLineLength + 1) static unsigned int uartNowEvents = 0; static void emit(int fd, int type, int code, int val) { struct input_event ie; ie.type = type; ie.code = code; ie.value = val; ie.time.tv_sec = 0; ie.time.tv_usec = 0; write(fd, &ie, sizeof(ie)); } static void onUartKey(unsigned char ch) { if (ch != (unsigned char)'u' && ch != (unsigned char)'U' && ch != (unsigned char)'d' && ch != (unsigned char)'D' && ch != (unsigned char)'l' && ch != (unsigned char)'L' && ch != (unsigned char)'r' && ch != (unsigned char)'R' && ch != (unsigned char)'s' && ch != (unsigned char)'S' && ch != (unsigned char)'x' && ch != (unsigned char)'X' && ch != (unsigned char)'y' && ch != (unsigned char)'Y' && ch != (unsigned char)'z' && ch != (unsigned char)'Z' && ch != (unsigned char)'a' && ch != (unsigned char)'A' && ch != (unsigned char)'b' && ch != (unsigned char)'B' && ch != (unsigned char)'c' && ch != (unsigned char)'C' && ch != (unsigned char)'h' && ch != (unsigned char)'H' && ch != (unsigned char)'i' && ch != (unsigned char)'I' && ch != (unsigned char)'j' && ch != (unsigned char)'J' && ch != (unsigned char)'k' && ch != (unsigned char)'K' && ch != (unsigned char)'t' && ch != (unsigned char)'T' && ch != (unsigned char)'o' && ch != (unsigned char)'O' && ch != (unsigned char)'p' && ch != (unsigned char)'P' && ch != (unsigned char)'q' && ch != (unsigned char)'Q' && ch != (unsigned char)'g' && ch != (unsigned char)'G' && ch != (unsigned char)'e' && ch != (unsigned char)'E' && ch != (unsigned char)'f' && ch != (unsigned char)'F' && ch != (unsigned char)'m' && ch != (unsigned char)'M' && ch != (unsigned char)'w' && ch != (unsigned char)'W' ) return; if (ch == (unsigned char)'u') { uartNowEvents &= ~_U1_; goto BAITOUT; } if (ch == (unsigned char)'d') { uartNowEvents &= ~_D1_; goto BAITOUT; } if (ch == (unsigned char)'l') { uartNowEvents &= ~_L1_; goto BAITOUT; } if (ch == (unsigned char)'r') { uartNowEvents &= ~_R1_; goto BAITOUT; } if (ch == (unsigned char)'s') { uartNowEvents &= ~_S1_; goto BAITOUT; } if (ch == (unsigned char)'x') { uartNowEvents &= ~_X1_; goto BAITOUT; } if (ch == (unsigned char)'y') { uartNowEvents &= ~_Y1_; goto BAITOUT; } if (ch == (unsigned char)'z') { uartNowEvents &= ~_Z1_; goto BAITOUT; } if (ch == (unsigned char)'a') { uartNowEvents &= ~_A1_; goto BAITOUT; } if (ch == (unsigned char)'b') { uartNowEvents &= ~_B1_; goto BAITOUT; } if (ch == (unsigned char)'c') { uartNowEvents &= ~_C1_; goto BAITOUT; } if (ch == (unsigned char)'U') { uartNowEvents |= _U1_; goto BAITOUT; } if (ch == (unsigned char)'D') { uartNowEvents |= _D1_; goto BAITOUT; } if (ch == (unsigned char)'L') { uartNowEvents |= _L1_; goto BAITOUT; } if (ch == (unsigned char)'R') { uartNowEvents |= _R1_; goto BAITOUT; } if (ch == (unsigned char)'S') { uartNowEvents |= _S1_; goto BAITOUT; } if (ch == (unsigned char)'X') { uartNowEvents |= _X1_; goto BAITOUT; } if (ch == (unsigned char)'Y') { uartNowEvents |= _Y1_; goto BAITOUT; } if (ch == (unsigned char)'Z') { uartNowEvents |= _Z1_; goto BAITOUT; } if (ch == (unsigned char)'A') { uartNowEvents |= _A1_; goto BAITOUT; } if (ch == (unsigned char)'B') { uartNowEvents |= _B1_; goto BAITOUT; } if (ch == (unsigned char)'C') { uartNowEvents |= _C1_; goto BAITOUT; } if (ch == (unsigned char)'h') { uartNowEvents &= ~_U2_; goto BAITOUT; } if (ch == (unsigned char)'i') { uartNowEvents &= ~_D2_; goto BAITOUT; } if (ch == (unsigned char)'j') { uartNowEvents &= ~_L2_; goto BAITOUT; } if (ch == (unsigned char)'k') { uartNowEvents &= ~_R2_; goto BAITOUT; } if (ch == (unsigned char)'t') { uartNowEvents &= ~_S2_; goto BAITOUT; } if (ch == (unsigned char)'o') { uartNowEvents &= ~_X2_; goto BAITOUT; } if (ch == (unsigned char)'p') { uartNowEvents &= ~_Y2_; goto BAITOUT; } if (ch == (unsigned char)'q') { uartNowEvents &= ~_Z2_; goto BAITOUT; } if (ch == (unsigned char)'g') { uartNowEvents &= ~_A2_; goto BAITOUT; } if (ch == (unsigned char)'e') { uartNowEvents &= ~_B2_; goto BAITOUT; } if (ch == (unsigned char)'f') { uartNowEvents &= ~_C2_; goto BAITOUT; } if (ch == (unsigned char)'H') { uartNowEvents |= _U2_; goto BAITOUT; } if (ch == (unsigned char)'I') { uartNowEvents |= _D2_; goto BAITOUT; } if (ch == (unsigned char)'J') { uartNowEvents |= _L2_; goto BAITOUT; } if (ch == (unsigned char)'K') { uartNowEvents |= _R2_; goto BAITOUT; } if (ch == (unsigned char)'T') { uartNowEvents |= _S2_; goto BAITOUT; } if (ch == (unsigned char)'O') { uartNowEvents |= _X2_; goto BAITOUT; } if (ch == (unsigned char)'P') { uartNowEvents |= _Y2_; goto BAITOUT; } if (ch == (unsigned char)'Q') { uartNowEvents |= _Z2_; goto BAITOUT; } if (ch == (unsigned char)'G') { uartNowEvents |= _A2_; goto BAITOUT; } if (ch == (unsigned char)'E') { uartNowEvents |= _B2_; goto BAITOUT; } if (ch == (unsigned char)'F') { uartNowEvents |= _C2_; goto BAITOUT; } if (ch == (unsigned char)'m') { uartNowEvents &= ~_M_; goto BAITOUT; } if (ch == (unsigned char)'w') { uartNowEvents &= ~_W_; goto BAITOUT; } if (ch == (unsigned char)'M') { uartNowEvents |= _M_; goto BAITOUT; } if (ch == (unsigned char)'W') { uartNowEvents |= _W_; goto BAITOUT; } BAITOUT: if (ch == (unsigned char)'U') emit(uinputfd, EV_KEY, keypad_codes[_u1_].code, ACTION_DOWN); if (ch == (unsigned char)'u') emit(uinputfd, EV_KEY, keypad_codes[_u1_].code, ACTION_UP); if (ch == (unsigned char)'D') { emit(uinputfd, EV_KEY, keypad_codes[_d1_].code, ACTION_DOWN); //PRINTF("D\n"); } if (ch == (unsigned char)'d') { emit(uinputfd, EV_KEY, keypad_codes[_d1_].code, ACTION_UP); //PRINTF("d\n"); } if (ch == (unsigned char)'L') emit(uinputfd, EV_KEY, keypad_codes[_l1_].code, ACTION_DOWN); if (ch == (unsigned char)'l') emit(uinputfd, EV_KEY, keypad_codes[_l1_].code, ACTION_UP); if (ch == (unsigned char)'R') emit(uinputfd, EV_KEY, keypad_codes[_r1_].code, ACTION_DOWN); if (ch == (unsigned char)'r') emit(uinputfd, EV_KEY, keypad_codes[_r1_].code, ACTION_UP); if (ch == (unsigned char)'S') emit(uinputfd, EV_KEY, keypad_codes[_s1_].code, ACTION_DOWN); if (ch == (unsigned char)'s') emit(uinputfd, EV_KEY, keypad_codes[_s1_].code, ACTION_UP); if (ch == (unsigned char)'X') emit(uinputfd, EV_KEY, keypad_codes[_x1_].code, ACTION_DOWN); if (ch == (unsigned char)'x') emit(uinputfd, EV_KEY, keypad_codes[_x1_].code, ACTION_UP); if (ch == (unsigned char)'Y') emit(uinputfd, EV_KEY, keypad_codes[_y1_].code, ACTION_DOWN); if (ch == (unsigned char)'y') emit(uinputfd, EV_KEY, keypad_codes[_y1_].code, ACTION_UP); if (ch == (unsigned char)'Z') emit(uinputfd, EV_KEY, keypad_codes[_z1_].code, ACTION_DOWN); if (ch == (unsigned char)'z') emit(uinputfd, EV_KEY, keypad_codes[_z1_].code, ACTION_UP); if (ch == (unsigned char)'A') emit(uinputfd, EV_KEY, keypad_codes[_a1_].code, ACTION_DOWN); if (ch == (unsigned char)'a') emit(uinputfd, EV_KEY, keypad_codes[_a1_].code, ACTION_UP); if (ch == (unsigned char)'B') emit(uinputfd, EV_KEY, keypad_codes[_b1_].code, ACTION_DOWN); if (ch == (unsigned char)'b') emit(uinputfd, EV_KEY, keypad_codes[_b1_].code, ACTION_UP); if (ch == (unsigned char)'C') emit(uinputfd, EV_KEY, keypad_codes[_c1_].code, ACTION_DOWN); if (ch == (unsigned char)'c') emit(uinputfd, EV_KEY, keypad_codes[_c1_].code, ACTION_UP); if (ch == (unsigned char)'H') emit(uinputfd, EV_KEY, keypad_codes[_u2_].code, ACTION_DOWN); if (ch == (unsigned char)'h') emit(uinputfd, EV_KEY, keypad_codes[_u2_].code, ACTION_UP); if (ch == (unsigned char)'I') emit(uinputfd, EV_KEY, keypad_codes[_d2_].code, ACTION_DOWN); if (ch == (unsigned char)'i') emit(uinputfd, EV_KEY, keypad_codes[_d2_].code, ACTION_UP); if (ch == (unsigned char)'J') emit(uinputfd, EV_KEY, keypad_codes[_l2_].code, ACTION_DOWN); if (ch == (unsigned char)'j') emit(uinputfd, EV_KEY, keypad_codes[_l2_].code, ACTION_UP); if (ch == (unsigned char)'K') emit(uinputfd, EV_KEY, keypad_codes[_r2_].code, ACTION_DOWN); if (ch == (unsigned char)'k') emit(uinputfd, EV_KEY, keypad_codes[_r2_].code, ACTION_UP); if (ch == (unsigned char)'T') emit(uinputfd, EV_KEY, keypad_codes[_s2_].code, ACTION_DOWN); if (ch == (unsigned char)'t') emit(uinputfd, EV_KEY, keypad_codes[_s2_].code, ACTION_UP); if (ch == (unsigned char)'O') emit(uinputfd, EV_KEY, keypad_codes[_x2_].code, ACTION_DOWN); if (ch == (unsigned char)'o') emit(uinputfd, EV_KEY, keypad_codes[_x2_].code, ACTION_UP); if (ch == (unsigned char)'P') emit(uinputfd, EV_KEY, keypad_codes[_y2_].code, ACTION_DOWN); if (ch == (unsigned char)'p') emit(uinputfd, EV_KEY, keypad_codes[_y2_].code, ACTION_UP); if (ch == (unsigned char)'Q') emit(uinputfd, EV_KEY, keypad_codes[_z2_].code, ACTION_DOWN); if (ch == (unsigned char)'q') emit(uinputfd, EV_KEY, keypad_codes[_z2_].code, ACTION_UP); if (ch == (unsigned char)'G') emit(uinputfd, EV_KEY, keypad_codes[_a2_].code, ACTION_DOWN); if (ch == (unsigned char)'g') emit(uinputfd, EV_KEY, keypad_codes[_a2_].code, ACTION_UP); if (ch == (unsigned char)'E') emit(uinputfd, EV_KEY, keypad_codes[_b2_].code, ACTION_DOWN); if (ch == (unsigned char)'e') emit(uinputfd, EV_KEY, keypad_codes[_b2_].code, ACTION_UP); if (ch == (unsigned char)'F') emit(uinputfd, EV_KEY, keypad_codes[_c2_].code, ACTION_DOWN); if (ch == (unsigned char)'f') emit(uinputfd, EV_KEY, keypad_codes[_c2_].code, ACTION_UP); if (ch == (unsigned char)'M') emit(uinputfd, EV_KEY, keypad_codes[_m_].code, ACTION_DOWN); if (ch == (unsigned char)'m') emit(uinputfd, EV_KEY, keypad_codes[_m_].code, ACTION_UP); if (ch == (unsigned char)'W') emit(uinputfd, EV_KEY, keypad_codes[_w_].code, ACTION_DOWN); if (ch == (unsigned char)'w') emit(uinputfd, EV_KEY, keypad_codes[_w_].code, ACTION_UP); emit(uinputfd, EV_SYN, SYN_REPORT, 0); return; } int main (int argc, char **argv) { struct termios term, save; int res, v, maxfd = 0; fd_set rset; struct timeval tv; //unsigned char ch; //struct pollfd serial_poll; struct timespec start_time, now_time; unsigned long long int start, now; struct uinput_user_dev uidev = {0}; int i = 0; char line[512]; uinputfd = open("/dev/uinput", O_WRONLY | O_NONBLOCK); if (0 > uinputfd) exit(1); if (ioctl(uinputfd, UI_SET_EVBIT, EV_KEY) < 0) exit(2); for (i = 0; i < KEYPAD_KEYNUMBER; i++) { if (ioctl(uinputfd, UI_SET_KEYBIT, keypad_codes[i].code) < 0) exit(3); } snprintf(uidev.name, UINPUT_MAX_NAME_SIZE, "uinput-serial"); uidev.id.bustype = BUS_VIRTUAL, uidev.id.vendor = 0x1, uidev.id.product = 0x1, uidev.id.version = 1; if (write(uinputfd, &uidev, sizeof(uidev)) < 0) exit(4); if(ioctl(uinputfd, UI_DEV_CREATE) < 0) exit(5); sleep(1); ttyfd = open(TTY_SERIAL, O_RDWR | O_NOCTTY | O_NDELAY); if (0 > ttyfd) exit(6); memset(&term, 0, sizeof(struct termios)); if (0 > tcgetattr(ttyfd, &term)) close(ttyfd), ttyfd = -1, exit(7); memcpy((void *)&save, (void *)&term, sizeof(struct termios)); term.c_cflag |= B115200, term.c_cflag |= CLOCAL, term.c_cflag |= CREAD, term.c_cflag &= ~PARENB, term.c_cflag &= ~CSTOPB; term.c_cflag &= ~CSIZE, term.c_cflag |= CS8, term.c_iflag = IGNPAR, term.c_cc[VMIN] = 1, term.c_cc[VTIME] = 0; #if 1 term.c_iflag = 0, term.c_oflag = 0, term.c_lflag = 0; #endif cfsetispeed(&term, B115200), cfsetospeed(&term, B115200); if (0 > tcsetattr(ttyfd, TCSANOW, &term)) close(ttyfd), ttyfd = -1, exit(8); if (0 > (v = fcntl(ttyfd, F_GETFL, 0))) close(ttyfd), ttyfd = -1, exit(9); if (0 > fcntl(ttyfd, F_SETFL, v | O_NONBLOCK)) close(ttyfd), ttyfd = -1, exit(10); if (0 > tcflush(ttyfd, TCIFLUSH)) close(ttyfd), ttyfd = -1, exit(11); clock_gettime(CLOCK_MONOTONIC, &start_time); start = start_time.tv_sec * 1000 + start_time.tv_nsec / 1000000; //PRINTF("LOOP ...\n"); for (;;) { FD_ZERO(&rset); FD_SET(ttyfd, &rset); maxfd = 0; if (maxfd < ttyfd) maxfd = ttyfd; memset(&tv, 0, sizeof(tv)); tv.tv_sec = SELECT_EXPIRY_NINISECONDS / 1000; tv.tv_usec = (SELECT_EXPIRY_NINISECONDS % 1000) * 1000; //res = select(maxfd + 1, &rset, 0, 0, &tv); res = select(maxfd + 1, &rset, 0, 0, 0); if (0 > res) close(ttyfd), ttyfd = -1, exit(12); if (0 == res) continue; if (FD_ISSET(ttyfd, &rset)) { clock_gettime(CLOCK_MONOTONIC, &now_time); now = now_time.tv_sec * 1000 + now_time.tv_nsec / 1000000; //res = read(ttyfd, (void *)&ch, sizeof(ch)); res = read(ttyfd, (void *)line, sizeof(line)); if (0 >= res) close(ttyfd), ttyfd = -1, exit(13); for (i = 0; i < res; i++) onUartKey(line[i]); //emit(uinputfd, EV_SYN, SYN_REPORT, 0); if (now - start >= SELECT_EXPIRY_NINISECONDS) { //break; } } } tcsetattr(ttyfd, TCSANOW, &save); close(ttyfd), ttyfd = -1; sleep(1); ioctl(uinputfd, UI_DEV_DESTROY); close(uinputfd), uinputfd = -1; return 0; }
範例 II (Pthread 版本) :
#include <stdio.h> #include <unistd.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <errno.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> #include <stdarg.h> #include <stdlib.h> #include <time.h> #include <sys/mount.h> // for mount #include <fcntl.h> #include <signal.h> #include <netinet/tcp.h> #include <inttypes.h> #include <sched.h> #include <assert.h> #include <sys/ioctl.h> #include <ctype.h> #include <termios.h> #include <poll.h> #include <linux/uinput.h> #include <linux/input-event-codes.h> /* This routine is used for receive the uart specific characters and fire input key events accordingly. So if this routine is used, the serial console must be disabled. I. how to disable serial console? 1. In dts: bootargs = "mem=16M init=/sbin/init root=/dev/mtdblock3"; 2. Mask the "ttyMk0" in target /etc/inittab 3. Add the following in target /etc/rc.local if [ -x /usr/bin/fireUartKeys ]; then /usr/bin/fireUartKeys & fi II. how to compile? arm-linux-gnueabi-g++ fireUartKeys.cpp -o fireUartKeys -lpthread */ #define USE_PTHREAD 1 #ifdef USE_PTHREAD #include <pthread.h> #include "list.h" struct pool_t { struct list_head list; unsigned char c; }; static struct pool_t pl; static pthread_t tEmit = 0; static pthread_cond_t cPoolEmpty; static int poolEmpty = 1; static pthread_mutex_t mPoolEmpty = PTHREAD_MUTEX_INITIALIZER; #endif // USE_PTHREAD #define TTY_SERIAL "/dev/ttyMK0" #define SELECT_EXPIRY_NINISECONDS 100ULL #define ACTION_DOWN 1 #define ACTION_UP 0 #define _u1_ 0 #define _d1_ 1 #define _l1_ 2 #define _r1_ 3 #define _s1_ 4 #define _x1_ 5 #define _y1_ 6 #define _z1_ 7 #define _a1_ 8 #define _b1_ 9 #define _c1_ 10 #define _u2_ 11 #define _d2_ 12 #define _l2_ 13 #define _r2_ 14 #define _s2_ 15 #define _x2_ 16 #define _y2_ 17 #define _z2_ 18 #define _a2_ 19 #define _b2_ 20 #define _c2_ 21 #define _m_ 22 #define _w_ 23 #define _U1_ (1 << _u1_) #define _D1_ (1 << _d1_) #define _L1_ (1 << _l1_) #define _R1_ (1 << _r1_) #define _S1_ (1 << _s1_) #define _X1_ (1 << _x1_) #define _Y1_ (1 << _y1_) #define _Z1_ (1 << _z1_) #define _A1_ (1 << _a1_) #define _B1_ (1 << _b1_) #define _C1_ (1 << _c1_) #define _U2_ (1 << _u2_) #define _D2_ (1 << _d2_) #define _L2_ (1 << _l2_) #define _R2_ (1 << _r2_) #define _S2_ (1 << _s2_) #define _X2_ (1 << _x2_) #define _Y2_ (1 << _y2_) #define _Z2_ (1 << _z2_) #define _A2_ (1 << _a2_) #define _B2_ (1 << _b2_) #define _C2_ (1 << _c2_) #define _M_ (1 << _m_) #define _W_ (1 << _w_) struct code_t { int index; int code; const char *name; }; static struct code_t keypad_codes[] = { {_u1_, KEY_UP, "P1_UP"}, {_d1_, KEY_DOWN, "P1_DW"}, {_l1_, KEY_LEFT, "P1_LF"}, {_r1_, KEY_RIGHT, "P1_RG"}, {_s1_, KEY_ENTER, "P1_ST"}, {_x1_, KEY_X, "P1_X "}, {_y1_, KEY_Y, "P1_Y "}, {_z1_, KEY_Z, "P1_Z "}, {_a1_, KEY_A, "P1_A "}, {_b1_, KEY_B, "P1_B "}, {_c1_, KEY_C, "P1_C "}, {_u2_, KEY_KP8, "P2_UP"}, {_d2_, KEY_KP2, "P2_DW"}, {_l2_, KEY_KP4, "P2_LF"}, {_r2_, KEY_KP6, "P2_RG"}, {_s2_, KEY_SPACE, "P2_ST"}, {_x2_, KEY_F4, "P2_X "}, {_y2_, KEY_F5, "P2_Y "}, {_z2_, KEY_F6, "P2_Z "}, {_a2_, KEY_F1, "P2_A "}, {_b2_, KEY_F8, "P2_B "}, {_c2_, KEY_F3, "P2_C "}, {_m_, KEY_M, "MD"}, {_w_, KEY_R, "RW"}, }; #define KEYPAD_KEYNUMBER (sizeof(keypad_codes)/sizeof(struct code_t)) static unsigned int uartNowEvents = 0; static int uinputfd = -1; static int ttyfd = -1; static char ttyLine[1024] = {0}; static int ttyLineLength = 0; #define PRINTF(f_, ...) \ sprintf(ttyLine, f_, ##__VA_ARGS__), \ ttyLineLength = strlen(ttyLine), \ ttyLine[ttyLineLength] = 0, \ write(ttyfd, (void *)ttyLine, ttyLineLength + 1) static void emit(int fd, int type, int code, int val) { struct input_event ie = {0}; ie.type = type; ie.code = code; ie.value = val; write(fd, &ie, sizeof(ie)); } #ifdef USE_PTHREAD static void CleanupLock(void *param) { pthread_mutex_unlock((pthread_mutex_t *)param); } static void *EmitThread(void *param) { unsigned char ch; struct pool_t *e; // entry struct list_head *pos, *q; unsigned char buffer[1024 * 4] = {0}; int n = 0, i = 0; ///////////////////////////// // Wait for somebody tell WAIT: pthread_mutex_lock(&mPoolEmpty); pthread_cleanup_push(CleanupLock, (void *)&mPoolEmpty); while (poolEmpty) pthread_cond_wait(&cPoolEmpty, &mPoolEmpty); pthread_cleanup_pop(1); ///////////////////////////// // <need-fast> pthread_mutex_lock(&mPoolEmpty); pthread_cleanup_push(CleanupLock, (void *)&mPoolEmpty); n = 0; list_for_each_safe(pos, q, &pl.list) { e = list_entry(pos, struct pool_t, list); memcpy(&buffer[n++], &e->c, sizeof(unsigned char)); list_del(pos), free(e); } poolEmpty = 1; pthread_cleanup_pop(1); // </need-fast> for (i = 0; i < n; i++) { ch = buffer[i]; if (ch == (unsigned char)'U') emit(uinputfd, EV_KEY, keypad_codes[_u1_].code, ACTION_DOWN); if (ch == (unsigned char)'u') emit(uinputfd, EV_KEY, keypad_codes[_u1_].code, ACTION_UP); if (ch == (unsigned char)'D') emit(uinputfd, EV_KEY, keypad_codes[_d1_].code, ACTION_DOWN); if (ch == (unsigned char)'d') emit(uinputfd, EV_KEY, keypad_codes[_d1_].code, ACTION_UP); if (ch == (unsigned char)'L') emit(uinputfd, EV_KEY, keypad_codes[_l1_].code, ACTION_DOWN); if (ch == (unsigned char)'l') emit(uinputfd, EV_KEY, keypad_codes[_l1_].code, ACTION_UP); if (ch == (unsigned char)'R') emit(uinputfd, EV_KEY, keypad_codes[_r1_].code, ACTION_DOWN); if (ch == (unsigned char)'r') emit(uinputfd, EV_KEY, keypad_codes[_r1_].code, ACTION_UP); if (ch == (unsigned char)'S') emit(uinputfd, EV_KEY, keypad_codes[_s1_].code, ACTION_DOWN); if (ch == (unsigned char)'s') emit(uinputfd, EV_KEY, keypad_codes[_s1_].code, ACTION_UP); if (ch == (unsigned char)'X') emit(uinputfd, EV_KEY, keypad_codes[_x1_].code, ACTION_DOWN); if (ch == (unsigned char)'x') emit(uinputfd, EV_KEY, keypad_codes[_x1_].code, ACTION_UP); if (ch == (unsigned char)'Y') emit(uinputfd, EV_KEY, keypad_codes[_y1_].code, ACTION_DOWN); if (ch == (unsigned char)'y') emit(uinputfd, EV_KEY, keypad_codes[_y1_].code, ACTION_UP); if (ch == (unsigned char)'Z') emit(uinputfd, EV_KEY, keypad_codes[_z1_].code, ACTION_DOWN); if (ch == (unsigned char)'z') emit(uinputfd, EV_KEY, keypad_codes[_z1_].code, ACTION_UP); if (ch == (unsigned char)'A') emit(uinputfd, EV_KEY, keypad_codes[_a1_].code, ACTION_DOWN); if (ch == (unsigned char)'a') emit(uinputfd, EV_KEY, keypad_codes[_a1_].code, ACTION_UP); if (ch == (unsigned char)'B') emit(uinputfd, EV_KEY, keypad_codes[_b1_].code, ACTION_DOWN); if (ch == (unsigned char)'b') emit(uinputfd, EV_KEY, keypad_codes[_b1_].code, ACTION_UP); if (ch == (unsigned char)'C') emit(uinputfd, EV_KEY, keypad_codes[_c1_].code, ACTION_DOWN); if (ch == (unsigned char)'c') emit(uinputfd, EV_KEY, keypad_codes[_c1_].code, ACTION_UP); if (ch == (unsigned char)'H') emit(uinputfd, EV_KEY, keypad_codes[_u2_].code, ACTION_DOWN); if (ch == (unsigned char)'h') emit(uinputfd, EV_KEY, keypad_codes[_u2_].code, ACTION_UP); if (ch == (unsigned char)'I') emit(uinputfd, EV_KEY, keypad_codes[_d2_].code, ACTION_DOWN); if (ch == (unsigned char)'i') emit(uinputfd, EV_KEY, keypad_codes[_d2_].code, ACTION_UP); if (ch == (unsigned char)'J') emit(uinputfd, EV_KEY, keypad_codes[_l2_].code, ACTION_DOWN); if (ch == (unsigned char)'j') emit(uinputfd, EV_KEY, keypad_codes[_l2_].code, ACTION_UP); if (ch == (unsigned char)'K') emit(uinputfd, EV_KEY, keypad_codes[_r2_].code, ACTION_DOWN); if (ch == (unsigned char)'k') emit(uinputfd, EV_KEY, keypad_codes[_r2_].code, ACTION_UP); if (ch == (unsigned char)'T') emit(uinputfd, EV_KEY, keypad_codes[_s2_].code, ACTION_DOWN); if (ch == (unsigned char)'t') emit(uinputfd, EV_KEY, keypad_codes[_s2_].code, ACTION_UP); if (ch == (unsigned char)'O') emit(uinputfd, EV_KEY, keypad_codes[_x2_].code, ACTION_DOWN); if (ch == (unsigned char)'o') emit(uinputfd, EV_KEY, keypad_codes[_x2_].code, ACTION_UP); if (ch == (unsigned char)'P') emit(uinputfd, EV_KEY, keypad_codes[_y2_].code, ACTION_DOWN); if (ch == (unsigned char)'p') emit(uinputfd, EV_KEY, keypad_codes[_y2_].code, ACTION_UP); if (ch == (unsigned char)'Q') emit(uinputfd, EV_KEY, keypad_codes[_z2_].code, ACTION_DOWN); if (ch == (unsigned char)'q') emit(uinputfd, EV_KEY, keypad_codes[_z2_].code, ACTION_UP); if (ch == (unsigned char)'G') emit(uinputfd, EV_KEY, keypad_codes[_a2_].code, ACTION_DOWN); if (ch == (unsigned char)'g') emit(uinputfd, EV_KEY, keypad_codes[_a2_].code, ACTION_UP); if (ch == (unsigned char)'E') emit(uinputfd, EV_KEY, keypad_codes[_b2_].code, ACTION_DOWN); if (ch == (unsigned char)'e') emit(uinputfd, EV_KEY, keypad_codes[_b2_].code, ACTION_UP); if (ch == (unsigned char)'F') emit(uinputfd, EV_KEY, keypad_codes[_c2_].code, ACTION_DOWN); if (ch == (unsigned char)'f') emit(uinputfd, EV_KEY, keypad_codes[_c2_].code, ACTION_UP); if (ch == (unsigned char)'M') emit(uinputfd, EV_KEY, keypad_codes[_m_].code, ACTION_DOWN); if (ch == (unsigned char)'m') emit(uinputfd, EV_KEY, keypad_codes[_m_].code, ACTION_UP); if (ch == (unsigned char)'W') emit(uinputfd, EV_KEY, keypad_codes[_w_].code, ACTION_DOWN); if (ch == (unsigned char)'w') emit(uinputfd, EV_KEY, keypad_codes[_w_].code, ACTION_UP); emit(uinputfd, EV_SYN, SYN_REPORT, 0); ///////////////////////////// // 1 mini-second interval usleep(1); } goto WAIT; return 0; } static void onUartChar(unsigned char ch) { struct pool_t *e; if (ch != (unsigned char)'u' && ch != (unsigned char)'U' && ch != (unsigned char)'d' && ch != (unsigned char)'D' && ch != (unsigned char)'l' && ch != (unsigned char)'L' && ch != (unsigned char)'r' && ch != (unsigned char)'R' && ch != (unsigned char)'s' && ch != (unsigned char)'S' && ch != (unsigned char)'x' && ch != (unsigned char)'X' && ch != (unsigned char)'y' && ch != (unsigned char)'Y' && ch != (unsigned char)'z' && ch != (unsigned char)'Z' && ch != (unsigned char)'a' && ch != (unsigned char)'A' && ch != (unsigned char)'b' && ch != (unsigned char)'B' && ch != (unsigned char)'c' && ch != (unsigned char)'C' && ch != (unsigned char)'h' && ch != (unsigned char)'H' && ch != (unsigned char)'i' && ch != (unsigned char)'I' && ch != (unsigned char)'j' && ch != (unsigned char)'J' && ch != (unsigned char)'k' && ch != (unsigned char)'K' && ch != (unsigned char)'t' && ch != (unsigned char)'T' && ch != (unsigned char)'o' && ch != (unsigned char)'O' && ch != (unsigned char)'p' && ch != (unsigned char)'P' && ch != (unsigned char)'q' && ch != (unsigned char)'Q' && ch != (unsigned char)'g' && ch != (unsigned char)'G' && ch != (unsigned char)'e' && ch != (unsigned char)'E' && ch != (unsigned char)'f' && ch != (unsigned char)'F' && ch != (unsigned char)'m' && ch != (unsigned char)'M' && ch != (unsigned char)'w' && ch != (unsigned char)'W' ) return; if (ch == (unsigned char)'u') { uartNowEvents &= ~_U1_; goto TELL_WAIT; } if (ch == (unsigned char)'d') { uartNowEvents &= ~_D1_; goto TELL_WAIT; } if (ch == (unsigned char)'l') { uartNowEvents &= ~_L1_; goto TELL_WAIT; } if (ch == (unsigned char)'r') { uartNowEvents &= ~_R1_; goto TELL_WAIT; } if (ch == (unsigned char)'s') { uartNowEvents &= ~_S1_; goto TELL_WAIT; } if (ch == (unsigned char)'x') { uartNowEvents &= ~_X1_; goto TELL_WAIT; } if (ch == (unsigned char)'y') { uartNowEvents &= ~_Y1_; goto TELL_WAIT; } if (ch == (unsigned char)'z') { uartNowEvents &= ~_Z1_; goto TELL_WAIT; } if (ch == (unsigned char)'a') { uartNowEvents &= ~_A1_; goto TELL_WAIT; } if (ch == (unsigned char)'b') { uartNowEvents &= ~_B1_; goto TELL_WAIT; } if (ch == (unsigned char)'c') { uartNowEvents &= ~_C1_; goto TELL_WAIT; } if (ch == (unsigned char)'U') { uartNowEvents |= _U1_; goto TELL_WAIT; } if (ch == (unsigned char)'D') { uartNowEvents |= _D1_; goto TELL_WAIT; } if (ch == (unsigned char)'L') { uartNowEvents |= _L1_; goto TELL_WAIT; } if (ch == (unsigned char)'R') { uartNowEvents |= _R1_; goto TELL_WAIT; } if (ch == (unsigned char)'S') { uartNowEvents |= _S1_; goto TELL_WAIT; } if (ch == (unsigned char)'X') { uartNowEvents |= _X1_; goto TELL_WAIT; } if (ch == (unsigned char)'Y') { uartNowEvents |= _Y1_; goto TELL_WAIT; } if (ch == (unsigned char)'Z') { uartNowEvents |= _Z1_; goto TELL_WAIT; } if (ch == (unsigned char)'A') { uartNowEvents |= _A1_; goto TELL_WAIT; } if (ch == (unsigned char)'B') { uartNowEvents |= _B1_; goto TELL_WAIT; } if (ch == (unsigned char)'C') { uartNowEvents |= _C1_; goto TELL_WAIT; } if (ch == (unsigned char)'h') { uartNowEvents &= ~_U2_; goto TELL_WAIT; } if (ch == (unsigned char)'i') { uartNowEvents &= ~_D2_; goto TELL_WAIT; } if (ch == (unsigned char)'j') { uartNowEvents &= ~_L2_; goto TELL_WAIT; } if (ch == (unsigned char)'k') { uartNowEvents &= ~_R2_; goto TELL_WAIT; } if (ch == (unsigned char)'t') { uartNowEvents &= ~_S2_; goto TELL_WAIT; } if (ch == (unsigned char)'o') { uartNowEvents &= ~_X2_; goto TELL_WAIT; } if (ch == (unsigned char)'p') { uartNowEvents &= ~_Y2_; goto TELL_WAIT; } if (ch == (unsigned char)'q') { uartNowEvents &= ~_Z2_; goto TELL_WAIT; } if (ch == (unsigned char)'g') { uartNowEvents &= ~_A2_; goto TELL_WAIT; } if (ch == (unsigned char)'e') { uartNowEvents &= ~_B2_; goto TELL_WAIT; } if (ch == (unsigned char)'f') { uartNowEvents &= ~_C2_; goto TELL_WAIT; } if (ch == (unsigned char)'H') { uartNowEvents |= _U2_; goto TELL_WAIT; } if (ch == (unsigned char)'I') { uartNowEvents |= _D2_; goto TELL_WAIT; } if (ch == (unsigned char)'J') { uartNowEvents |= _L2_; goto TELL_WAIT; } if (ch == (unsigned char)'K') { uartNowEvents |= _R2_; goto TELL_WAIT; } if (ch == (unsigned char)'T') { uartNowEvents |= _S2_; goto TELL_WAIT; } if (ch == (unsigned char)'O') { uartNowEvents |= _X2_; goto TELL_WAIT; } if (ch == (unsigned char)'P') { uartNowEvents |= _Y2_; goto TELL_WAIT; } if (ch == (unsigned char)'Q') { uartNowEvents |= _Z2_; goto TELL_WAIT; } if (ch == (unsigned char)'G') { uartNowEvents |= _A2_; goto TELL_WAIT; } if (ch == (unsigned char)'E') { uartNowEvents |= _B2_; goto TELL_WAIT; } if (ch == (unsigned char)'F') { uartNowEvents |= _C2_; goto TELL_WAIT; } if (ch == (unsigned char)'m') { uartNowEvents &= ~_M_; goto TELL_WAIT; } if (ch == (unsigned char)'w') { uartNowEvents &= ~_W_; goto TELL_WAIT; } if (ch == (unsigned char)'M') { uartNowEvents |= _M_; goto TELL_WAIT; } if (ch == (unsigned char)'W') { uartNowEvents |= _W_; goto TELL_WAIT; } TELL_WAIT: e = (struct pool_t *)malloc(sizeof(struct pool_t)); memcpy(&e->c, &ch, sizeof(ch)); pthread_mutex_lock(&mPoolEmpty); pthread_cleanup_push(CleanupLock, (void *)&mPoolEmpty); list_add_tail(&e->list, &pl.list); poolEmpty = 0; pthread_cond_signal(&cPoolEmpty); pthread_cleanup_pop(1); return; } #else static void onUartChar(unsigned char ch) { if (ch != (unsigned char)'u' && ch != (unsigned char)'U' && ch != (unsigned char)'d' && ch != (unsigned char)'D' && ch != (unsigned char)'l' && ch != (unsigned char)'L' && ch != (unsigned char)'r' && ch != (unsigned char)'R' && ch != (unsigned char)'s' && ch != (unsigned char)'S' && ch != (unsigned char)'x' && ch != (unsigned char)'X' && ch != (unsigned char)'y' && ch != (unsigned char)'Y' && ch != (unsigned char)'z' && ch != (unsigned char)'Z' && ch != (unsigned char)'a' && ch != (unsigned char)'A' && ch != (unsigned char)'b' && ch != (unsigned char)'B' && ch != (unsigned char)'c' && ch != (unsigned char)'C' && ch != (unsigned char)'h' && ch != (unsigned char)'H' && ch != (unsigned char)'i' && ch != (unsigned char)'I' && ch != (unsigned char)'j' && ch != (unsigned char)'J' && ch != (unsigned char)'k' && ch != (unsigned char)'K' && ch != (unsigned char)'t' && ch != (unsigned char)'T' && ch != (unsigned char)'o' && ch != (unsigned char)'O' && ch != (unsigned char)'p' && ch != (unsigned char)'P' && ch != (unsigned char)'q' && ch != (unsigned char)'Q' && ch != (unsigned char)'g' && ch != (unsigned char)'G' && ch != (unsigned char)'e' && ch != (unsigned char)'E' && ch != (unsigned char)'f' && ch != (unsigned char)'F' && ch != (unsigned char)'m' && ch != (unsigned char)'M' && ch != (unsigned char)'w' && ch != (unsigned char)'W' ) return; if (ch == (unsigned char)'u') { uartNowEvents &= ~_U1_; goto BAITOUT; } if (ch == (unsigned char)'d') { uartNowEvents &= ~_D1_; goto BAITOUT; } if (ch == (unsigned char)'l') { uartNowEvents &= ~_L1_; goto BAITOUT; } if (ch == (unsigned char)'r') { uartNowEvents &= ~_R1_; goto BAITOUT; } if (ch == (unsigned char)'s') { uartNowEvents &= ~_S1_; goto BAITOUT; } if (ch == (unsigned char)'x') { uartNowEvents &= ~_X1_; goto BAITOUT; } if (ch == (unsigned char)'y') { uartNowEvents &= ~_Y1_; goto BAITOUT; } if (ch == (unsigned char)'z') { uartNowEvents &= ~_Z1_; goto BAITOUT; } if (ch == (unsigned char)'a') { uartNowEvents &= ~_A1_; goto BAITOUT; } if (ch == (unsigned char)'b') { uartNowEvents &= ~_B1_; goto BAITOUT; } if (ch == (unsigned char)'c') { uartNowEvents &= ~_C1_; goto BAITOUT; } if (ch == (unsigned char)'U') { uartNowEvents |= _U1_; goto BAITOUT; } if (ch == (unsigned char)'D') { uartNowEvents |= _D1_; goto BAITOUT; } if (ch == (unsigned char)'L') { uartNowEvents |= _L1_; goto BAITOUT; } if (ch == (unsigned char)'R') { uartNowEvents |= _R1_; goto BAITOUT; } if (ch == (unsigned char)'S') { uartNowEvents |= _S1_; goto BAITOUT; } if (ch == (unsigned char)'X') { uartNowEvents |= _X1_; goto BAITOUT; } if (ch == (unsigned char)'Y') { uartNowEvents |= _Y1_; goto BAITOUT; } if (ch == (unsigned char)'Z') { uartNowEvents |= _Z1_; goto BAITOUT; } if (ch == (unsigned char)'A') { uartNowEvents |= _A1_; goto BAITOUT; } if (ch == (unsigned char)'B') { uartNowEvents |= _B1_; goto BAITOUT; } if (ch == (unsigned char)'C') { uartNowEvents |= _C1_; goto BAITOUT; } if (ch == (unsigned char)'h') { uartNowEvents &= ~_U2_; goto BAITOUT; } if (ch == (unsigned char)'i') { uartNowEvents &= ~_D2_; goto BAITOUT; } if (ch == (unsigned char)'j') { uartNowEvents &= ~_L2_; goto BAITOUT; } if (ch == (unsigned char)'k') { uartNowEvents &= ~_R2_; goto BAITOUT; } if (ch == (unsigned char)'t') { uartNowEvents &= ~_S2_; goto BAITOUT; } if (ch == (unsigned char)'o') { uartNowEvents &= ~_X2_; goto BAITOUT; } if (ch == (unsigned char)'p') { uartNowEvents &= ~_Y2_; goto BAITOUT; } if (ch == (unsigned char)'q') { uartNowEvents &= ~_Z2_; goto BAITOUT; } if (ch == (unsigned char)'g') { uartNowEvents &= ~_A2_; goto BAITOUT; } if (ch == (unsigned char)'e') { uartNowEvents &= ~_B2_; goto BAITOUT; } if (ch == (unsigned char)'f') { uartNowEvents &= ~_C2_; goto BAITOUT; } if (ch == (unsigned char)'H') { uartNowEvents |= _U2_; goto BAITOUT; } if (ch == (unsigned char)'I') { uartNowEvents |= _D2_; goto BAITOUT; } if (ch == (unsigned char)'J') { uartNowEvents |= _L2_; goto BAITOUT; } if (ch == (unsigned char)'K') { uartNowEvents |= _R2_; goto BAITOUT; } if (ch == (unsigned char)'T') { uartNowEvents |= _S2_; goto BAITOUT; } if (ch == (unsigned char)'O') { uartNowEvents |= _X2_; goto BAITOUT; } if (ch == (unsigned char)'P') { uartNowEvents |= _Y2_; goto BAITOUT; } if (ch == (unsigned char)'Q') { uartNowEvents |= _Z2_; goto BAITOUT; } if (ch == (unsigned char)'G') { uartNowEvents |= _A2_; goto BAITOUT; } if (ch == (unsigned char)'E') { uartNowEvents |= _B2_; goto BAITOUT; } if (ch == (unsigned char)'F') { uartNowEvents |= _C2_; goto BAITOUT; } if (ch == (unsigned char)'m') { uartNowEvents &= ~_M_; goto BAITOUT; } if (ch == (unsigned char)'w') { uartNowEvents &= ~_W_; goto BAITOUT; } if (ch == (unsigned char)'M') { uartNowEvents |= _M_; goto BAITOUT; } if (ch == (unsigned char)'W') { uartNowEvents |= _W_; goto BAITOUT; } BAITOUT: if (ch == (unsigned char)'U') emit(uinputfd, EV_KEY, keypad_codes[_u1_].code, ACTION_DOWN); if (ch == (unsigned char)'u') emit(uinputfd, EV_KEY, keypad_codes[_u1_].code, ACTION_UP); if (ch == (unsigned char)'D') emit(uinputfd, EV_KEY, keypad_codes[_d1_].code, ACTION_DOWN); if (ch == (unsigned char)'d') emit(uinputfd, EV_KEY, keypad_codes[_d1_].code, ACTION_UP); if (ch == (unsigned char)'L') emit(uinputfd, EV_KEY, keypad_codes[_l1_].code, ACTION_DOWN); if (ch == (unsigned char)'l') emit(uinputfd, EV_KEY, keypad_codes[_l1_].code, ACTION_UP); if (ch == (unsigned char)'R') emit(uinputfd, EV_KEY, keypad_codes[_r1_].code, ACTION_DOWN); if (ch == (unsigned char)'r') emit(uinputfd, EV_KEY, keypad_codes[_r1_].code, ACTION_UP); if (ch == (unsigned char)'S') emit(uinputfd, EV_KEY, keypad_codes[_s1_].code, ACTION_DOWN); if (ch == (unsigned char)'s') emit(uinputfd, EV_KEY, keypad_codes[_s1_].code, ACTION_UP); if (ch == (unsigned char)'X') emit(uinputfd, EV_KEY, keypad_codes[_x1_].code, ACTION_DOWN); if (ch == (unsigned char)'x') emit(uinputfd, EV_KEY, keypad_codes[_x1_].code, ACTION_UP); if (ch == (unsigned char)'Y') emit(uinputfd, EV_KEY, keypad_codes[_y1_].code, ACTION_DOWN); if (ch == (unsigned char)'y') emit(uinputfd, EV_KEY, keypad_codes[_y1_].code, ACTION_UP); if (ch == (unsigned char)'Z') emit(uinputfd, EV_KEY, keypad_codes[_z1_].code, ACTION_DOWN); if (ch == (unsigned char)'z') emit(uinputfd, EV_KEY, keypad_codes[_z1_].code, ACTION_UP); if (ch == (unsigned char)'A') emit(uinputfd, EV_KEY, keypad_codes[_a1_].code, ACTION_DOWN); if (ch == (unsigned char)'a') emit(uinputfd, EV_KEY, keypad_codes[_a1_].code, ACTION_UP); if (ch == (unsigned char)'B') emit(uinputfd, EV_KEY, keypad_codes[_b1_].code, ACTION_DOWN); if (ch == (unsigned char)'b') emit(uinputfd, EV_KEY, keypad_codes[_b1_].code, ACTION_UP); if (ch == (unsigned char)'C') emit(uinputfd, EV_KEY, keypad_codes[_c1_].code, ACTION_DOWN); if (ch == (unsigned char)'c') emit(uinputfd, EV_KEY, keypad_codes[_c1_].code, ACTION_UP); if (ch == (unsigned char)'H') emit(uinputfd, EV_KEY, keypad_codes[_u2_].code, ACTION_DOWN); if (ch == (unsigned char)'h') emit(uinputfd, EV_KEY, keypad_codes[_u2_].code, ACTION_UP); if (ch == (unsigned char)'I') emit(uinputfd, EV_KEY, keypad_codes[_d2_].code, ACTION_DOWN); if (ch == (unsigned char)'i') emit(uinputfd, EV_KEY, keypad_codes[_d2_].code, ACTION_UP); if (ch == (unsigned char)'J') emit(uinputfd, EV_KEY, keypad_codes[_l2_].code, ACTION_DOWN); if (ch == (unsigned char)'j') emit(uinputfd, EV_KEY, keypad_codes[_l2_].code, ACTION_UP); if (ch == (unsigned char)'K') emit(uinputfd, EV_KEY, keypad_codes[_r2_].code, ACTION_DOWN); if (ch == (unsigned char)'k') emit(uinputfd, EV_KEY, keypad_codes[_r2_].code, ACTION_UP); if (ch == (unsigned char)'T') emit(uinputfd, EV_KEY, keypad_codes[_s2_].code, ACTION_DOWN); if (ch == (unsigned char)'t') emit(uinputfd, EV_KEY, keypad_codes[_s2_].code, ACTION_UP); if (ch == (unsigned char)'O') emit(uinputfd, EV_KEY, keypad_codes[_x2_].code, ACTION_DOWN); if (ch == (unsigned char)'o') emit(uinputfd, EV_KEY, keypad_codes[_x2_].code, ACTION_UP); if (ch == (unsigned char)'P') emit(uinputfd, EV_KEY, keypad_codes[_y2_].code, ACTION_DOWN); if (ch == (unsigned char)'p') emit(uinputfd, EV_KEY, keypad_codes[_y2_].code, ACTION_UP); if (ch == (unsigned char)'Q') emit(uinputfd, EV_KEY, keypad_codes[_z2_].code, ACTION_DOWN); if (ch == (unsigned char)'q') emit(uinputfd, EV_KEY, keypad_codes[_z2_].code, ACTION_UP); if (ch == (unsigned char)'G') emit(uinputfd, EV_KEY, keypad_codes[_a2_].code, ACTION_DOWN); if (ch == (unsigned char)'g') emit(uinputfd, EV_KEY, keypad_codes[_a2_].code, ACTION_UP); if (ch == (unsigned char)'E') emit(uinputfd, EV_KEY, keypad_codes[_b2_].code, ACTION_DOWN); if (ch == (unsigned char)'e') emit(uinputfd, EV_KEY, keypad_codes[_b2_].code, ACTION_UP); if (ch == (unsigned char)'F') emit(uinputfd, EV_KEY, keypad_codes[_c2_].code, ACTION_DOWN); if (ch == (unsigned char)'f') emit(uinputfd, EV_KEY, keypad_codes[_c2_].code, ACTION_UP); if (ch == (unsigned char)'M') emit(uinputfd, EV_KEY, keypad_codes[_m_].code, ACTION_DOWN); if (ch == (unsigned char)'m') emit(uinputfd, EV_KEY, keypad_codes[_m_].code, ACTION_UP); if (ch == (unsigned char)'W') emit(uinputfd, EV_KEY, keypad_codes[_w_].code, ACTION_DOWN); if (ch == (unsigned char)'w') emit(uinputfd, EV_KEY, keypad_codes[_w_].code, ACTION_UP); emit(uinputfd, EV_SYN, SYN_REPORT, 0); return; } #endif // USE_PTHREAD int main (int argc, char **argv) { struct termios term, save; int res, v, maxfd = 0; fd_set rset; struct timeval tv; struct timespec start_time, now_time; unsigned long long int start, now; struct uinput_user_dev uidev = {0}; int i = 0; char line[512]; uinputfd = open("/dev/uinput", O_WRONLY | O_NONBLOCK); if (0 > uinputfd) exit(1); if (ioctl(uinputfd, UI_SET_EVBIT, EV_KEY) < 0) exit(2); for (i = 0; i < KEYPAD_KEYNUMBER; i++) { if (ioctl(uinputfd, UI_SET_KEYBIT, keypad_codes[i].code) < 0) exit(3); } snprintf(uidev.name, UINPUT_MAX_NAME_SIZE, "uinput-serial"); uidev.id.bustype = BUS_VIRTUAL, uidev.id.vendor = 0x1, uidev.id.product = 0x1, uidev.id.version = 1; if (write(uinputfd, &uidev, sizeof(uidev)) < 0) exit(4); if(ioctl(uinputfd, UI_DEV_CREATE) < 0) exit(5); sleep(1); ttyfd = open(TTY_SERIAL, O_RDWR | O_NOCTTY | O_NDELAY); if (0 > ttyfd) exit(6); memset(&term, 0, sizeof(struct termios)); if (0 > tcgetattr(ttyfd, &term)) close(ttyfd), ttyfd = -1, exit(7); memcpy((void *)&save, (void *)&term, sizeof(struct termios)); term.c_cflag |= B115200, term.c_cflag |= CLOCAL, term.c_cflag |= CREAD, term.c_cflag &= ~PARENB, term.c_cflag &= ~CSTOPB; term.c_cflag &= ~CSIZE, term.c_cflag |= CS8, term.c_iflag = IGNPAR, term.c_cc[VMIN] = 1, term.c_cc[VTIME] = 0; term.c_iflag = 0, term.c_oflag = 0, term.c_lflag = 0; cfsetispeed(&term, B115200), cfsetospeed(&term, B115200); if (0 > tcsetattr(ttyfd, TCSANOW, &term)) close(ttyfd), ttyfd = -1, exit(8); if (0 > (v = fcntl(ttyfd, F_GETFL, 0))) close(ttyfd), ttyfd = -1, exit(9); if (0 > fcntl(ttyfd, F_SETFL, v | O_NONBLOCK)) close(ttyfd), ttyfd = -1, exit(10); if (0 > tcflush(ttyfd, TCIFLUSH)) close(ttyfd), ttyfd = -1, exit(11); clock_gettime(CLOCK_MONOTONIC, &start_time); start = start_time.tv_sec * 1000 + start_time.tv_nsec / 1000000; #ifdef USE_PTHREAD INIT_LIST_HEAD(&pl.list); pthread_cond_init(&cPoolEmpty, NULL); pthread_create(&tEmit, NULL, EmitThread, 0); #endif for (;;) { FD_ZERO(&rset); FD_SET(ttyfd, &rset); maxfd = 0; if (maxfd < ttyfd) maxfd = ttyfd; memset(&tv, 0, sizeof(tv)); tv.tv_sec = SELECT_EXPIRY_NINISECONDS / 1000; tv.tv_usec = (SELECT_EXPIRY_NINISECONDS % 1000) * 1000; //res = select(maxfd + 1, &rset, 0, 0, &tv); res = select(maxfd + 1, &rset, 0, 0, 0); if (0 > res) close(ttyfd), ttyfd = -1, exit(12); if (0 == res) continue; if (FD_ISSET(ttyfd, &rset)) { clock_gettime(CLOCK_MONOTONIC, &now_time); now = now_time.tv_sec * 1000 + now_time.tv_nsec / 1000000; res = read(ttyfd, (void *)line, sizeof(line)); if (0 >= res) close(ttyfd), ttyfd = -1, exit(13); for (i = 0; i < res; i++) { onUartChar(line[i]); } if (now - start >= SELECT_EXPIRY_NINISECONDS) { } } } tcsetattr(ttyfd, TCSANOW, &save); close(ttyfd), ttyfd = -1; sleep(1); ioctl(uinputfd, UI_DEV_DESTROY); close(uinputfd), uinputfd = -1; return 0; }
- list.h
-
#ifndef __LIST_H #define __LIST_H /* This file is from Linux Kernel (include/linux/list.h) * and modified by simply removing hardware prefetching of list items. * Here by copyright, credits attributed to wherever they belong. * Kulesh Shanmugasundaram (kulesh [squiggly] isis.poly.edu) */ /* * Simple doubly linked list implementation. * * Some of the internal functions ("__xxx") are useful when * manipulating whole lists rather than single entries, as * sometimes we already know the next/prev entries and we can * generate better code by using them directly rather than * using the generic single-entry routines. */ struct list_head { struct list_head *next, *prev; }; #define LIST_HEAD_INIT(name) { &(name), &(name) } #define LIST_HEAD(name) \ struct list_head name = LIST_HEAD_INIT(name) #define INIT_LIST_HEAD(ptr) do { \ (ptr)->next = (ptr); (ptr)->prev = (ptr); \ } while (0) /* * Insert a new entry between two known consecutive entries. * * This is only for internal list manipulation where we know * the prev/next entries already! */ static inline void __list_add(struct list_head *neu, struct list_head *prev, struct list_head *next) { next->prev = neu; neu->next = next; neu->prev = prev; prev->next = neu; } /** * list_add - add a new entry * @new: new entry to be added * @head: list head to add it after * * Insert a new entry after the specified head. * This is good for implementing stacks. */ static inline void list_add(struct list_head *neu, struct list_head *head) { __list_add(neu, head, head->next); } /** * list_add_tail - add a new entry * @new: new entry to be added * @head: list head to add it before * * Insert a new entry before the specified head. * This is useful for implementing queues. */ static inline void list_add_tail(struct list_head *neu, struct list_head *head) { __list_add(neu, head->prev, head); } /* * Delete a list entry by making the prev/next entries * point to each other. * * This is only for internal list manipulation where we know * the prev/next entries already! */ static inline void __list_del(struct list_head *prev, struct list_head *next) { next->prev = prev; prev->next = next; } /** * list_del - deletes entry from list. * @entry: the element to delete from the list. * Note: list_empty on entry does not return true after this, the entry is in an undefined state. */ static inline void list_del(struct list_head *entry) { __list_del(entry->prev, entry->next); //entry->next = (void *) 0; //entry->prev = (void *) 0; entry->next = 0; entry->prev = 0; } /** * list_del_init - deletes entry from list and reinitialize it. * @entry: the element to delete from the list. */ static inline void list_del_init(struct list_head *entry) { __list_del(entry->prev, entry->next); INIT_LIST_HEAD(entry); } /** * list_move - delete from one list and add as another's head * @list: the entry to move * @head: the head that will precede our entry */ static inline void list_move(struct list_head *list, struct list_head *head) { __list_del(list->prev, list->next); list_add(list, head); } /** * list_move_tail - delete from one list and add as another's tail * @list: the entry to move * @head: the head that will follow our entry */ static inline void list_move_tail(struct list_head *list, struct list_head *head) { __list_del(list->prev, list->next); list_add_tail(list, head); } /** * list_empty - tests whether a list is empty * @head: the list to test. */ static inline int list_empty(struct list_head *head) { return head->next == head; } static inline void __list_splice(struct list_head *list, struct list_head *head) { struct list_head *first = list->next; struct list_head *last = list->prev; struct list_head *at = head->next; first->prev = head; head->next = first; last->next = at; at->prev = last; } /** * list_splice - join two lists * @list: the new list to add. * @head: the place to add it in the first list. */ static inline void list_splice(struct list_head *list, struct list_head *head) { if (!list_empty(list)) __list_splice(list, head); } /** * list_splice_init - join two lists and reinitialise the emptied list. * @list: the new list to add. * @head: the place to add it in the first list. * * The list at @list is reinitialised */ static inline void list_splice_init(struct list_head *list, struct list_head *head) { if (!list_empty(list)) { __list_splice(list, head); INIT_LIST_HEAD(list); } } /** * list_entry - get the struct for this entry * @ptr: the &struct list_head pointer. * @type: the type of the struct this is embedded in. * @member: the name of the list_struct within the struct. */ #define list_entry(ptr, type, member) \ ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) /** * list_for_each - iterate over a list * @pos: the &struct list_head to use as a loop counter. * @head: the head for your list. */ #define list_for_each(pos, head) \ for (pos = (head)->next; pos != (head); \ pos = pos->next) /** * list_for_each_prev - iterate over a list backwards * @pos: the &struct list_head to use as a loop counter. * @head: the head for your list. */ #define list_for_each_prev(pos, head) \ for (pos = (head)->prev; pos != (head); \ pos = pos->prev) /** * list_for_each_safe - iterate over a list safe against removal of list entry * @pos: the &struct list_head to use as a loop counter. * @n: another &struct list_head to use as temporary storage * @head: the head for your list. */ #define list_for_each_safe(pos, n, head) \ for (pos = (head)->next, n = pos->next; pos != (head); \ pos = n, n = pos->next) /** * list_for_each_entry - iterate over list of given type * @pos: the type * to use as a loop counter. * @head: the head for your list. * @member: the name of the list_struct within the struct. */ #define list_for_each_entry(pos, head, member) \ for (pos = list_entry((head)->next, typeof(*pos), member); \ &pos->member != (head); \ pos = list_entry(pos->member.next, typeof(*pos), member)) /** * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry * @pos: the type * to use as a loop counter. * @n: another type * to use as temporary storage * @head: the head for your list. * @member: the name of the list_struct within the struct. */ #define list_for_each_entry_safe(pos, n, head, member) \ for (pos = list_entry((head)->next, typeof(*pos), member), \ n = list_entry(pos->member.next, typeof(*pos), member); \ &pos->member != (head); \ pos = n, n = list_entry(n->member.next, typeof(*n), member)) #endif
參考資料
http://www.softteco.com/blog/touch-hold-swipe-release-gesture-simulation-in-android-unit-test/
https://www.cnblogs.com/hwy89289709/p/6754300.html
https://victoryuembeddedlinux.blogspot.com/2011/04/driversysfs.html
Email: jasonc@mail2000.com.tw
留言列表