2.4G无线遥控器鼠标解决办法

来源:互联网 发布:考研作息知乎 编辑:程序博客网 时间:2024/04/27 22:41

    

           接上次讨论的2.4G input校验有问题, frameworks里没有加入对鼠标事件的支持。

           1.在EventHub.h文件里:

             enum {
    /* The input device is a keyboard. */
    INPUT_DEVICE_CLASS_KEYBOARD      = 0x00000001,

    /* The input device is an alpha-numeric keyboard (not just a dial pad). */
    INPUT_DEVICE_CLASS_ALPHAKEY      = 0x00000002,

    /* The input device is a touchscreen (either single-touch or multi-touch). */
    INPUT_DEVICE_CLASS_TOUCHSCREEN   = 0x00000004,

    /* The input device is a trackball. */
    INPUT_DEVICE_CLASS_TRACKBALL     = 0x00000008,

    /* The input device is a multi-touch touchscreen. */
    INPUT_DEVICE_CLASS_TOUCHSCREEN_MT= 0x00000010,

    /* The input device is a directional pad (implies keyboard, has DPAD keys). */
    INPUT_DEVICE_CLASS_DPAD          = 0x00000020,

    /* The input device is a gamepad (implies keyboard, has BUTTON keys). */
    INPUT_DEVICE_CLASS_GAMEPAD       = 0x00000040,

    /* The input device has switches. */
    INPUT_DEVICE_CLASS_SWITCH        = 0x00000080,

    /* The input device is a mouse. */
    INPUT_DEVICE_CLASS_MOUSE         = 0x00000100, //加入这行
};

  2.在InputReader.h

增加MouseInputMapper类声明

  class MouseInputMapper : public InputMapper {
public:
    MouseInputMapper(InputDevice* device, int32_t associatedDisplayId);

    virtual uint32_t getSources();
    virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo);
    virtual void dump(String8& dump);
    virtual void reset();
    virtual void process(const RawEvent* rawEvent);

    virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode);

private:
    Mutex mLock;

    int32_t mAssociatedDisplayId;

    struct Accumulator {
        enum {
            FIELD_BTN_LEFT = 1,
            FIELD_REL_X = 2,
            FIELD_REL_Y = 4,
            FIELD_BTN_RIGHT = 8,
            FIELD_BTN_MIDDLE = 16,
            FIELD_BTN_SIDE = 32,
            FIELD_BTN_EXTRA = 64,
            FIELD_BTN_FORWARD = 128,
            FIELD_BTN_BACK = 256,
            FIELD_REL_WHEEL = 512,
        };

        uint32_t fields;

        bool btnLeft;
        bool btnRight;
        bool btnMiddle;
        bool btnSide;
        bool btnExtra;
        bool btnForward;
        bool btnBack;
        bool btnScrollUp;
        bool btnScrollDown;
        int32_t relX;
        int32_t relY;
        int32_t absX;
        int32_t absY;

        inline void clear() {
            fields = 0;
        }
    } mAccumulator;

    struct LockedState {
        bool down;
        nsecs_t downTime;
    } mLocked;

    struct Keyevent {
        bool down;
        int keycode;
    };

    void initializeLocked();

    void sync(nsecs_t when);
    void sendKey();
};

