close


 

從 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;
    }
    ...
}
...

 

 

black_dot.jpg

 

 

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

 

 

 

 

 

 

jXSwN.png
 

 

Email: jasonc@mail2000.com.tw

 

 

 

 

 

arrow
arrow

    Lexra 發表在 痞客邦 留言(0) 人氣()