summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDianne Hackborn <hackbod@google.com>2010-07-15 22:22:42 -0700
committerAndroid (Google) Code Review <android-gerrit@google.com>2010-07-15 22:22:42 -0700
commit75a91389f1938214397aaee262f4136e6bb6b094 (patch)
treeb9279c75bdd3d131cdb4f423b4f31f9363efd455
parent02c8730c1bf19daf48bec8c6995df676a00a73b1 (diff)
parent2c6081ce3593712f30dacd990a97209c791d6ced (diff)
downloadframeworks_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.java33
-rw-r--r--core/jni/android_app_NativeActivity.cpp252
-rw-r--r--include/android_runtime/android_app_NativeActivity.h72
-rw-r--r--include/ui/Input.h2
-rw-r--r--libs/ui/Input.cpp17
-rw-r--r--native/android/input.cpp6
-rw-r--r--native/include/android/input.h12
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().
*/