Merge "Implement native key pre-dispatching to IMEs." into gingerbread
This commit is contained in:
committed by
Android (Google) Code Review
commit
75a91389f1
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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,8 +286,120 @@ void AInputQueue::dispatchEvent(android::KeyEvent* event) {
|
||||
LOG_TRACE("dispatchEvent: dispatching=%d write=%d\n", mDispatchingKeys.size(),
|
||||
mDispatchKeyWrite);
|
||||
mDispatchingKeys.add(event);
|
||||
wakeupDispatch();
|
||||
mLock.unlock();
|
||||
|
||||
}
|
||||
|
||||
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 (mUnhandledKeys.size() > 0) {
|
||||
event = mUnhandledKeys[0];
|
||||
mUnhandledKeys.removeAt(0);
|
||||
}
|
||||
mLock.unlock();
|
||||
|
||||
LOG_TRACE("consumeUnhandledEvent: KeyEvent=%p", event);
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
KeyEvent* AInputQueue::consumePreDispatchingEvent(int* outSeq) {
|
||||
KeyEvent* event = NULL;
|
||||
|
||||
mLock.lock();
|
||||
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);
|
||||
}
|
||||
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));
|
||||
@@ -244,31 +413,6 @@ restart:
|
||||
else LOGW("Truncated writing to dispatch fd: %d", res);
|
||||
}
|
||||
|
||||
KeyEvent* AInputQueue::consumeUnhandledEvent() {
|
||||
KeyEvent* event = NULL;
|
||||
|
||||
mLock.lock();
|
||||
if (mPendingKeys.size() > 0) {
|
||||
event = mPendingKeys[0];
|
||||
mPendingKeys.removeAt(0);
|
||||
}
|
||||
mLock.unlock();
|
||||
|
||||
LOG_TRACE("consumeUnhandledEvent: KeyEvent=%p", event);
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
void AInputQueue::doDefaultKey(KeyEvent* keyEvent) {
|
||||
mLock.lock();
|
||||
LOG_TRACE("Default key: pending=%d write=%d\n", mPendingKeys.size(), mWorkWrite);
|
||||
if (mPendingKeys.size() <= 0 && mWorkWrite >= 0) {
|
||||
write_work(mWorkWrite, CMD_DEF_KEY);
|
||||
}
|
||||
mPendingKeys.add(keyEvent);
|
||||
mLock.unlock();
|
||||
}
|
||||
|
||||
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,
|
||||
|
||||
@@ -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
|
||||
//<2F>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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -615,6 +615,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().
|
||||
|
||||
Reference in New Issue
Block a user