mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 712973 - Use InputReader from libui in gonk widget backend, r=cjones
This commit is contained in:
parent
c2c5ac8482
commit
ea2588584c
@ -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
|
||||
|
@ -425,6 +425,7 @@ OS_LIBS += \
|
||||
-lmedia \
|
||||
-lhardware_legacy \
|
||||
-lhardware \
|
||||
-lutils \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user