Event处理参考代码(Android 2.1)

IWindowManager.aidl

IWindowManager

interface IWindowManager
{
    ......   
    // These require the READ_INPUT_STATE permission.
    int getSwitchState(int sw);
    int getSwitchStateForDevice(int devid, int sw);
    int getScancodeState(int sw);
    int getScancodeStateForDevice(int devid, int sw);
    int getTrackballScancodeState(int sw);
    int getDPadScancodeState(int sw);
    int getKeycodeState(int sw);
    int getKeycodeStateForDevice(int devid, int sw);
    int getTrackballKeycodeState(int sw);
    int getDPadKeycodeState(int sw);
    
    // Report whether the hardware supports the given keys; returns true if successful
    boolean hasKeys(in int[] keycodes, inout boolean[] keyExists);
    
    ......
}

WindowManagerService.java

WindowManagerService

private WindowManagerService(Context context, PowerManagerService pm,
            boolean haveInputMethods) {
    
    ......
    
    mQueue = new KeyQ();

    mInputThread = new InputDispatcherThread();

    PolicyThread thr = new PolicyThread(mPolicy, this, context, pm);
    thr.start();

    synchronized (thr) {
        while (!thr.mRunning) {
            try {
                thr.wait();
            } catch (InterruptedException e) {
            }
        }
    }

    mInputThread.start();

    // Add ourself to the Watchdog monitors.
    Watchdog.getInstance().addMonitor(this);
}

InputDispatcherThread

private final class InputDispatcherThread extends Thread {

    ......
    private void process() {
        android.os.Process.setThreadPriority(
                android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY);

        ......
        while (true) {
        
            ......
            // 从KeyQ获取Event
            QueuedEvent ev = mQueue.getEvent(
                (int)((!configChanged && curTime < nextKeyTime)
                        ? (nextKeyTime-curTime) : 0));

            ......
            try {
                if (ev != null) {
                
                    ......
                    switch (ev.classType) {
                        // 处理keyboard事件
                        case RawInputEvent.CLASS_KEYBOARD:
                            KeyEvent ke = (KeyEvent)ev.event;
                            if (ke.isDown()) {
                                lastKey = ke;
                                downTime = curTime;
                                keyRepeatCount = 0;
                                lastKeyTime = curTime;
                                nextKeyTime = lastKeyTime
                                        + ViewConfiguration.getLongPressTimeout();
                            } else {
                                lastKey = null;
                                downTime = 0;
                                // Arbitrary long timeout.
                                lastKeyTime = curTime;
                                nextKeyTime = curTime + LONG_WAIT;
                            }
                            dispatchKey((KeyEvent)ev.event, 0, 0);
                            mQueue.recycleEvent(ev);
                            break;
                        // 处理touch事件
                        case RawInputEvent.CLASS_TOUCHSCREEN:
                            //Slog.i(TAG, "Read next event " + ev);
                            dispatchPointer(ev, (MotionEvent)ev.event, 0, 0);
                            break;
                        // 处理轨迹球事件
                        case RawInputEvent.CLASS_TRACKBALL:
                            dispatchTrackball(ev, (MotionEvent)ev.event, 0, 0);
                            break;
                        case RawInputEvent.CLASS_CONFIGURATION_CHANGED:
                            configChanged = true;
                            break;
                        default:
                            mQueue.recycleEvent(ev);
                        break;
                    }

                } 
                
                ......
            } catch (Exception e) {
            }
        }
    }
}

KeyInputQueue.java

KeyInputQueue

KeyInputQueue(Context context, HapticFeedbackCallback  hapticFeedbackCallback) {
    
    ......
    mFirst = new QueuedEvent();
    mLast = new QueuedEvent();
    mFirst.next = mLast;
    mLast.prev = mFirst;

    mThread.start();
}

mThread

Thread mThread = new Thread("InputDeviceReader") {
    public void run() {
        android.os.Process.setThreadPriority(
                android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY);
        
        RawInputEvent ev = new RawInputEvent();
        while (true) {
            try {
                InputDevice di;

                // block, doesn't release the monitor
                readEvent(ev);
            }
        }
    }
}