3.EventHub.cpp

   // See if this is a trackball (or mouse).
    if (test_bit(BTN_MOUSE, key_bitmask)) {
        uint8_t rel_bitmask[sizeof_bit_array(REL_MAX + 1)];
        memset(rel_bitmask, 0, sizeof(rel_bitmask));
        LOGV("Getting relative controllers...");
        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 |= (test_bit(BTN_LEFT, key_bitmask) && test_bit(BTN_RIGHT, key_bitmask)) ?
                        INPUT_DEVICE_CLASS_MOUSE : INPUT_DEVICE_CLASS_TRACKBALL;//增加这行
            }
        }
    }

  4.InputDispatcher.cpp

     bool isTouchEvent = ! ((entry->source & AINPUT_SOURCE_TOUCHSCREEN) ^ AINPUT_SOURCE_TOUCHSCREEN);
    bool isMouseEvent = ! ((entry->source & AINPUT_SOURCE_MOUSE) ^ AINPUT_SOURCE_MOUSE);
    bool isDownEvent = (entry->action & AMOTION_EVENT_ACTION_MASK) == AMOTION_EVENT_ACTION_DOWN;

    // Identify targets.
    if (! mCurrentInputTargetsValid) {
        int32_t injectionResult;
        if (isTouchEvent || (isMouseEvent && (isDownEvent || mTouchState.down))) {
            // Touch-like event.  (eg. touchscreen or mouse drag-n-drop )
            injectionResult = findTouchedWindowTargetsLocked(currentTime,
                    entry, nextWakeupTime);
        } else {
            // Non touch event.  (eg. trackball or mouse simple move)
            injectionResult = findFocusedWindowTargetsLocked(currentTime,
                    entry, nextWakeupTime);
        }
        if (injectionResult == INPUT_EVENT_INJECTION_PENDING) {
            return false;
        }

        setInjectionResultLocked(entry, injectionResult);
        if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) {
            return true;
        }

        addMonitoringTargetsLocked();
        commitTargetsLocked();
    }

5.InputReader.cpp

  1).InputDevice* InputReader::createDevice(int32_t deviceId, const String8& name, uint32_t classes) {
    InputDevice* device = new InputDevice(this, deviceId, name);

    const int32_t associatedDisplayId = 0; // FIXME: hardcoded for current single-display devices

    // Switch-like devices.
    if (classes & INPUT_DEVICE_CLASS_SWITCH) {
        device->addMapper(new SwitchInputMapper(device));
    }

    // Keyboard-like devices.
    uint32_t keyboardSources = 0;
    int32_t keyboardType = AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC;
    if (classes & INPUT_DEVICE_CLASS_KEYBOARD) {
        keyboardSources |= AINPUT_SOURCE_KEYBOARD;
    }
    if (classes & INPUT_DEVICE_CLASS_ALPHAKEY) {
        keyboardType = AINPUT_KEYBOARD_TYPE_ALPHABETIC;
    }
    if (classes & INPUT_DEVICE_CLASS_DPAD) {
        keyboardSources |= AINPUT_SOURCE_DPAD;
    }

    if (keyboardSources != 0) {
        device->addMapper(new KeyboardInputMapper(device,
                associatedDisplayId, keyboardSources, keyboardType));
    }

    // Trackball-like devices.
    if (classes & INPUT_DEVICE_CLASS_TRACKBALL) {
        device->addMapper(new TrackballInputMapper(device, associatedDisplayId));
    }

    // Touchscreen-like devices.
    if (classes & INPUT_DEVICE_CLASS_TOUCHSCREEN_MT) {
        device->addMapper(new MultiTouchInputMapper(device, associatedDisplayId));
    } else if (classes & INPUT_DEVICE_CLASS_TOUCHSCREEN) {
        device->addMapper(new SingleTouchInputMapper(device, associatedDisplayId));
    }

    // Mouse-like devices.
    if (classes & INPUT_DEVICE_CLASS_MOUSE) {
        device->addMapper(new MouseInputMapper(device, associatedDisplayId));
    }

    return device;
}

 2).

//加入鼠标操作函数

  // --- MouseInputMapper ---

MouseInputMapper::MouseInputMapper(InputDevice* device, int32_t associatedDisplayId) :
        InputMapper(device), mAssociatedDisplayId(associatedDisplayId) {
    initializeLocked();
}

uint32_t MouseInputMapper::getSources() {
    return AINPUT_SOURCE_MOUSE;
}

void MouseInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
    InputMapper::populateDeviceInfo(info);
}

