Some work on the input_server:

* Rewrote event handling: instead of writing every single device message to
  the event port, they are just queued in a list, and the event loop is only
  notified if necessary (ie. if a notification has been sent already, new
  events are just queued up until the input_server found the time to process
  them).
* This also fixed a big memory leak: every message processed by EnqueueDeviceMessage()
  (IOW every key or mouse event) was leaked!
* no longer abuses gInputMethodListLocker to lock the method event queue
  (it now uses the standard event queue lock).
* removed the completely superfluous, weird and decelerating event caching mechanism
* tried to find a better distribution of work between _SanitizeEvents(),
  _MethodizeEvents(), and _DispatchEvents().
* HandleSetMousePosition() now only does what it's supposed to do (this currently
  causes the mouse to jump at the start, though).
* now uses the "Message4" for message sending if available.
* fixed "kb_mouse_settings.h" to include all headers it needs.
* some more cleanup.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@14966 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2005-11-16 17:25:58 +00:00
parent 6d865282d4
commit 128ddaa3e3
6 changed files with 530 additions and 529 deletions
+14 -21
View File
@@ -1,41 +1,34 @@
//
// kb_mouse_settings.h
//
/*
* Copyright 2001-2005, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef _KB_MOUSE_SETTINGS_H
#define _KB_MOUSE_SETTINGS_H
#include <SupportDefs.h>
#ifdef __cplusplus
extern "C" {
#endif
#include <InterfaceDefs.h>
typedef struct {
bigtime_t key_repeat_delay;
int32 key_repeat_rate;
bigtime_t key_repeat_delay;
int32 key_repeat_rate;
} kb_settings;
#define kb_settings_file "Keyboard_settings"
typedef struct {
bool enabled;
int32 accel_factor;
int32 speed;
bool enabled;
int32 accel_factor;
int32 speed;
} mouse_accel;
typedef struct {
int32 type;
mouse_map map;
mouse_accel accel;
bigtime_t click_speed;
mouse_accel accel;
bigtime_t click_speed;
} mouse_settings;
#define mouse_settings_file "Mouse_settings"
#ifdef __cplusplus
}
#endif
#endif
#endif /* _KB_MOUSE_SETTINGS_H */
+46 -52
View File
@@ -1,34 +1,30 @@
// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
//
// Copyright (c) 2004, Haiku
//
// This software is part of the Haiku distribution and is covered
// by the Haiku license.
//
//
// File: BottomlineWindow.cpp
// Author: Jérôme Duval
// Description: Input server bottomline window
// Created : January 24, 2005
//
// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
/*
* Copyright 2004-2005, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Jérôme Duval
*/
#include "BottomlineWindow.h"
#include "InputServer.h"
#include "WindowPrivate.h"
BottomlineWindow::BottomlineWindow(const BFont *font)
: BWindow(BRect(0,0,350,16), "",
kLeftTitledWindowLook,
B_FLOATING_ALL_WINDOW_FEEL,
B_NOT_V_RESIZABLE | B_NOT_CLOSABLE |
B_NOT_ZOOMABLE | B_NOT_MINIMIZABLE | B_AVOID_FOCUS |
B_WILL_ACCEPT_FIRST_CLICK)
#include <TextView.h>
BottomlineWindow::BottomlineWindow()
: BWindow(BRect(0, 0, 350, 16), "",
kLeftTitledWindowLook,
B_FLOATING_ALL_WINDOW_FEEL,
B_NOT_V_RESIZABLE | B_NOT_CLOSABLE | B_NOT_ZOOMABLE | B_NOT_MINIMIZABLE
| B_AVOID_FOCUS | B_WILL_ACCEPT_FIRST_CLICK)
{
BRect textRect = Bounds();
textRect.OffsetTo(B_ORIGIN);
textRect.InsetBy(2,2);
fTextView = new BTextView(Bounds(), "", textRect, font, NULL, B_FOLLOW_ALL, B_WILL_DRAW | B_FRAME_EVENTS);
fTextView = new BTextView(Bounds(), "", textRect, be_plain_font,
NULL, B_FOLLOW_ALL, B_WILL_DRAW | B_FRAME_EVENTS);
AddChild(fTextView);
fTextView->SetText("");
@@ -73,45 +69,43 @@ BottomlineWindow::QuitRequested()
void
BottomlineWindow::HandleInputMethodEvent(BMessage *msg, BList *list)
BottomlineWindow::HandleInputMethodEvent(BMessage* event, EventList& newEvents)
{
CALLED();
PostMessage(msg, fTextView);
PostMessage(event, fTextView);
int32 opcode = -1;
const char* string = NULL;
msg->FindInt32("be:opcode", &opcode);
msg->FindString("be:string", &string);
const char* string;
bool confirmed;
int32 opcode;
if (event->FindInt32("be:opcode", &opcode) != B_OK
|| opcode != B_INPUT_METHOD_CHANGED
|| event->FindBool("be:confirmed", &confirmed) != B_OK
|| !confirmed
|| event->FindString("be:string", &string) != B_OK)
return;
SERIAL_PRINT(("IME : %i, %s\n", opcode, string));
if (opcode != B_INPUT_METHOD_CHANGED)
return;
bool confirmed = false;
if ((msg->FindBool("be:confirmed", &confirmed) != B_OK)
|| !confirmed)
return;
SERIAL_PRINT(("IME : confirmed\n"));
if (string != NULL) {
int32 offset = 0;
int32 length = strlen(string);
int32 next_offset = 0;
while (offset < length) {
for (++next_offset; (string[next_offset] & 0xC0) == 0x80; ++next_offset)
;
int32 length = strlen(string);
int32 offset = 0;
int32 nextOffset = 0;
BMessage *newmsg = new BMessage(B_KEY_DOWN);
newmsg->AddInt32("key", 0);
newmsg->AddInt64("when", system_time());
newmsg->AddData("bytes", B_STRING_TYPE, string + offset, next_offset - offset);
list->AddItem(newmsg);
offset = next_offset;
while (offset < length) {
// this is supposed to go to the next UTF-8 character
for (++nextOffset; (string[nextOffset] & 0xC0) == 0x80; ++nextOffset)
;
BMessage *newEvent = new BMessage(B_KEY_DOWN);
if (newEvent != NULL) {
newEvent->AddInt32("key", 0);
newEvent->AddInt64("when", system_time());
newEvent->AddData("bytes", B_STRING_TYPE, string + offset, nextOffset - offset);
newEvents.AddItem(newEvent);
}
offset = nextOffset;
}
}
+26 -30
View File
@@ -1,38 +1,34 @@
// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
//
// Copyright (c) 2005, Haiku
//
// This software is part of the Haiku distribution and is covered
// by the Haiku license.
//
//
// File: TMWindow.h
// Author: Jérôme Duval
// Description: Input server bottomline window
// Created : January 24, 2005
//
// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
/*
* Copyright 2004-2005, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Jérôme Duval
*/
#ifndef BOTTOMLINE_WINDOW_H
#define BOTTOMLINE_WINDOW_H
#ifndef BOTTOMLINEWINDOW_H
#define BOTTOMLINEWINDOW_H
#include "InputServer.h"
#include <Message.h>
#include <TextView.h>
#include <Window.h>
class BottomlineWindow : public BWindow
{
public:
BottomlineWindow(const BFont *font);
~BottomlineWindow();
void MessageReceived(BMessage *msg);
virtual bool QuitRequested();
class BTextView;
void HandleInputMethodEvent(BMessage *msg, BList *list);
//private:
BTextView *fTextView;
class BottomlineWindow : public BWindow {
public:
BottomlineWindow();
virtual ~BottomlineWindow();
virtual void MessageReceived(BMessage* message);
virtual bool QuitRequested();
void HandleInputMethodEvent(BMessage* event, EventList& newEvents);
private:
BTextView *fTextView;
};
#endif //BOTTOMLINEWINDOW_H
#endif // BOTTOMLINE_WINDOW_H
+417 -397
View File
@@ -6,10 +6,12 @@
#include "InputServer.h"
#include "InputServerTypes.h"
#include "BottomlineWindow.h"
#include "kb_mouse_driver.h"
#include "MethodReplicant.h"
#include <AppServerLink.h>
#include <MessagePrivate.h>
#include <Autolock.h>
#include <Deskbar.h>
@@ -38,11 +40,11 @@
// received from app_server when screen res changed, but could be sent to too.
#ifdef COMPILE_FOR_R5
extern "C" status_t _kget_safemode_option_(const char *parameter,
#ifdef HAIKU_TARGET_PLATFORM_HAIKU
extern "C" status_t _kern_get_safemode_option(const char *parameter,
char *buffer, size_t *_bufferSize);
#else
extern "C" status_t _kern_get_safemode_option(const char *parameter,
extern "C" status_t _kget_safemode_option_(const char *parameter,
char *buffer, size_t *_bufferSize);
#endif
@@ -140,8 +142,8 @@ InputServer::InputServer()
fInputDeviceListLocker("input server device list"),
fChars(NULL),
fScreen(B_MAIN_SCREEN_ID),
fBLWindow(NULL),
fIMAware(false),
fInputMethodWindow(NULL),
fInputMethodAware(false),
fCursorSem(-1),
fAppServerPort(-1),
fCursorArea(-1)
@@ -154,15 +156,15 @@ InputServer::InputServer()
CALLED();
gInputServer = this;
EventLoop();
_StartEventLoop();
char parameter[32];
size_t parameterLength = sizeof(parameter);
#ifdef COMPILE_FOR_R5
if (_kget_safemode_option_(B_SAFEMODE_SAFE_MODE, parameter, &parameterLength) == B_OK)
#else
#ifdef HAIKU_TARGET_PLATFORM_HAIKU
if (_kern_get_safemode_option(B_SAFEMODE_SAFE_MODE, parameter, &parameterLength) == B_OK)
#else
if (_kget_safemode_option_(B_SAFEMODE_SAFE_MODE, parameter, &parameterLength) == B_OK)
#endif
{
if (!strcasecmp(parameter, "enabled") || !strcasecmp(parameter, "on")
@@ -760,79 +762,25 @@ InputServer::HandleGetSetMouseSpeed(BMessage* message, BMessage* reply)
status_t
InputServer::HandleSetMousePosition(BMessage* message, BMessage* outbound)
InputServer::HandleSetMousePosition(BMessage* message, BMessage* reply)
{
CALLED();
// this assumes that both supplied pointers are identical
BPoint where;
if (message->FindPoint("where", &where) != B_OK)
return B_BAD_VALUE;
ASSERT(outbound == message);
// create a new event for this and enqueue it to the event list just like any other
int32 xValue, yValue;
BMessage* event = new BMessage(B_MOUSE_MOVED);
if (event == NULL)
return B_NO_MEMORY;
switch (message->what) {
case B_MOUSE_MOVED:
case B_MOUSE_DOWN:
case B_MOUSE_UP:
case FAST_MOUSE_MOVED:
// get point and button from msg
if ((outbound->FindInt32("x", &xValue) == B_OK)
&& (outbound->FindInt32("y", &yValue) == B_OK)) {
fMousePos.x += xValue;
fMousePos.y -= yValue;
fMousePos.ConstrainTo(fFrame);
outbound->RemoveName("x");
outbound->RemoveName("y");
outbound->AddPoint("where", fMousePos);
outbound->AddInt32("modifiers", fKeyInfo.modifiers);
PRINT(("new position : %f, %f, %ld, %ld\n", fMousePos.x, fMousePos.y, xValue, yValue));
} else if (outbound->FindPoint("where", &fMousePos) == B_OK) {
outbound->RemoveName("where");
fMousePos.ConstrainTo(fFrame);
outbound->AddPoint("where", fMousePos);
outbound->AddInt32("modifiers", fKeyInfo.modifiers);
PRINT(("new position : %f, %f\n", fMousePos.x, fMousePos.y));
}
if (fCursorBuffer) {
#ifndef HAIKU_TARGET_PLATFORM_HAIKU
fCursorBuffer[0] = (0x3 << 30L)
| ((uint32)fMousePos.x & 0x7fff) << 15
| ((uint32)fMousePos.y & 0x7fff);
PRINT(("released cursorSem with value : %08lx\n", fCursorBuffer[0]));
release_sem(fCursorSem);
#else
atomic_set((int32*)&fCursorBuffer->pos, (uint32)fMousePos.x << 16UL
| ((uint32)fMousePos.y & 0xffff));
if (atomic_or(&fCursorBuffer->read, 1) == 0)
release_sem_etc(fCursorSem, 0, B_RELEASE_ALL);
#endif
}
break;
// some Key Down and up codes ..
case B_KEY_DOWN:
case B_KEY_UP:
case B_UNMAPPED_KEY_DOWN:
case B_UNMAPPED_KEY_UP:
case B_MODIFIERS_CHANGED:
{
ssize_t size = 0;
uint8 *data = NULL;
outbound->FindInt32("modifiers", (int32*)&fKeyInfo.modifiers);
if (outbound->FindData("states", B_UINT8_TYPE,
(const void**)&data, &size) == B_OK
&& size == (ssize_t)sizeof(fKeyInfo.key_states)) {
PRINT(("updated keyinfo\n"));
memcpy(fKeyInfo.key_states, data, size);
}
PRINT(("keyinfo %ld %ld\n", size, (ssize_t)sizeof(fKeyInfo.key_states)));
break;
}
default:
break;
event->AddPoint("where", where);
event->AddBool("be:set_mouse", true);
if (EnqueueDeviceMessage(event) != B_OK) {
delete event;
return B_NO_MEMORY;
}
return B_OK;
@@ -938,34 +886,41 @@ InputServer::HandleFocusUnfocusIMAwareView(BMessage* message,
if (message->what == IS_FOCUS_IM_AWARE_VIEW) {
PRINT(("HandleFocusUnfocusIMAwareView : entering\n"));
fIMAware = true;
fInputMethodAware = true;
} else {
PRINT(("HandleFocusUnfocusIMAwareView : leaving\n"));
fIMAware = false;
fInputMethodAware = false;
}
return B_OK;
}
/** Enqueues the message into the event queue.
* The message must only be deleted in case this method returns an error.
*/
status_t
InputServer::EnqueueDeviceMessage(BMessage* message)
{
CALLED();
// TODO: message is not deleted???
// TODO: why use ports for in-house messaging???
BAutolock _(fEventQueueLock);
if (!fEventQueue.AddItem(message))
return B_NO_MEMORY;
ssize_t length = message->FlattenedSize();
char buffer[length];
status_t err;
if ((err = message->Flatten(buffer,length)) < B_OK)
return err;
return write_port(fEventLooperPort, 0, buffer, length);
if (fEventQueue.CountItems() == 1) {
// notify event loop only if we haven't already done so
write_port_etc(fEventLooperPort, 1, NULL, 0, B_RELATIVE_TIMEOUT, 0);
}
return B_OK;
}
/** Enqueues the message into the method queue.
* The message must only be deleted in case this method returns an error.
*/
status_t
InputServer::EnqueueMethodMessage(BMessage* message)
{
@@ -981,27 +936,14 @@ InputServer::EnqueueMethodMessage(BMessage* message)
}
#endif
LockMethodQueue();
fMethodQueue.AddItem(message);
UnlockMethodQueue();
BAutolock _(fEventQueueLock);
if (!fMethodQueue.AddItem(message))
return B_NO_MEMORY;
write_port_etc(fEventLooperPort, 0, NULL, 0, B_RELATIVE_TIMEOUT, 0);
return B_OK;
}
status_t
InputServer::UnlockMethodQueue()
{
gInputMethodListLocker.Unlock();
return B_OK;
}
status_t
InputServer::LockMethodQueue()
{
gInputMethodListLocker.Lock();
if (fMethodQueue.CountItems() == 1) {
// notify event loop only if we haven't already done so
write_port_etc(fEventLooperPort, 0, NULL, 0, B_RELATIVE_TIMEOUT, 0);
}
return B_OK;
}
@@ -1009,7 +951,7 @@ InputServer::LockMethodQueue()
status_t
InputServer::SetNextMethod(bool direction)
{
LockMethodQueue();
gInputMethodListLocker.Lock();
int32 index = gInputMethodList.IndexOf(fActiveMethod);
index += (direction ? 1 : -1);
@@ -1026,7 +968,7 @@ InputServer::SetNextMethod(bool direction)
SetActiveMethod(method);
UnlockMethodQueue();
gInputMethodListLocker.Unlock();
return B_OK;
}
@@ -1059,31 +1001,6 @@ InputServer::SetMethodReplicant(const BMessenger* messenger)
}
status_t
InputServer::EventLoop()
{
CALLED();
fEventLooperPort = create_port(100, "input server event loop");
if (fEventLooperPort < 0) {
PRINTERR(("InputServer: create_port error: (0x%x) %s\n",
fEventLooperPort, strerror(fEventLooperPort)));
return fEventLooperPort;
}
thread_id thread = spawn_thread(_PortWatcher, "_input_server_event_loop_",
B_REAL_TIME_DISPLAY_PRIORITY + 3, this);
if (thread < B_OK || resume_thread(thread) < B_OK) {
if (thread >= B_OK)
kill_thread(thread);
delete_port(fEventLooperPort);
fEventLooperPort = -1;
return thread < B_OK ? thread : B_ERROR;
}
return B_OK;
}
bool
InputServer::EventLoopRunning()
{
@@ -1091,241 +1008,6 @@ InputServer::EventLoopRunning()
}
bool
InputServer::DispatchEvents(BList* eventList)
{
CALLED();
CacheEvents(eventList);
if (fEventsCache.CountItems() > 0) {
BMessage* event;
for (int32 i = 0; NULL != (event = (BMessage *)fEventsCache.ItemAt(i)); i++) {
// now we must send each event to the app_server
if (event->what == B_INPUT_METHOD_EVENT && !fIMAware) {
SERIAL_PRINT(("IME received\n"));
int32 opcode = -1;
event->FindInt32("be:opcode", &opcode);
BList events;
if (!fBLWindow && opcode == B_INPUT_METHOD_STARTED)
fBLWindow = new BottomlineWindow(be_plain_font);
if (fBLWindow) {
fBLWindow->HandleInputMethodEvent(event, &events);
if (!events.IsEmpty()) {
fBLWindow->PostMessage(B_QUIT_REQUESTED);
fBLWindow = NULL;
fEventsCache.AddList(&events);
}
}
} else
DispatchEvent(event);
delete event;
}
fEventsCache.MakeEmpty();
}
return true;
}
status_t
InputServer::DispatchEvent(BMessage* message)
{
CALLED();
switch (message->what) {
case B_KEY_DOWN:
case B_KEY_UP:
case B_UNMAPPED_KEY_UP:
case B_UNMAPPED_KEY_DOWN: {
uint32 modifiers;
ssize_t size;
uint8 *data;
if (message->FindData("states", B_UINT8_TYPE, (const void**)&data, &size) != B_OK)
message->AddData("states", B_UINT8_TYPE, fKeyInfo.key_states, 16);
if (message->FindInt32("modifiers", (int32*)&modifiers) != B_OK)
message->AddInt32("modifiers", fKeyInfo.modifiers);
break;
}
}
ssize_t length = message->FlattenedSize();
char buffer[length];
status_t err;
if ((err = message->Flatten(buffer,length)) < B_OK)
return err;
if (fAppServerPort > 0)
write_port(fAppServerPort, 0, buffer, length);
return B_OK;
}
bool
InputServer::CacheEvents(BList* eventsToCache)
{
CALLED();
SanitizeEvents(eventsToCache);
MethodizeEvents(eventsToCache, true);
FilterEvents(eventsToCache);
fEventsCache.AddList(eventsToCache);
eventsToCache->MakeEmpty();
return true;
}
const BList*
InputServer::GetNextEvents(BList *)
{
return NULL;
}
/** This method applies all defined filters to each event in the
* supplied list. The supplied list is modified to reflect the
* output of the filters.
* The method returns true if the filters were applied to all
* events without error and false otherwise.
*/
bool
InputServer::FilterEvents(BList* eventsToFilter)
{
CALLED();
if (NULL == eventsToFilter)
return false;
BInputServerFilter* currentFilter;
int32 filterIndex = 0;
while ((currentFilter = (BInputServerFilter*)gInputFilterList.ItemAt(filterIndex)) != NULL) {
// Apply the current filter to all available event messages.
int32 eventIndex = 0;
BMessage *currentEvent;
while ((currentEvent = (BMessage*)eventsToFilter->ItemAt(eventIndex)) != NULL) {
// Storage for new event messages generated by the filter.
BList outList;
// Apply the current filter to the current event message.
PRINT(("InputServer::FilterEvents Filter called\n"));
filter_result result = currentFilter->Filter(currentEvent, &outList);
if (result == B_SKIP_MESSAGE) {
// Use the result in out_list (if any); ignore current message.
eventsToFilter->RemoveItem(eventIndex);
eventsToFilter->AddList(&outList, eventIndex);
eventIndex += outList.CountItems();
// NOTE: eventsToFilter now owns outList's items.
} else {
// Free resources associated with items in outList.
void* outItem;
for (int32 i = 0; (outItem = outList.ItemAt(i)) != NULL; i++) {
delete (BMessage*)outItem;
}
}
if (result == B_DISPATCH_MESSAGE) {
// Use the result in current_message; ignore outList.
eventIndex++;
} else {
// Error
return false;
}
}
filterIndex++;
}
return true;
}
bool
InputServer::SanitizeEvents(BList* events)
{
CALLED();
int32 index = 0;
BMessage *event;
PRINT(("SanitizeEvents: %ld \n", events->CountItems()));
while ((event = (BMessage*)events->ItemAt(index)) != NULL) {
PRINT(("SanitizeEvents: what:%lx\n", event->what));
switch (event->what) {
case B_KEY_DOWN:
case B_UNMAPPED_KEY_DOWN:
// we scan for Alt+Space key down events which means we change to next input method
// Note : Shift+Alt+Space key allows to change to the previous input method
PRINT(("SanitizeEvents: %lx, %lx\n", fKeyInfo.modifiers,
fKeyInfo.key_states[KEY_Spacebar >> 3]));
if ((fKeyInfo.modifiers & B_COMMAND_KEY) != 0
&& (fKeyInfo.key_states[KEY_Spacebar >> 3]
& (1 << (7 - (KEY_Spacebar % 8))))) {
SetNextMethod(!fKeyInfo.modifiers & B_SHIFT_KEY);
// this event isn't sent to the user
events->RemoveItem(index);
delete event;
continue;
}
break;
}
index++;
}
return true;
}
bool
InputServer::MethodizeEvents(BList* events, bool)
{
CALLED();
if (fActiveMethod) {
BList newList;
newList.AddList(&fMethodQueue);
fMethodQueue.MakeEmpty();
for (int32 i=0; i<events->CountItems(); i++) {
BMessage *item = (BMessage *)events->ItemAt(i);
BList filterList;
filter_result result = fActiveMethod->Filter(item, &filterList);
switch (result) {
case B_SKIP_MESSAGE:
delete item;
case B_DISPATCH_MESSAGE:
if (filterList.CountItems() > 0) {
newList.AddList(&filterList);
delete item;
} else
newList.AddItem(item);
}
newList.AddList(&fMethodQueue);
fMethodQueue.MakeEmpty();
}
events->MakeEmpty();
events->AddList(&newList);
}
return true;
}
/** The fInputDeviceListLocker must be locked when calling this function */
InputDeviceListItem*
@@ -1571,20 +1253,45 @@ InputServer::SafeMode()
}
int32
InputServer::_PortWatcher(void* arg)
status_t
InputServer::_StartEventLoop()
{
InputServer* self = (InputServer*)arg;
self->_WatchPort();
CALLED();
fEventLooperPort = create_port(100, "input server events");
if (fEventLooperPort < 0) {
PRINTERR(("InputServer: create_port error: (0x%x) %s\n",
fEventLooperPort, strerror(fEventLooperPort)));
return fEventLooperPort;
}
thread_id thread = spawn_thread(_EventLooper, "_input_server_event_loop_",
B_REAL_TIME_DISPLAY_PRIORITY + 3, this);
if (thread < B_OK || resume_thread(thread) < B_OK) {
if (thread >= B_OK)
kill_thread(thread);
delete_port(fEventLooperPort);
fEventLooperPort = -1;
return thread < B_OK ? thread : B_ERROR;
}
return B_OK;
}
void
InputServer::_WatchPort()
status_t
InputServer::_EventLooper(void* arg)
{
while (true) {
InputServer* self = (InputServer*)arg;
self->_EventLoop();
return B_OK;
}
void
InputServer::_EventLoop()
{
while (true) {
// Block until we find the size of the next message
ssize_t length = port_buffer_size(fEventLooperPort);
if (length < B_OK) {
@@ -1606,40 +1313,353 @@ InputServer::_WatchPort()
continue;
}
if (length == 0) {
BList list;
DispatchEvents(&list);
continue;
EventList events;
if (fEventQueueLock.Lock()) {
// move the items to our own list to block the event queue as short as possible
events.AddList(&fEventQueue);
fEventQueue.MakeEmpty();
fEventQueueLock.Unlock();
}
BMessage* event = new BMessage;
if (length > 0) {
BMessage* event = new BMessage;
if ((err = event->Unflatten(buffer)) < 0) {
PRINTERR(("[InputServer] Unflatten() error: (0x%lx) %s\n", err, strerror(err)));
delete event;
continue;
if ((err = event->Unflatten(buffer)) < 0) {
PRINTERR(("[InputServer] Unflatten() error: (0x%lx) %s\n", err, strerror(err)));
delete event;
}
events.AddItem(event);
}
// This is where the message should be processed.
// here we test for a message coming from app_server, screen resolution change could have happened
if (event->what == FAST_MOUSE_MOVED) {
BRect frame = fScreen.Frame();
if (frame != fFrame) {
fMousePos.x = fMousePos.x * frame.Width() / fFrame.Width();
fMousePos.y = fMousePos.y * frame.Height() / fFrame.Height();
fFrame = frame;
if (_SanitizeEvents(events)
&& _MethodizeEvents(events)
&& _FilterEvents(events))
_DispatchEvents(events);
}
}
/** Frees events from unwanted fields, adds missing fields, and removes
* unwanted events altogether.
* As a side effect, it will also update the internal mouse states.
*/
bool
InputServer::_SanitizeEvents(EventList& events)
{
CALLED();
int32 index = 0;
BMessage *event;
while ((event = (BMessage*)events.ItemAt(index)) != NULL) {
switch (event->what) {
case FAST_MOUSE_MOVED:
{
// here we test for a message coming from app_server,
// screen resolution change could have happened
BRect frame = fScreen.Frame();
if (frame != fFrame) {
fMousePos.x = fMousePos.x * frame.Width() / fFrame.Width();
fMousePos.y = fMousePos.y * frame.Height() / fFrame.Height();
fFrame = frame;
} else {
// TODO: discard event
}
event->what = B_MOUSE_MOVED;
event->AddPoint("where", fMousePos);
// supposed to fall through
}
case B_MOUSE_MOVED:
case B_MOUSE_DOWN:
{
int32 buttons;
if (event->FindInt32("buttons", &buttons) != B_OK)
event->AddInt32("buttons", 0);
// supposed to fall through
}
case B_MOUSE_UP:
{
BPoint where;
int32 x, y;
if (event->FindInt32("x", &x) == B_OK
&& event->FindInt32("y", &y) == B_OK) {
fMousePos.x += x;
fMousePos.y -= y;
fMousePos.ConstrainTo(fFrame);
event->RemoveName("x");
event->RemoveName("y");
event->AddPoint("where", fMousePos);
PRINT(("new position: %f, %f, %ld, %ld\n",
fMousePos.x, fMousePos.y, xValue, yValue));
} else if (event->FindPoint("where", &where) == B_OK) {
fMousePos = where;
fMousePos.ConstrainTo(fFrame);
event->ReplacePoint("where", fMousePos);
PRINT(("new position : %f, %f\n", fMousePos.x, fMousePos.y));
}
event->AddInt32("modifiers", fKeyInfo.modifiers);
break;
}
case B_KEY_DOWN:
case B_UNMAPPED_KEY_DOWN:
if (fActiveMethod == NULL)
break;
// we scan for Alt+Space key down events which means we change
// to next input method
// (pressing "shift" will let us switch to the previous method)
PRINT(("SanitizeEvents: %lx, %lx\n", fKeyInfo.modifiers,
fKeyInfo.key_states[KEY_Spacebar >> 3]));
if ((fKeyInfo.modifiers & B_COMMAND_KEY) != 0
&& (fKeyInfo.key_states[KEY_Spacebar >> 3]
& (1 << (7 - (KEY_Spacebar % 8))))) {
SetNextMethod(!fKeyInfo.modifiers & B_SHIFT_KEY);
// this event isn't sent to the user
events.RemoveItemAt(index);
delete event;
continue;
}
break;
}
HandleSetMousePosition(event, event);
index++;
}
BList list;
list.AddItem(event);
DispatchEvents(&list);
return true;
}
PRINT(("Event written to port\n"));
/** Applies the filters of the active input method to the
* incoming events. It will also move the events in the method
* queue to the event list.
*/
bool
InputServer::_MethodizeEvents(EventList& events)
{
CALLED();
if (fActiveMethod == NULL)
return true;
int32 count = events.CountItems();
for (int32 i = 0; i < count;) {
_FilterEvent(fActiveMethod, events, i, count);
}
if (!fInputMethodAware) {
// special handling for non-input-method-aware views
for (int32 i = 0; i < count; i++) {
BMessage* event = events.ItemAt(i);
if (event->what != B_INPUT_METHOD_EVENT)
continue;
SERIAL_PRINT(("IME received\n"));
int32 opcode;
if (fInputMethodWindow == NULL
&& event->FindInt32("be:opcode", &opcode) == B_OK
&& opcode == B_INPUT_METHOD_STARTED)
fInputMethodWindow = new (nothrow) BottomlineWindow();
if (fInputMethodWindow != NULL) {
EventList newEvents;
fInputMethodWindow->HandleInputMethodEvent(event, newEvents);
if (!newEvents.IsEmpty()) {
fInputMethodWindow->PostMessage(B_QUIT_REQUESTED);
fInputMethodWindow = NULL;
// replace event with new events (but don't scan them again
// for input method messages)
events.RemoveItemAt(i);
delete event;
events.AddList(&newEvents, i);
i += newEvents.CountItems() - 1;
count = events.CountItems();
}
}
}
}
// move the method events into the event queue - they are not
// "methodized" either
BAutolock _(fEventQueueLock);
events.AddList(&fMethodQueue);
fMethodQueue.MakeEmpty();
return events.CountItems() > 0;
}
/** This method applies all defined filters to each event in the
* supplied list. The supplied list is modified to reflect the
* output of the filters.
* The method returns true if the filters were applied to all
* events without error and false otherwise.
*/
bool
InputServer::_FilterEvents(EventList& events)
{
CALLED();
BAutolock _(gInputFilterListLocker);
int32 count = gInputFilterList.CountItems();
int32 eventCount = events.CountItems();
for (int32 i = 0; i < count; i++) {
BInputServerFilter* filter = (BInputServerFilter*)gInputFilterList.ItemAt(i);
// Apply the current filter to all available event messages.
for (int32 eventIndex = 0; eventIndex < eventCount;) {
_FilterEvent(filter, events, eventIndex, eventCount);
}
}
return eventCount != 0;
}
void
InputServer::_DispatchEvents(EventList& events)
{
CALLED();
int32 count = events.CountItems();
for (int32 i = 0; i < count; i++) {
BMessage* event = events.ItemAt(i);
// now we must send each event to the app_server
_DispatchEvent(event);
delete event;
}
events.MakeEmpty();
}
/** Applies the given filter to the event list.
* For your convenience, it also alters the \a index and \a count arguments
* ready for the next call to this method.
*/
void
InputServer::_FilterEvent(BInputServerFilter* filter, EventList& events,
int32& index, int32& count)
{
BMessage* event = events.ItemAt(index);
BList newEvents;
filter_result result = filter->Filter(event, &newEvents);
if (result == B_SKIP_MESSAGE || newEvents.CountItems() > 0) {
// we no longer need the current event
events.RemoveItemAt(index);
delete event;
if (result == B_DISPATCH_MESSAGE) {
// add the new events - but don't methodize them again
events.AsBList()->AddList(&newEvents, index);
index += newEvents.CountItems();
count = events.CountItems();
} else
count--;
} else
index++;
}
status_t
InputServer::_DispatchEvent(BMessage* event)
{
CALLED();
switch (event->what) {
case B_MOUSE_MOVED:
case B_MOUSE_DOWN:
case B_MOUSE_UP:
if (fCursorBuffer) {
#ifndef HAIKU_TARGET_PLATFORM_HAIKU
fCursorBuffer[0] = (0x3 << 30L)
| ((uint32)fMousePos.x & 0x7fff) << 15
| ((uint32)fMousePos.y & 0x7fff);
PRINT(("released cursorSem with value : %08lx\n", fCursorBuffer[0]));
release_sem(fCursorSem);
#else
atomic_set((int32*)&fCursorBuffer->pos, (uint32)fMousePos.x << 16UL
| ((uint32)fMousePos.y & 0xffff));
if (atomic_or(&fCursorBuffer->read, 1) == 0)
release_sem_etc(fCursorSem, 0, B_RELEASE_ALL);
#endif
}
break;
case B_KEY_DOWN:
case B_KEY_UP:
case B_UNMAPPED_KEY_DOWN:
case B_UNMAPPED_KEY_UP:
case B_MODIFIERS_CHANGED:
{
// update or add modifiers
uint32 modifiers;
if (event->FindInt32("modifiers", (int32*)&modifiers) == B_OK)
fKeyInfo.modifiers = modifiers;
else
event->AddInt32("modifiers", fKeyInfo.modifiers);
// update or add key states
const uint8 *data;
ssize_t size;
if (event->FindData("states", B_UINT8_TYPE,
(const void**)&data, &size) == B_OK) {
PRINT(("updated keyinfo\n"));
if (size == sizeof(fKeyInfo.key_states))
memcpy(fKeyInfo.key_states, data, size);
} else {
event->AddData("states", B_UINT8_TYPE, fKeyInfo.key_states,
sizeof(fKeyInfo.key_states));
}
PRINT(("keyinfo %ld %ld\n", size, (ssize_t)sizeof(fKeyInfo.key_states)));
break;
}
default:
break;
}
#if defined(HAIKU_TARGET_PLATFORM_HAIKU) && defined(USING_MESSAGE4)
BMessenger reply;
BMessage::Private messagePrivate(event);
return messagePrivate.SendMessage(fAppServerPort, 0, true, 0, false, reply);
#else
ssize_t length = event->FlattenedSize();
char buffer[length];
status_t err;
if ((err = event->Flatten(buffer,length)) < B_OK)
return err;
return write_port(fAppServerPort, 0, buffer, length);
#endif
}
+26 -25
View File
@@ -7,7 +7,6 @@
#include "AddOnManager.h"
#include "BottomlineWindow.h"
#include "DeviceManager.h"
#include "KeyboardSettings.h"
#include "MouseSettings.h"
@@ -23,6 +22,7 @@
#include <InterfaceDefs.h>
#include <Locker.h>
#include <Message.h>
#include <ObjectList.h>
#include <OS.h>
#include <Screen.h>
#include <SupportDefs.h>
@@ -35,6 +35,10 @@
#define INPUTSERVER_SIGNATURE "application/x-vnd.Be-input_server"
// use this when target should replace R5 input_server
typedef BObjectList<BMessage> EventList;
class BottomlineWindow;
class InputDeviceListItem {
public:
InputDeviceListItem(BInputServerDevice& serverDevice, input_device_ref& device);
@@ -87,14 +91,12 @@ class _BMethodAddOn_ {
BMessenger fMessenger;
};
class KeymapMethod : public BInputServerMethod {
public:
KeymapMethod();
~KeymapMethod();
};
class InputServer : public BApplication {
public:
InputServer();
@@ -125,23 +127,12 @@ class InputServer : public BApplication {
status_t EnqueueDeviceMessage(BMessage* message);
status_t EnqueueMethodMessage(BMessage* message);
status_t UnlockMethodQueue();
status_t LockMethodQueue();
status_t SetNextMethod(bool direction);
void SetActiveMethod(BInputServerMethod* method);
const BMessenger* MethodReplicant();
void SetMethodReplicant(const BMessenger *replicant);
status_t EventLoop();
bool EventLoopRunning();
bool DispatchEvents(BList* eventList);
status_t DispatchEvent(BMessage* event);
bool CacheEvents(BList* eventList);
const BList* GetNextEvents(BList*);
bool FilterEvents(BList* eventList);
bool SanitizeEvents(BList* eventList);
bool MethodizeEvents(BList* eventList, bool);
status_t GetDeviceInfo(const char* name, input_device_type *_type,
bool *_isRunning = NULL);
status_t UnregisterDevices(BInputServerDevice& serverDevice,
@@ -180,13 +171,22 @@ class InputServer : public BApplication {
status_t _LoadSystemKeymap();
void _InitKeyboardMouseStates();
status_t _StartEventLoop();
void _EventLoop();
static status_t _EventLooper(void *arg);
bool _SanitizeEvents(EventList& events);
bool _MethodizeEvents(EventList& events);
bool _FilterEvents(EventList& events);
void _DispatchEvents(EventList& events);
void _FilterEvent(BInputServerFilter* filter, EventList& events,
int32& index, int32& count);
status_t _DispatchEvent(BMessage* event);
status_t _AcquireInput(BMessage& message, BMessage& reply);
void _ReleaseInput(BMessage* message);
void _WatchPort();
static int32 _PortWatcher(void *arg);
// static bool doStartStopDevice(void*, void*);
InputDeviceListItem* _FindInputDeviceListItem(BInputServerDevice& device);
private:
@@ -199,8 +199,8 @@ class InputServer : public BApplication {
BList fInputDeviceList;
BLocker fInputDeviceListLocker;
KeyboardSettings fKeyboardSettings;
MouseSettings fMouseSettings;
KeyboardSettings fKeyboardSettings;
MouseSettings fMouseSettings;
BPoint fMousePos; // current mouse position
key_info fKeyInfo; // current key info
@@ -212,16 +212,17 @@ class InputServer : public BApplication {
AddOnManager* fAddOnManager;
BList fEventsCache;
BScreen fScreen;
BRect fFrame;
BLocker fEventQueueLock;
EventList fEventQueue;
BInputServerMethod* fActiveMethod;
BList fMethodQueue;
EventList fMethodQueue;
const BMessenger* fReplicantMessenger;
BottomlineWindow* fBLWindow;
bool fIMAware;
BottomlineWindow* fInputMethodWindow;
bool fInputMethodAware;
sem_id fCursorSem;
port_id fAppServerPort;
+1 -4
View File
@@ -32,10 +32,7 @@ SEARCH on US-International.keymap
AddResources input_server : input_server.rdef ;
UsePrivateHeaders app ;
UsePrivateHeaders input ;
UsePrivateHeaders interface ;
UsePrivateHeaders storage ;
UsePrivateHeaders app input interface shared storage ;
SubDirC++Flags -DADD_ON_STABLE_SECONDS=1 ; # for AddOnMonitorHandler.cpp