native方法

public static native String getDeviceName(int deviceId);
public static native int getDeviceClasses(int deviceId);
public static native void addExcludedDevice(String deviceName);
public static native boolean getAbsoluteInfo(int deviceId, int axis,
                                             InputDevice.AbsoluteInfo outInfo);
public static native int getSwitchState(int sw);
public static native int getSwitchState(int deviceId, int sw);
public static native int nativeGetScancodeState(int code);
public static native int nativeGetScancodeState(int deviceId, int code);
public static native int nativeGetKeycodeState(int code);
public static native int nativeGetKeycodeState(int deviceId, int code);
public static native int scancodeToKeycode(int deviceId, int scancode);
public static native boolean hasKeys(int[] keycodes, boolean[] keyExists);

private static native boolean readEvent(RawInputEvent outEvent);

com_android_server_KeyInputQueue.cpp

android_server_KeyInputQueue_readEvent

static jboolean
android_server_KeyInputQueue_readEvent(JNIEnv* env, jobject clazz,
                                          jobject event)
{
    gLock.lock();
    sp<EventHub> hub = gHub;
    if (hub == NULL) {
        hub = new EventHub;
        gHub = hub;
    }
    gLock.unlock();

    int32_t deviceId;
    int32_t type;
    int32_t scancode, keycode;
    uint32_t flags;
    int32_t value;
    nsecs_t when;
    bool res = hub->getEvent(&deviceId, &type, &scancode, &keycode,
            &flags, &value, &when);

    env->SetIntField(event, gInputOffsets.mDeviceId, (jint)deviceId);
    env->SetIntField(event, gInputOffsets.mType, (jint)type);
    env->SetIntField(event, gInputOffsets.mScancode, (jint)scancode);
    env->SetIntField(event, gInputOffsets.mKeycode, (jint)keycode);
    env->SetIntField(event, gInputOffsets.mFlags, (jint)flags);
    env->SetIntField(event, gInputOffsets.mValue, value);
    env->SetLongField(event, gInputOffsets.mWhen,
                        (jlong)(nanoseconds_to_milliseconds(when)));

    return res;
}

EventHub.h

enum设备类型

enum {
    CLASS_KEYBOARD      = 0x00000001,
    CLASS_ALPHAKEY      = 0x00000002,
    CLASS_TOUCHSCREEN   = 0x00000004,
    CLASS_TRACKBALL     = 0x00000008,
    CLASS_TOUCHSCREEN_MT= 0x00000010,
    CLASS_DPAD          = 0x00000020
};

EventHub.cpp

EventHub::getEvent

bool EventHub::getEvent(int32_t* outDeviceId, int32_t* outType,
        int32_t* outScancode, int32_t* outKeycode, uint32_t *outFlags,
        int32_t* outValue, nsecs_t* outWhen)
{

    ......
    // Note that we only allow one caller to getEvent(), so don't need
    // to do locking here...  only when adding/removing devices.

    if (!mOpened) {
        mError = openPlatformInput() ? NO_ERROR : UNKNOWN_ERROR;
        mOpened = true;
    }

    while(1) {

        ......
        release_wake_lock(WAKE_LOCK_ID);

        pollres = poll(mFDs, mFDCount, -1);

        acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);

        if (pollres <= 0) {
            if (errno != EINTR) {
                LOGW("select failed (errno=%d)\n", errno);
                usleep(100000);
            }
            continue;
        }

        ...... 
    }
}

EventHub::openPlatformInput

bool EventHub::openPlatformInput(void)
{
    int res;

    ......
    
    // device_path = "/dev/input";
    res = scan_dir(device_path);
    if(res < 0) {
    }

    return true;
}

EventHub::scan_dir

