Bug 712973 - Use InputReader from libui in gonk widget backend, r=cjones

This commit is contained in:
Michael Wu 2012-01-25 11:00:34 -08:00
parent c2c5ac8482
commit ea2588584c
4 changed files with 355 additions and 393 deletions

View File

@ -337,6 +337,7 @@ if test -n "$gonkdir" ; then
AC_DEFINE(ANDROID)
AC_DEFINE(HAVE_SYS_UIO_H)
AC_DEFINE(HAVE_PTHREADS)
CROSS_COMPILE=1
MOZ_CHROME_FILE_FORMAT=omni
ZLIB_DIR=yes

View File

@ -425,6 +425,7 @@ OS_LIBS += \
-lmedia \
-lhardware_legacy \
-lhardware \
-lutils \
$(NULL)
endif

View File

@ -42,7 +42,6 @@
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <linux/input.h>
#include <signal.h>
#include <sys/epoll.h>
#include <sys/ioctl.h>
@ -53,6 +52,7 @@
#include "nscore.h"
#include "mozilla/FileUtils.h"
#include "mozilla/Mutex.h"
#include "mozilla/Services.h"
#include "nsAppShell.h"
#include "nsGkAtoms.h"
@ -61,26 +61,9 @@
#include "nsWindow.h"
#include "android/log.h"
#ifndef ABS_MT_TOUCH_MAJOR
// Taken from include/linux/input.h
// XXX update the bionic input.h so we don't have to do this!
#define ABS_X 0x00
#define ABS_Y 0x01
// ...
#define ABS_MT_TOUCH_MAJOR 0x30 /* Major axis of touching ellipse */
#define ABS_MT_TOUCH_MINOR 0x31 /* Minor axis (omit if circular) */
#define ABS_MT_WIDTH_MAJOR 0x32 /* Major axis of approaching ellipse */
#define ABS_MT_WIDTH_MINOR 0x33 /* Minor axis (omit if circular) */
#define ABS_MT_ORIENTATION 0x34 /* Ellipse orientation */
#define ABS_MT_POSITION_X 0x35 /* Center X ellipse position */
#define ABS_MT_POSITION_Y 0x36 /* Center Y ellipse position */
#define ABS_MT_TOOL_TYPE 0x37 /* Type of touching device */
#define ABS_MT_BLOB_ID 0x38 /* Group a set of packets as a blob */
#define ABS_MT_TRACKING_ID 0x39 /* Unique ID of initiated contact */
#define ABS_MT_PRESSURE 0x3a /* Pressure on contact area */
#define SYN_MT_REPORT 2
#endif
#include "ui/EventHub.h"
#include "ui/InputReader.h"
#include "ui/InputDispatcher.h"
#define LOG(args...) \
__android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args)
@ -93,6 +76,7 @@
#endif
using namespace mozilla;
using namespace android;
bool gDrawRequest = false;
static nsAppShell *gAppShell = NULL;
@ -123,21 +107,15 @@ pipeHandler(int fd, FdHandler *data)
} while (len > 0);
}
static
PRUint64 timevalToMS(const struct timeval &time)
{
return time.tv_sec * 1000 + time.tv_usec / 1000;
}
static void
sendMouseEvent(PRUint32 msg, struct timeval& time, int x, int y)
sendMouseEvent(PRUint32 msg, uint64_t timeMs, int x, int y)
{
nsMouseEvent event(true, msg, NULL,
nsMouseEvent::eReal, nsMouseEvent::eNormal);
event.refPoint.x = x;
event.refPoint.y = y;
event.time = timevalToMS(time);
event.time = timeMs;
event.isShift = false;
event.isControl = false;
event.isMeta = false;
@ -152,64 +130,64 @@ sendMouseEvent(PRUint32 msg, struct timeval& time, int x, int y)
static nsEventStatus
sendKeyEventWithMsg(PRUint32 keyCode,
PRUint32 msg,
const timeval &time,
uint64_t timeMs,
PRUint32 flags)
{
nsKeyEvent event(true, msg, NULL);
event.keyCode = keyCode;
event.time = timevalToMS(time);
event.time = timeMs;
event.flags |= flags;
return nsWindow::DispatchInputEvent(event);
}
static void
sendKeyEvent(PRUint32 keyCode, bool down, const timeval &time)
sendKeyEvent(PRUint32 keyCode, bool down, uint64_t timeMs)
{
nsEventStatus status =
sendKeyEventWithMsg(keyCode, down ? NS_KEY_DOWN : NS_KEY_UP, time, 0);
sendKeyEventWithMsg(keyCode, down ? NS_KEY_DOWN : NS_KEY_UP, timeMs, 0);
if (down) {
sendKeyEventWithMsg(keyCode, NS_KEY_PRESS, time,
sendKeyEventWithMsg(keyCode, NS_KEY_PRESS, timeMs,
status == nsEventStatus_eConsumeNoDefault ?
NS_EVENT_FLAG_NO_DEFAULT : 0);
}
}
static void
sendSpecialKeyEvent(nsIAtom *command, const timeval &time)
sendSpecialKeyEvent(nsIAtom *command, uint64_t timeMs)
{
nsCommandEvent event(true, nsGkAtoms::onAppCommand, command, NULL);
event.time = timevalToMS(time);
event.time = timeMs;
nsWindow::DispatchInputEvent(event);
}
static void
maybeSendKeyEvent(int keyCode, bool pressed, const timeval& time)
maybeSendKeyEvent(int keyCode, bool pressed, uint64_t timeMs)
{
switch (keyCode) {
case KEY_BACK:
sendKeyEvent(NS_VK_ESCAPE, pressed, time);
sendKeyEvent(NS_VK_ESCAPE, pressed, timeMs);
break;
case KEY_MENU:
if (!pressed)
sendSpecialKeyEvent(nsGkAtoms::Menu, time);
sendSpecialKeyEvent(nsGkAtoms::Menu, timeMs);
break;
case KEY_SEARCH:
if (pressed)
sendSpecialKeyEvent(nsGkAtoms::Search, time);
sendSpecialKeyEvent(nsGkAtoms::Search, timeMs);
break;
case KEY_HOME:
sendKeyEvent(NS_VK_HOME, pressed, time);
sendKeyEvent(NS_VK_HOME, pressed, timeMs);
break;
case KEY_POWER:
sendKeyEvent(NS_VK_SLEEP, pressed, time);
sendKeyEvent(NS_VK_SLEEP, pressed, timeMs);
break;
case KEY_VOLUMEUP:
if (pressed)
sendSpecialKeyEvent(nsGkAtoms::VolumeUp, time);
sendSpecialKeyEvent(nsGkAtoms::VolumeUp, timeMs);
break;
case KEY_VOLUMEDOWN:
if (pressed)
sendSpecialKeyEvent(nsGkAtoms::VolumeDown, time);
sendSpecialKeyEvent(nsGkAtoms::VolumeDown, timeMs);
break;
default:
VERBOSE_LOG("Got unknown key event code. type 0x%04x code 0x%04x value %d",
@ -217,35 +195,139 @@ maybeSendKeyEvent(int keyCode, bool pressed, const timeval& time)
}
}
static void
maybeSendKeyEvent(const input_event& e)
struct UserInputData {
uint64_t timeMs;
enum {
MOTION_DATA,
KEY_DATA
} type;
int32_t action;
int32_t flags;
int32_t metaState;
union {
struct {
int32_t keyCode;
int32_t scanCode;
} key;
struct {
PointerCoords coords;
} motion;
};
};
class GeckoInputReaderPolicy : public InputReaderPolicyInterface {
public:
GeckoInputReaderPolicy() {}
virtual bool getDisplayInfo(int32_t displayId,
int32_t* width, int32_t* height, int32_t* orientation);
virtual bool filterTouchEvents();
virtual bool filterJumpyTouchEvents();
virtual nsecs_t getVirtualKeyQuietTime();
virtual void getVirtualKeyDefinitions(const String8& deviceName,
Vector<VirtualKeyDefinition>& outVirtualKeyDefinitions);
virtual void getInputDeviceCalibration(const String8& deviceName,
InputDeviceCalibration& outCalibration);
virtual void getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames);
protected:
virtual ~GeckoInputReaderPolicy() {}
};
class GeckoInputDispatcher : public InputDispatcherInterface {
public:
GeckoInputDispatcher()
: mQueueLock("GeckoInputDispatcher::mQueueMutex")
{}
virtual void dump(String8& dump);
// Called on the main thread
virtual void dispatchOnce();
// notify* methods are called on the InputReaderThread
virtual void notifyConfigurationChanged(nsecs_t eventTime);
virtual void notifyKey(nsecs_t eventTime, int32_t deviceId, int32_t source,
uint32_t policyFlags, int32_t action, int32_t flags, int32_t keyCode,
int32_t scanCode, int32_t metaState, nsecs_t downTime);
virtual void notifyMotion(nsecs_t eventTime, int32_t deviceId, int32_t source,
uint32_t policyFlags, int32_t action, int32_t flags,
int32_t metaState, int32_t edgeFlags,
uint32_t pointerCount, const int32_t* pointerIds, const PointerCoords* pointerCoords,
float xPrecision, float yPrecision, nsecs_t downTime);
virtual void notifySwitch(nsecs_t when,
int32_t switchCode, int32_t switchValue, uint32_t policyFlags);
virtual int32_t injectInputEvent(const InputEvent* event,
int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis);
virtual void setInputWindows(const Vector<InputWindow>& inputWindows);
virtual void setFocusedApplication(const InputApplication* inputApplication);
virtual void setInputDispatchMode(bool enabled, bool frozen);
virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel, bool monitor);
virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel);
protected:
virtual ~GeckoInputDispatcher() {}
private:
// mQueueLock should generally be locked while using mEventQueue.
// UserInputData is pushed on on the InputReaderThread and
// popped and dispatched on the main thread.
mozilla::Mutex mQueueLock;
std::queue<UserInputData> mEventQueue;
};
// GeckoInputReaderPolicy
bool
GeckoInputReaderPolicy::getDisplayInfo(int32_t displayId,
int32_t* width,
int32_t* height,
int32_t* orientation)
{
if (e.type != EV_KEY) {
VERBOSE_LOG("Got unknown key event type. type 0x%04x code 0x%04x value %d",
e.type, e.code, e.value);
return;
}
// 0 is the default displayId. We only support one display
if (displayId)
return false;
if (e.value != 0 && e.value != 1) {
VERBOSE_LOG("Got unknown key event value. type 0x%04x code 0x%04x value %d",
e.type, e.code, e.value);
return;
}
bool pressed = e.value == 1;
maybeSendKeyEvent(e.code, pressed, e.time);
if (width)
*width = gScreenBounds.width;
if (height)
*height = gScreenBounds.height;
if (orientation)
*orientation = ROTATION_0;
return true;
}
static void
configureVButtons(FdHandler& data)
bool
GeckoInputReaderPolicy::filterTouchEvents()
{
return false;
}
bool
GeckoInputReaderPolicy::filterJumpyTouchEvents()
{
return false;
}
nsecs_t
GeckoInputReaderPolicy::getVirtualKeyQuietTime()
{
return 0;
}
void
GeckoInputReaderPolicy::getVirtualKeyDefinitions(const String8& deviceName,
Vector<VirtualKeyDefinition>& outVirtualKeyDefinitions)
{
outVirtualKeyDefinitions.clear();
char vbuttonsPath[PATH_MAX];
snprintf(vbuttonsPath, sizeof(vbuttonsPath),
"/sys/board_properties/virtualkeys.%s",
data.name);
deviceName.string());
ScopedClose fd(open(vbuttonsPath, O_RDONLY));
if (0 > fd.mFd) {
LOG("No vbuttons for mt device %s", data.name);
LOG("No vbuttons for mt device %s", deviceName.string());
return;
}
@ -263,31 +345,23 @@ configureVButtons(FdHandler& data)
config[nread] = '\0';
LOG("Device %s has vbutton config '%s'", data.name, config);
LOG("Device %s has vbutton config '%s'", deviceName.string(), config);
char* startStr = config;
for (size_t i = 0; i < FdHandler::kMaxVButtons; ++i) {
FdHandler::VButton& vbutton = data.vbuttons[i];
char* token;
char* state;
char* first = config;
char* magic;
char* state;
while ((magic = strtok_r(first, ":", &state))) {
// XXX not clear what "0x01" is ... maybe a version
// number? See InputManager.java.
if (!(token = strtok_r(startStr, ":", &state)) ||
strcmp(token, "0x01")) {
if (strcmp(magic, "0x01")) {
LOG(" magic 0x01 tag missing");
break;
}
startStr = NULL;
first = NULL;
if (!(token = strtok_r(NULL, ":", &state))) {
LOG(" failed to read keycode");
break;
}
vbutton.keyCode = atoi(token);
const char *centerX, *centerY, *width, *height;
if (!((centerX = strtok_r(NULL, ":", &state)) &&
const char *scanCode, *centerX, *centerY, *width, *height;
if (!((scanCode = strtok_r(NULL, ":", &state)) &&
(centerX = strtok_r(NULL, ":", &state)) &&
(centerY = strtok_r(NULL, ":", &state)) &&
(width = strtok_r(NULL, ":", &state)) &&
(height = strtok_r(NULL, ":", &state)))) {
@ -299,247 +373,194 @@ configureVButtons(FdHandler& data)
// space. That means the values in /sys/board_config make
// assumptions about how the raw input events are mapped
// ... le sigh.
nsIntRect rect;
rect.width = atoi(width);
rect.height = atoi(height);
rect.x = atoi(centerX) - rect.width / 2;
rect.y = atoi(centerY) - rect.height / 2;
vbutton.buttonRect = rect;
VirtualKeyDefinition def;
def.scanCode = atoi(scanCode);
def.centerX = atoi(centerX);
def.centerY = atoi(centerY);
def.width = atoi(width);
def.height = atoi(height);
outVirtualKeyDefinitions.push(def);
LOG(" configured vbutton code=%d at <x=%d,y=%d,w=%d,h=%d>",
vbutton.keyCode, rect.x, rect.y, rect.width, rect.height);
def.scanCode, def.centerX, def.centerY, def.width, def.height);
}
}
static bool
calibrateMultitouchDevice(FdHandler& data)
void
GeckoInputReaderPolicy::getInputDeviceCalibration(const String8& deviceName, InputDeviceCalibration& outCalibration)
{
if (data.calibrated)
return true;
if (gScreenBounds.IsEmpty()) {
// The framebuffer hasn't been initialized yet. We *could*
// force it to be initialized here, but that's another patch.
LOG("Deferring multitouch calibrate, fb not ready");
return false;
}
struct input_absinfo xInfo, yInfo;
if (0 > ioctl(data.fd, EVIOCGABS(ABS_MT_POSITION_X), &xInfo) ||
0 > ioctl(data.fd, EVIOCGABS(ABS_MT_POSITION_Y), &yInfo)) {
LOG("Couldn't get absinfo for multitouch axes");
return false;
}
LOG("Input coordinate bounds: xmin=%d, xmax=%d, ymin=%d, ymax=%d",
xInfo.minimum, xInfo.maximum, yInfo.minimum, yInfo.maximum);
data.inputMinX = xInfo.minimum;
data.inputMinY = yInfo.minimum;
data.inputToScreenScaleX =
float(gScreenBounds.width) / float(xInfo.maximum - xInfo.minimum);
data.inputToScreenScaleY =
float(gScreenBounds.height) / float(yInfo.maximum - yInfo.minimum);
configureVButtons(data);
data.calibrated = true;
return true;
outCalibration.clear();
}
static void
multitouchHandler(int fd, FdHandler *data)
void
GeckoInputReaderPolicy::getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames)
{
if (!calibrateMultitouchDevice(*data))
return;
// The Linux's input documentation (Documentation/input/input.txt)
// says that we'll always read a multiple of sizeof(input_event) bytes here.
input_event events[16];
int event_count = read(fd, events, sizeof(events));
if (event_count < 0) {
LOG("Error reading in multitouchHandler");
return;
}
MOZ_ASSERT(event_count % sizeof(input_event) == 0);
event_count /= sizeof(struct input_event);
for (int i = 0; i < event_count; i++) {
input_event *event = &events[i];
if (event->type == EV_ABS) {
if (data->mtState == FdHandler::MT_IGNORE)
continue;
if (data->mtState == FdHandler::MT_START)
data->mtState = FdHandler::MT_COLLECT;
switch (event->code) {
case ABS_MT_TOUCH_MAJOR:
data->mtMajor = event->value;
break;
case ABS_MT_TOUCH_MINOR:
case ABS_MT_WIDTH_MAJOR:
case ABS_MT_WIDTH_MINOR:
case ABS_MT_ORIENTATION:
case ABS_MT_TOOL_TYPE:
case ABS_MT_BLOB_ID:
case ABS_MT_TRACKING_ID:
case ABS_MT_PRESSURE:
break;
case ABS_MT_POSITION_X:
data->mtX = data->inputXToScreenX(event->value);
break;
case ABS_MT_POSITION_Y:
data->mtY = data->inputYToScreenY(event->value);
break;
default:
VERBOSE_LOG("Got unknown mt event type 0x%04x with code 0x%04x and value %d",
event->type, event->code, event->value);
break;
}
} else if (event->type == EV_SYN) {
switch (event->code) {
case SYN_MT_REPORT:
if (data->mtState == FdHandler::MT_COLLECT)
data->mtState = FdHandler::MT_IGNORE;
break;
case SYN_REPORT:
if (!data->mtMajor || data->mtState == FdHandler::MT_START) {
data->mtDown = false;
if (data->keyCode) {
maybeSendKeyEvent(data->keyCode, data->mtDown,
event->time);
data->keyCode = 0;
} else {
sendMouseEvent(NS_MOUSE_BUTTON_UP, event->time,
data->mtX, data->mtY);
}
} else if (!data->mtDown) {
int x = data->mtX, y = data->mtY;
bool isKeyEvent = false;
if (!gScreenBounds.Contains(x, y)) {
// Off-screen mt down. Should be a vbutton.
for (size_t i = 0; i < FdHandler::kMaxVButtons; ++i) {
const FdHandler::VButton& vbutton = data->vbuttons[i];
if (vbutton.buttonRect.IsEmpty())
break;
if (vbutton.buttonRect.Contains(x, y)) {
isKeyEvent = true;
data->keyCode = vbutton.keyCode;
break;
}
}
}
data->mtDown = true;
if (isKeyEvent) {
maybeSendKeyEvent(data->keyCode, data->mtDown,
event->time);
} else {
sendMouseEvent(NS_MOUSE_BUTTON_DOWN, event->time,
data->mtX, data->mtY);
}
} else if (!data->keyCode) {
sendMouseEvent(NS_MOUSE_MOVE, event->time,
data->mtX, data->mtY);
data->mtDown = true;
}
data->mtState = FdHandler::MT_START;
break;
default:
VERBOSE_LOG("Got unknown mt event type 0x%04x with code 0x%04x and value %d",
event->type, event->code, event->value);
}
} else
VERBOSE_LOG("Got unknown mt event type 0x%04x with code 0x%04x and value %d",
event->type, event->code, event->value);
}
outExcludedDeviceNames.clear();
}
static void
singleTouchHandler(int fd, FdHandler *data)
// GeckoInputDispatcher
void
GeckoInputDispatcher::dump(String8& dump)
{
// The Linux's input documentation (Documentation/input/input.txt)
// says that we'll always read a multiple of sizeof(input_event) bytes here.
input_event events[16];
int event_count = read(fd, events, sizeof(events));
if (event_count < 0) {
LOG("Error reading in singleTouchHandler");
return;
}
void
GeckoInputDispatcher::dispatchOnce()
{
UserInputData data;
{
MutexAutoLock lock(mQueueLock);
if (mEventQueue.empty())
return;
data = mEventQueue.front();
mEventQueue.pop();
if (!mEventQueue.empty())
gAppShell->NotifyNativeEvent();
}
MOZ_ASSERT(event_count % sizeof(input_event) == 0);
event_count /= sizeof(struct input_event);
for (int i = 0; i < event_count; i++) {
input_event *event = &events[i];
if (event->type == EV_KEY) {
switch (event->code) {
case BTN_TOUCH:
data->mtDown = event->value;
break;
default:
maybeSendKeyEvent(*event);
}
} else if (event->type == EV_ABS) {
switch (event->code) {
case ABS_X:
data->mtX = event->value;
break;
case ABS_Y:
data->mtY = event->value;
break;
default:
LOG("Got unknown st abs event type 0x%04x with code 0x%04x and value %d",
event->type, event->code, event->value);
}
} else if (event->type == EV_SYN) {
if (data->mtState == FdHandler::MT_START) {
MOZ_ASSERT(data->mtDown);
sendMouseEvent(NS_MOUSE_BUTTON_DOWN, event->time,
data->mtX, data->mtY);
data->mtState = FdHandler::MT_COLLECT;
} else if (data->mtDown) {
MOZ_ASSERT(data->mtDown);
sendMouseEvent(NS_MOUSE_MOVE, event->time,
data->mtX, data->mtY);
} else {
MOZ_ASSERT(!data->mtDown);
sendMouseEvent(NS_MOUSE_BUTTON_UP, event->time,
data->mtX, data->mtY);
data->mtDown = false;
data->mtState = FdHandler::MT_START;
}
switch (data.type) {
case UserInputData::MOTION_DATA: {
PRUint32 msg;
switch (data.action) {
case AMOTION_EVENT_ACTION_DOWN:
msg = NS_MOUSE_BUTTON_DOWN;
break;
case AMOTION_EVENT_ACTION_MOVE:
msg = NS_MOUSE_MOVE;
break;
case AMOTION_EVENT_ACTION_UP:
msg = NS_MOUSE_BUTTON_UP;
break;
}
sendMouseEvent(msg,
data.timeMs,
data.motion.coords.x,
data.motion.coords.y);
break;
}
case UserInputData::KEY_DATA:
maybeSendKeyEvent(data.key.scanCode,
data.action == AKEY_EVENT_ACTION_DOWN,
data.timeMs);
break;
}
}
static void
keyHandler(int fd, FdHandler *data)
void
GeckoInputDispatcher::notifyConfigurationChanged(nsecs_t eventTime)
{
input_event events[16];
ssize_t bytesRead = read(fd, events, sizeof(events));
if (bytesRead < 0) {
LOG("Error reading in keyHandler");
return;
}
static uint64_t
nanosecsToMillisecs(nsecs_t nsecs)
{
return nsecs / 1000000;
}
void
GeckoInputDispatcher::notifyKey(nsecs_t eventTime,
int32_t deviceId,
int32_t source,
uint32_t policyFlags,
int32_t action,
int32_t flags,
int32_t keyCode,
int32_t scanCode,
int32_t metaState,
nsecs_t downTime)
{
UserInputData data;
data.timeMs = nanosecsToMillisecs(eventTime);
data.type = UserInputData::KEY_DATA;
data.action = action;
data.flags = flags;
data.metaState = metaState;
data.key.keyCode = keyCode;
data.key.scanCode = scanCode;
{
MutexAutoLock lock(mQueueLock);
mEventQueue.push(data);
}
MOZ_ASSERT(bytesRead % sizeof(input_event) == 0);
gAppShell->NotifyNativeEvent();
}
for (unsigned int i = 0; i < bytesRead / sizeof(struct input_event); i++) {
const input_event &e = events[i];
if (e.type == EV_SYN) {
// Ignore this event; it just signifies that a key was pressed.
continue;
}
maybeSendKeyEvent(e);
void
GeckoInputDispatcher::notifyMotion(nsecs_t eventTime,
int32_t deviceId,
int32_t source,
uint32_t policyFlags,
int32_t action,
int32_t flags,
int32_t metaState,
int32_t edgeFlags,
uint32_t pointerCount,
const int32_t* pointerIds,
const PointerCoords* pointerCoords,
float xPrecision,
float yPrecision,
nsecs_t downTime)
{
UserInputData data;
data.timeMs = nanosecsToMillisecs(eventTime);
data.type = UserInputData::MOTION_DATA;
data.action = action;
data.flags = flags;
data.metaState = metaState;
data.motion.coords = *pointerCoords;
{
MutexAutoLock lock(mQueueLock);
mEventQueue.push(data);
}
gAppShell->NotifyNativeEvent();
}
void
GeckoInputDispatcher::notifySwitch(nsecs_t when,
int32_t switchCode,
int32_t switchValue,
uint32_t policyFlags)
{
}
int32_t
GeckoInputDispatcher::injectInputEvent(const InputEvent* event,
int32_t injectorPid,
int32_t injectorUid,
int32_t syncMode,
int32_t timeoutMillis)
{
return INPUT_EVENT_INJECTION_SUCCEEDED;
}
void
GeckoInputDispatcher::setInputWindows(const Vector<InputWindow>& inputWindows)
{
}
void
GeckoInputDispatcher::setFocusedApplication(const InputApplication* inputApplication)
{
}
void
GeckoInputDispatcher::setInputDispatchMode(bool enabled, bool frozen)
{
}
status_t
GeckoInputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel,
bool monitor)
{
return OK;
}
status_t
GeckoInputDispatcher::unregisterInputChannel(const sp<InputChannel>& inputChannel)
{
return OK;
}
nsAppShell::nsAppShell()
@ -551,6 +572,9 @@ nsAppShell::nsAppShell()
nsAppShell::~nsAppShell()
{
status_t result = mReaderThread->requestExitAndWait();
if (result)
LOG("Could not stop reader thread - %d", result);
gAppShell = NULL;
}
@ -569,52 +593,15 @@ nsAppShell::Init()
rv = AddFdHandler(signalfds[0], pipeHandler, "");
NS_ENSURE_SUCCESS(rv, rv);
DIR *dir = opendir("/dev/input");
NS_ENSURE_TRUE(dir, NS_ERROR_UNEXPECTED);
mEventHub = new EventHub();
mReaderPolicy = new GeckoInputReaderPolicy();
mDispatcher = new GeckoInputDispatcher();
#define IS_BIT_SET(bit, flags) (flags[bit >> 3] & (1 << (bit & 0x7)))
struct dirent *entry;
while ((entry = readdir(dir))) {
char entryName[64];
char entryPath[MAXPATHLEN];
if (snprintf(entryPath, sizeof(entryPath),
"/dev/input/%s", entry->d_name) < 0) {
LOG("Couldn't generate path while enumerating input devices!");
continue;
}
int fd = open(entryPath, O_RDONLY);
if (ioctl(fd, EVIOCGNAME(sizeof(entryName)), entryName) >= 0)
LOG("Found device %s - %s", entry->d_name, entryName);
else
continue;
FdHandlerCallback handlerFunc = NULL;
char flags[(NS_MAX(ABS_MAX, KEY_MAX) + 1) / 8];
if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(flags)), flags) >= 0 &&
IS_BIT_SET(ABS_MT_POSITION_X, flags)) {
LOG("Found multitouch input device");
handlerFunc = multitouchHandler;
} else if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(flags)), flags) >= 0 &&
IS_BIT_SET(ABS_X, flags)) {
LOG("Found single touch input device");
handlerFunc = singleTouchHandler;
} else if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(flags)), flags) >= 0) {
LOG("Found key input device");
handlerFunc = keyHandler;
}
// Register the handler, if we have one.
if (!handlerFunc)
continue;
rv = AddFdHandler(fd, handlerFunc, entryName);
if (NS_FAILED(rv))
LOG("Failed to add fd to epoll fd");
}
mReader = new InputReader(mEventHub, mReaderPolicy, mDispatcher);
mReaderThread = new InputReaderThread(mReader);
status_t result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
NS_ENSURE_FALSE(result, NS_ERROR_UNEXPECTED);
return rv;
}
@ -655,6 +642,8 @@ nsAppShell::ProcessNextNativeEvent(bool mayWait)
for (int i = 0; i < event_count; i++)
mHandlers[events[i].data.u32].run();
mDispatcher->dispatchOnce();
// NativeEventCallback always schedules more if it needs it
// so we can coalesce these.
// See the implementation in nsBaseAppShell.cpp for more info

