bin/pc: Mark non-returning function as void
[haiku.git] / src / servers / input / InputServer.cpp
blob396bb0526db622912bb230ceb24c8c008cecbc75
1 /*
2 * Copyright 2002-2013 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 */
7 #include "InputServer.h"
8 #include "InputServerTypes.h"
9 #include "BottomlineWindow.h"
10 #include "MethodReplicant.h"
12 #include <driver_settings.h>
13 #include <keyboard_mouse_driver.h>
14 #include <safemode_defs.h>
15 #include <syscalls.h>
17 #include <AppServerLink.h>
18 #include <MessagePrivate.h>
19 #include <ObjectListPrivate.h>
20 #include <RosterPrivate.h>
22 #include <Autolock.h>
23 #include <Deskbar.h>
24 #include <Directory.h>
25 #include <Entry.h>
26 #include <File.h>
27 #include <FindDirectory.h>
28 #include <Locker.h>
29 #include <Message.h>
30 #include <OS.h>
31 #include <Path.h>
32 #include <Roster.h>
33 #include <String.h>
35 #include <stdio.h>
36 #include <strings.h>
38 #include "SystemKeymap.h"
39 // this is an automatically generated file
41 #include <ServerProtocol.h>
43 using std::nothrow;
46 // Global InputServer member variables.
48 InputServer* gInputServer;
50 BList InputServer::gInputFilterList;
51 BLocker InputServer::gInputFilterListLocker("is_filter_queue_sem");
53 BList InputServer::gInputMethodList;
54 BLocker InputServer::gInputMethodListLocker("is_method_queue_sem");
56 KeymapMethod InputServer::gKeymapMethod;
59 extern "C" _EXPORT BView* instantiate_deskbar_item();
62 // #pragma mark - InputDeviceListItem
65 InputDeviceListItem::InputDeviceListItem(BInputServerDevice& serverDevice,
66 const input_device_ref& device)
68 fServerDevice(&serverDevice),
69 fDevice(),
70 fRunning(false)
72 fDevice.name = strdup(device.name);
73 fDevice.type = device.type;
74 fDevice.cookie = device.cookie;
78 InputDeviceListItem::~InputDeviceListItem()
80 free(fDevice.name);
84 void
85 InputDeviceListItem::Start()
87 PRINT((" Starting: %s\n", fDevice.name));
88 status_t err = fServerDevice->Start(fDevice.name, fDevice.cookie);
89 if (err != B_OK) {
90 PRINTERR((" error: %s (%lx)\n", strerror(err), err));
92 fRunning = err == B_OK;
96 void
97 InputDeviceListItem::Stop()
99 PRINT((" Stopping: %s\n", fDevice.name));
100 fServerDevice->Stop(fDevice.name, fDevice.cookie);
101 fRunning = false;
105 void
106 InputDeviceListItem::Control(uint32 code, BMessage* message)
108 fServerDevice->Control(fDevice.name, fDevice.cookie, code, message);
112 bool
113 InputDeviceListItem::HasName(const char* name) const
115 if (name == NULL)
116 return false;
118 return !strcmp(name, fDevice.name);
122 bool
123 InputDeviceListItem::HasType(input_device_type type) const
125 return type == fDevice.type;
129 bool
130 InputDeviceListItem::Matches(const char* name, input_device_type type) const
132 if (name != NULL)
133 return HasName(name);
135 return HasType(type);
139 // #pragma mark -
142 InputServer::InputServer()
144 BApplication(INPUTSERVER_SIGNATURE),
145 fKeyboardID(0),
146 fInputDeviceListLocker("input server device list"),
147 fKeyboardSettings(),
148 fMouseSettings(),
149 fChars(NULL),
150 fScreen(B_MAIN_SCREEN_ID),
151 fEventQueueLock("input server event queue"),
152 fReplicantMessenger(NULL),
153 fInputMethodWindow(NULL),
154 fInputMethodAware(false),
155 fCursorSem(-1),
156 fAppServerPort(-1),
157 fAppServerTeam(-1),
158 fCursorArea(-1)
160 CALLED();
161 gInputServer = this;
163 set_thread_priority(find_thread(NULL), B_URGENT_DISPLAY_PRIORITY);
164 // elevate priority for client interaction
166 _StartEventLoop();
168 _InitKeyboardMouseStates();
170 fAddOnManager = new(std::nothrow) ::AddOnManager();
171 if (fAddOnManager != NULL) {
172 // We need to Run() the AddOnManager looper after having loaded
173 // the initial add-ons, otherwise we may deadlock when the looper
174 // thread for some reason already receives node monitor notifications
175 // while we are still locked ourselves and are executing LoadState()
176 // at the same time (which may lock the add-on looper thread).
177 // NOTE: At first sight this may look like we may loose node monitor
178 // notifications while the thread is not yet running, but in fact those
179 // message should just pile up and be processed later.
180 fAddOnManager->LoadState();
181 fAddOnManager->Run();
184 BMessenger messenger(this);
185 BRoster().StartWatching(messenger, B_REQUEST_LAUNCHED);
189 InputServer::~InputServer()
191 CALLED();
192 if (fAddOnManager->Lock())
193 fAddOnManager->Quit();
195 _ReleaseInput(NULL);
199 void
200 InputServer::ArgvReceived(int32 argc, char** argv)
202 CALLED();
204 if (argc == 2 && strcmp(argv[1], "-q") == 0) {
205 PRINT(("InputServer::ArgvReceived - Restarting ...\n"));
206 PostMessage(B_QUIT_REQUESTED);
211 void
212 InputServer::_InitKeyboardMouseStates()
214 CALLED();
215 // This is where we determine the screen resolution from the app_server and
216 // find the center of the screen
217 // fMousePos is then set to the center of the screen.
219 fFrame = fScreen.Frame();
220 if (fFrame == BRect(0, 0, 0, 0))
221 fFrame = BRect(0, 0, 799, 599);
222 fMousePos = BPoint((int32)((fFrame.right + 1) / 2),
223 (int32)((fFrame.bottom + 1) / 2));
225 memset(&fKeyInfo, 0, sizeof(fKeyInfo));
227 if (_LoadKeymap() != B_OK)
228 _LoadSystemKeymap();
230 BMessage msg(B_MOUSE_MOVED);
231 HandleSetMousePosition(&msg, &msg);
233 fActiveMethod = &gKeymapMethod;
237 status_t
238 InputServer::_LoadKeymap()
240 BPath path;
241 if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK)
242 return B_BAD_VALUE;
244 path.Append("Key_map");
246 status_t err;
248 BFile file(path.Path(), B_READ_ONLY);
249 if ((err = file.InitCheck()) != B_OK)
250 return err;
252 if (file.Read(&fKeys, sizeof(fKeys)) < (ssize_t)sizeof(fKeys))
253 return B_BAD_VALUE;
255 for (uint32 i = 0; i < sizeof(fKeys) / 4; i++)
256 ((uint32*)&fKeys)[i] = B_BENDIAN_TO_HOST_INT32(((uint32*)&fKeys)[i]);
258 if (file.Read(&fCharsSize, sizeof(uint32)) < (ssize_t)sizeof(uint32))
259 return B_BAD_VALUE;
261 fCharsSize = B_BENDIAN_TO_HOST_INT32(fCharsSize);
262 if (fCharsSize <= 0)
263 return B_BAD_VALUE;
265 delete[] fChars;
266 fChars = new (nothrow) char[fCharsSize];
267 if (fChars == NULL)
268 return B_NO_MEMORY;
270 if (file.Read(fChars, fCharsSize) != (signed)fCharsSize)
271 return B_BAD_VALUE;
273 return B_OK;
277 status_t
278 InputServer::_LoadSystemKeymap()
280 delete[] fChars;
281 fKeys = kSystemKeymap;
282 fCharsSize = kSystemKeyCharsSize;
283 fChars = new (nothrow) char[fCharsSize];
284 if (fChars == NULL)
285 return B_NO_MEMORY;
287 memcpy(fChars, kSystemKeyChars, fCharsSize);
289 // TODO: why are we doing this?
290 return _SaveKeymap(true);
294 status_t
295 InputServer::_SaveKeymap(bool isDefault)
297 // we save this keymap to file
298 BPath path;
299 if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK)
300 return B_BAD_VALUE;
302 path.Append("Key_map");
304 BFile file;
305 status_t err = file.SetTo(path.Path(), B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE);
306 if (err != B_OK) {
307 PRINTERR(("error %s\n", strerror(err)));
308 return err;
311 for (uint32 i = 0; i < sizeof(fKeys) / sizeof(uint32); i++) {
312 ((uint32*)&fKeys)[i] = B_HOST_TO_BENDIAN_INT32(((uint32*)&fKeys)[i]);
315 if ((err = file.Write(&fKeys, sizeof(fKeys))) < (ssize_t)sizeof(fKeys))
316 return err;
318 for (uint32 i = 0; i < sizeof(fKeys) / sizeof(uint32); i++) {
319 ((uint32*)&fKeys)[i] = B_BENDIAN_TO_HOST_INT32(((uint32*)&fKeys)[i]);
322 uint32 size = B_HOST_TO_BENDIAN_INT32(fCharsSize);
324 if ((err = file.Write(&size, sizeof(uint32))) < (ssize_t)sizeof(uint32))
325 return B_BAD_VALUE;
327 if ((err = file.Write(fChars, fCharsSize)) < (ssize_t)fCharsSize)
328 return err;
330 // don't bother reporting an error if this fails, since this isn't fatal
331 // the keymap will still be functional, and will just be identified as (Current) in prefs instead of its
332 // actual name
333 if (isDefault)
334 file.WriteAttr("keymap:name", B_STRING_TYPE, 0, kSystemKeymapName, strlen(kSystemKeymapName));
336 return B_OK;
340 bool
341 InputServer::QuitRequested()
343 CALLED();
344 if (!BApplication::QuitRequested())
345 return false;
347 PostMessage(SYSTEM_SHUTTING_DOWN);
349 bool shutdown = false;
350 CurrentMessage()->FindBool("_shutdown_", &shutdown);
352 // Don't actually quit when the system is being shutdown
353 if (shutdown) {
354 return false;
355 } else {
356 fAddOnManager->SaveState();
358 delete_port(fEventLooperPort);
359 // the event looper thread will exit after this
360 fEventLooperPort = -1;
361 return true;
366 void
367 InputServer::ReadyToRun()
369 CALLED();
371 // say hello to the app_server
373 BPrivate::AppServerLink link;
374 link.StartMessage(AS_REGISTER_INPUT_SERVER);
375 link.Flush();
379 status_t
380 InputServer::_AcquireInput(BMessage& message, BMessage& reply)
382 // TODO: it currently just gets everything we have
383 area_id area;
384 if (message.FindInt32("cursor area", &area) == B_OK) {
385 // try to clone the area
386 fCursorBuffer = NULL;
388 fCursorSem = create_sem(0, "cursor semaphore");
389 if (fCursorSem >= B_OK) {
390 fCursorArea = clone_area("input server cursor", (void**)&fCursorBuffer,
391 B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, area);
395 if (message.FindInt32("remote team", &fAppServerTeam) != B_OK)
396 fAppServerTeam = -1;
398 fAppServerPort = create_port(200, "input server target");
399 if (fAppServerPort < B_OK) {
400 _ReleaseInput(&message);
401 return fAppServerPort;
404 reply.AddBool("has keyboard", true);
405 reply.AddBool("has mouse", true);
406 reply.AddInt32("event port", fAppServerPort);
408 if (fCursorBuffer != NULL) {
409 // cursor shared buffer is supported
410 reply.AddInt32("cursor semaphore", fCursorSem);
413 return B_OK;
417 void
418 InputServer::_ReleaseInput(BMessage* /*message*/)
420 if (fCursorBuffer != NULL) {
421 fCursorBuffer = NULL;
422 delete_sem(fCursorSem);
423 delete_area(fCursorArea);
425 fCursorSem = -1;
426 fCursorArea = -1;
429 delete_port(fAppServerPort);
433 void
434 InputServer::MessageReceived(BMessage* message)
436 CALLED();
438 BMessage reply;
439 status_t status = B_OK;
441 PRINT(("%s what:%c%c%c%c\n", __PRETTY_FUNCTION__, (char)(message->what >> 24),
442 (char)(message->what >> 16), (char)(message->what >> 8), (char)message->what));
444 switch (message->what) {
445 case IS_SET_METHOD:
446 HandleSetMethod(message);
447 break;
448 case IS_GET_MOUSE_TYPE:
449 status = HandleGetSetMouseType(message, &reply);
450 break;
451 case IS_SET_MOUSE_TYPE:
452 status = HandleGetSetMouseType(message, &reply);
453 break;
454 case IS_GET_MOUSE_ACCELERATION:
455 status = HandleGetSetMouseAcceleration(message, &reply);
456 break;
457 case IS_SET_MOUSE_ACCELERATION:
458 status = HandleGetSetMouseAcceleration(message, &reply);
459 break;
460 case IS_GET_KEY_REPEAT_DELAY:
461 status = HandleGetSetKeyRepeatDelay(message, &reply);
462 break;
463 case IS_SET_KEY_REPEAT_DELAY:
464 status = HandleGetSetKeyRepeatDelay(message, &reply);
465 break;
466 case IS_GET_KEY_INFO:
467 status = HandleGetKeyInfo(message, &reply);
468 break;
469 case IS_GET_MODIFIERS:
470 status = HandleGetModifiers(message, &reply);
471 break;
472 case IS_GET_MODIFIER_KEY:
473 status = HandleGetModifierKey(message, &reply);
474 break;
475 case IS_SET_MODIFIER_KEY:
476 status = HandleSetModifierKey(message, &reply);
477 break;
478 case IS_SET_KEYBOARD_LOCKS:
479 status = HandleSetKeyboardLocks(message, &reply);
480 break;
481 case IS_GET_MOUSE_SPEED:
482 status = HandleGetSetMouseSpeed(message, &reply);
483 break;
484 case IS_SET_MOUSE_SPEED:
485 status = HandleGetSetMouseSpeed(message, &reply);
486 break;
487 case IS_SET_MOUSE_POSITION:
488 status = HandleSetMousePosition(message, &reply);
489 break;
490 case IS_GET_MOUSE_MAP:
491 status = HandleGetSetMouseMap(message, &reply);
492 break;
493 case IS_SET_MOUSE_MAP:
494 status = HandleGetSetMouseMap(message, &reply);
495 break;
496 case IS_GET_KEYBOARD_ID:
497 status = HandleGetSetKeyboardID(message, &reply);
498 break;
499 case IS_SET_KEYBOARD_ID:
500 status = HandleGetSetKeyboardID(message, &reply);
501 break;
502 case IS_GET_CLICK_SPEED:
503 status = HandleGetSetClickSpeed(message, &reply);
504 break;
505 case IS_SET_CLICK_SPEED:
506 status = HandleGetSetClickSpeed(message, &reply);
507 break;
508 case IS_GET_KEY_REPEAT_RATE:
509 status = HandleGetSetKeyRepeatRate(message, &reply);
510 break;
511 case IS_SET_KEY_REPEAT_RATE:
512 status = HandleGetSetKeyRepeatRate(message, &reply);
513 break;
514 case IS_GET_KEY_MAP:
515 status = HandleGetSetKeyMap(message, &reply);
516 break;
517 case IS_RESTORE_KEY_MAP:
518 status = HandleGetSetKeyMap(message, &reply);
519 break;
520 case IS_FOCUS_IM_AWARE_VIEW:
521 status = HandleFocusUnfocusIMAwareView(message, &reply);
522 break;
523 case IS_UNFOCUS_IM_AWARE_VIEW:
524 status = HandleFocusUnfocusIMAwareView(message, &reply);
525 break;
527 // app_server communication
528 case IS_ACQUIRE_INPUT:
529 status = _AcquireInput(*message, reply);
530 break;
531 case IS_RELEASE_INPUT:
532 _ReleaseInput(message);
533 return;
534 case IS_SCREEN_BOUNDS_UPDATED:
536 // This is what the R5 app_server sends us when the screen
537 // configuration changes
538 BRect frame;
539 if (message->FindRect("screen_bounds", &frame) != B_OK)
540 frame = fScreen.Frame();
542 if (frame == fFrame)
543 break;
545 BPoint pos(fMousePos.x * frame.Width() / fFrame.Width(),
546 fMousePos.y * frame.Height() / fFrame.Height());
547 fFrame = frame;
549 BMessage set;
550 set.AddPoint("where", pos);
551 HandleSetMousePosition(&set, NULL);
552 break;
555 // device looper related
556 case IS_FIND_DEVICES:
557 case IS_WATCH_DEVICES:
558 case IS_IS_DEVICE_RUNNING:
559 case IS_START_DEVICE:
560 case IS_STOP_DEVICE:
561 case IS_CONTROL_DEVICES:
562 case SYSTEM_SHUTTING_DOWN:
563 case IS_METHOD_REGISTER:
564 fAddOnManager->PostMessage(message);
565 return;
567 case IS_SAVE_SETTINGS:
568 fKeyboardSettings.Save();
569 fMouseSettings.SaveSettings();
570 return;
572 case IS_SAVE_KEYMAP:
573 _SaveKeymap();
574 return;
576 case B_SOME_APP_LAUNCHED:
578 const char *signature;
579 // TODO: what's this for?
580 if (message->FindString("be:signature", &signature)==B_OK) {
581 PRINT(("input_server : %s\n", signature));
582 if (strcmp(signature, "application/x-vnd.Be-TSKB")==0) {
586 return;
589 case kMsgAppServerRestarted:
591 BApplication::MessageReceived(message);
592 BPrivate::AppServerLink link;
593 link.StartMessage(AS_REGISTER_INPUT_SERVER);
594 link.Flush();
595 return;
598 default:
599 return;
602 reply.AddInt32("status", status);
603 message->SendReply(&reply);
607 void
608 InputServer::HandleSetMethod(BMessage* message)
610 CALLED();
611 int32 cookie;
612 if (message->FindInt32("cookie", &cookie) != B_OK)
613 return;
614 if (cookie == gKeymapMethod.fOwner->Cookie()) {
615 SetActiveMethod(&gKeymapMethod);
616 } else {
617 BAutolock lock(InputServer::gInputMethodListLocker);
618 for (int32 i = 0; i < gInputMethodList.CountItems(); i++) {
619 BInputServerMethod* method
620 = (BInputServerMethod*)InputServer::gInputMethodList.ItemAt(i);
621 if (method->fOwner->Cookie() == cookie) {
622 PRINT(("%s cookie %" B_PRId32 "\n", __PRETTY_FUNCTION__,
623 cookie));
624 SetActiveMethod(method);
625 break;
632 status_t
633 InputServer::HandleGetSetMouseType(BMessage* message, BMessage* reply)
635 int32 type;
636 if (message->FindInt32("mouse_type", &type) == B_OK) {
637 fMouseSettings.SetMouseType(type);
638 be_app_messenger.SendMessage(IS_SAVE_SETTINGS);
640 BMessage msg(IS_CONTROL_DEVICES);
641 msg.AddInt32("type", B_POINTING_DEVICE);
642 msg.AddInt32("code", B_MOUSE_TYPE_CHANGED);
643 return fAddOnManager->PostMessage(&msg);
646 return reply->AddInt32("mouse_type", fMouseSettings.MouseType());
650 status_t
651 InputServer::HandleGetSetMouseAcceleration(BMessage* message,
652 BMessage* reply)
654 int32 factor;
655 if (message->FindInt32("speed", &factor) == B_OK) {
656 fMouseSettings.SetAccelerationFactor(factor);
657 be_app_messenger.SendMessage(IS_SAVE_SETTINGS);
659 BMessage msg(IS_CONTROL_DEVICES);
660 msg.AddInt32("type", B_POINTING_DEVICE);
661 msg.AddInt32("code", B_MOUSE_ACCELERATION_CHANGED);
662 return fAddOnManager->PostMessage(&msg);
665 return reply->AddInt32("speed", fMouseSettings.AccelerationFactor());
669 status_t
670 InputServer::HandleGetSetKeyRepeatDelay(BMessage* message, BMessage* reply)
672 bigtime_t delay;
673 if (message->FindInt64("delay", &delay) == B_OK) {
674 fKeyboardSettings.SetKeyboardRepeatDelay(delay);
675 be_app_messenger.SendMessage(IS_SAVE_SETTINGS);
677 BMessage msg(IS_CONTROL_DEVICES);
678 msg.AddInt32("type", B_KEYBOARD_DEVICE);
679 msg.AddInt32("code", B_KEY_REPEAT_DELAY_CHANGED);
680 return fAddOnManager->PostMessage(&msg);
683 return reply->AddInt64("delay", fKeyboardSettings.KeyboardRepeatDelay());
687 status_t
688 InputServer::HandleGetKeyInfo(BMessage* message, BMessage* reply)
690 return reply->AddData("key_info", B_ANY_TYPE, &fKeyInfo, sizeof(fKeyInfo));
694 status_t
695 InputServer::HandleGetModifiers(BMessage* message, BMessage* reply)
697 return reply->AddInt32("modifiers", fKeyInfo.modifiers);
701 status_t
702 InputServer::HandleGetModifierKey(BMessage* message, BMessage* reply)
704 int32 modifier;
706 if (message->FindInt32("modifier", &modifier) == B_OK) {
707 switch (modifier) {
708 case B_CAPS_LOCK:
709 return reply->AddInt32("key", fKeys.caps_key);
710 case B_NUM_LOCK:
711 return reply->AddInt32("key", fKeys.num_key);
712 case B_SCROLL_LOCK:
713 return reply->AddInt32("key", fKeys.scroll_key);
714 case B_LEFT_SHIFT_KEY:
715 return reply->AddInt32("key", fKeys.left_shift_key);
716 case B_RIGHT_SHIFT_KEY:
717 return reply->AddInt32("key", fKeys.right_shift_key);
718 case B_LEFT_COMMAND_KEY:
719 return reply->AddInt32("key", fKeys.left_command_key);
720 case B_RIGHT_COMMAND_KEY:
721 return reply->AddInt32("key", fKeys.right_command_key);
722 case B_LEFT_CONTROL_KEY:
723 return reply->AddInt32("key", fKeys.left_control_key);
724 case B_RIGHT_CONTROL_KEY:
725 return reply->AddInt32("key", fKeys.right_control_key);
726 case B_LEFT_OPTION_KEY:
727 return reply->AddInt32("key", fKeys.left_option_key);
728 case B_RIGHT_OPTION_KEY:
729 return reply->AddInt32("key", fKeys.right_option_key);
730 case B_MENU_KEY:
731 return reply->AddInt32("key", fKeys.menu_key);
734 return B_ERROR;
738 status_t
739 InputServer::HandleSetModifierKey(BMessage* message, BMessage* reply)
741 int32 modifier, key;
742 if (message->FindInt32("modifier", &modifier) == B_OK
743 && message->FindInt32("key", &key) == B_OK) {
744 switch (modifier) {
745 case B_CAPS_LOCK:
746 fKeys.caps_key = key;
747 break;
748 case B_NUM_LOCK:
749 fKeys.num_key = key;
750 break;
751 case B_SCROLL_LOCK:
752 fKeys.scroll_key = key;
753 break;
754 case B_LEFT_SHIFT_KEY:
755 fKeys.left_shift_key = key;
756 break;
757 case B_RIGHT_SHIFT_KEY:
758 fKeys.right_shift_key = key;
759 break;
760 case B_LEFT_COMMAND_KEY:
761 fKeys.left_command_key = key;
762 break;
763 case B_RIGHT_COMMAND_KEY:
764 fKeys.right_command_key = key;
765 break;
766 case B_LEFT_CONTROL_KEY:
767 fKeys.left_control_key = key;
768 break;
769 case B_RIGHT_CONTROL_KEY:
770 fKeys.right_control_key = key;
771 break;
772 case B_LEFT_OPTION_KEY:
773 fKeys.left_option_key = key;
774 break;
775 case B_RIGHT_OPTION_KEY:
776 fKeys.right_option_key = key;
777 break;
778 case B_MENU_KEY:
779 fKeys.menu_key = key;
780 break;
781 default:
782 return B_ERROR;
785 // TODO: unmap the key ?
787 be_app_messenger.SendMessage(IS_SAVE_KEYMAP);
789 BMessage msg(IS_CONTROL_DEVICES);
790 msg.AddInt32("type", B_KEYBOARD_DEVICE);
791 msg.AddInt32("code", B_KEY_MAP_CHANGED);
792 return fAddOnManager->PostMessage(&msg);
795 return B_ERROR;
799 status_t
800 InputServer::HandleSetKeyboardLocks(BMessage* message, BMessage* reply)
802 if (message->FindInt32("locks", (int32*)&fKeys.lock_settings) == B_OK) {
803 be_app_messenger.SendMessage(IS_SAVE_KEYMAP);
805 BMessage msg(IS_CONTROL_DEVICES);
806 msg.AddInt32("type", B_KEYBOARD_DEVICE);
807 msg.AddInt32("code", B_KEY_LOCKS_CHANGED);
808 return fAddOnManager->PostMessage(&msg);
811 return B_ERROR;
815 status_t
816 InputServer::HandleGetSetMouseSpeed(BMessage* message, BMessage* reply)
818 int32 speed;
819 if (message->FindInt32("speed", &speed) == B_OK) {
820 fMouseSettings.SetMouseSpeed(speed);
821 be_app_messenger.SendMessage(IS_SAVE_SETTINGS);
823 BMessage msg(IS_CONTROL_DEVICES);
824 msg.AddInt32("type", B_POINTING_DEVICE);
825 msg.AddInt32("code", B_MOUSE_SPEED_CHANGED);
826 return fAddOnManager->PostMessage(&msg);
829 return reply->AddInt32("speed", fMouseSettings.MouseSpeed());
833 status_t
834 InputServer::HandleSetMousePosition(BMessage* message, BMessage* reply)
836 CALLED();
838 BPoint where;
839 if (message->FindPoint("where", &where) != B_OK)
840 return B_BAD_VALUE;
842 // create a new event for this and enqueue it to the event list just like any other
844 BMessage* event = new BMessage(B_MOUSE_MOVED);
845 if (event == NULL)
846 return B_NO_MEMORY;
848 event->AddPoint("where", where);
849 event->AddBool("be:set_mouse", true);
850 if (EnqueueDeviceMessage(event) != B_OK) {
851 delete event;
852 return B_NO_MEMORY;
855 return B_OK;
859 status_t
860 InputServer::HandleGetSetMouseMap(BMessage* message, BMessage* reply)
862 mouse_map *map;
863 ssize_t size;
864 if (message->FindData("mousemap", B_RAW_TYPE, (const void**)&map, &size) == B_OK) {
865 fMouseSettings.SetMapping(*map);
866 be_app_messenger.SendMessage(IS_SAVE_SETTINGS);
868 BMessage msg(IS_CONTROL_DEVICES);
869 msg.AddInt32("type", B_POINTING_DEVICE);
870 msg.AddInt32("code", B_MOUSE_MAP_CHANGED);
871 return fAddOnManager->PostMessage(&msg);
872 } else {
873 mouse_map map;
874 fMouseSettings.Mapping(map);
875 return reply->AddData("mousemap", B_RAW_TYPE, &map, sizeof(mouse_map));
880 status_t
881 InputServer::HandleGetSetKeyboardID(BMessage* message, BMessage* reply)
883 int16 id;
884 if (message->FindInt16("id", &id) == B_OK) {
885 fKeyboardID = (uint16)id;
886 return B_OK;
888 return reply->AddInt16("id", fKeyboardID);
892 status_t
893 InputServer::HandleGetSetClickSpeed(BMessage* message, BMessage* reply)
895 bigtime_t clickSpeed;
896 if (message->FindInt64("speed", &clickSpeed) == B_OK) {
897 fMouseSettings.SetClickSpeed(clickSpeed);
898 be_app_messenger.SendMessage(IS_SAVE_SETTINGS);
900 BMessage msg(IS_CONTROL_DEVICES);
901 msg.AddInt32("type", B_POINTING_DEVICE);
902 msg.AddInt32("code", B_CLICK_SPEED_CHANGED);
903 return fAddOnManager->PostMessage(&msg);
906 return reply->AddInt64("speed", fMouseSettings.ClickSpeed());
910 status_t
911 InputServer::HandleGetSetKeyRepeatRate(BMessage* message, BMessage* reply)
913 int32 keyRepeatRate;
914 if (message->FindInt32("rate", &keyRepeatRate) == B_OK) {
915 fKeyboardSettings.SetKeyboardRepeatRate(keyRepeatRate);
916 be_app_messenger.SendMessage(IS_SAVE_SETTINGS);
918 BMessage msg(IS_CONTROL_DEVICES);
919 msg.AddInt32("type", B_KEYBOARD_DEVICE);
920 msg.AddInt32("code", B_KEY_REPEAT_RATE_CHANGED);
921 return fAddOnManager->PostMessage(&msg);
924 return reply->AddInt32("rate", fKeyboardSettings.KeyboardRepeatRate());
928 status_t
929 InputServer::HandleGetSetKeyMap(BMessage* message, BMessage* reply)
931 CALLED();
933 if (message->what == IS_GET_KEY_MAP) {
934 status_t status = reply->AddData("keymap", B_ANY_TYPE, &fKeys, sizeof(fKeys));
935 if (status == B_OK)
936 status = reply->AddData("key_buffer", B_ANY_TYPE, fChars, fCharsSize);
938 return status;
941 if (_LoadKeymap() != B_OK)
942 _LoadSystemKeymap();
944 BMessage msg(IS_CONTROL_DEVICES);
945 msg.AddInt32("type", B_KEYBOARD_DEVICE);
946 msg.AddInt32("code", B_KEY_MAP_CHANGED);
947 return fAddOnManager->PostMessage(&msg);
951 status_t
952 InputServer::HandleFocusUnfocusIMAwareView(BMessage* message,
953 BMessage* reply)
955 CALLED();
957 BMessenger messenger;
958 status_t status = message->FindMessenger("view", &messenger);
959 if (status != B_OK)
960 return status;
962 // check if current view is ours
964 if (message->what == IS_FOCUS_IM_AWARE_VIEW) {
965 PRINT(("HandleFocusUnfocusIMAwareView : entering\n"));
966 fInputMethodAware = true;
967 } else {
968 PRINT(("HandleFocusUnfocusIMAwareView : leaving\n"));
969 fInputMethodAware = false;
972 return B_OK;
976 /*! Enqueues the message into the event queue.
977 The message must only be deleted in case this method returns an error.
979 status_t
980 InputServer::EnqueueDeviceMessage(BMessage* message)
982 CALLED();
984 BAutolock _(fEventQueueLock);
985 if (!fEventQueue.AddItem(message))
986 return B_NO_MEMORY;
988 if (fEventQueue.CountItems() == 1) {
989 // notify event loop only if we haven't already done so
990 write_port_etc(fEventLooperPort, 1, NULL, 0, B_RELATIVE_TIMEOUT, 0);
992 return B_OK;
996 /*! Enqueues the message into the method queue.
997 The message must only be deleted in case this method returns an error.
999 status_t
1000 InputServer::EnqueueMethodMessage(BMessage* message)
1002 CALLED();
1003 PRINT(("%s what:%c%c%c%c\n", __PRETTY_FUNCTION__, (char)(message->what >> 24),
1004 (char)(message->what >> 16), (char)(message->what >> 8), (char)message->what));
1006 #ifdef DEBUG
1007 if (message->what == 'IMEV') {
1008 int32 code;
1009 message->FindInt32("be:opcode", &code);
1010 PRINT(("%s be:opcode %li\n", __PRETTY_FUNCTION__, code));
1012 #endif
1014 BAutolock _(fEventQueueLock);
1015 if (!fMethodQueue.AddItem(message))
1016 return B_NO_MEMORY;
1018 if (fMethodQueue.CountItems() == 1) {
1019 // notify event loop only if we haven't already done so
1020 write_port_etc(fEventLooperPort, 0, NULL, 0, B_RELATIVE_TIMEOUT, 0);
1022 return B_OK;
1026 status_t
1027 InputServer::SetNextMethod(bool direction)
1029 gInputMethodListLocker.Lock();
1031 int32 index = gInputMethodList.IndexOf(fActiveMethod);
1032 int32 oldIndex = index;
1034 index += (direction ? 1 : -1);
1036 if (index < -1)
1037 index = gInputMethodList.CountItems() - 1;
1038 if (index >= gInputMethodList.CountItems())
1039 index = -1;
1041 if (index == oldIndex)
1042 return B_BAD_INDEX;
1044 BInputServerMethod *method = &gKeymapMethod;
1046 if (index != -1)
1047 method = (BInputServerMethod *)gInputMethodList.ItemAt(index);
1049 SetActiveMethod(method);
1051 gInputMethodListLocker.Unlock();
1052 return B_OK;
1056 void
1057 InputServer::SetActiveMethod(BInputServerMethod* method)
1059 CALLED();
1060 if (fActiveMethod)
1061 fActiveMethod->fOwner->MethodActivated(false);
1063 fActiveMethod = method;
1065 if (fActiveMethod)
1066 fActiveMethod->fOwner->MethodActivated(true);
1070 const BMessenger*
1071 InputServer::MethodReplicant()
1073 return fReplicantMessenger;
1077 void
1078 InputServer::SetMethodReplicant(const BMessenger* messenger)
1080 fReplicantMessenger = messenger;
1084 bool
1085 InputServer::EventLoopRunning()
1087 return fEventLooperPort >= B_OK;
1091 status_t
1092 InputServer::GetDeviceInfo(const char* name, input_device_type *_type,
1093 bool *_isRunning)
1095 BAutolock lock(fInputDeviceListLocker);
1097 for (int32 i = fInputDeviceList.CountItems() - 1; i >= 0; i--) {
1098 InputDeviceListItem* item = (InputDeviceListItem*)fInputDeviceList.ItemAt(i);
1100 if (item->HasName(name)) {
1101 if (_type)
1102 *_type = item->Type();
1103 if (_isRunning)
1104 *_isRunning = item->Running();
1106 return B_OK;
1110 return B_NAME_NOT_FOUND;
1114 status_t
1115 InputServer::GetDeviceInfos(BMessage *msg)
1117 CALLED();
1118 BAutolock lock(fInputDeviceListLocker);
1120 for (int32 i = fInputDeviceList.CountItems() - 1; i >= 0; i--) {
1121 InputDeviceListItem* item = (InputDeviceListItem*)fInputDeviceList.ItemAt(i);
1122 msg->AddString("device", item->Name());
1123 msg->AddInt32("type", item->Type());
1125 return B_OK;
1129 status_t
1130 InputServer::UnregisterDevices(BInputServerDevice& serverDevice,
1131 input_device_ref **devices)
1133 CALLED();
1134 BAutolock lock(fInputDeviceListLocker);
1136 if (devices != NULL) {
1137 // remove the devices as specified only
1138 input_device_ref *device = NULL;
1139 for (int32 i = 0; (device = devices[i]) != NULL; i++) {
1140 for (int32 j = fInputDeviceList.CountItems() - 1; j >= 0; j--) {
1141 InputDeviceListItem* item = (InputDeviceListItem*)fInputDeviceList.ItemAt(j);
1143 if (item->ServerDevice() == &serverDevice && item->HasName(device->name)) {
1144 item->Stop();
1145 if (fInputDeviceList.RemoveItem(j))
1146 delete item;
1147 break;
1151 } else {
1152 // remove all devices from this BInputServerObject
1153 for (int32 i = fInputDeviceList.CountItems() - 1; i >= 0; i--) {
1154 InputDeviceListItem* item = (InputDeviceListItem*)fInputDeviceList.ItemAt(i);
1156 if (item->ServerDevice() == &serverDevice) {
1157 item->Stop();
1158 if (fInputDeviceList.RemoveItem(i))
1159 delete item;
1164 return B_OK;
1168 status_t
1169 InputServer::RegisterDevices(BInputServerDevice& serverDevice,
1170 input_device_ref** devices)
1172 if (devices == NULL)
1173 return B_BAD_VALUE;
1175 BAutolock lock(fInputDeviceListLocker);
1177 input_device_ref *device = NULL;
1178 for (int32 i = 0; (device = devices[i]) != NULL; i++) {
1179 if (device->type != B_POINTING_DEVICE
1180 && device->type != B_KEYBOARD_DEVICE
1181 && device->type != B_UNDEFINED_DEVICE)
1182 continue;
1184 // find existing input server device
1186 bool found = false;
1187 for (int32 j = fInputDeviceList.CountItems() - 1; j >= 0; j--) {
1188 InputDeviceListItem* item = (InputDeviceListItem*)fInputDeviceList.ItemAt(j);
1190 if (item->HasName(device->name)) {
1191 debug_printf("InputServer::RegisterDevices() device_ref already exists: %s\n", device->name);
1192 PRINT(("RegisterDevices found %s\n", device->name));
1193 found = true;
1194 break;
1198 if (!found) {
1199 PRINT(("RegisterDevices not found %s\n", device->name));
1200 InputDeviceListItem* item = new (nothrow) InputDeviceListItem(serverDevice,
1201 *device);
1202 if (item != NULL && fInputDeviceList.AddItem(item)) {
1203 item->Start();
1204 } else {
1205 delete item;
1206 return B_NO_MEMORY;
1211 return B_OK;
1215 status_t
1216 InputServer::StartStopDevices(const char* name, input_device_type type,
1217 bool doStart)
1219 CALLED();
1220 BAutolock lock(fInputDeviceListLocker);
1222 for (int32 i = fInputDeviceList.CountItems() - 1; i >= 0; i--) {
1223 InputDeviceListItem* item
1224 = (InputDeviceListItem*)fInputDeviceList.ItemAt(i);
1225 if (!item)
1226 continue;
1228 if (item->Matches(name, type)) {
1229 if (doStart == item->Running()) {
1230 if (name)
1231 return B_OK;
1232 else
1233 continue;
1236 if (doStart)
1237 item->Start();
1238 else
1239 item->Stop();
1241 if (name)
1242 return B_OK;
1246 if (name) {
1247 // item not found
1248 return B_ERROR;
1251 return B_OK;
1256 status_t
1257 InputServer::StartStopDevices(BInputServerDevice& serverDevice, bool doStart)
1259 CALLED();
1260 BAutolock lock(fInputDeviceListLocker);
1262 for (int32 i = fInputDeviceList.CountItems() - 1; i >= 0; i--) {
1263 InputDeviceListItem* item = (InputDeviceListItem*)fInputDeviceList.ItemAt(i);
1265 if (item->ServerDevice() != &serverDevice)
1266 continue;
1268 if (doStart == item->Running())
1269 continue;
1271 if (doStart)
1272 item->Start();
1273 else
1274 item->Stop();
1277 return B_OK;
1281 status_t
1282 InputServer::ControlDevices(const char* name, input_device_type type,
1283 uint32 code, BMessage* message)
1285 CALLED();
1286 BAutolock lock(fInputDeviceListLocker);
1288 for (int32 i = fInputDeviceList.CountItems() - 1; i >= 0; i--) {
1289 InputDeviceListItem* item = (InputDeviceListItem*)fInputDeviceList.ItemAt(i);
1290 if (!item)
1291 continue;
1293 if (item->Matches(name, type)) {
1294 item->Control(code, message);
1296 if (name)
1297 return B_OK;
1301 if (name)
1302 return B_ERROR;
1304 return B_OK;
1308 bool
1309 InputServer::SafeMode()
1311 char parameter[32];
1312 size_t parameterLength = sizeof(parameter);
1314 if (_kern_get_safemode_option(B_SAFEMODE_SAFE_MODE, parameter,
1315 &parameterLength) == B_OK) {
1316 if (!strcasecmp(parameter, "enabled") || !strcasecmp(parameter, "on")
1317 || !strcasecmp(parameter, "true") || !strcasecmp(parameter, "yes")
1318 || !strcasecmp(parameter, "enable") || !strcmp(parameter, "1")) {
1319 return true;
1323 if (_kern_get_safemode_option(B_SAFEMODE_DISABLE_USER_ADD_ONS, parameter,
1324 &parameterLength) == B_OK) {
1325 if (!strcasecmp(parameter, "enabled") || !strcasecmp(parameter, "on")
1326 || !strcasecmp(parameter, "true") || !strcasecmp(parameter, "yes")
1327 || !strcasecmp(parameter, "enable") || !strcmp(parameter, "1")) {
1328 return true;
1332 return false;
1336 status_t
1337 InputServer::_StartEventLoop()
1339 CALLED();
1340 fEventLooperPort = create_port(100, "input server events");
1341 if (fEventLooperPort < 0) {
1342 PRINTERR(("InputServer: create_port error: (0x%lx) %s\n",
1343 fEventLooperPort, strerror(fEventLooperPort)));
1344 return fEventLooperPort;
1347 thread_id thread = spawn_thread(_EventLooper, "_input_server_event_loop_",
1348 B_REAL_TIME_DISPLAY_PRIORITY + 3, this);
1349 if (thread < B_OK || resume_thread(thread) < B_OK) {
1350 if (thread >= B_OK)
1351 kill_thread(thread);
1352 delete_port(fEventLooperPort);
1353 fEventLooperPort = -1;
1354 return thread < B_OK ? thread : B_ERROR;
1357 return B_OK;
1361 status_t
1362 InputServer::_EventLooper(void* arg)
1364 InputServer* self = (InputServer*)arg;
1365 self->_EventLoop();
1367 return B_OK;
1371 void
1372 InputServer::_EventLoop()
1374 while (true) {
1375 // Block until we find the size of the next message
1376 ssize_t length = port_buffer_size(fEventLooperPort);
1377 if (length < B_OK) {
1378 PRINT(("[Event Looper] port gone, exiting.\n"));
1379 return;
1382 PRINT(("[Event Looper] BMessage Size = %lu\n", length));
1384 char buffer[length];
1385 int32 code;
1386 status_t err = read_port(fEventLooperPort, &code, buffer, length);
1387 if (err != length) {
1388 if (err >= 0) {
1389 PRINTERR(("InputServer: failed to read full packet (read %lu of %lu)\n", err, length));
1390 } else {
1391 PRINTERR(("InputServer: read_port error: (0x%lx) %s\n", err, strerror(err)));
1393 continue;
1396 EventList events;
1397 if (fEventQueueLock.Lock()) {
1398 // move the items to our own list to block the event queue as short as possible
1399 events.AddList(&fEventQueue);
1400 fEventQueue.MakeEmpty();
1401 fEventQueueLock.Unlock();
1404 if (length > 0) {
1405 BMessage* event = new BMessage;
1407 if ((err = event->Unflatten(buffer)) < 0) {
1408 PRINTERR(("[InputServer] Unflatten() error: (0x%lx) %s\n", err, strerror(err)));
1409 delete event;
1410 continue;
1413 events.AddItem(event);
1416 // This is where the message should be processed.
1418 if (_SanitizeEvents(events)
1419 && _MethodizeEvents(events)
1420 && _FilterEvents(events)) {
1421 _UpdateMouseAndKeys(events);
1422 _DispatchEvents(events);
1428 /*! Updates the internal mouse position and keyboard info. */
1429 void
1430 InputServer::_UpdateMouseAndKeys(EventList& events)
1432 for (int32 index = 0;BMessage* event = (BMessage*)events.ItemAt(index);
1433 index++) {
1434 switch (event->what) {
1435 case B_MOUSE_DOWN:
1436 case B_MOUSE_UP:
1437 case B_MOUSE_MOVED:
1438 event->FindPoint("where", &fMousePos);
1439 break;
1441 case B_KEY_DOWN:
1442 case B_UNMAPPED_KEY_DOWN:
1443 // update modifiers
1444 uint32 modifiers;
1445 if (event->FindInt32("modifiers", (int32*)&modifiers) == B_OK)
1446 fKeyInfo.modifiers = modifiers;
1448 // update key states
1449 const uint8 *data;
1450 ssize_t size;
1451 if (event->FindData("states", B_UINT8_TYPE,
1452 (const void**)&data, &size) == B_OK) {
1453 PRINT(("updated keyinfo\n"));
1454 if (size == sizeof(fKeyInfo.key_states))
1455 memcpy(fKeyInfo.key_states, data, size);
1458 if (fActiveMethod == NULL)
1459 break;
1461 // we scan for Alt+Space key down events which means we change
1462 // to next input method
1463 // (pressing "shift" will let us switch to the previous method)
1465 // If there is only one input method, SetNextMethod will return
1466 // B_BAD_INDEX and the event will be forwarded to the user.
1468 PRINT(("SanitizeEvents: %lx, %x\n", fKeyInfo.modifiers,
1469 fKeyInfo.key_states[KEY_Spacebar >> 3]));
1471 uint8 byte;
1472 if (event->FindInt8("byte", (int8*)&byte) < B_OK)
1473 byte = 0;
1475 if ((((fKeyInfo.modifiers & B_COMMAND_KEY) != 0 && byte == ' ')
1476 || byte == B_HANKAKU_ZENKAKU)
1477 && SetNextMethod((fKeyInfo.modifiers & B_SHIFT_KEY) == 0)
1478 == B_OK) {
1479 // this event isn't sent to the user
1480 events.RemoveItemAt(index);
1481 delete event;
1482 continue;
1484 break;
1490 /*! Frees events from unwanted fields, adds missing fields, and removes
1491 unwanted events altogether.
1493 bool
1494 InputServer::_SanitizeEvents(EventList& events)
1496 CALLED();
1498 for (int32 index = 0; BMessage* event = (BMessage*)events.ItemAt(index);
1499 index++) {
1500 switch (event->what) {
1501 case B_MOUSE_MOVED:
1502 case B_MOUSE_DOWN:
1504 int32 buttons;
1505 if (event->FindInt32("buttons", &buttons) != B_OK)
1506 event->AddInt32("buttons", 0);
1508 // supposed to fall through
1510 case B_MOUSE_UP:
1512 BPoint where;
1513 int32 x, y;
1514 float absX, absY;
1516 if (event->FindInt32("x", &x) == B_OK
1517 && event->FindInt32("y", &y) == B_OK) {
1518 where.x = fMousePos.x + x;
1519 where.y = fMousePos.y - y;
1521 event->RemoveName("x");
1522 event->RemoveName("y");
1523 event->AddInt32("be:delta_x", x);
1524 event->AddInt32("be:delta_y", y);
1526 PRINT(("new position: %f, %f, %ld, %ld\n",
1527 where.x, where.y, x, y));
1528 } else if (event->FindFloat("x", &absX) == B_OK
1529 && event->FindFloat("y", &absY) == B_OK) {
1530 // The device gives us absolute screen coords in range 0..1;
1531 // convert them to absolute screen position
1532 // (the message is supposed to contain the original
1533 // absolute coordinates as "be:tablet_x/y").
1534 where.x = absX * fFrame.Width();
1535 where.y = absY * fFrame.Height();
1537 event->RemoveName("x");
1538 event->RemoveName("y");
1539 PRINT(("new position : %f, %f\n", where.x, where.y));
1540 } else if (event->FindPoint("where", &where) == B_OK) {
1541 PRINT(("new position : %f, %f\n", where.x, where.y));
1544 // Constrain and filter the mouse coords and add the final
1545 // point to the message.
1546 where.x = roundf(where.x);
1547 where.y = roundf(where.y);
1548 where.ConstrainTo(fFrame);
1549 if (event->ReplacePoint("where", where) != B_OK)
1550 event->AddPoint("where", where);
1552 if (!event->HasInt64("when"))
1553 event->AddInt64("when", system_time());
1555 event->AddInt32("modifiers", fKeyInfo.modifiers);
1556 break;
1558 case B_KEY_DOWN:
1559 case B_UNMAPPED_KEY_DOWN:
1560 // add modifiers
1561 if (!event->HasInt32("modifiers"))
1562 event->AddInt32("modifiers", fKeyInfo.modifiers);
1564 // add key states
1565 if (!event->HasData("states", B_UINT8_TYPE)) {
1566 event->AddData("states", B_UINT8_TYPE, fKeyInfo.key_states,
1567 sizeof(fKeyInfo.key_states));
1569 break;
1573 return true;
1577 /*! Applies the filters of the active input method to the
1578 incoming events. It will also move the events in the method
1579 queue to the event list.
1581 bool
1582 InputServer::_MethodizeEvents(EventList& events)
1584 CALLED();
1586 if (fActiveMethod == NULL)
1587 return true;
1589 int32 count = events.CountItems();
1590 for (int32 i = 0; i < count;) {
1591 _FilterEvent(fActiveMethod, events, i, count);
1595 // move the method events into the event queue - they are not
1596 // "methodized" either
1597 BAutolock _(fEventQueueLock);
1598 events.AddList(&fMethodQueue);
1599 fMethodQueue.MakeEmpty();
1602 if (!fInputMethodAware) {
1603 // special handling for non-input-method-aware views
1605 int32 newCount = events.CountItems();
1606 // we may add new events in this loop that don't need to be checked again
1608 for (int32 i = 0; i < newCount; i++) {
1609 BMessage* event = events.ItemAt(i);
1611 if (event->what != B_INPUT_METHOD_EVENT)
1612 continue;
1614 SERIAL_PRINT(("IME received\n"));
1616 bool removeEvent = true;
1618 int32 opcode;
1619 if (event->FindInt32("be:opcode", &opcode) == B_OK) {
1620 bool inlineOnly;
1621 if (event->FindBool("be:inline_only", &inlineOnly) != B_OK)
1622 inlineOnly = false;
1624 if (inlineOnly) {
1625 BMessage translated;
1626 bool confirmed;
1627 if (opcode == B_INPUT_METHOD_CHANGED
1628 && event->FindBool("be:confirmed", &confirmed) == B_OK && confirmed
1629 && event->FindMessage("be:translated", &translated) == B_OK) {
1630 // translate event for the non-aware view
1631 *event = translated;
1632 removeEvent = false;
1634 } else {
1635 if (fInputMethodWindow == NULL
1636 && opcode == B_INPUT_METHOD_STARTED)
1637 fInputMethodWindow = new (nothrow) BottomlineWindow();
1639 if (fInputMethodWindow != NULL) {
1640 EventList newEvents;
1641 fInputMethodWindow->HandleInputMethodEvent(event, newEvents);
1643 if (!newEvents.IsEmpty()) {
1644 events.AddList(&newEvents);
1645 opcode = B_INPUT_METHOD_STOPPED;
1648 if (opcode == B_INPUT_METHOD_STOPPED) {
1649 fInputMethodWindow->PostMessage(B_QUIT_REQUESTED);
1650 fInputMethodWindow = NULL;
1656 if (removeEvent) {
1657 // the inline/bottom window has eaten the event
1658 events.RemoveItemAt(i--);
1659 delete event;
1660 newCount--;
1665 return events.CountItems() > 0;
1669 /*! This method applies all defined filters to each event in the
1670 supplied list. The supplied list is modified to reflect the
1671 output of the filters.
1672 The method returns true if the filters were applied to all
1673 events without error and false otherwise.
1675 bool
1676 InputServer::_FilterEvents(EventList& events)
1678 CALLED();
1679 BAutolock _(gInputFilterListLocker);
1681 int32 count = gInputFilterList.CountItems();
1682 int32 eventCount = events.CountItems();
1684 for (int32 i = 0; i < count; i++) {
1685 BInputServerFilter* filter = (BInputServerFilter*)gInputFilterList.ItemAt(i);
1687 // Apply the current filter to all available event messages.
1689 for (int32 eventIndex = 0; eventIndex < eventCount;) {
1690 _FilterEvent(filter, events, eventIndex, eventCount);
1694 return eventCount != 0;
1698 void
1699 InputServer::_DispatchEvents(EventList& events)
1701 CALLED();
1703 int32 count = events.CountItems();
1705 for (int32 i = 0; i < count; i++) {
1706 BMessage* event = events.ItemAt(i);
1708 // now we must send each event to the app_server
1709 _DispatchEvent(event);
1710 delete event;
1713 events.MakeEmpty();
1717 /*! Applies the given filter to the event list.
1718 For your convenience, it also alters the \a index and \a count arguments
1719 ready for the next call to this method.
1721 void
1722 InputServer::_FilterEvent(BInputServerFilter* filter, EventList& events,
1723 int32& index, int32& count)
1725 BMessage* event = events.ItemAt(index);
1727 BList newEvents;
1728 filter_result result = filter->Filter(event, &newEvents);
1730 if (result == B_SKIP_MESSAGE || newEvents.CountItems() > 0) {
1731 // we no longer need the current event
1732 events.RemoveItemAt(index);
1733 delete event;
1735 if (result == B_DISPATCH_MESSAGE) {
1736 EventList addedEvents;
1737 EventList::Private(&addedEvents).AsBList()->AddList(&newEvents);
1738 _SanitizeEvents(addedEvents);
1739 // add the new events - but don't methodize them again
1740 events.AddList(&addedEvents, index);
1741 index += newEvents.CountItems();
1742 count = events.CountItems();
1743 } else
1744 count--;
1745 } else
1746 index++;
1750 status_t
1751 InputServer::_DispatchEvent(BMessage* event)
1753 CALLED();
1755 switch (event->what) {
1756 case B_MOUSE_MOVED:
1757 case B_MOUSE_DOWN:
1758 case B_MOUSE_UP:
1759 if (fCursorBuffer) {
1760 atomic_set((int32*)&fCursorBuffer->pos, (uint32)fMousePos.x << 16UL
1761 | ((uint32)fMousePos.y & 0xffff));
1762 if (atomic_or(&fCursorBuffer->read, 1) == 0)
1763 release_sem(fCursorSem);
1765 break;
1767 case B_KEY_DOWN:
1768 case B_KEY_UP:
1769 case B_UNMAPPED_KEY_DOWN:
1770 case B_UNMAPPED_KEY_UP:
1771 case B_MODIFIERS_CHANGED:
1773 // update or add modifiers
1774 uint32 modifiers;
1775 if (event->FindInt32("modifiers", (int32*)&modifiers) == B_OK)
1776 fKeyInfo.modifiers = modifiers;
1777 else
1778 event->AddInt32("modifiers", fKeyInfo.modifiers);
1780 // update or add key states
1781 const uint8 *data;
1782 ssize_t size;
1783 if (event->FindData("states", B_UINT8_TYPE,
1784 (const void**)&data, &size) == B_OK) {
1785 PRINT(("updated keyinfo\n"));
1786 if (size == sizeof(fKeyInfo.key_states))
1787 memcpy(fKeyInfo.key_states, data, size);
1788 } else {
1789 event->AddData("states", B_UINT8_TYPE, fKeyInfo.key_states,
1790 sizeof(fKeyInfo.key_states));
1793 break;
1796 default:
1797 break;
1800 BMessenger reply;
1801 BMessage::Private messagePrivate(event);
1802 return messagePrivate.SendMessage(fAppServerPort, fAppServerTeam, 0, 0,
1803 false, reply);
1807 // #pragma mark -
1810 extern "C" void
1811 RegisterDevices(input_device_ref** devices)
1813 CALLED();
1817 BView *
1818 instantiate_deskbar_item()
1820 return new MethodReplicant(INPUTSERVER_SIGNATURE);
1824 // #pragma mark -
1828 main(int /*argc*/, char** /*argv*/)
1830 InputServer *inputServer = new InputServer;
1832 inputServer->Run();
1833 delete inputServer;
1835 return 0;