int EventHub::scan_dir(const char *dirname)
{
    char devname[PATH_MAX];
    char *filename;
    DIR *dir;
    struct dirent *de;
    dir = opendir(dirname);
    if(dir == NULL)
        return -1;
    strcpy(devname, dirname);
    filename = devname + strlen(devname);
    *filename++ = '/';
    while((de = readdir(dir))) {
        if(de->d_name[0] == '.' &&
           (de->d_name[1] == '\0' ||
            (de->d_name[1] == '.' && de->d_name[2] == '\0')))
            continue;
        strcpy(filename, de->d_name);
        open_device(devname);
    }
    closedir(dir);
    return 0;
}

EventHub::open_device

int EventHub::open_device(const char *deviceName)
{
    ......
    AutoMutex _l(mLock);

    // 打开设备节点
    fd = open(deviceName, O_RDWR);
    if(fd < 0) {
        return -1;
    }

    ......    
    // 处理keyboard
    uint8_t key_bitmask[(KEY_MAX+7)/8];
    memset(key_bitmask, 0, sizeof(key_bitmask));
    if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(key_bitmask)), key_bitmask) >= 0) {
        for (int i=0; i<((BTN_MISC+7)/8); i++) {
            if (key_bitmask[i] != 0) {
                device->classes |= CLASS_KEYBOARD;
                break;
            }
        }
        if ((device->classes & CLASS_KEYBOARD) != 0) {
            device->keyBitmask = new uint8_t[sizeof(key_bitmask)];
            if (device->keyBitmask != NULL) {
                memcpy(device->keyBitmask, key_bitmask, sizeof(key_bitmask));
            } else {
                delete device;
                return -1;
            }
        }
    }
    
    // 处理轨迹球
    if (test_bit(BTN_MOUSE, key_bitmask)) {
        uint8_t rel_bitmask[(REL_MAX+7)/8];
        memset(rel_bitmask, 0, sizeof(rel_bitmask));
        if (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(rel_bitmask)), rel_bitmask) >= 0)
        {
            if (test_bit(REL_X, rel_bitmask) && test_bit(REL_Y, rel_bitmask)) {
                device->classes |= CLASS_TRACKBALL;
            }
        }
    }
    
    uint8_t abs_bitmask[(ABS_MAX+7)/8];
    memset(abs_bitmask, 0, sizeof(abs_bitmask));
    ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bitmask)), abs_bitmask);
    
    // 处理多点触摸
    if (test_bit(ABS_MT_TOUCH_MAJOR, abs_bitmask)
            && test_bit(ABS_MT_POSITION_X, abs_bitmask)
            && test_bit(ABS_MT_POSITION_Y, abs_bitmask)) {
        device->classes |= CLASS_TOUCHSCREEN | CLASS_TOUCHSCREEN_MT;
        
    // 处理单点触摸
    } else if (test_bit(BTN_TOUCH, key_bitmask)
            && test_bit(ABS_X, abs_bitmask) && test_bit(ABS_Y, abs_bitmask)) {
        device->classes |= CLASS_TOUCHSCREEN;
    }

    // 处理*.kl映射文件
    if ((device->classes&CLASS_KEYBOARD) != 0) {
        char tmpfn[sizeof(name)];
        char keylayoutFilename[300];

        device->name = name;

        strcpy(tmpfn, name);
        for (char *p = strchr(tmpfn, ' '); p && *p; p = strchr(tmpfn, ' '))
            *p = '_';

        // 查找所有*.kl文件
        const char* root = getenv("ANDROID_ROOT");
        snprintf(keylayoutFilename, sizeof(keylayoutFilename),
                 "%s/usr/keylayout/%s.kl", root, tmpfn);
        bool defaultKeymap = false;
        if (access(keylayoutFilename, R_OK)) {
            snprintf(keylayoutFilename, sizeof(keylayoutFilename),
                     "%s/usr/keylayout/%s", root, "qwerty.kl");
            defaultKeymap = true;
        }
        // 读取*.kl文件
        device->layoutMap->load(keylayoutFilename);

        // 设置系统属性
        if (!mHaveFirstKeyboard && !defaultKeymap && strstr(name, "-keypad")) {
            // the built-in keyboard has a well-known device ID of 0,
            // this device better not go away.
            mHaveFirstKeyboard = true;
            mFirstKeyboardId = device->id;
            property_set("hw.keyboards.0.devname", name);
        } else {
            // ensure mFirstKeyboardId is set to -something-.
            if (mFirstKeyboardId == 0) {
                mFirstKeyboardId = device->id;
            }
        }
        char propName[100];
        sprintf(propName, "hw.keyboards.%u.devname", device->id);
        property_set(propName, name);
        
        ......
    }

    mDevicesById[devid].device = device;
    device->next = mOpeningDevices;
    mOpeningDevices = device;
    mDevices[mFDCount] = device;

    mFDCount++;
    return 0;
}