View File

@ -38,10 +38,15 @@
#ifndef nsAppShell_h
#define nsAppShell_h
#include <queue>
#include "mozilla/Mutex.h"
#include "nsBaseAppShell.h"
#include "nsRect.h"
#include "nsTArray.h"
#include "utils/RefBase.h"
namespace mozilla {
bool ProcessNextEvent();
void NotifyEvent();
@ -55,10 +60,6 @@ typedef void(*FdHandlerCallback)(int, FdHandler *);
class FdHandler {
public:
FdHandler()
: mtState(MT_START)
, keyCode(0)
, mtDown(false)
, calibrated(false)
{
memset(name, 0, sizeof(name));
}
@ -66,57 +67,21 @@ public:
int fd;
char name[64];
FdHandlerCallback func;
enum mtStates {
MT_START,
MT_COLLECT,
MT_IGNORE
} mtState;
int mtX, mtY;
int mtMajor;
int keyCode;
bool mtDown;
// FIXME/bug 712973: we should be using libui here instead of
// recreating all that logic ourselves. Please don't extend the
// hacks here further than what's below.
bool calibrated;
// Multitouch events are delivered to us in "input space", which
// is a coordinate space defined by the multitouch device driver.
// The coordinate space has top-left at P_min = <inputMinX,
// inputMinY> when in normal-portrait orientation. The input
// device and the screen might have different resolutions. The
// resolution difference is Scale = <inputToScreenScaleX,
// inputToScreenScaleY>. So going from input to screen space
// (when in normal portrait orientation) is an affine transform
// defined by
//
// P_screen = Scale * (P_input - P_min)
//
int inputMinX, inputMinY;
float inputToScreenScaleX, inputToScreenScaleY;
// Some touch devices use virtual buttons instead of hardware
// buttons. When the device uses vbuttons, we convert touch
// events into key events of type |keyCode| when the start of the
// touch is within |buttonRect|. |buttonRect| must be disjoint
// from the screen rect.
static const size_t kMaxVButtons = 4;
struct VButton {
nsIntRect buttonRect; // in screen space
int keyCode;
} vbuttons[kMaxVButtons];
void run()
{
func(fd, this);
}
int inputXToScreenX(int inputX) {
return inputToScreenScaleX * (inputX - inputMinX);
}
int inputYToScreenY(int inputY) {
return inputToScreenScaleY * (inputY - inputMinY);
}
};
namespace android {
class EventHub;
class InputReader;
class InputReaderThread;
}
class GeckoInputReaderPolicy;
class GeckoInputDispatcher;
class nsAppShell : public nsBaseAppShell {
public:
nsAppShell();
@ -138,6 +103,12 @@ private:
// This is somewhat racy but is perfectly safe given how the callback works
bool mNativeCallbackRequest;
nsTArray<FdHandler> mHandlers;
android::sp<android::EventHub> mEventHub;
android::sp<GeckoInputReaderPolicy> mReaderPolicy;
android::sp<GeckoInputDispatcher> mDispatcher;
android::sp<android::InputReader> mReader;
android::sp<android::InputReaderThread> mReaderThread;
};
#endif /* nsAppShell_h */