diff options
author | Dianne Hackborn <hackbod@google.com> | 2010-07-15 22:22:42 -0700 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2010-07-15 22:22:42 -0700 |
commit | 75a91389f1938214397aaee262f4136e6bb6b094 (patch) | |
tree | b9279c75bdd3d131cdb4f423b4f31f9363efd455 | |
parent | 02c8730c1bf19daf48bec8c6995df676a00a73b1 (diff) | |
parent | 2c6081ce3593712f30dacd990a97209c791d6ced (diff) | |
download | frameworks_base-75a91389f1938214397aaee262f4136e6bb6b094.zip frameworks_base-75a91389f1938214397aaee262f4136e6bb6b094.tar.gz frameworks_base-75a91389f1938214397aaee262f4136e6bb6b094.tar.bz2 |
Merge "Implement native key pre-dispatching to IMEs." into gingerbread
-rw-r--r-- | core/java/android/app/NativeActivity.java | 33 | ||||
-rw-r--r-- | core/jni/android_app_NativeActivity.cpp | 252 | ||||
-rw-r--r-- | include/android_runtime/android_app_NativeActivity.h | 72 | ||||
-rw-r--r-- | include/ui/Input.h | 2 | ||||
-rw-r--r-- | libs/ui/Input.cpp | 17 | ||||
-rw-r--r-- | native/android/input.cpp | 6 | ||||
-rw-r--r-- | native/include/android/input.h | 12 |
7 files changed, 339 insertions, 55 deletions
diff --git a/core/java/android/app/NativeActivity.java b/core/java/android/app/NativeActivity.java index 3238b82..eaf0675 100644 --- a/core/java/android/app/NativeActivity.java +++ b/core/java/android/app/NativeActivity.java @@ -1,5 +1,8 @@ package android.app; +import com.android.internal.view.IInputMethodCallback; +import com.android.internal.view.IInputMethodSession; + import dalvik.system.PathClassLoader; import android.content.Context; @@ -25,6 +28,7 @@ import android.view.ViewTreeObserver.OnGlobalLayoutListener; import android.view.inputmethod.InputMethodManager; import java.io.File; +import java.lang.ref.WeakReference; /** * Convenience for implementing an activity that will be implemented @@ -36,6 +40,7 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback2, private NativeContentView mNativeContentView; private InputMethodManager mIMM; + private InputMethodCallback mInputMethodCallback; private int mNativeHandle; @@ -73,6 +78,7 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback2, private native void onInputChannelDestroyedNative(int handle, InputChannel channel); private native void onContentRectChangedNative(int handle, int x, int y, int w, int h); private native void dispatchKeyEventNative(int handle, KeyEvent event); + private native void finishPreDispatchKeyEventNative(int handle, int seq, boolean handled); static class NativeContentView extends View { NativeActivity mActivity; @@ -86,12 +92,34 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback2, } } + static class InputMethodCallback extends IInputMethodCallback.Stub { + WeakReference<NativeActivity> mNa; + + InputMethodCallback(NativeActivity na) { + mNa = new WeakReference<NativeActivity>(na); + } + + @Override + public void finishedEvent(int seq, boolean handled) { + NativeActivity na = mNa.get(); + if (na != null) { + na.finishPreDispatchKeyEventNative(na.mNativeHandle, seq, handled); + } + } + + @Override + public void sessionCreated(IInputMethodSession session) { + // Stub -- not for use in the client. + } + } + @Override protected void onCreate(Bundle savedInstanceState) { String libname = "main"; ActivityInfo ai; mIMM = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE); + mInputMethodCallback = new InputMethodCallback(this); getWindow().takeSurface(this); getWindow().takeInputQueue(this); @@ -292,6 +320,11 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback2, } } + void preDispatchKeyEvent(KeyEvent event, int seq) { + mIMM.dispatchKeyEvent(this, seq, event, + mInputMethodCallback); + } + void setWindowFlags(int flags, int mask) { getWindow().setFlags(flags, mask); } diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp index c17b504..1feb3b3 100644 --- a/core/jni/android_app_NativeActivity.cpp +++ b/core/jni/android_app_NativeActivity.cpp @@ -45,6 +45,7 @@ static struct { jclass clazz; jmethodID dispatchUnhandledKeyEvent; + jmethodID preDispatchKeyEvent; jmethodID setWindowFlags; jmethodID setWindowFormat; jmethodID showIme; @@ -104,7 +105,7 @@ static bool read_work(int fd, ActivityWork* outWork) { using namespace android; AInputQueue::AInputQueue(const sp<InputChannel>& channel, int workWrite) : - mWorkWrite(workWrite), mConsumer(channel) { + mWorkWrite(workWrite), mConsumer(channel), mSeq(0) { int msgpipe[2]; if (pipe(msgpipe)) { LOGW("could not create pipe: %s", strerror(errno)); @@ -157,6 +158,8 @@ int32_t AInputQueue::hasEvents() { int32_t AInputQueue::getEvent(AInputEvent** outEvent) { *outEvent = NULL; + bool finishNow = false; + char byteread; ssize_t nRead = read(mDispatchKeyRead, &byteread, 1); if (nRead == 1) { @@ -165,10 +168,34 @@ int32_t AInputQueue::getEvent(AInputEvent** outEvent) { KeyEvent* kevent = mDispatchingKeys[0]; *outEvent = kevent; mDispatchingKeys.removeAt(0); - mDeliveringKeys.add(kevent); + in_flight_event inflight; + inflight.event = kevent; + inflight.seq = -1; + inflight.doFinish = false; + mInFlightEvents.push(inflight); + } + if (mFinishPreDispatches.size() > 0) { + finish_pre_dispatch finish(mFinishPreDispatches[0]); + mFinishPreDispatches.removeAt(0); + const size_t N = mInFlightEvents.size(); + for (size_t i=0; i<N; i++) { + const in_flight_event& inflight(mInFlightEvents[i]); + if (inflight.seq == finish.seq) { + *outEvent = inflight.event; + finishNow = finish.handled; + } + } + if (*outEvent == NULL) { + LOGW("getEvent couldn't find inflight for seq %d", finish.seq); + } } mLock.unlock(); - if (*outEvent != NULL) { + + if (finishNow) { + finishEvent(*outEvent, true); + *outEvent = NULL; + return -1; + } else if (*outEvent != NULL) { return 0; } } @@ -181,7 +208,7 @@ int32_t AInputQueue::getEvent(AInputEvent** outEvent) { } InputEvent* myEvent = NULL; - res = mConsumer.consume(&mInputEventFactory, &myEvent); + res = mConsumer.consume(this, &myEvent); if (res != android::OK) { LOGW("channel '%s' ~ Failed to consume input event. status=%d", mConsumer.getChannel()->getName().string(), res); @@ -189,39 +216,69 @@ int32_t AInputQueue::getEvent(AInputEvent** outEvent) { return -1; } + in_flight_event inflight; + inflight.event = myEvent; + inflight.seq = -1; + inflight.doFinish = true; + mInFlightEvents.push(inflight); + *outEvent = myEvent; return 0; } +bool AInputQueue::preDispatchEvent(AInputEvent* event) { + if (((InputEvent*)event)->getType() != AINPUT_EVENT_TYPE_KEY) { + // The IME only cares about key events. + return false; + } + + // For now we only send system keys to the IME... this avoids having + // critical keys like DPAD go through this path. We really need to have + // the IME report which keys it wants. + if (!((KeyEvent*)event)->isSystemKey()) { + return false; + } + + return preDispatchKey((KeyEvent*)event); +} + void AInputQueue::finishEvent(AInputEvent* event, bool handled) { - bool needFinished = true; + LOG_TRACE("finishEvent: %p handled=%d", event, handled ? 1 : 0); if (!handled && ((InputEvent*)event)->getType() == AINPUT_EVENT_TYPE_KEY && ((KeyEvent*)event)->hasDefaultAction()) { // The app didn't handle this, but it may have a default action // associated with it. We need to hand this back to Java to be // executed. - doDefaultKey((KeyEvent*)event); - needFinished = false; + doUnhandledKey((KeyEvent*)event); + return; } - const size_t N = mDeliveringKeys.size(); + mLock.lock(); + const size_t N = mInFlightEvents.size(); for (size_t i=0; i<N; i++) { - if (mDeliveringKeys[i] == event) { - delete event; - mDeliveringKeys.removeAt(i); - needFinished = false; - break; + const in_flight_event& inflight(mInFlightEvents[i]); + if (inflight.event == event) { + if (inflight.doFinish) { + int32_t res = mConsumer.sendFinishedSignal(); + if (res != android::OK) { + LOGW("Failed to send finished signal on channel '%s'. status=%d", + mConsumer.getChannel()->getName().string(), res); + } + } + if (static_cast<InputEvent*>(event)->getType() == AINPUT_EVENT_TYPE_KEY) { + mAvailKeyEvents.push(static_cast<KeyEvent*>(event)); + } else { + mAvailMotionEvents.push(static_cast<MotionEvent*>(event)); + } + mInFlightEvents.removeAt(i); + mLock.unlock(); + return; } } + mLock.unlock(); - if (needFinished) { - int32_t res = mConsumer.sendFinishedSignal(); - if (res != android::OK) { - LOGW("Failed to send finished signal on channel '%s'. status=%d", - mConsumer.getChannel()->getName().string(), res); - } - } + LOGW("finishEvent called for unknown event: %p", event); } void AInputQueue::dispatchEvent(android::KeyEvent* event) { @@ -229,28 +286,28 @@ void AInputQueue::dispatchEvent(android::KeyEvent* event) { LOG_TRACE("dispatchEvent: dispatching=%d write=%d\n", mDispatchingKeys.size(), mDispatchKeyWrite); mDispatchingKeys.add(event); + wakeupDispatch(); mLock.unlock(); - -restart: - char dummy = 0; - int res = write(mDispatchKeyWrite, &dummy, sizeof(dummy)); - if (res < 0 && errno == EINTR) { - goto restart; - } - - if (res == sizeof(dummy)) return; +} - if (res < 0) LOGW("Failed writing to dispatch fd: %s", strerror(errno)); - else LOGW("Truncated writing to dispatch fd: %d", res); +void AInputQueue::finishPreDispatch(int seq, bool handled) { + mLock.lock(); + LOG_TRACE("finishPreDispatch: seq=%d handled=%d\n", seq, handled ? 1 : 0); + finish_pre_dispatch finish; + finish.seq = seq; + finish.handled = handled; + mFinishPreDispatches.add(finish); + wakeupDispatch(); + mLock.unlock(); } KeyEvent* AInputQueue::consumeUnhandledEvent() { KeyEvent* event = NULL; mLock.lock(); - if (mPendingKeys.size() > 0) { - event = mPendingKeys[0]; - mPendingKeys.removeAt(0); + if (mUnhandledKeys.size() > 0) { + event = mUnhandledKeys[0]; + mUnhandledKeys.removeAt(0); } mLock.unlock(); @@ -259,16 +316,103 @@ KeyEvent* AInputQueue::consumeUnhandledEvent() { return event; } -void AInputQueue::doDefaultKey(KeyEvent* keyEvent) { +KeyEvent* AInputQueue::consumePreDispatchingEvent(int* outSeq) { + KeyEvent* event = NULL; + mLock.lock(); - LOG_TRACE("Default key: pending=%d write=%d\n", mPendingKeys.size(), mWorkWrite); - if (mPendingKeys.size() <= 0 && mWorkWrite >= 0) { + if (mPreDispatchingKeys.size() > 0) { + const in_flight_event& inflight(mPreDispatchingKeys[0]); + event = static_cast<KeyEvent*>(inflight.event); + *outSeq = inflight.seq; + mPreDispatchingKeys.removeAt(0); + } + mLock.unlock(); + + LOG_TRACE("consumePreDispatchingEvent: KeyEvent=%p", event); + + return event; +} + +KeyEvent* AInputQueue::createKeyEvent() { + mLock.lock(); + KeyEvent* event; + if (mAvailKeyEvents.size() <= 0) { + event = new KeyEvent(); + } else { + event = mAvailKeyEvents.top(); + mAvailKeyEvents.pop(); + } + mLock.unlock(); + return event; +} + +MotionEvent* AInputQueue::createMotionEvent() { + mLock.lock(); + MotionEvent* event; + if (mAvailMotionEvents.size() <= 0) { + event = new MotionEvent(); + } else { + event = mAvailMotionEvents.top(); + mAvailMotionEvents.pop(); + } + mLock.unlock(); + return event; +} + +void AInputQueue::doUnhandledKey(KeyEvent* keyEvent) { + mLock.lock(); + LOG_TRACE("Unhandled key: pending=%d write=%d\n", mUnhandledKeys.size(), mWorkWrite); + if (mUnhandledKeys.size() <= 0 && mWorkWrite >= 0) { write_work(mWorkWrite, CMD_DEF_KEY); } - mPendingKeys.add(keyEvent); + mUnhandledKeys.add(keyEvent); mLock.unlock(); } +bool AInputQueue::preDispatchKey(KeyEvent* keyEvent) { + mLock.lock(); + LOG_TRACE("preDispatch key: pending=%d write=%d\n", mPreDispatchingKeys.size(), mWorkWrite); + const size_t N = mInFlightEvents.size(); + for (size_t i=0; i<N; i++) { + in_flight_event& inflight(mInFlightEvents.editItemAt(i)); + if (inflight.event == keyEvent) { + if (inflight.seq >= 0) { + // This event has already been pre-dispatched! + LOG_TRACE("Event already pre-dispatched!"); + mLock.unlock(); + return false; + } + mSeq++; + if (mSeq < 0) mSeq = 1; + inflight.seq = mSeq; + + if (mPreDispatchingKeys.size() <= 0 && mWorkWrite >= 0) { + write_work(mWorkWrite, CMD_DEF_KEY); + } + mPreDispatchingKeys.add(inflight); + mLock.unlock(); + return true; + } + } + + LOGW("preDispatchKey called for unknown event: %p", keyEvent); + return false; +} + +void AInputQueue::wakeupDispatch() { +restart: + char dummy = 0; + int res = write(mDispatchKeyWrite, &dummy, sizeof(dummy)); + if (res < 0 && errno == EINTR) { + goto restart; + } + + if (res == sizeof(dummy)) return; + + if (res < 0) LOGW("Failed writing to dispatch fd: %s", strerror(errno)); + else LOGW("Truncated writing to dispatch fd: %d", res); +} + namespace android { // ------------------------------------------------------------------------ @@ -417,11 +561,14 @@ static bool mainWorkCallback(int fd, int events, void* data) { code->env, keyEvent); code->env->CallVoidMethod(code->clazz, gNativeActivityClassInfo.dispatchUnhandledKeyEvent, inputEventObj); - int32_t res = code->nativeInputQueue->getConsumer().sendFinishedSignal(); - if (res != OK) { - LOGW("Failed to send finished signal on channel '%s'. status=%d", - code->nativeInputQueue->getConsumer().getChannel()->getName().string(), res); - } + code->nativeInputQueue->finishEvent(keyEvent, true); + } + int seq; + while ((keyEvent=code->nativeInputQueue->consumePreDispatchingEvent(&seq)) != NULL) { + jobject inputEventObj = android_view_KeyEvent_fromNative( + code->env, keyEvent); + code->env->CallVoidMethod(code->clazz, + gNativeActivityClassInfo.preDispatchKeyEvent, inputEventObj, seq); } } break; case CMD_SET_WINDOW_FORMAT: { @@ -766,13 +913,26 @@ dispatchKeyEvent_native(JNIEnv* env, jobject clazz, jint handle, jobject eventOb if (handle != 0) { NativeCode* code = (NativeCode*)handle; if (code->nativeInputQueue != NULL) { - KeyEvent* event = new KeyEvent(); + KeyEvent* event = code->nativeInputQueue->createKeyEvent(); android_view_KeyEvent_toNative(env, eventObj, event); code->nativeInputQueue->dispatchEvent(event); } } } +static void +finishPreDispatchKeyEvent_native(JNIEnv* env, jobject clazz, jint handle, + jint seq, jboolean handled) +{ + LOG_TRACE("finishPreDispatchKeyEvent_native"); + if (handle != 0) { + NativeCode* code = (NativeCode*)handle; + if (code->nativeInputQueue != NULL) { + code->nativeInputQueue->finishPreDispatch(seq, handled ? true : false); + } + } +} + static const JNINativeMethod g_methods[] = { { "loadNativeCode", "(Ljava/lang/String;Landroid/os/MessageQueue;Ljava/lang/String;Ljava/lang/String;ILandroid/content/res/AssetManager;)I", (void*)loadNativeCode_native }, @@ -792,6 +952,7 @@ static const JNINativeMethod g_methods[] = { { "onInputChannelDestroyedNative", "(ILandroid/view/InputChannel;)V", (void*)onInputChannelDestroyed_native }, { "onContentRectChangedNative", "(IIIII)V", (void*)onContentRectChanged_native }, { "dispatchKeyEventNative", "(ILandroid/view/KeyEvent;)V", (void*)dispatchKeyEvent_native }, + { "finishPreDispatchKeyEventNative", "(IIZ)V", (void*)finishPreDispatchKeyEvent_native }, }; static const char* const kNativeActivityPathName = "android/app/NativeActivity"; @@ -814,6 +975,9 @@ int register_android_app_NativeActivity(JNIEnv* env) GET_METHOD_ID(gNativeActivityClassInfo.dispatchUnhandledKeyEvent, gNativeActivityClassInfo.clazz, "dispatchUnhandledKeyEvent", "(Landroid/view/KeyEvent;)V"); + GET_METHOD_ID(gNativeActivityClassInfo.preDispatchKeyEvent, + gNativeActivityClassInfo.clazz, + "preDispatchKeyEvent", "(Landroid/view/KeyEvent;I)V"); GET_METHOD_ID(gNativeActivityClassInfo.setWindowFlags, gNativeActivityClassInfo.clazz, diff --git a/include/android_runtime/android_app_NativeActivity.h b/include/android_runtime/android_app_NativeActivity.h index d7a9a2c..c388ba8 100644 --- a/include/android_runtime/android_app_NativeActivity.h +++ b/include/android_runtime/android_app_NativeActivity.h @@ -42,8 +42,26 @@ extern void android_NativeActivity_hideSoftInput( /* * NDK input queue API. + * + * Here is the event flow: + * 1. Event arrives in input consumer, and is returned by getEvent(). + * 2. Application calls preDispatchEvent(): + * a. Event is assigned a sequence ID and enqueued in mPreDispatchingKeys. + * b. Main thread picks up event, hands to input method. + * c. Input method eventually returns sequence # and whether it was handled. + * d. finishPreDispatch() is called to enqueue the information. + * e. next getEvent() call will: + * - finish any pre-dispatch events that the input method handled + * - return the next pre-dispatched event that the input method didn't handle. + * f. (A preDispatchEvent() call on this event will now return false). + * 3. Application calls finishEvent() with whether it was handled. + * - If handled is true, the event is finished. + * - If handled is false, the event is put on mUnhandledKeys, and: + * a. Main thread receives event from consumeUnhandledEvent(). + * b. Java sends event through default key handler. + * c. event is finished. */ -struct AInputQueue { +struct AInputQueue : public android::InputEventFactoryInterface { public: /* Creates a consumer associated with an input channel. */ explicit AInputQueue(const android::sp<android::InputChannel>& channel, int workWrite); @@ -59,8 +77,9 @@ public: int32_t getEvent(AInputEvent** outEvent); - void finishEvent(AInputEvent* event, bool handled); + bool preDispatchEvent(AInputEvent* event); + void finishEvent(AInputEvent* event, bool handled); // ---------------------------------------------------------- @@ -68,28 +87,63 @@ public: void dispatchEvent(android::KeyEvent* event); + void finishPreDispatch(int seq, bool handled); + android::KeyEvent* consumeUnhandledEvent(); + android::KeyEvent* consumePreDispatchingEvent(int* outSeq); + + virtual android::KeyEvent* createKeyEvent(); + virtual android::MotionEvent* createMotionEvent(); int mWorkWrite; private: - void doDefaultKey(android::KeyEvent* keyEvent); + void doUnhandledKey(android::KeyEvent* keyEvent); + bool preDispatchKey(android::KeyEvent* keyEvent); + void wakeupDispatch(); android::InputConsumer mConsumer; - android::PreallocatedInputEventFactory mInputEventFactory; android::sp<android::PollLoop> mPollLoop; int mDispatchKeyRead; int mDispatchKeyWrite; - // This is only touched by the event reader thread. It is the current - // key events that came out of the mDispatchingKeys list and are now - //Êdelivered to the app. - android::Vector<android::KeyEvent*> mDeliveringKeys; + struct in_flight_event { + android::InputEvent* event; + int seq; + bool doFinish; + }; + + struct finish_pre_dispatch { + int seq; + bool handled; + }; android::Mutex mLock; - android::Vector<android::KeyEvent*> mPendingKeys; + + int mSeq; + + // Cache of previously allocated key events. + android::Vector<android::KeyEvent*> mAvailKeyEvents; + // Cache of previously allocated motion events. + android::Vector<android::MotionEvent*> mAvailMotionEvents; + + // All input events that are actively being processed. + android::Vector<in_flight_event> mInFlightEvents; + + // Key events that the app didn't handle, and are pending for + // delivery to the activity's default key handling. + android::Vector<android::KeyEvent*> mUnhandledKeys; + + // Keys that arrived in the Java framework and need to be + // dispatched to the app. android::Vector<android::KeyEvent*> mDispatchingKeys; + + // Key events that are pending to be pre-dispatched to the IME. + android::Vector<in_flight_event> mPreDispatchingKeys; + + // Event sequence numbers that we have finished pre-dispatching. + android::Vector<finish_pre_dispatch> mFinishPreDispatches; }; #endif // _ANDROID_APP_NATIVEACTIVITY_H diff --git a/include/ui/Input.h b/include/ui/Input.h index f069888..d9b1091 100644 --- a/include/ui/Input.h +++ b/include/ui/Input.h @@ -152,6 +152,7 @@ public: protected: void initialize(int32_t deviceId, int32_t source); + void initialize(const InputEvent& from); private: int32_t mDeviceId; @@ -202,6 +203,7 @@ public: int32_t repeatCount, nsecs_t downTime, nsecs_t eventTime); + void initialize(const KeyEvent& from); private: int32_t mAction; diff --git a/libs/ui/Input.cpp b/libs/ui/Input.cpp index e5f014f..5253c72 100644 --- a/libs/ui/Input.cpp +++ b/libs/ui/Input.cpp @@ -18,6 +18,11 @@ void InputEvent::initialize(int32_t deviceId, int32_t source) { mSource = source; } +void InputEvent::initialize(const InputEvent& from) { + mDeviceId = from.mDeviceId; + mSource = from.mSource; +} + // class KeyEvent bool KeyEvent::hasDefaultAction(int32_t keyCode) { @@ -106,6 +111,18 @@ void KeyEvent::initialize( mEventTime = eventTime; } +void KeyEvent::initialize(const KeyEvent& from) { + InputEvent::initialize(from); + mAction = from.mAction; + mFlags = from.mFlags; + mKeyCode = from.mKeyCode; + mScanCode = from.mScanCode; + mMetaState = from.mMetaState; + mRepeatCount = from.mRepeatCount; + mDownTime = from.mDownTime; + mEventTime = from.mEventTime; +} + // class MotionEvent void MotionEvent::initialize( diff --git a/native/android/input.cpp b/native/android/input.cpp index 4e1b6dc..59bf711 100644 --- a/native/android/input.cpp +++ b/native/android/input.cpp @@ -248,7 +248,7 @@ void AInputQueue_detachLooper(AInputQueue* queue) { queue->detachLooper(); } -int AInputQueue_hasEvents(AInputQueue* queue) { +int32_t AInputQueue_hasEvents(AInputQueue* queue) { return queue->hasEvents(); } @@ -256,6 +256,10 @@ int32_t AInputQueue_getEvent(AInputQueue* queue, AInputEvent** outEvent) { return queue->getEvent(outEvent); } +int32_t AInputQueue_preDispatchEvent(AInputQueue* queue, AInputEvent* event) { + return queue->preDispatchEvent(event) ? 1 : 0; +} + void AInputQueue_finishEvent(AInputQueue* queue, AInputEvent* event, int handled) { queue->finishEvent(event, handled != 0); } diff --git a/native/include/android/input.h b/native/include/android/input.h index ce79cd4..0b8c7e4 100644 --- a/native/include/android/input.h +++ b/native/include/android/input.h @@ -607,7 +607,7 @@ void AInputQueue_detachLooper(AInputQueue* queue); * input queue. Returns 1 if the queue has events; 0 if * it does not have events; and a negative value if there is an error. */ -int AInputQueue_hasEvents(AInputQueue* queue); +int32_t AInputQueue_hasEvents(AInputQueue* queue); /* * Returns the next available event from the queue. Returns a negative @@ -616,6 +616,16 @@ int AInputQueue_hasEvents(AInputQueue* queue); int32_t AInputQueue_getEvent(AInputQueue* queue, AInputEvent** outEvent); /* + * Sends the key for standard pre-dispatching -- that is, possibly deliver + * it to the current IME to be consumed before the app. Returns 0 if it + * was not pre-dispatched, meaning you can process it right now. If non-zero + * is returned, you must abandon the current event processing and allow the + * event to appear again in the event queue (if it does not get consumed during + * pre-dispatching). + */ +int32_t AInputQueue_preDispatchEvent(AInputQueue* queue, AInputEvent* event); + +/* * Report that dispatching has finished with the given event. * This must be called after receiving an event with AInputQueue_get_event(). */ |