diff options
author | Amit Pundir <amitpundir@ti.com> | 2011-03-29 12:11:43 +0530 |
---|---|---|
committer | Patrik Ryd <patrik.ryd@linaro.org> | 2011-06-22 09:10:46 +0200 |
commit | 075f940788bdd4fd6a607d062d25e54f91e1c2fb (patch) | |
tree | a903f266c8ab97aed15be5275a2092f6be12b312 | |
parent | 54d3e90592792fa951903a52b6c647f93b51b7c1 (diff) | |
download | base-075f940788bdd4fd6a607d062d25e54f91e1c2fb.tar.gz |
[LINARO-ONLY] Gingerbread mouse cursor patch
This mouse cursor patch is provided by Gregoire Gentil from AlwaysInnovating
http://git.alwaysinnovating.com/cgit.cgi/ai.android/commit/?id=a721f7e2ab6e680257cc9cb5ecaee6238e615ff2
Right click (back operation) and Middle click (menu key) support added by Rowboat.
Signed-off-by: Amit Pundir <amitpundir@ti.com>
(cherry picked from commit 17128d44ab04c5b7cb2911e8b1c9f837aa9b36a5)
[LINARO] from: git remote add rowboat git://gitorious.org/rowboat/frameworks-base.git
-rw-r--r-- | core/java/android/view/IWindowManager.aidl | 3 | ||||
-rw-r--r-- | core/java/android/view/MotionEvent.java | 8 | ||||
-rw-r--r-- | core/java/android/view/ViewRoot.java | 18 | ||||
-rw-r--r-- | include/ui/EventHub.h | 3 | ||||
-rw-r--r-- | include/ui/InputReader.h | 51 | ||||
-rw-r--r-- | libs/ui/EventHub.cpp | 5 | ||||
-rw-r--r-- | libs/ui/InputDispatcher.cpp | 10 | ||||
-rw-r--r-- | libs/ui/InputReader.cpp | 230 | ||||
-rw-r--r-- | services/java/com/android/server/WindowManagerService.java | 80 |
9 files changed, 399 insertions, 9 deletions
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index d4dd05c19adc..b125ec018ef9 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -51,6 +51,9 @@ interface IWindowManager IWindowSession openSession(in IInputMethodClient client, in IInputContext inputContext); boolean inputMethodClientHasFocus(IInputMethodClient client); + + // Draws the mouse cursor on the screen + boolean moveMouseSurface(int dx, int dy); // These can only be called when injecting events to your own window, // or by holding the INJECT_EVENTS permission. These methods may block diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java index c2fec968172c..dc2aef887ab7 100644 --- a/core/java/android/view/MotionEvent.java +++ b/core/java/android/view/MotionEvent.java @@ -781,6 +781,14 @@ public final class MotionEvent extends InputEvent implements Parcelable { return mDataSamples[mLastDataSampleIndex + SAMPLE_Y] + mYOffset; } + public final float getXOffset() { + return mXOffset; + } + + public final float getYOffset() { + return mYOffset; + } + /** * {@link #getPressure(int)} for the first pointer index (may be an * arbitrary pointer identifier). diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java index c58207ee9999..f4e0bb7b1d11 100644 --- a/core/java/android/view/ViewRoot.java +++ b/core/java/android/view/ViewRoot.java @@ -215,6 +215,8 @@ public final class ViewRoot extends Handler implements ViewParent, final ViewConfiguration mViewConfiguration; + static IWindowManager wm; + /** * see {@link #playSoundEffect(int)} */ @@ -227,9 +229,8 @@ public final class ViewRoot extends Handler implements ViewParent, if (!mInitialized) { try { InputMethodManager imm = InputMethodManager.getInstance(mainLooper); - sWindowSession = IWindowManager.Stub.asInterface( - ServiceManager.getService("window")) - .openSession(imm.getClient(), imm.getInputContext()); + wm = IWindowManager.Stub.asInterface(ServiceManager.getService("window")); + sWindowSession = wm.openSession(imm.getClient(), imm.getInputContext()); mInitialized = true; } catch (RemoteException e) { } @@ -2174,6 +2175,7 @@ public final class ViewRoot extends Handler implements ViewParent, mTranslator.translateEventInScreenToAppWindow(event); } + boolean isMouse = ((event.getSource() & InputDevice.SOURCE_MOUSE) ^ InputDevice.SOURCE_MOUSE) == 0; boolean handled; if (mView != null && mAdded) { @@ -2837,7 +2839,15 @@ public final class ViewRoot extends Handler implements ViewParent, private void dispatchMotion(MotionEvent event, boolean sendDone) { int source = event.getSource(); - if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) { + if (((source & InputDevice.SOURCE_MOUSE) ^ InputDevice.SOURCE_MOUSE) == 0) { + try{ + wm.moveMouseSurface((int)event.getX() - (int)event.getXOffset(), + (int)event.getY() - (int)event.getYOffset()); + }catch (RemoteException e){ + Log.e(TAG,"RemoteException thrown in moveMouseSurface"); + } + dispatchPointer(event, sendDone); + }else if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) { dispatchPointer(event, sendDone); } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) { dispatchTrackball(event, sendDone); diff --git a/include/ui/EventHub.h b/include/ui/EventHub.h index d78e35fbfa6c..958754125d37 100644 --- a/include/ui/EventHub.h +++ b/include/ui/EventHub.h @@ -119,6 +119,9 @@ enum { /* The input device has switches. */ INPUT_DEVICE_CLASS_SWITCH = 0x00000080, + + /* The input device is a mouse. */ + INPUT_DEVICE_CLASS_MOUSE = 0x00000100, }; /* diff --git a/include/ui/InputReader.h b/include/ui/InputReader.h index 7568ba72329a..cf93fb0aba33 100644 --- a/include/ui/InputReader.h +++ b/include/ui/InputReader.h @@ -504,6 +504,57 @@ private: void sync(nsecs_t when); }; +class MouseInputMapper : public InputMapper { +public: + MouseInputMapper(InputDevice* device, int32_t associatedDisplayId); + virtual ~MouseInputMapper(); + + 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_MOUSE = 1, + FIELD_REL_X = 2, + FIELD_REL_Y = 4, + FIELD_BTN_RIGHT = 8, + FIELD_BTN_MIDDLE = 16 + }; + + uint32_t fields; + + bool btnMouse; + bool btnRight; + bool btnMiddle; + 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; + + void initializeLocked(); + + void sync(nsecs_t when); +}; class TouchInputMapper : public InputMapper { public: diff --git a/libs/ui/EventHub.cpp b/libs/ui/EventHub.cpp index 41daa9ca0dbc..5f920a73d4ee 100644 --- a/libs/ui/EventHub.cpp +++ b/libs/ui/EventHub.cpp @@ -719,7 +719,10 @@ int EventHub::openDevice(const char *deviceName) { 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 |= INPUT_DEVICE_CLASS_TRACKBALL; + if (test_bit(BTN_LEFT, key_bitmask) && test_bit(BTN_RIGHT, key_bitmask)) + device->classes |= INPUT_DEVICE_CLASS_MOUSE; + else + device->classes |= INPUT_DEVICE_CLASS_TRACKBALL; } } } diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp index 46baf9d14fe2..09bfdd19b5c3 100644 --- a/libs/ui/InputDispatcher.cpp +++ b/libs/ui/InputDispatcher.cpp @@ -733,17 +733,19 @@ bool InputDispatcher::dispatchMotionLocked( return true; } - bool isPointerEvent = entry->source & AINPUT_SOURCE_CLASS_POINTER; + 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 (isPointerEvent) { - // Pointer event. (eg. touchscreen) + 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) + // Non touch event. (eg. trackball or mouse simple move) injectionResult = findFocusedWindowTargetsLocked(currentTime, entry, nextWakeupTime); } diff --git a/libs/ui/InputReader.cpp b/libs/ui/InputReader.cpp index 83b382b9a7b0..df0174a86269 100644 --- a/libs/ui/InputReader.cpp +++ b/libs/ui/InputReader.cpp @@ -340,6 +340,11 @@ InputDevice* InputReader::createDevice(int32_t deviceId, const String8& name, ui device->addMapper(new TrackballInputMapper(device, associatedDisplayId)); } + // Mouse-like devices. + if (classes & INPUT_DEVICE_CLASS_MOUSE) { + device->addMapper(new MouseInputMapper(device, associatedDisplayId)); + } + // Touchscreen-like devices. if (classes & INPUT_DEVICE_CLASS_TOUCHSCREEN_MT) { device->addMapper(new MultiTouchInputMapper(device, associatedDisplayId)); @@ -1227,6 +1232,231 @@ int32_t TrackballInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scan } +// --- MouseInputMapper --- + +MouseInputMapper::MouseInputMapper(InputDevice* device, int32_t associatedDisplayId) : + InputMapper(device), mAssociatedDisplayId(associatedDisplayId) { + initializeLocked(); +} + +MouseInputMapper::~MouseInputMapper() { +} + +uint32_t MouseInputMapper::getSources() { + return AINPUT_SOURCE_MOUSE; +} + +void MouseInputMapper::populateDeviceInfo(InputDeviceInfo* info) { + InputMapper::populateDeviceInfo(info); +} + +void MouseInputMapper::dump(String8& dump) { + { // acquire lock + 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); + } // release lock +} + +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::reset() { + for (;;) { + { // acquire lock + AutoMutex _l(mLock); + + if (! mLocked.down) { + initializeLocked(); + break; // done + } + } // release lock + + // Synthesize mouse button up event on reset. + nsecs_t when = systemTime(SYSTEM_TIME_MONOTONIC); + mAccumulator.fields = Accumulator::FIELD_BTN_MOUSE; + mAccumulator.btnMouse = false; + sync(when); + } + + InputMapper::reset(); +} + +void MouseInputMapper::process(const RawEvent* rawEvent) { + switch (rawEvent->type) { + case EV_KEY: + switch (rawEvent->scanCode) { + case BTN_MOUSE: + mAccumulator.fields |= Accumulator::FIELD_BTN_MOUSE; + mAccumulator.btnMouse = rawEvent->value != 0; + // Sync now since BTN_MOUSE is not necessarily followed by SYN_REPORT and + // we need to ensure that we report the up/down promptly. + sync(rawEvent->when); + break; + case BTN_RIGHT: + // Back Button + mAccumulator.fields |= Accumulator::FIELD_BTN_RIGHT; + mAccumulator.btnRight = rawEvent->value != 0; + sync(rawEvent->when); + break; + case BTN_MIDDLE: + // Menu Button + mAccumulator.fields |= Accumulator::FIELD_BTN_MIDDLE; + mAccumulator.btnMiddle = rawEvent->value != 0; + sync(rawEvent->when); + break; + } + 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; + } + break; + + case EV_SYN: + switch (rawEvent->scanCode) { + case SYN_REPORT: + sync(rawEvent->when); + break; + } + break; + } +} + +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; + nsecs_t downTime; + { // acquire lock + AutoMutex _l(mLock); + + if (fields & Accumulator::FIELD_BTN_RIGHT) { + getDispatcher()->notifyKey(when, getDeviceId(), AINPUT_SOURCE_DPAD, 0, + mAccumulator.btnRight ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP, + AKEY_EVENT_FLAG_FROM_SYSTEM, 0x4 /*Keycode*/, 0x18 /*Scancode*/, mContext->getGlobalMetaState(), when); + } + + if (fields & Accumulator::FIELD_BTN_MIDDLE) { + getDispatcher()->notifyKey(when, getDeviceId(), AINPUT_SOURCE_DPAD, 0, + mAccumulator.btnMiddle ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP, + AKEY_EVENT_FLAG_FROM_SYSTEM, 0x52 /*Keycode*/, 0x19/*Scancode*/, mContext->getGlobalMetaState(), when); + } + + bool downChanged = fields & Accumulator::FIELD_BTN_MOUSE; + + if (downChanged) { + if (mAccumulator.btnMouse) { + mLocked.down = true; + mLocked.downTime = when; + } else { + mLocked.down = false; + } + motionEventAction = mLocked.down ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP; + } else { + motionEventAction = AMOTION_EVENT_ACTION_MOVE; + } + + 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; + } + + // Rotate motion based on display orientation if needed. + // Note: getDisplayInfo is non-reentrant so we can continue holding the lock. + + float temp; + switch (orientation) { + case InputReaderPolicyInterface::ROTATION_90: + temp = x; + x = y; + y = - temp; + temp = screenHeight; + screenHeight = screenWidth; + screenWidth = temp; + break; + + case InputReaderPolicyInterface::ROTATION_180: + x = - x; + y = - y; + break; + + case InputReaderPolicyInterface::ROTATION_270: + temp = x; + x = - y; + y = temp; + temp = screenHeight; + screenHeight = screenWidth; + screenWidth = temp; + break; + } + + 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(); + 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(); +} + +int32_t MouseInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) { + if (scanCode >= BTN_MOUSE && scanCode < BTN_JOYSTICK) { + return getEventHub()->getScanCodeState(getDeviceId(), scanCode); + } else { + return AKEY_STATE_UNKNOWN; + } +} + + // --- TouchInputMapper --- TouchInputMapper::TouchInputMapper(InputDevice* device, int32_t associatedDisplayId) : diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java index efd0bb49dc1b..9e9d55a4db93 100644 --- a/services/java/com/android/server/WindowManagerService.java +++ b/services/java/com/android/server/WindowManagerService.java @@ -60,6 +60,7 @@ import android.content.res.Configuration; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Paint; +import android.graphics.Path; import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.Region; @@ -372,6 +373,13 @@ public class WindowManagerService extends IWindowManager.Stub boolean mBlurShown; Watermark mWatermark; + Surface mMouseSurface; + int mShowMouse = 0; + private int mMlx; + private int mMly; + int mMlw; + int mMlh; + int mTransactionSequence = 0; final float[] mTmpFloats = new float[9]; @@ -5400,6 +5408,30 @@ public class WindowManagerService extends IWindowManager.Stub } } + public boolean moveMouseSurface(int x, int y){ + if (mMouseSurface != null && (x != 0 || y != 0)) { + synchronized(mWindowMap) { + Surface.openTransaction(); + WindowState top = (WindowState)mWindows.get(mWindows.size() - 1); + try { + int mDisplayWidth = mDisplay.getWidth(); + mMlx = x; + mMly = y; + mMouseSurface.setPosition(mMlx, mMly); + mMouseSurface.setLayer(top.mAnimLayer + 1); + if (mShowMouse != 1) { + mMouseSurface.show(); + mShowMouse = 1; + } + } catch ( RuntimeException e) { + Slog.e(TAG, "Failure showing mouse surface",e); + } + Surface.closeTransaction(); + } + } + return true; + } + /** * Injects a keystroke event into the UI. * Even when sync is false, this method may block while waiting for current @@ -8497,6 +8529,54 @@ public class WindowManagerService extends IWindowManager.Stub createWatermark = true; } + if (mMouseSurface == null) { + int mMx, mMy, mMw, mMh; + Canvas mCanvas; + Path mPath = new Path(); + mMw = 12; + mMh = 20; + mMx = (mDisplay.getWidth() - mMw) / 2; + mMy = (mDisplay.getHeight() - mMh) / 2; + try { + /* + *First Mouse event, create Surface + */ + mMouseSurface = + new Surface(mFxSession, + 0, -1, mMw, mMh, + PixelFormat.TRANSPARENT, + Surface.FX_SURFACE_NORMAL); + mCanvas = mMouseSurface.lockCanvas(null); + Paint tPaint = new Paint(); + tPaint.setStyle(Paint.Style.STROKE); + tPaint.setStrokeWidth(2); + tPaint.setColor(0xffffffff); + mPath.moveTo(0.0f, 0.0f); + mPath.lineTo(12.0f, 12.0f); + mPath.lineTo(7.0f, 12.0f); + mPath.lineTo(11.0f, 20.0f); + mPath.lineTo(8.0f, 21.0f); + mPath.lineTo(4.0f, 13.0f); + mPath.lineTo(0.0f, 17.0f); + mPath.close(); + mCanvas.clipPath(mPath); + mCanvas.drawColor(0xff000000); + mCanvas.drawPath(mPath, tPaint); + + mMouseSurface.unlockCanvasAndPost(mCanvas); + mMouseSurface.openTransaction(); + mMouseSurface.setSize(mMw, mMh); + mMouseSurface.closeTransaction(); + + } catch (Exception e) { + Slog.e(TAG, "Exception creating mouse surface",e); + } + mMlx = mMx; + mMly = mMy; + mMlw = mMw; + mMlh = mMh; + } + if (SHOW_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION"); Surface.openTransaction(); |