blob: 7df820e34295b7177973e2675c8c7496dcc6d16f [file] [log] [blame]
/* Copyright (C) 2010 The Android Open Source Project
**
** This software is licensed under the terms of the GNU General Public
** License version 2, as published by the Free Software Foundation, and
** may be copied, distributed, and modified under those terms.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
*/
/*
* Contains the Core-side of the "user events" service. Here we receive and
* handle user events sent from the UI.
*/
#include "user-events.h"
#include "android/globals.h"
#include "android/android.h"
#include "android/looper.h"
#include "android/async-utils.h"
#include "android/sync-utils.h"
#include "android/utils/system.h"
#include "android/utils/debug.h"
#include "android/protocol/user-events-protocol.h"
#include "android/protocol/user-events-impl.h"
/* Enumerates state values for the event reader in the UserEventsImpl descriptor.
*/
typedef enum UserEventsImplState {
/* The reader is waiting on event header. */
EXPECTS_HEADER,
/* The reader is waiting on event parameters. */
EXPECTS_PARAMETERS,
} UserEventsImplState;
/* Core user events service descriptor. */
typedef struct UserEventsImpl {
/* Reader to receive user events. */
AsyncReader user_events_reader;
/* I/O associated with this descriptor. */
LoopIo io;
/* Looper used to communicate user events. */
Looper* looper;
/* Socket for this service. */
int sock;
/* State of the service (see UE_STATE_XXX for possible values). */
UserEventsImplState state;
/* Current event header. */
UserEventHeader event_header;
/* Current event parameters. */
union {
UserEventGeneric generic_event;
UserEventMouse mouse_event;
UserEventKeycode keycode_event;
};
} UserEventsImpl;
/* Implemented in android/console.c */
extern void destroy_user_events_client(void);
/* One and only one UserEventsImpl instance. */
static UserEventsImpl _UserEventsImpl;
/* Asynchronous I/O callback reading user events.
* Param:
* opaque - UserEventsImpl instance.
*/
static void
_userEventsImpl_io_func(void* opaque, int fd, unsigned events)
{
UserEventsImpl* ueimpl;
AsyncStatus status;
if (events & LOOP_IO_WRITE) {
// We don't use async writer here, so we don't expect
// any write callbacks.
derror("Unexpected LOOP_IO_WRITE in _userEventsImpl_io_func\n");
return;
}
ueimpl = (UserEventsImpl*)opaque;
// Read whatever is expected from the socket.
status = asyncReader_read(&ueimpl->user_events_reader);
switch (status) {
case ASYNC_COMPLETE:
switch (ueimpl->state) {
case EXPECTS_HEADER:
// We just read event header. Now we expect event parameters.
ueimpl->state = EXPECTS_PARAMETERS;
// Setup the reader depending on the event type.
switch (ueimpl->event_header.event_type) {
case AUSER_EVENT_MOUSE:
asyncReader_init(&ueimpl->user_events_reader,
&ueimpl->mouse_event,
sizeof(ueimpl->mouse_event),
&ueimpl->io);
break;
case AUSER_EVENT_KEYCODE:
asyncReader_init(&ueimpl->user_events_reader,
&ueimpl->keycode_event,
sizeof(ueimpl->keycode_event),
&ueimpl->io);
break;
case AUSER_EVENT_GENERIC:
asyncReader_init(&ueimpl->user_events_reader,
&ueimpl->generic_event,
sizeof(ueimpl->generic_event),
&ueimpl->io);
break;
default:
derror("Unexpected user event type %d\n",
ueimpl->event_header.event_type);
break;
}
break;
case EXPECTS_PARAMETERS:
// We just read event parameters. Lets fire the event.
switch (ueimpl->event_header.event_type) {
case AUSER_EVENT_MOUSE:
user_event_mouse(ueimpl->mouse_event.dx,
ueimpl->mouse_event.dy,
ueimpl->mouse_event.dz,
ueimpl->mouse_event.buttons_state);
break;
case AUSER_EVENT_KEYCODE:
user_event_keycode(ueimpl->keycode_event.keycode);
break;
case AUSER_EVENT_GENERIC:
user_event_generic(ueimpl->generic_event.type,
ueimpl->generic_event.code,
ueimpl->generic_event.value);
break;
default:
derror("Unexpected user event type %d\n",
ueimpl->event_header.event_type);
break;
}
// Prepare to receive the next event header.
ueimpl->event_header.event_type = -1;
ueimpl->state = EXPECTS_HEADER;
asyncReader_init(&ueimpl->user_events_reader,
&ueimpl->event_header,
sizeof(ueimpl->event_header), &ueimpl->io);
break;
}
break;
case ASYNC_ERROR:
loopIo_dontWantRead(&ueimpl->io);
if (errno == ECONNRESET) {
// UI has exited. We need to destroy user event service.
destroy_user_events_client();
} else {
derror("User event read error %d -> %s\n", errno, errno_str);
}
break;
case ASYNC_NEED_MORE:
// Transfer will eventually come back into this routine.
return;
}
}
int
userEventsImpl_create(int fd)
{
_UserEventsImpl.sock = fd;
_UserEventsImpl.event_header.event_type = -1;
_UserEventsImpl.state = EXPECTS_HEADER;
_UserEventsImpl.looper = looper_newCore();
loopIo_init(&_UserEventsImpl.io, _UserEventsImpl.looper, _UserEventsImpl.sock,
_userEventsImpl_io_func, &_UserEventsImpl);
asyncReader_init(&_UserEventsImpl.user_events_reader,
&_UserEventsImpl.event_header,
sizeof(_UserEventsImpl.event_header), &_UserEventsImpl.io);
return 0;
}
void
userEventsImpl_destroy(void)
{
if (_UserEventsImpl.looper != NULL) {
// Stop all I/O that may still be going on.
loopIo_done(&_UserEventsImpl.io);
looper_free(_UserEventsImpl.looper);
_UserEventsImpl.looper = NULL;
}
}