haiku/src/servers/input/InputServer.cpp

1969 lines
45 KiB
C++

/*
* Copyright 2002-2013 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include "InputServer.h"
#include "InputServerTypes.h"
#include "BottomlineWindow.h"
#include "MethodReplicant.h"
#include <driver_settings.h>
#include <keyboard_mouse_driver.h>
#include <safemode_defs.h>
#include <syscalls.h>
#include <AppServerLink.h>
#include <MessagePrivate.h>
#include <ObjectListPrivate.h>
#include <RosterPrivate.h>
#include <Autolock.h>
#include <Deskbar.h>
#include <Directory.h>
#include <Entry.h>
#include <File.h>
#include <FindDirectory.h>
#include <Locker.h>
#include <Message.h>
#include <OS.h>
#include <Path.h>
#include <Roster.h>
#include <String.h>
#include <stdio.h>
#include <strings.h>
#include "SystemKeymap.h"
// this is an automatically generated file
#include <ServerProtocol.h>
using std::nothrow;
// Global InputServer member variables.
InputServer* gInputServer;
BList InputServer::gInputFilterList;
BLocker InputServer::gInputFilterListLocker("is_filter_queue_sem");
BList InputServer::gInputMethodList;
BLocker InputServer::gInputMethodListLocker("is_method_queue_sem");
KeymapMethod InputServer::gKeymapMethod;
extern "C" _EXPORT BView* instantiate_deskbar_item();
// #pragma mark - InputDeviceListItem
InputDeviceListItem::InputDeviceListItem(BInputServerDevice& serverDevice,
const input_device_ref& device)
:
fServerDevice(&serverDevice),
fDevice(),
fRunning(false)
{
fDevice.name = strdup(device.name);
fDevice.type = device.type;
fDevice.cookie = device.cookie;
}
InputDeviceListItem::~InputDeviceListItem()
{
free(fDevice.name);
}
void
InputDeviceListItem::Start()
{
PRINT((" Starting: %s\n", fDevice.name));
status_t err = fServerDevice->Start(fDevice.name, fDevice.cookie);
if (err != B_OK) {
PRINTERR((" error: %s (%" B_PRIx32 ")\n", strerror(err), err));
}
fRunning = err == B_OK;
}
void
InputDeviceListItem::Stop()
{
PRINT((" Stopping: %s\n", fDevice.name));
fServerDevice->Stop(fDevice.name, fDevice.cookie);
fRunning = false;
}
void
InputDeviceListItem::Control(uint32 code, BMessage* message)
{
fServerDevice->Control(fDevice.name, fDevice.cookie, code, message);
}
bool
InputDeviceListItem::HasName(const char* name) const
{
if (name == NULL)
return false;
return !strcmp(name, fDevice.name);
}
bool
InputDeviceListItem::HasType(input_device_type type) const
{
return type == fDevice.type;
}
bool
InputDeviceListItem::Matches(const char* name, input_device_type type) const
{
if (name != NULL)
return HasName(name);
return HasType(type);
}
// #pragma mark -
InputServer::InputServer()
:
BApplication(INPUTSERVER_SIGNATURE),
fKeyboardID(0),
fInputDeviceListLocker("input server device list"),
fKeyboardSettings(),
fMouseSettings(),
fChars(NULL),
fScreen(B_MAIN_SCREEN_ID),
fEventQueueLock("input server event queue"),
fReplicantMessenger(NULL),
fInputMethodWindow(NULL),
fInputMethodAware(false),
fCursorSem(-1),
fAppServerPort(-1),
fAppServerTeam(-1),
fCursorArea(-1)
{
CALLED();
gInputServer = this;
set_thread_priority(find_thread(NULL), B_URGENT_DISPLAY_PRIORITY);
// elevate priority for client interaction
_StartEventLoop();
_InitKeyboardMouseStates();
fAddOnManager = new(std::nothrow) ::AddOnManager();
if (fAddOnManager != NULL) {
// We need to Run() the AddOnManager looper after having loaded
// the initial add-ons, otherwise we may deadlock when the looper
// thread for some reason already receives node monitor notifications
// while we are still locked ourselves and are executing LoadState()
// at the same time (which may lock the add-on looper thread).
// NOTE: At first sight this may look like we may loose node monitor
// notifications while the thread is not yet running, but in fact those
// message should just pile up and be processed later.
fAddOnManager->LoadState();
fAddOnManager->Run();
}
BMessenger messenger(this);
BRoster().StartWatching(messenger, B_REQUEST_LAUNCHED);
}
InputServer::~InputServer()
{
CALLED();
if (fAddOnManager->Lock())
fAddOnManager->Quit();
_ReleaseInput(NULL);
}
void
InputServer::ArgvReceived(int32 argc, char** argv)
{
CALLED();
if (argc == 2 && strcmp(argv[1], "-q") == 0) {
PRINT(("InputServer::ArgvReceived - Restarting ...\n"));
PostMessage(B_QUIT_REQUESTED);
}
}
void
InputServer::_InitKeyboardMouseStates()
{
CALLED();
// This is where we determine the screen resolution from the app_server and
// find the center of the screen
// fMousePos is then set to the center of the screen.
fFrame = fScreen.Frame();
if (fFrame == BRect(0, 0, 0, 0))
fFrame = BRect(0, 0, 799, 599);
fMousePos = BPoint((int32)((fFrame.right + 1) / 2),
(int32)((fFrame.bottom + 1) / 2));
memset(&fKeyInfo, 0, sizeof(fKeyInfo));
if (_LoadKeymap() != B_OK)
_LoadSystemKeymap();
BMessage msg(B_MOUSE_MOVED);
HandleSetMousePosition(&msg, &msg);
fActiveMethod = &gKeymapMethod;
}
status_t
InputServer::_LoadKeymap()
{
BPath path;
if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK)
return B_BAD_VALUE;
path.Append("Key_map");
status_t err;
BFile file(path.Path(), B_READ_ONLY);
if ((err = file.InitCheck()) != B_OK)
return err;
if (file.Read(&fKeys, sizeof(fKeys)) < (ssize_t)sizeof(fKeys))
return B_BAD_VALUE;
for (uint32 i = 0; i < sizeof(fKeys) / 4; i++)
((uint32*)&fKeys)[i] = B_BENDIAN_TO_HOST_INT32(((uint32*)&fKeys)[i]);
if (file.Read(&fCharsSize, sizeof(uint32)) < (ssize_t)sizeof(uint32))
return B_BAD_VALUE;
fCharsSize = B_BENDIAN_TO_HOST_INT32(fCharsSize);
if (fCharsSize <= 0)
return B_BAD_VALUE;
delete[] fChars;
fChars = new (nothrow) char[fCharsSize];
if (fChars == NULL)
return B_NO_MEMORY;
if (file.Read(fChars, fCharsSize) != (signed)fCharsSize)
return B_BAD_VALUE;
return B_OK;
}
status_t
InputServer::_LoadSystemKeymap()
{
delete[] fChars;
fKeys = kSystemKeymap;
fCharsSize = kSystemKeyCharsSize;
fChars = new (nothrow) char[fCharsSize];
if (fChars == NULL)
return B_NO_MEMORY;
memcpy(fChars, kSystemKeyChars, fCharsSize);
// TODO: why are we doing this?
return _SaveKeymap(true);
}
status_t
InputServer::_SaveKeymap(bool isDefault)
{
// we save this keymap to file
BPath path;
if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK)
return B_BAD_VALUE;
path.Append("Key_map");
BFile file;
status_t err = file.SetTo(path.Path(), B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE);
if (err != B_OK) {
PRINTERR(("error %s\n", strerror(err)));
return err;
}
for (uint32 i = 0; i < sizeof(fKeys) / sizeof(uint32); i++) {
((uint32*)&fKeys)[i] = B_HOST_TO_BENDIAN_INT32(((uint32*)&fKeys)[i]);
}
if ((err = file.Write(&fKeys, sizeof(fKeys))) < (ssize_t)sizeof(fKeys))
return err;
for (uint32 i = 0; i < sizeof(fKeys) / sizeof(uint32); i++) {
((uint32*)&fKeys)[i] = B_BENDIAN_TO_HOST_INT32(((uint32*)&fKeys)[i]);
}
uint32 size = B_HOST_TO_BENDIAN_INT32(fCharsSize);
if ((err = file.Write(&size, sizeof(uint32))) < (ssize_t)sizeof(uint32))
return B_BAD_VALUE;
if ((err = file.Write(fChars, fCharsSize)) < (ssize_t)fCharsSize)
return err;
// don't bother reporting an error if this fails, since this isn't fatal
// the keymap will still be functional, and will just be identified as (Current) in prefs instead of its
// actual name
if (isDefault) {
const BString systemKeymapName(kSystemKeymapName);
file.WriteAttrString("keymap:name", &systemKeymapName);
}
return B_OK;
}
bool
InputServer::QuitRequested()
{
CALLED();
if (!BApplication::QuitRequested())
return false;
PostMessage(SYSTEM_SHUTTING_DOWN);
bool shutdown = false;
CurrentMessage()->FindBool("_shutdown_", &shutdown);
// Don't actually quit when the system is being shutdown
if (shutdown) {
return false;
} else {
fAddOnManager->SaveState();
delete_port(fEventLooperPort);
// the event looper thread will exit after this
fEventLooperPort = -1;
return true;
}
}
void
InputServer::ReadyToRun()
{
CALLED();
// say hello to the app_server
BPrivate::AppServerLink link;
link.StartMessage(AS_REGISTER_INPUT_SERVER);
link.Flush();
}
status_t
InputServer::_AcquireInput(BMessage& message, BMessage& reply)
{
// TODO: it currently just gets everything we have
area_id area;
if (message.FindInt32("cursor area", &area) == B_OK) {
// try to clone the area
fCursorBuffer = NULL;
fCursorSem = create_sem(0, "cursor semaphore");
if (fCursorSem >= B_OK) {
fCursorArea = clone_area("input server cursor", (void**)&fCursorBuffer,
B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, area);
}
}
if (message.FindInt32("remote team", &fAppServerTeam) != B_OK)
fAppServerTeam = -1;
fAppServerPort = create_port(200, "input server target");
if (fAppServerPort < B_OK) {
_ReleaseInput(&message);
return fAppServerPort;
}
reply.AddBool("has keyboard", true);
reply.AddBool("has mouse", true);
reply.AddInt32("event port", fAppServerPort);
if (fCursorBuffer != NULL) {
// cursor shared buffer is supported
reply.AddInt32("cursor semaphore", fCursorSem);
}
return B_OK;
}
void
InputServer::_ReleaseInput(BMessage* /*message*/)
{
if (fCursorBuffer != NULL) {
fCursorBuffer = NULL;
delete_sem(fCursorSem);
delete_area(fCursorArea);
fCursorSem = -1;
fCursorArea = -1;
}
delete_port(fAppServerPort);
}
void
InputServer::MessageReceived(BMessage* message)
{
CALLED();
BMessage reply;
status_t status = B_OK;
PRINT(("%s what:%c%c%c%c\n", __PRETTY_FUNCTION__, (char)(message->what >> 24),
(char)(message->what >> 16), (char)(message->what >> 8), (char)message->what));
switch (message->what) {
case IS_SET_METHOD:
HandleSetMethod(message);
break;
case IS_GET_MOUSE_TYPE:
status = HandleGetSetMouseType(message, &reply);
break;
case IS_SET_MOUSE_TYPE:
status = HandleGetSetMouseType(message, &reply);
break;
case IS_GET_MOUSE_ACCELERATION:
status = HandleGetSetMouseAcceleration(message, &reply);
break;
case IS_SET_MOUSE_ACCELERATION:
status = HandleGetSetMouseAcceleration(message, &reply);
break;
case IS_GET_KEY_REPEAT_DELAY:
status = HandleGetSetKeyRepeatDelay(message, &reply);
break;
case IS_SET_KEY_REPEAT_DELAY:
status = HandleGetSetKeyRepeatDelay(message, &reply);
break;
case IS_GET_KEY_INFO:
status = HandleGetKeyInfo(message, &reply);
break;
case IS_GET_MODIFIERS:
status = HandleGetModifiers(message, &reply);
break;
case IS_GET_MODIFIER_KEY:
status = HandleGetModifierKey(message, &reply);
break;
case IS_SET_MODIFIER_KEY:
status = HandleSetModifierKey(message, &reply);
break;
case IS_SET_KEYBOARD_LOCKS:
status = HandleSetKeyboardLocks(message, &reply);
break;
case IS_GET_MOUSE_SPEED:
status = HandleGetSetMouseSpeed(message, &reply);
break;
case IS_SET_MOUSE_SPEED:
status = HandleGetSetMouseSpeed(message, &reply);
break;
case IS_SET_MOUSE_POSITION:
status = HandleSetMousePosition(message, &reply);
break;
case IS_GET_MOUSE_MAP:
status = HandleGetSetMouseMap(message, &reply);
break;
case IS_SET_MOUSE_MAP:
status = HandleGetSetMouseMap(message, &reply);
break;
case IS_GET_KEYBOARD_ID:
status = HandleGetSetKeyboardID(message, &reply);
break;
case IS_SET_KEYBOARD_ID:
status = HandleGetSetKeyboardID(message, &reply);
break;
case IS_GET_CLICK_SPEED:
status = HandleGetSetClickSpeed(message, &reply);
break;
case IS_SET_CLICK_SPEED:
status = HandleGetSetClickSpeed(message, &reply);
break;
case IS_GET_KEY_REPEAT_RATE:
status = HandleGetSetKeyRepeatRate(message, &reply);
break;
case IS_SET_KEY_REPEAT_RATE:
status = HandleGetSetKeyRepeatRate(message, &reply);
break;
case IS_GET_KEY_MAP:
status = HandleGetSetKeyMap(message, &reply);
break;
case IS_RESTORE_KEY_MAP:
status = HandleGetSetKeyMap(message, &reply);
break;
case IS_FOCUS_IM_AWARE_VIEW:
status = HandleFocusUnfocusIMAwareView(message, &reply);
break;
case IS_UNFOCUS_IM_AWARE_VIEW:
status = HandleFocusUnfocusIMAwareView(message, &reply);
break;
// app_server communication
case IS_ACQUIRE_INPUT:
status = _AcquireInput(*message, reply);
break;
case IS_RELEASE_INPUT:
_ReleaseInput(message);
return;
case IS_SCREEN_BOUNDS_UPDATED:
{
// This is what the R5 app_server sends us when the screen
// configuration changes
BRect frame;
if (message->FindRect("screen_bounds", &frame) != B_OK)
frame = fScreen.Frame();
if (frame == fFrame)
break;
BPoint pos(fMousePos.x * frame.Width() / fFrame.Width(),
fMousePos.y * frame.Height() / fFrame.Height());
fFrame = frame;
BMessage set;
set.AddPoint("where", pos);
HandleSetMousePosition(&set, NULL);
break;
}
// device looper related
case IS_FIND_DEVICES:
case IS_WATCH_DEVICES:
case IS_IS_DEVICE_RUNNING:
case IS_START_DEVICE:
case IS_STOP_DEVICE:
case IS_CONTROL_DEVICES:
case SYSTEM_SHUTTING_DOWN:
case IS_METHOD_REGISTER:
fAddOnManager->PostMessage(message);
return;
case IS_SAVE_SETTINGS:
fKeyboardSettings.Save();
fMouseSettings.SaveSettings();
return;
case IS_SAVE_KEYMAP:
_SaveKeymap();
return;
case B_SOME_APP_LAUNCHED:
{
const char *signature;
// TODO: what's this for?
if (message->FindString("be:signature", &signature)==B_OK) {
PRINT(("input_server : %s\n", signature));
if (strcmp(signature, "application/x-vnd.Be-TSKB")==0) {
}
}
return;
}
case kMsgAppServerRestarted:
{
BApplication::MessageReceived(message);
BPrivate::AppServerLink link;
link.StartMessage(AS_REGISTER_INPUT_SERVER);
link.Flush();
return;
}
default:
return;
}
reply.AddInt32("status", status);
message->SendReply(&reply);
}
void
InputServer::HandleSetMethod(BMessage* message)
{
CALLED();
int32 cookie;
if (message->FindInt32("cookie", &cookie) != B_OK)
return;
if (cookie == gKeymapMethod.fOwner->Cookie()) {
SetActiveMethod(&gKeymapMethod);
} else {
BAutolock lock(InputServer::gInputMethodListLocker);
for (int32 i = 0; i < gInputMethodList.CountItems(); i++) {
BInputServerMethod* method
= (BInputServerMethod*)InputServer::gInputMethodList.ItemAt(i);
if (method->fOwner->Cookie() == cookie) {
PRINT(("%s cookie %" B_PRId32 "\n", __PRETTY_FUNCTION__,
cookie));
SetActiveMethod(method);
break;
}
}
}
}
status_t
InputServer::HandleGetSetMouseType(BMessage* message, BMessage* reply)
{
BString mouseName;
MouseSettings* settings = NULL;
if (message->FindString("mouse_name", &mouseName) == B_OK) {
settings = fMouseSettings.GetMouseSettings(mouseName);
if (settings == NULL)
return B_NAME_NOT_FOUND;
}
int32 type;
if (message->FindInt32("mouse_type", &type) == B_OK) {
if (settings != NULL)
settings->SetMouseType(type);
else {
// TODO if no mouse_name was specified, apply the setting to
// all mouses
return B_NOT_SUPPORTED;
}
be_app_messenger.SendMessage(IS_SAVE_SETTINGS);
BMessage msg(IS_CONTROL_DEVICES);
msg.AddInt32("type", B_POINTING_DEVICE);
msg.AddInt32("code", B_MOUSE_TYPE_CHANGED);
return fAddOnManager->PostMessage(&msg);
}
if (settings != NULL) {
return reply->AddInt32("mouse_type",
settings->MouseType());
} else {
// TODO return type of the "first" mouse?
return B_NOT_SUPPORTED;
}
}
status_t
InputServer::HandleGetSetMouseAcceleration(BMessage* message,
BMessage* reply)
{
BString mouseName;
MouseSettings* settings = NULL;
if (message->FindString("mouse_name", &mouseName) == B_OK) {
settings = fMouseSettings.GetMouseSettings(mouseName);
if (settings == NULL)
return B_NAME_NOT_FOUND;
}
int32 factor;
if (message->FindInt32("speed", &factor) == B_OK) {
if (settings != NULL)
settings->SetAccelerationFactor(factor);
else {
// TODO if no mouse_name was specified, apply the setting to
// all mouses
return B_NOT_SUPPORTED;
}
be_app_messenger.SendMessage(IS_SAVE_SETTINGS);
BMessage msg(IS_CONTROL_DEVICES);
msg.AddInt32("type", B_POINTING_DEVICE);
msg.AddInt32("code", B_MOUSE_ACCELERATION_CHANGED);
return fAddOnManager->PostMessage(&msg);
}
if (settings != NULL)
return reply->AddInt32("speed", settings->AccelerationFactor());
else {
// TODO return type of the "first" mouse?
return B_NOT_SUPPORTED;
}
}
status_t
InputServer::HandleGetSetKeyRepeatDelay(BMessage* message, BMessage* reply)
{
bigtime_t delay;
if (message->FindInt64("delay", &delay) == B_OK) {
fKeyboardSettings.SetKeyboardRepeatDelay(delay);
be_app_messenger.SendMessage(IS_SAVE_SETTINGS);
BMessage msg(IS_CONTROL_DEVICES);
msg.AddInt32("type", B_KEYBOARD_DEVICE);
msg.AddInt32("code", B_KEY_REPEAT_DELAY_CHANGED);
return fAddOnManager->PostMessage(&msg);
}
return reply->AddInt64("delay", fKeyboardSettings.KeyboardRepeatDelay());
}
status_t
InputServer::HandleGetKeyInfo(BMessage* message, BMessage* reply)
{
return reply->AddData("key_info", B_ANY_TYPE, &fKeyInfo, sizeof(fKeyInfo));
}
status_t
InputServer::HandleGetModifiers(BMessage* message, BMessage* reply)
{
return reply->AddInt32("modifiers", fKeyInfo.modifiers);
}
status_t
InputServer::HandleGetModifierKey(BMessage* message, BMessage* reply)
{
int32 modifier;
if (message->FindInt32("modifier", &modifier) == B_OK) {
switch (modifier) {
case B_CAPS_LOCK:
return reply->AddInt32("key", fKeys.caps_key);
case B_NUM_LOCK:
return reply->AddInt32("key", fKeys.num_key);
case B_SCROLL_LOCK:
return reply->AddInt32("key", fKeys.scroll_key);
case B_LEFT_SHIFT_KEY:
return reply->AddInt32("key", fKeys.left_shift_key);
case B_RIGHT_SHIFT_KEY:
return reply->AddInt32("key", fKeys.right_shift_key);
case B_LEFT_COMMAND_KEY:
return reply->AddInt32("key", fKeys.left_command_key);
case B_RIGHT_COMMAND_KEY:
return reply->AddInt32("key", fKeys.right_command_key);
case B_LEFT_CONTROL_KEY:
return reply->AddInt32("key", fKeys.left_control_key);
case B_RIGHT_CONTROL_KEY:
return reply->AddInt32("key", fKeys.right_control_key);
case B_LEFT_OPTION_KEY:
return reply->AddInt32("key", fKeys.left_option_key);
case B_RIGHT_OPTION_KEY:
return reply->AddInt32("key", fKeys.right_option_key);
case B_MENU_KEY:
return reply->AddInt32("key", fKeys.menu_key);
}
}
return B_ERROR;
}
status_t
InputServer::HandleSetModifierKey(BMessage* message, BMessage* reply)
{
int32 modifier, key;
if (message->FindInt32("modifier", &modifier) == B_OK
&& message->FindInt32("key", &key) == B_OK) {
switch (modifier) {
case B_CAPS_LOCK:
fKeys.caps_key = key;
break;
case B_NUM_LOCK:
fKeys.num_key = key;
break;
case B_SCROLL_LOCK:
fKeys.scroll_key = key;
break;
case B_LEFT_SHIFT_KEY:
fKeys.left_shift_key = key;
break;
case B_RIGHT_SHIFT_KEY:
fKeys.right_shift_key = key;
break;
case B_LEFT_COMMAND_KEY:
fKeys.left_command_key = key;
break;
case B_RIGHT_COMMAND_KEY:
fKeys.right_command_key = key;
break;
case B_LEFT_CONTROL_KEY:
fKeys.left_control_key = key;
break;
case B_RIGHT_CONTROL_KEY:
fKeys.right_control_key = key;
break;
case B_LEFT_OPTION_KEY:
fKeys.left_option_key = key;
break;
case B_RIGHT_OPTION_KEY:
fKeys.right_option_key = key;
break;
case B_MENU_KEY:
fKeys.menu_key = key;
break;
default:
return B_ERROR;
}
// TODO: unmap the key ?
be_app_messenger.SendMessage(IS_SAVE_KEYMAP);
BMessage msg(IS_CONTROL_DEVICES);
msg.AddInt32("type", B_KEYBOARD_DEVICE);
msg.AddInt32("code", B_KEY_MAP_CHANGED);
return fAddOnManager->PostMessage(&msg);
}
return B_ERROR;
}
status_t
InputServer::HandleSetKeyboardLocks(BMessage* message, BMessage* reply)
{
if (message->FindInt32("locks", (int32*)&fKeys.lock_settings) == B_OK) {
be_app_messenger.SendMessage(IS_SAVE_KEYMAP);
BMessage msg(IS_CONTROL_DEVICES);
msg.AddInt32("type", B_KEYBOARD_DEVICE);
msg.AddInt32("code", B_KEY_LOCKS_CHANGED);
return fAddOnManager->PostMessage(&msg);
}
return B_ERROR;
}
// #pragma mark - Mouse settings
/** This method does all possible efforts to return some settings.
*
* The settings will be created if they do not exist. If a mouse name is
* specified, the settings for that mouse are created and used. Otherwise,
* default settings are returned.
*/
MouseSettings*
InputServer::_GetSettingsForMouse(BString mouseName)
{
// If no mouse name is specified, use the first one found in settings
if (mouseName == "") {
std::map<BString, MouseSettings*>::iterator itr
= fMouseSettingsObject.begin();
if (itr != fMouseSettingsObject.end())
return itr->second;
}
// If a mouse name is specified or there are no settings yet, get or create
// some
return fMouseSettings.AddMouseSettings(mouseName);
}
status_t
InputServer::HandleGetSetMouseSpeed(BMessage* message, BMessage* reply)
{
BString mouseName;
message->FindString("mouse_name", &mouseName);
MouseSettings* settings = _GetSettingsForMouse(mouseName);
if (settings == NULL)
return B_NO_MEMORY;
int32 speed;
if (message->FindInt32("speed", &speed) == B_OK) {
settings->SetMouseSpeed(speed);
be_app_messenger.SendMessage(IS_SAVE_SETTINGS);
BMessage msg(IS_CONTROL_DEVICES);
msg.AddInt32("type", B_POINTING_DEVICE);
msg.AddInt32("code", B_MOUSE_SPEED_CHANGED);
return fAddOnManager->PostMessage(&msg);
}
return reply->AddInt32("speed", settings->MouseSpeed());
}
status_t
InputServer::HandleGetSetMouseMap(BMessage* message, BMessage* reply)
{
BString mouseName;
message->FindString("mouse_name", &mouseName);
MouseSettings* settings = _GetSettingsForMouse(mouseName);
if (settings == NULL)
return B_NO_MEMORY;
mouse_map *map;
ssize_t size;
if (message->FindData("mousemap", B_RAW_TYPE, (const void**)&map, &size) == B_OK) {
settings->SetMapping(*map);
be_app_messenger.SendMessage(IS_SAVE_SETTINGS);
BMessage msg(IS_CONTROL_DEVICES);
msg.AddInt32("type", B_POINTING_DEVICE);
msg.AddInt32("code", B_MOUSE_MAP_CHANGED);
return fAddOnManager->PostMessage(&msg);
}
mouse_map getmap;
settings->Mapping(getmap);
return reply->AddData("mousemap", B_RAW_TYPE, &getmap, sizeof(mouse_map));
}
status_t
InputServer::HandleGetSetClickSpeed(BMessage* message, BMessage* reply)
{
BString mouseName;
message->FindString("mouse_name", &mouseName);
MouseSettings* settings = _GetSettingsForMouse(mouseName);
if (settings == NULL)
return B_NO_MEMORY;
bigtime_t clickSpeed;
if (message->FindInt64("speed", &clickSpeed) == B_OK) {
settings->SetClickSpeed(clickSpeed);
be_app_messenger.SendMessage(IS_SAVE_SETTINGS);
BMessage msg(IS_CONTROL_DEVICES);
msg.AddInt32("type", B_POINTING_DEVICE);
msg.AddInt32("code", B_CLICK_SPEED_CHANGED);
return fAddOnManager->PostMessage(&msg);
}
return reply->AddInt64("speed", settings->ClickSpeed());
}
status_t
InputServer::HandleSetMousePosition(BMessage* message, BMessage* reply)
{
CALLED();
BPoint where;
if (message->FindPoint("where", &where) != B_OK)
return B_BAD_VALUE;
// create a new event for this and enqueue it to the event list just like any other
BMessage* event = new BMessage(B_MOUSE_MOVED);
if (event == NULL)
return B_NO_MEMORY;
event->AddPoint("where", where);
event->AddBool("be:set_mouse", true);
if (EnqueueDeviceMessage(event) != B_OK) {
delete event;
return B_NO_MEMORY;
}
return B_OK;
}
// #pragma mark - Keyboard settings
status_t
InputServer::HandleGetSetKeyboardID(BMessage* message, BMessage* reply)
{
int16 id;
if (message->FindInt16("id", &id) == B_OK) {
fKeyboardID = (uint16)id;
return B_OK;
}
return reply->AddInt16("id", fKeyboardID);
}
status_t
InputServer::HandleGetSetKeyRepeatRate(BMessage* message, BMessage* reply)
{
int32 keyRepeatRate;
if (message->FindInt32("rate", &keyRepeatRate) == B_OK) {
fKeyboardSettings.SetKeyboardRepeatRate(keyRepeatRate);
be_app_messenger.SendMessage(IS_SAVE_SETTINGS);
BMessage msg(IS_CONTROL_DEVICES);
msg.AddInt32("type", B_KEYBOARD_DEVICE);
msg.AddInt32("code", B_KEY_REPEAT_RATE_CHANGED);
return fAddOnManager->PostMessage(&msg);
}
return reply->AddInt32("rate", fKeyboardSettings.KeyboardRepeatRate());
}
status_t
InputServer::HandleGetSetKeyMap(BMessage* message, BMessage* reply)
{
CALLED();
status_t status;
if (message->what == IS_GET_KEY_MAP) {
status = reply->AddData("keymap", B_ANY_TYPE, &fKeys, sizeof(fKeys));
if (status == B_OK)
status = reply->AddData("key_buffer", B_ANY_TYPE, fChars, fCharsSize);
return status;
}
status = _LoadKeymap();
if (status != B_OK) {
status = _LoadSystemKeymap();
if (status != B_OK)
return status;
}
BMessage msg(IS_CONTROL_DEVICES);
msg.AddInt32("type", B_KEYBOARD_DEVICE);
msg.AddInt32("code", B_KEY_MAP_CHANGED);
status = fAddOnManager->PostMessage(&msg);
if (status == B_OK) {
BMessage appMsg(B_KEY_MAP_LOADED);
be_roster->Broadcast(&appMsg);
}
return status;
}
status_t
InputServer::HandleFocusUnfocusIMAwareView(BMessage* message,
BMessage* reply)
{
CALLED();
BMessenger messenger;
status_t status = message->FindMessenger("view", &messenger);
if (status != B_OK)
return status;
// check if current view is ours
if (message->what == IS_FOCUS_IM_AWARE_VIEW) {
PRINT(("HandleFocusUnfocusIMAwareView : entering\n"));
fInputMethodAware = true;
} else {
PRINT(("HandleFocusUnfocusIMAwareView : leaving\n"));
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();
BAutolock _(fEventQueueLock);
if (!fEventQueue.AddItem(message))
return B_NO_MEMORY;
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)
{
CALLED();
PRINT(("%s what:%c%c%c%c\n", __PRETTY_FUNCTION__,
(char)(message->what >> 24), (char)(message->what >> 16),
(char)(message->what >> 8), (char)message->what));
#ifdef DEBUG
if (message->what == 'IMEV') {
int32 code;
message->FindInt32("be:opcode", &code);
PRINT(("%s be:opcode %" B_PRId32 "\n", __PRETTY_FUNCTION__, code));
}
#endif
BAutolock _(fEventQueueLock);
if (!fMethodQueue.AddItem(message))
return B_NO_MEMORY;
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;
}
status_t
InputServer::SetNextMethod(bool direction)
{
gInputMethodListLocker.Lock();
int32 index = gInputMethodList.IndexOf(fActiveMethod);
int32 oldIndex = index;
index += (direction ? 1 : -1);
if (index < -1)
index = gInputMethodList.CountItems() - 1;
if (index >= gInputMethodList.CountItems())
index = -1;
if (index == oldIndex)
return B_BAD_INDEX;
BInputServerMethod *method = &gKeymapMethod;
if (index != -1)
method = (BInputServerMethod *)gInputMethodList.ItemAt(index);
SetActiveMethod(method);
gInputMethodListLocker.Unlock();
return B_OK;
}
void
InputServer::SetActiveMethod(BInputServerMethod* method)
{
CALLED();
if (fActiveMethod)
fActiveMethod->fOwner->MethodActivated(false);
fActiveMethod = method;
if (fActiveMethod)
fActiveMethod->fOwner->MethodActivated(true);
}
const BMessenger*
InputServer::MethodReplicant()
{
return fReplicantMessenger;
}
void
InputServer::SetMethodReplicant(const BMessenger* messenger)
{
fReplicantMessenger = messenger;
}
bool
InputServer::EventLoopRunning()
{
return fEventLooperPort >= B_OK;
}
status_t
InputServer::GetDeviceInfo(const char* name, input_device_type *_type,
bool *_isRunning)
{
BAutolock lock(fInputDeviceListLocker);
for (int32 i = fInputDeviceList.CountItems() - 1; i >= 0; i--) {
InputDeviceListItem* item = (InputDeviceListItem*)fInputDeviceList.ItemAt(i);
if (item->HasName(name)) {
if (_type)
*_type = item->Type();
if (_isRunning)
*_isRunning = item->Running();
return B_OK;
}
}
return B_NAME_NOT_FOUND;
}
status_t
InputServer::GetDeviceInfos(BMessage *msg)
{
CALLED();
BAutolock lock(fInputDeviceListLocker);
for (int32 i = fInputDeviceList.CountItems() - 1; i >= 0; i--) {
InputDeviceListItem* item = (InputDeviceListItem*)fInputDeviceList.ItemAt(i);
msg->AddString("device", item->Name());
msg->AddInt32("type", item->Type());
}
return B_OK;
}
status_t
InputServer::UnregisterDevices(BInputServerDevice& serverDevice,
input_device_ref **devices)
{
CALLED();
BAutolock lock(fInputDeviceListLocker);
if (devices != NULL) {
// remove the devices as specified only
input_device_ref *device = NULL;
for (int32 i = 0; (device = devices[i]) != NULL; i++) {
for (int32 j = fInputDeviceList.CountItems() - 1; j >= 0; j--) {
InputDeviceListItem* item = (InputDeviceListItem*)fInputDeviceList.ItemAt(j);
if (item->ServerDevice() == &serverDevice && item->HasName(device->name)) {
item->Stop();
if (fInputDeviceList.RemoveItem(j)) {
BMessage message(IS_NOTIFY_DEVICE);
message.AddBool("added", false);
message.AddString("name", item->Name());
message.AddInt32("type", item->Type());
fAddOnManager->PostMessage(&message);
delete item;
}
break;
}
}
}
} else {
// remove all devices from this BInputServerObject
for (int32 i = fInputDeviceList.CountItems() - 1; i >= 0; i--) {
InputDeviceListItem* item = (InputDeviceListItem*)fInputDeviceList.ItemAt(i);
if (item->ServerDevice() == &serverDevice) {
item->Stop();
if (fInputDeviceList.RemoveItem(i))
delete item;
}
}
}
return B_OK;
}
status_t
InputServer::RegisterDevices(BInputServerDevice& serverDevice,
input_device_ref** devices)
{
if (devices == NULL)
return B_BAD_VALUE;
BAutolock lock(fInputDeviceListLocker);
input_device_ref *device = NULL;
for (int32 i = 0; (device = devices[i]) != NULL; i++) {
if (device->type != B_POINTING_DEVICE
&& device->type != B_KEYBOARD_DEVICE
&& device->type != B_UNDEFINED_DEVICE)
continue;
// find existing input server device
bool found = false;
for (int32 j = fInputDeviceList.CountItems() - 1; j >= 0; j--) {
InputDeviceListItem* item = (InputDeviceListItem*)fInputDeviceList.ItemAt(j);
if (item->HasName(device->name)) {
debug_printf("InputServer::RegisterDevices() device_ref already exists: %s\n", device->name);
PRINT(("RegisterDevices found %s\n", device->name));
found = true;
break;
}
}
if (!found) {
PRINT(("RegisterDevices not found %s\n", device->name));
InputDeviceListItem* item = new (nothrow) InputDeviceListItem(serverDevice,
*device);
if (item != NULL && fInputDeviceList.AddItem(item)) {
item->Start();
BMessage message(IS_NOTIFY_DEVICE);
message.AddBool("added", true);
message.AddString("name", item->Name());
message.AddInt32("type", item->Type());
fAddOnManager->PostMessage(&message);
} else {
delete item;
return B_NO_MEMORY;
}
}
}
return B_OK;
}
status_t
InputServer::StartStopDevices(const char* name, input_device_type type,
bool doStart)
{
CALLED();
BAutolock lock(fInputDeviceListLocker);
for (int32 i = fInputDeviceList.CountItems() - 1; i >= 0; i--) {
InputDeviceListItem* item
= (InputDeviceListItem*)fInputDeviceList.ItemAt(i);
if (!item)
continue;
if (item->Matches(name, type)) {
if (doStart == item->Running()) {
if (name)
return B_OK;
else
continue;
}
if (doStart)
item->Start();
else
item->Stop();
BMessage message(IS_NOTIFY_DEVICE);
message.AddBool("started", doStart);
message.AddString("name", item->Name());
message.AddInt32("type", item->Type());
fAddOnManager->PostMessage(&message);
if (name)
return B_OK;
}
}
if (name) {
// item not found
return B_ERROR;
}
return B_OK;
}
status_t
InputServer::StartStopDevices(BInputServerDevice& serverDevice, bool doStart)
{
CALLED();
BAutolock lock(fInputDeviceListLocker);
for (int32 i = fInputDeviceList.CountItems() - 1; i >= 0; i--) {
InputDeviceListItem* item = (InputDeviceListItem*)fInputDeviceList.ItemAt(i);
if (item->ServerDevice() != &serverDevice)
continue;
if (doStart == item->Running())
continue;
if (doStart)
item->Start();
else
item->Stop();
BMessage message(IS_NOTIFY_DEVICE);
message.AddBool("started", doStart);
message.AddString("name", item->Name());
message.AddInt32("type", item->Type());
fAddOnManager->PostMessage(&message);
}
return B_OK;
}
status_t
InputServer::ControlDevices(const char* name, input_device_type type,
uint32 code, BMessage* message)
{
CALLED();
BAutolock lock(fInputDeviceListLocker);
for (int32 i = fInputDeviceList.CountItems() - 1; i >= 0; i--) {
InputDeviceListItem* item = (InputDeviceListItem*)fInputDeviceList.ItemAt(i);
if (!item)
continue;
if (item->Matches(name, type)) {
item->Control(code, message);
if (name)
return B_OK;
}
}
if (name)
return B_ERROR;
return B_OK;
}
bool
InputServer::SafeMode()
{
char parameter[32];
size_t parameterLength = sizeof(parameter);
if (_kern_get_safemode_option(B_SAFEMODE_SAFE_MODE, parameter,
&parameterLength) == B_OK) {
if (!strcasecmp(parameter, "enabled") || !strcasecmp(parameter, "on")
|| !strcasecmp(parameter, "true") || !strcasecmp(parameter, "yes")
|| !strcasecmp(parameter, "enable") || !strcmp(parameter, "1")) {
return true;
}
}
if (_kern_get_safemode_option(B_SAFEMODE_DISABLE_USER_ADD_ONS, parameter,
&parameterLength) == B_OK) {
if (!strcasecmp(parameter, "enabled") || !strcasecmp(parameter, "on")
|| !strcasecmp(parameter, "true") || !strcasecmp(parameter, "yes")
|| !strcasecmp(parameter, "enable") || !strcmp(parameter, "1")) {
return true;
}
}
return false;
}
status_t
InputServer::_StartEventLoop()
{
CALLED();
fEventLooperPort = create_port(100, "input server events");
if (fEventLooperPort < 0) {
PRINTERR(("InputServer: create_port error: (0x%" B_PRIx32 ") %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;
}
status_t
InputServer::_EventLooper(void* arg)
{
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) {
PRINT(("[Event Looper] port gone, exiting.\n"));
return;
}
PRINT(("[Event Looper] BMessage Size = %lu\n", length));
char buffer[length];
int32 code;
status_t err = read_port(fEventLooperPort, &code, buffer, length);
if (err != length) {
if (err >= 0) {
PRINTERR(("InputServer: failed to read full packet "
"(read %" B_PRIu32 " of %lu)\n", err, length));
} else {
PRINTERR(("InputServer: read_port error: (0x%" B_PRIx32
") %s\n", err, strerror(err)));
}
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();
}
if (length > 0) {
BMessage* event = new BMessage;
if ((err = event->Unflatten(buffer)) < 0) {
PRINTERR(("[InputServer] Unflatten() error: (0x%" B_PRIx32
") %s\n", err, strerror(err)));
delete event;
continue;
}
events.AddItem(event);
}
// This is where the message should be processed.
if (_SanitizeEvents(events)
&& _MethodizeEvents(events)
&& _FilterEvents(events)) {
_UpdateMouseAndKeys(events);
_DispatchEvents(events);
}
}
}
/*! Updates the internal mouse position and keyboard info. */
void
InputServer::_UpdateMouseAndKeys(EventList& events)
{
for (int32 index = 0;BMessage* event = (BMessage*)events.ItemAt(index);
index++) {
switch (event->what) {
case B_MOUSE_DOWN:
case B_MOUSE_UP:
case B_MOUSE_MOVED:
event->FindPoint("where", &fMousePos);
break;
case B_KEY_DOWN:
case B_UNMAPPED_KEY_DOWN:
// update modifiers
uint32 modifiers;
if (event->FindInt32("modifiers", (int32*)&modifiers) == B_OK)
fKeyInfo.modifiers = modifiers;
// update 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);
}
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)
// If there is only one input method, SetNextMethod will return
// B_BAD_INDEX and the event will be forwarded to the user.
PRINT(("SanitizeEvents: %" B_PRIx32 ", %x\n", fKeyInfo.modifiers,
fKeyInfo.key_states[KEY_Spacebar >> 3]));
uint8 byte;
if (event->FindInt8("byte", (int8*)&byte) < B_OK)
byte = 0;
if ((((fKeyInfo.modifiers & B_COMMAND_KEY) != 0 && byte == ' ')
|| byte == B_HANKAKU_ZENKAKU)
&& SetNextMethod((fKeyInfo.modifiers & B_SHIFT_KEY) == 0)
== B_OK) {
// this event isn't sent to the user
events.RemoveItemAt(index);
delete event;
continue;
}
break;
}
}
}
/*! Frees events from unwanted fields, adds missing fields, and removes
unwanted events altogether.
*/
bool
InputServer::_SanitizeEvents(EventList& events)
{
CALLED();
for (int32 index = 0; BMessage* event = (BMessage*)events.ItemAt(index);
index++) {
switch (event->what) {
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;
float absX, absY;
if (event->FindInt32("x", &x) == B_OK
&& event->FindInt32("y", &y) == B_OK) {
where.x = fMousePos.x + x;
where.y = fMousePos.y - y;
event->RemoveName("x");
event->RemoveName("y");
event->AddInt32("be:delta_x", x);
event->AddInt32("be:delta_y", y);
PRINT(("new position: %f, %f, %" B_PRId32 ", %" B_PRId32
"\n", where.x, where.y, x, y));
} else if (event->FindFloat("x", &absX) == B_OK
&& event->FindFloat("y", &absY) == B_OK) {
// The device gives us absolute screen coords in range 0..1;
// convert them to absolute screen position
// (the message is supposed to contain the original
// absolute coordinates as "be:tablet_x/y").
where.x = absX * fFrame.Width();
where.y = absY * fFrame.Height();
event->RemoveName("x");
event->RemoveName("y");
PRINT(("new position : %f, %f\n", where.x, where.y));
} else if (event->FindPoint("where", &where) == B_OK) {
PRINT(("new position : %f, %f\n", where.x, where.y));
}
// Constrain and filter the mouse coords and add the final
// point to the message.
where.x = roundf(where.x);
where.y = roundf(where.y);
where.ConstrainTo(fFrame);
if (event->ReplacePoint("where", where) != B_OK)
event->AddPoint("where", where);
if (!event->HasInt64("when"))
event->AddInt64("when", system_time());
event->AddInt32("modifiers", fKeyInfo.modifiers);
break;
}
case B_KEY_DOWN:
case B_UNMAPPED_KEY_DOWN:
// add modifiers
if (!event->HasInt32("modifiers"))
event->AddInt32("modifiers", fKeyInfo.modifiers);
// add key states
if (!event->HasData("states", B_UINT8_TYPE)) {
event->AddData("states", B_UINT8_TYPE, fKeyInfo.key_states,
sizeof(fKeyInfo.key_states));
}
break;
}
}
return true;
}
/*! 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);
}
{
// move the method events into the event queue - they are not
// "methodized" either
BAutolock _(fEventQueueLock);
events.AddList(&fMethodQueue);
fMethodQueue.MakeEmpty();
}
if (!fInputMethodAware) {
// special handling for non-input-method-aware views
int32 newCount = events.CountItems();
// we may add new events in this loop that don't need to be checked again
for (int32 i = 0; i < newCount; i++) {
BMessage* event = events.ItemAt(i);
if (event->what != B_INPUT_METHOD_EVENT)
continue;
SERIAL_PRINT(("IME received\n"));
bool removeEvent = true;
int32 opcode;
if (event->FindInt32("be:opcode", &opcode) == B_OK) {
bool inlineOnly;
if (event->FindBool("be:inline_only", &inlineOnly) != B_OK)
inlineOnly = false;
if (inlineOnly) {
BMessage translated;
bool confirmed;
if (opcode == B_INPUT_METHOD_CHANGED
&& event->FindBool("be:confirmed", &confirmed) == B_OK && confirmed
&& event->FindMessage("be:translated", &translated) == B_OK) {
// translate event for the non-aware view
*event = translated;
removeEvent = false;
}
} else {
if (fInputMethodWindow == NULL
&& opcode == B_INPUT_METHOD_STARTED)
fInputMethodWindow = new (nothrow) BottomlineWindow();
if (fInputMethodWindow != NULL) {
EventList newEvents;
fInputMethodWindow->HandleInputMethodEvent(event, newEvents);
if (!newEvents.IsEmpty()) {
events.AddList(&newEvents);
opcode = B_INPUT_METHOD_STOPPED;
}
if (opcode == B_INPUT_METHOD_STOPPED) {
fInputMethodWindow->PostMessage(B_QUIT_REQUESTED);
fInputMethodWindow = NULL;
}
}
}
}
if (removeEvent) {
// the inline/bottom window has eaten the event
events.RemoveItemAt(i--);
delete event;
newCount--;
}
}
}
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) {
EventList addedEvents;
EventList::Private(&addedEvents).AsBList()->AddList(&newEvents);
_SanitizeEvents(addedEvents);
// add the new events - but don't methodize them again
events.AddList(&addedEvents, 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) {
atomic_set((int32*)&fCursorBuffer->pos, (uint32)fMousePos.x << 16UL
| ((uint32)fMousePos.y & 0xffff));
if (atomic_or(&fCursorBuffer->read, 1) == 0)
release_sem(fCursorSem);
}
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));
}
break;
}
default:
break;
}
BMessenger reply;
BMessage::Private messagePrivate(event);
return messagePrivate.SendMessage(fAppServerPort, fAppServerTeam, 0, 0,
false, reply);
}
// #pragma mark -
extern "C" void
RegisterDevices(input_device_ref** devices)
{
CALLED();
}
BView *
instantiate_deskbar_item()
{
return new MethodReplicant(INPUTSERVER_SIGNATURE);
}
// #pragma mark -
int
main(int /*argc*/, char** /*argv*/)
{
InputServer *inputServer = new InputServer;
inputServer->Run();
delete inputServer;
return 0;
}