void MouseInputMapper::dump(String8& dump) {
    AutoMutex _l(mLock);
    dump.append(INDENT2 "Mouse Input Mapper:\n");
    dump.appendFormat(INDENT3 "AssociatedDisplayId: %d\n", mAssociatedDisplayId);
    dump.appendFormat(INDENT3 "Down: %s\n", toString(mLocked.down));
    dump.appendFormat(INDENT3 "DownTime: %lld\n", mLocked.downTime);
}

void MouseInputMapper::reset() {
    for (;;) {
        { // acquire lock
            AutoMutex _l(mLock);

            if (! mLocked.down) {
                initializeLocked();
                break; // done
            }
        } // release lock

        // Synthesize trackball button up event on reset.
        nsecs_t when = systemTime(SYSTEM_TIME_MONOTONIC);
        mAccumulator.fields = Accumulator::FIELD_BTN_LEFT;
        mAccumulator.btnLeft = false;
        mAccumulator.btnScrollUp = false;
        mAccumulator.btnScrollDown = false;
        sync(when);
    }

    InputMapper::reset();
}

void MouseInputMapper::process(const RawEvent* rawEvent) {
    switch (rawEvent->type) {
    case EV_KEY:
        switch (rawEvent->scanCode) {
        case BTN_LEFT:
            mAccumulator.fields |= Accumulator::FIELD_BTN_LEFT;
            mAccumulator.btnLeft = rawEvent->value;
            break;
        case BTN_RIGHT:
            mAccumulator.fields |= Accumulator::FIELD_BTN_RIGHT;
            mAccumulator.btnRight = rawEvent->value;
            break;
        case BTN_MIDDLE:
            mAccumulator.fields |= Accumulator::FIELD_BTN_MIDDLE;
            mAccumulator.btnMiddle = rawEvent->value;
            break;
        case BTN_SIDE:
            mAccumulator.fields |= Accumulator::FIELD_BTN_SIDE;
            mAccumulator.btnSide = rawEvent->value;
            break;
        case BTN_EXTRA:
            mAccumulator.fields |= Accumulator::FIELD_BTN_EXTRA;
            mAccumulator.btnExtra = rawEvent->value;
            break;
        case BTN_FORWARD:
            mAccumulator.fields |= Accumulator::FIELD_BTN_FORWARD;
            mAccumulator.btnForward = rawEvent->value;
            break;
        case BTN_BACK:
            mAccumulator.fields |= Accumulator::FIELD_BTN_BACK;
            mAccumulator.btnBack = rawEvent->value;
            break;
        }
        sync(rawEvent->when);
        break;

    case EV_REL:
        switch (rawEvent->scanCode) {
        case REL_X:
            mAccumulator.fields |= Accumulator::FIELD_REL_X;
            mAccumulator.relX = rawEvent->value;
            break;
        case REL_Y:
            mAccumulator.fields |= Accumulator::FIELD_REL_Y;
            mAccumulator.relY = rawEvent->value;
            break;
        case REL_WHEEL:
            mAccumulator.fields |= Accumulator::FIELD_REL_WHEEL;
            mAccumulator.btnScrollUp = (rawEvent->value == 1);
            mAccumulator.btnScrollDown = (rawEvent->value == -1);
            break;
        }
        break;

    case EV_SYN:
        switch (rawEvent->scanCode) {
        case SYN_REPORT:
            sync(rawEvent->when);
            break;
        }
        break;
    }
}

int32_t MouseInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) {
    return (scanCode >= BTN_LEFT && scanCode < BTN_JOYSTICK) ?
            getEventHub()->getScanCodeState(getDeviceId(), scanCode) : AKEY_STATE_UNKNOWN;
}