KeyLayoutMap.cpp

KeyLayoutMap::load

status_t
KeyLayoutMap::load(const char* filename)
{
    int fd = open(filename, O_RDONLY);
    
    ......
    while (true) {
        String8 token = next_token(&p, &line);
        if (*p == '\0') {
            break;
        }
        switch (state)
        {
            case BEGIN:
                if (token == "key") {
                    state = SCANCODE;
                } else {
                    err = BAD_VALUE;
                    goto done;
                }
                break;
            case SCANCODE:
                scancode = strtol(token.string(), &end, 0);
                if (*end != '\0') {
                    goto done;
                }
                state = KEYCODE;
                break;
            case KEYCODE:
                keycode = token_to_value(token.string(), KEYCODES);
                if (keycode == 0) {
                    goto done;
                }
                state = FLAG;
                break;
            case FLAG:
                if (token == "key") {
                    if (scancode != -1) {
                        Key k = { keycode, flags };
                        m_keys.add(scancode, k);
                        state = SCANCODE;
                        scancode = -1;
                        keycode = -1;
                        flags = 0;
                        break;
                    }
                }
                tmp = token_to_value(token.string(), FLAGS);
                if (tmp == 0) {
                    goto done;
                }
                flags |= tmp;
                break;
        }
    }
    if (state == FLAG && scancode != -1 ) {
        Key k = { keycode, flags };
        m_keys.add(scancode, k);
    }

done:
    free(buf);
    close(fd);

    m_status = err;
    return err;
}

android_text_KeyCharacterMap.cpp

ctor

static jint
ctor(JNIEnv *env, jobject clazz, jint id)
{
    return reinterpret_cast<int>(KeyCharacterMap::load(id));
}

KeyCharacterMap.h

struct Key

struct Key
{
    int32_t keycode;
    uint16_t display_label;
    uint16_t number;
    uint16_t data[META_MASK + 1];
};

KeyCharacterMap.cpp

KeyCharacterMap::load

KeyCharacterMap*
KeyCharacterMap::load(int id)
{
    KeyCharacterMap* rv = NULL;
    char path[PATH_MAX];
    char propName[100];
    char dev[PROPERTY_VALUE_MAX];
    char tmpfn[PROPERTY_VALUE_MAX];
    int err;
    const char* root = getenv("ANDROID_ROOT");

    sprintf(propName, "hw.keyboards.%u.devname", id);
    err = property_get(propName, dev, "");
    if (err > 0) {
        strcpy(tmpfn, dev);
        for (char *p = strchr(tmpfn, ' '); p && *p; p = strchr(tmpfn, ' '))
            *p = '_';
        snprintf(path, sizeof(path), "%s/usr/keychars/%s.kcm.bin", root, tmpfn);
        rv = try_file(path);
        if (rv != NULL) {
            return rv;
        }
        LOGW("Error loading keycharmap file '%s'. %s='%s'", path, propName, dev);
    } else {
        LOGW("No keyboard for id %d", id);
    }

    snprintf(path, sizeof(path), "%s/usr/keychars/qwerty.kcm.bin", root);
    rv = try_file(path);
    if (rv == NULL) {
        LOGE("Can't find any keycharmaps (also tried %s)", path);
        return NULL;
    }
    LOGW("Using default keymap: %s", path);

    return rv;
}