void MouseInputMapper::initializeLocked() {
    mAccumulator.clear();

    mLocked.down = false;
    mLocked.downTime = 0;

    int32_t screenWidth;
    int32_t screenHeight;
    if (mAssociatedDisplayId < 0 || ! getPolicy()->getDisplayInfo(mAssociatedDisplayId, &screenWidth, &screenHeight, NULL)) {
        mAccumulator.absX = 0;
        mAccumulator.absY = 0;
    } else {
        mAccumulator.absX = screenWidth / 2;
        mAccumulator.absY = screenHeight / 2;
    }
}

void MouseInputMapper::sync(nsecs_t when) {
    uint32_t fields = mAccumulator.fields;
    if (fields == 0) {
        return; // no new state changes, so nothing to do
    }

    int motionEventAction;
    PointerCoords pointerCoords;
    Vector<Keyevent> events;
    nsecs_t downTime;
    { // acquire lock
        AutoMutex _l(mLock);

        if (fields & Accumulator::FIELD_BTN_LEFT) {
            if ((mLocked.down = mAccumulator.btnLeft)) {
                mLocked.downTime = when;
                motionEventAction = AMOTION_EVENT_ACTION_DOWN;
            } else {
                motionEventAction = AMOTION_EVENT_ACTION_UP;
            }
        } else {
            motionEventAction = AMOTION_EVENT_ACTION_MOVE;
        }

        Keyevent kevent;
        if (fields & Accumulator::FIELD_BTN_RIGHT) {
            kevent.down = mAccumulator.btnRight;
            kevent.keycode = mLocked.down ? AKEYCODE_HOME : AKEYCODE_BACK;
            events.push(kevent);
        }
        if (fields & Accumulator::FIELD_BTN_MIDDLE) {
            kevent.down = mAccumulator.btnMiddle;
            kevent.keycode = mLocked.down ? AKEYCODE_ENTER : AKEYCODE_MENU;
            events.push(kevent);
        }
        if (fields & Accumulator::FIELD_BTN_SIDE) {
            kevent.down = mAccumulator.btnSide;
            kevent.keycode = mLocked.down ? AKEYCODE_DPAD_RIGHT : AKEYCODE_HOME;
            events.push(kevent);
        }
        if (fields & Accumulator::FIELD_BTN_EXTRA) {
            kevent.down = mAccumulator.btnExtra;
            kevent.keycode = mLocked.down ? AKEYCODE_DPAD_LEFT : AKEYCODE_ENTER;
            events.push(kevent);
        }
        if (fields & Accumulator::FIELD_BTN_FORWARD) {
            kevent.down = mAccumulator.btnForward;
            kevent.keycode = AKEYCODE_DPAD_RIGHT;
            events.push(kevent);
        }
        if (fields & Accumulator::FIELD_BTN_BACK) {
            kevent.down = mAccumulator.btnBack;
            kevent.keycode = AKEYCODE_DPAD_LEFT;
            events.push(kevent);
        }
        if (fields & Accumulator::FIELD_REL_WHEEL) {
            if (mAccumulator.btnScrollUp) {
                kevent.keycode = mLocked.down ? AKEYCODE_MEDIA_NEXT : AKEYCODE_DPAD_UP;
                kevent.down = true;
                events.push(kevent);
                kevent.down = false;
                events.push(kevent);
            } else if (mAccumulator.btnScrollDown) {
                kevent.keycode = mLocked.down ? AKEYCODE_MEDIA_PREVIOUS : AKEYCODE_DPAD_DOWN;
                kevent.down = true;
                events.push(kevent);
                kevent.down = false;
                events.push(kevent);
            }
        }

        downTime = mLocked.downTime;

        float x = fields & Accumulator::FIELD_REL_X ? mAccumulator.relX : 0.0f;
        float y = fields & Accumulator::FIELD_REL_Y ? mAccumulator.relY : 0.0f;

        int32_t screenWidth;
        int32_t screenHeight;
        int32_t orientation;

        if (mAssociatedDisplayId  < 0 || ! getPolicy()->getDisplayInfo(mAssociatedDisplayId, &screenWidth, &screenHeight, &orientation)) {
            return;
        }

        float temp;
        if ((orientation == InputReaderPolicyInterface::ROTATION_90) ||
            (orientation == InputReaderPolicyInterface::ROTATION_270)) {
            temp = screenHeight;
            screenHeight = screenWidth;
            screenWidth = temp;
        }

        mAccumulator.absX = (mAccumulator.absX + x) > screenWidth ? screenWidth - 1 : ((mAccumulator.absX + x) < 0 ? 0 : mAccumulator.absX + x);
        mAccumulator.absY = (mAccumulator.absY + y) > screenHeight ? screenHeight - 1 : ((mAccumulator.absY + y) < 0 ? 0 : mAccumulator.absY + y);
        pointerCoords.x = mAccumulator.absX;
        pointerCoords.y = mAccumulator.absY;
        pointerCoords.pressure = mLocked.down ? 1.0f : 0.0f;
        pointerCoords.size = 0;
        pointerCoords.touchMajor = 0;
        pointerCoords.touchMinor = 0;
        pointerCoords.toolMajor = 0;
        pointerCoords.toolMinor = 0;
        pointerCoords.orientation = 0;
    } // release lock

    int32_t metaState = mContext->getGlobalMetaState();
    for (size_t i = 0; i < events.size(); ++i) {
        getDispatcher()->notifyKey(when, getDeviceId(), AINPUT_SOURCE_DPAD, 0,
                events[i].down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
                AKEY_EVENT_FLAG_FROM_SYSTEM, events[i].keycode, 0,
                metaState, when);
    }

    int32_t pointerId = 0;
    getDispatcher()->notifyMotion(when, getDeviceId(), AINPUT_SOURCE_MOUSE, 0,
            motionEventAction, 0, metaState, AMOTION_EVENT_EDGE_FLAG_NONE,
            1, &pointerId, &pointerCoords, 1, 1, downTime);
    mAccumulator.clear();
}

6.WindowManagerService.java

   1).导入其他包的类

    import com.android.internal.view.BaseInputHandler;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.view.InputHandler;
import android.view.InputQueue;

2).

ublic class WindowManagerService extends IWindowManager.Stub
        implements Watchdog.Monitor {

....

// Mouse pointer handling
    Handler mHandler = new Handler();
    Surface mPointerSurface;
    boolean mPointerVisible;
    int mPointerX;
    int mPointerY;
    InputChannel mPointerInputChannel;
    final InputHandler mPointerInputHandler = new BaseInputHandler() {
        @Override
        public void handleMotion(MotionEvent event, Runnable finishedCallback) {
            finishedCallback.run();

            boolean isMouse = ((event.getSource() & InputDevice.SOURCE_MOUSE) ^ InputDevice.SOURCE_MOUSE) == 0;
            if (isMouse) {
                mPointerX = (int) event.getRawX();
                mPointerY = (int) event.getRawY();
                showPointer();
            } else if (mPointerVisible) {
                hidePointer();
            }
        }
    };


  ...

}

3).

  private WindowManagerService(Context context, PowerManagerService pm,
            boolean haveInputMethods) {

               .....

             mInputManager.start();
            startMouseMonitor();//启动监听

             .....

}

4).show鼠标的指针

           private final void performLayoutAndPlaceSurfacesLockedInner(
             boolean recoveringMemory) {

          ....

            // Draw the mouse cursor, if necessary
            if (mPointerSurface != null) {
                if (mPointerVisible) {
                    WindowState top = (WindowState)mWindows.get(mWindows.size() - 1);
                    mPointerSurface.setPosition(mPointerX, mPointerY);
                    mPointerSurface.setLayer(top.mAnimLayer + 1);
                    mPointerSurface.show();
                } else {
                    mPointerSurface.hide();
                }
            }

         ...

         }

原创粉丝点击