161d7deeeSJérôme Duval /*****************************************************************************/ 261d7deeeSJérôme Duval // Mouse input server device addon 361d7deeeSJérôme Duval // Written by Stefano Ceccherini 461d7deeeSJérôme Duval // 561d7deeeSJérôme Duval // MouseInputDevice.cpp 661d7deeeSJérôme Duval // 761d7deeeSJérôme Duval // Copyright (c) 2004 Haiku Project 861d7deeeSJérôme Duval // 961d7deeeSJérôme Duval // Permission is hereby granted, free of charge, to any person obtaining a 1061d7deeeSJérôme Duval // copy of this software and associated documentation files (the "Software"), 1161d7deeeSJérôme Duval // to deal in the Software without restriction, including without limitation 1261d7deeeSJérôme Duval // the rights to use, copy, modify, merge, publish, distribute, sublicense, 1361d7deeeSJérôme Duval // and/or sell copies of the Software, and to permit persons to whom the 1461d7deeeSJérôme Duval // Software is furnished to do so, subject to the following conditions: 1561d7deeeSJérôme Duval // 1661d7deeeSJérôme Duval // The above copyright notice and this permission notice shall be included 1761d7deeeSJérôme Duval // in all copies or substantial portions of the Software. 1861d7deeeSJérôme Duval // 1961d7deeeSJérôme Duval // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 2061d7deeeSJérôme Duval // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 2161d7deeeSJérôme Duval // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 2261d7deeeSJérôme Duval // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 2361d7deeeSJérôme Duval // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 2461d7deeeSJérôme Duval // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 2561d7deeeSJérôme Duval // DEALINGS IN THE SOFTWARE. 2661d7deeeSJérôme Duval /*****************************************************************************/ 2761d7deeeSJérôme Duval #include "MouseInputDevice.h" 2861d7deeeSJérôme Duval 2961d7deeeSJérôme Duval #include <stdlib.h> 3061d7deeeSJérôme Duval #include <unistd.h> 3161d7deeeSJérôme Duval 323aa69c78SStefano Ceccherini //#define DEBUG 1 333aa69c78SStefano Ceccherini #if DEBUG 343aa69c78SStefano Ceccherini #define LOG(text) fputs(text, sLogFile) 353aa69c78SStefano Ceccherini #else 363aa69c78SStefano Ceccherini #define LOG(text) 373aa69c78SStefano Ceccherini #endif 383aa69c78SStefano Ceccherini 393aa69c78SStefano Ceccherini FILE *MouseInputDevice::sLogFile = NULL; 40*0dbc4befSStefano Ceccherini bool MouseInputDevice::sQuit = false; 413aa69c78SStefano Ceccherini 423aa69c78SStefano Ceccherini // TODO: These are "stolen" from the kb_mouse driver on bebits, which uses 433aa69c78SStefano Ceccherini // the same protocol as BeOS one. They're just here to test this add-on with 443aa69c78SStefano Ceccherini // the BeOS mouse driver. 4561d7deeeSJérôme Duval const static uint32 kGetMouseMovements = 10099; 4653d77642SJérôme Duval const static uint32 kGetMouseAccel = 10101; 4753d77642SJérôme Duval const static uint32 kSetMouseAccel = 10102; 4853d77642SJérôme Duval const static uint32 kSetMouseType = 10104; 4953d77642SJérôme Duval const static uint32 kSetMouseMap = 10106; 5053d77642SJérôme Duval const static uint32 kSetClickSpeed = 10108; 5161d7deeeSJérôme Duval 5261d7deeeSJérôme Duval struct mouse_movement { 5361d7deeeSJérôme Duval int32 ser_fd_index; 5461d7deeeSJérôme Duval int32 buttons; 5561d7deeeSJérôme Duval int32 xdelta; 5661d7deeeSJérôme Duval int32 ydelta; 5761d7deeeSJérôme Duval int32 click_count; 5861d7deeeSJérôme Duval int32 mouse_mods; 5961d7deeeSJérôme Duval int64 mouse_time; 6061d7deeeSJérôme Duval }; 6161d7deeeSJérôme Duval 6261d7deeeSJérôme Duval 63*0dbc4befSStefano Ceccherini struct mouse_device { 64*0dbc4befSStefano Ceccherini int driver_fd; 65*0dbc4befSStefano Ceccherini thread_id device_watcher; 66*0dbc4befSStefano Ceccherini uint32 buttons_state; 67*0dbc4befSStefano Ceccherini }; 68*0dbc4befSStefano Ceccherini 69*0dbc4befSStefano Ceccherini 7061d7deeeSJérôme Duval extern "C" 7161d7deeeSJérôme Duval BInputServerDevice * 7261d7deeeSJérôme Duval instantiate_input_device() 7361d7deeeSJérôme Duval { 7461d7deeeSJérôme Duval return new MouseInputDevice(); 7561d7deeeSJérôme Duval } 7661d7deeeSJérôme Duval 7761d7deeeSJérôme Duval 7861d7deeeSJérôme Duval MouseInputDevice::MouseInputDevice() 7953d77642SJérôme Duval : fThread(-1), 80*0dbc4befSStefano Ceccherini sQuit(false) 8161d7deeeSJérôme Duval { 823aa69c78SStefano Ceccherini // TODO: Open "/dev/input/mouse/serial/0" as well, and what about USB mouses ? 8361d7deeeSJérôme Duval fFd = open("dev/input/mouse/ps2/0", O_RDWR); 8461d7deeeSJérôme Duval if (fFd >= 0) 8561d7deeeSJérôme Duval fThread = spawn_thread(DeviceWatcher, "mouse watcher thread", 86e361bf69SJérôme Duval B_FIRST_REAL_TIME_PRIORITY+4, this); 8761d7deeeSJérôme Duval 883aa69c78SStefano Ceccherini #if DEBUG 89*0dbc4befSStefano Ceccherini if (sLogFile == NULL) 903aa69c78SStefano Ceccherini sLogFile = fopen("/var/log/mouse_device_log.log", "w"); 913aa69c78SStefano Ceccherini #endif 9261d7deeeSJérôme Duval } 9361d7deeeSJérôme Duval 9461d7deeeSJérôme Duval 9561d7deeeSJérôme Duval MouseInputDevice::~MouseInputDevice() 9661d7deeeSJérôme Duval { 9761d7deeeSJérôme Duval if (fThread >= 0) { 9861d7deeeSJérôme Duval status_t dummy; 9961d7deeeSJérôme Duval wait_for_thread(fThread, &dummy); 10061d7deeeSJérôme Duval } 10161d7deeeSJérôme Duval 10261d7deeeSJérôme Duval if (fFd >= 0) 10361d7deeeSJérôme Duval close(fFd); 10461d7deeeSJérôme Duval 1053aa69c78SStefano Ceccherini #if DEBUG 1063aa69c78SStefano Ceccherini fclose(sLogFile); 1073aa69c78SStefano Ceccherini #endif 10861d7deeeSJérôme Duval } 10961d7deeeSJérôme Duval 11061d7deeeSJérôme Duval 11161d7deeeSJérôme Duval status_t 11253d77642SJérôme Duval MouseInputDevice::InitFromSettings(uint32 opcode) 11353d77642SJérôme Duval { 11453d77642SJérôme Duval // retrieve current values 11553d77642SJérôme Duval 11653d77642SJérôme Duval if (get_mouse_map(&fSettings.map)!=B_OK) 11753d77642SJérôme Duval fprintf(stderr, "error when get_mouse_map\n"); 11853d77642SJérôme Duval else 11953d77642SJérôme Duval ioctl(fFd, kSetMouseMap, &fSettings.map); 12053d77642SJérôme Duval 12153d77642SJérôme Duval if (get_click_speed(&fSettings.click_speed)!=B_OK) 12253d77642SJérôme Duval fprintf(stderr, "error when get_click_speed\n"); 12353d77642SJérôme Duval else 12453d77642SJérôme Duval ioctl(fFd, kSetClickSpeed, &fSettings.click_speed); 12553d77642SJérôme Duval 12653d77642SJérôme Duval if (get_mouse_speed(&fSettings.accel.speed)!=B_OK) 12753d77642SJérôme Duval fprintf(stderr, "error when get_mouse_speed\n"); 12853d77642SJérôme Duval else { 12953d77642SJérôme Duval if (get_mouse_acceleration(&fSettings.accel.accel_factor)!=B_OK) 13053d77642SJérôme Duval fprintf(stderr, "error when get_mouse_acceleration\n"); 13153d77642SJérôme Duval else { 13253d77642SJérôme Duval mouse_accel accel; 13353d77642SJérôme Duval ioctl(fFd, kGetMouseAccel, &accel); 13453d77642SJérôme Duval accel.speed = fSettings.accel.speed; 13553d77642SJérôme Duval accel.accel_factor = fSettings.accel.accel_factor; 13653d77642SJérôme Duval ioctl(fFd, kSetMouseAccel, &fSettings.accel); 13753d77642SJérôme Duval } 13853d77642SJérôme Duval } 13953d77642SJérôme Duval 14053d77642SJérôme Duval if (get_mouse_type(&fSettings.type)!=B_OK) 14153d77642SJérôme Duval fprintf(stderr, "error when get_mouse_type\n"); 14253d77642SJérôme Duval else 14353d77642SJérôme Duval ioctl(fFd, kSetMouseType, &fSettings.type); 14453d77642SJérôme Duval 14553d77642SJérôme Duval return B_OK; 14653d77642SJérôme Duval } 14753d77642SJérôme Duval 14853d77642SJérôme Duval 14953d77642SJérôme Duval status_t 15061d7deeeSJérôme Duval MouseInputDevice::InitCheck() 15161d7deeeSJérôme Duval { 15253d77642SJérôme Duval InitFromSettings(); 15353d77642SJérôme Duval 154145a357dSStefano Ceccherini input_device_ref **devices = NULL; 155145a357dSStefano Ceccherini devices = (input_device_ref **)malloc(sizeof(input_device_ref *) * 2); 156145a357dSStefano Ceccherini if (!devices) 157145a357dSStefano Ceccherini return B_NO_MEMORY; 158145a357dSStefano Ceccherini 15961d7deeeSJérôme Duval input_device_ref mouse1 = { "Mouse 1", B_POINTING_DEVICE, (void *)this }; 16061d7deeeSJérôme Duval 161145a357dSStefano Ceccherini devices[0] = &mouse1; 162145a357dSStefano Ceccherini devices[1] = NULL; 16361d7deeeSJérôme Duval 16461d7deeeSJérôme Duval if (fFd >= 0 && fThread >= 0) { 16561d7deeeSJérôme Duval RegisterDevices(devices); 16661d7deeeSJérôme Duval return BInputServerDevice::InitCheck(); 16761d7deeeSJérôme Duval } 16861d7deeeSJérôme Duval return B_ERROR; 16961d7deeeSJérôme Duval } 17061d7deeeSJérôme Duval 17161d7deeeSJérôme Duval 17261d7deeeSJérôme Duval status_t 17361d7deeeSJérôme Duval MouseInputDevice::Start(const char *name, void *cookie) 17461d7deeeSJérôme Duval { 1753aa69c78SStefano Ceccherini char log[128]; 1763aa69c78SStefano Ceccherini snprintf(log, 128, "Start(%s)\n", name); 1773aa69c78SStefano Ceccherini 1783aa69c78SStefano Ceccherini LOG(log); 17961d7deeeSJérôme Duval resume_thread(fThread); 18061d7deeeSJérôme Duval 18161d7deeeSJérôme Duval return B_OK; 18261d7deeeSJérôme Duval } 18361d7deeeSJérôme Duval 18461d7deeeSJérôme Duval 18561d7deeeSJérôme Duval status_t 1863aa69c78SStefano Ceccherini MouseInputDevice::Stop(const char *name, void *cookie) 18761d7deeeSJérôme Duval { 1883aa69c78SStefano Ceccherini char log[128]; 1893aa69c78SStefano Ceccherini snprintf(log, 128, "Stop(%s)\n", name); 1903aa69c78SStefano Ceccherini 1913aa69c78SStefano Ceccherini LOG(log); 19261d7deeeSJérôme Duval 19361d7deeeSJérôme Duval suspend_thread(fThread); 19461d7deeeSJérôme Duval 19561d7deeeSJérôme Duval return B_OK; 19661d7deeeSJérôme Duval } 19761d7deeeSJérôme Duval 19861d7deeeSJérôme Duval 19961d7deeeSJérôme Duval status_t 20061d7deeeSJérôme Duval MouseInputDevice::Control(const char *name, void *cookie, 20161d7deeeSJérôme Duval uint32 command, BMessage *message) 20261d7deeeSJérôme Duval { 2033aa69c78SStefano Ceccherini char log[128]; 2043aa69c78SStefano Ceccherini snprintf(log, 128, "Control(%s, code: %lu)\n", name, command); 2053aa69c78SStefano Ceccherini 2063aa69c78SStefano Ceccherini LOG(log); 20753d77642SJérôme Duval 20853d77642SJérôme Duval if (command == B_NODE_MONITOR) 20953d77642SJérôme Duval HandleMonitor(message); 21053d77642SJérôme Duval else if (command >= B_MOUSE_TYPE_CHANGED 21153d77642SJérôme Duval && command <= B_MOUSE_ACCELERATION_CHANGED) { 21253d77642SJérôme Duval InitFromSettings(command); 21353d77642SJérôme Duval } 21453d77642SJérôme Duval return B_OK; 21553d77642SJérôme Duval } 21653d77642SJérôme Duval 21753d77642SJérôme Duval 21853d77642SJérôme Duval status_t 21953d77642SJérôme Duval MouseInputDevice::HandleMonitor(BMessage *message) 22053d77642SJérôme Duval { 22161d7deeeSJérôme Duval return B_OK; 22261d7deeeSJérôme Duval } 22361d7deeeSJérôme Duval 22461d7deeeSJérôme Duval 22561d7deeeSJérôme Duval int32 22661d7deeeSJérôme Duval MouseInputDevice::DeviceWatcher(void *arg) 22761d7deeeSJérôme Duval { 22861d7deeeSJérôme Duval MouseInputDevice *dev = (MouseInputDevice *)arg; 22961d7deeeSJérôme Duval mouse_movement movements; 23061d7deeeSJérôme Duval BMessage *message; 23161d7deeeSJérôme Duval char log[128]; 232*0dbc4befSStefano Ceccherini while (!sQuit) { 233145a357dSStefano Ceccherini if (ioctl(dev->fFd, kGetMouseMovements, &movements) < B_OK) 234145a357dSStefano Ceccherini continue; 23561d7deeeSJérôme Duval 236e361bf69SJérôme Duval uint32 buttons = dev->fButtons ^ movements.buttons; 23761d7deeeSJérôme Duval 23861d7deeeSJérôme Duval snprintf(log, 128, "buttons: %ld, x: %ld, y: %ld\n", 23961d7deeeSJérôme Duval movements.buttons, movements.xdelta, movements.ydelta); 24061d7deeeSJérôme Duval 2413aa69c78SStefano Ceccherini LOG(log); 2423aa69c78SStefano Ceccherini 2433aa69c78SStefano Ceccherini // TODO: B_MOUSE_DOWN and B_MOUSE_UP messages don't seem 2443aa69c78SStefano Ceccherini // to reach the application, 2453aa69c78SStefano Ceccherini // for some reason. Check if they reach the input server. 2463aa69c78SStefano Ceccherini if (buttons != 0) { 2473aa69c78SStefano Ceccherini message = new BMessage; 248e361bf69SJérôme Duval if (buttons & movements.buttons > 0) { 2493aa69c78SStefano Ceccherini message->what = B_MOUSE_DOWN; 2503aa69c78SStefano Ceccherini LOG("B_MOUSE_DOWN\n"); 2513aa69c78SStefano Ceccherini 252e361bf69SJérôme Duval } else { 2533aa69c78SStefano Ceccherini message->what = B_MOUSE_UP; 2543aa69c78SStefano Ceccherini LOG("B_MOUSE_UP\n"); 2553aa69c78SStefano Ceccherini } 2563aa69c78SStefano Ceccherini 2573aa69c78SStefano Ceccherini message->AddInt64("when", movements.mouse_time); 258e361bf69SJérôme Duval message->AddInt32("buttons", movements.buttons); 2593aa69c78SStefano Ceccherini message->AddInt32("clicks", movements.click_count); 260e361bf69SJérôme Duval message->AddInt32("x", movements.xdelta); 261e361bf69SJérôme Duval message->AddInt32("y", movements.ydelta); 26261d7deeeSJérôme Duval 26361d7deeeSJérôme Duval dev->EnqueueMessage(message); 2643aa69c78SStefano Ceccherini 2653aa69c78SStefano Ceccherini dev->fButtons = movements.buttons; 2663aa69c78SStefano Ceccherini 2673aa69c78SStefano Ceccherini } 2683aa69c78SStefano Ceccherini 2693aa69c78SStefano Ceccherini if (movements.xdelta != 0 || movements.ydelta != 0) { 2703aa69c78SStefano Ceccherini message = new BMessage(B_MOUSE_MOVED); 2713aa69c78SStefano Ceccherini if (message) { 2723aa69c78SStefano Ceccherini message->AddInt64("when", movements.mouse_time); 2733aa69c78SStefano Ceccherini message->AddInt32("buttons", movements.buttons); 2743aa69c78SStefano Ceccherini message->AddInt32("x", movements.xdelta); 2753aa69c78SStefano Ceccherini message->AddInt32("y", movements.ydelta); 2763aa69c78SStefano Ceccherini 2773aa69c78SStefano Ceccherini dev->EnqueueMessage(message); 2783aa69c78SStefano Ceccherini } 27961d7deeeSJérôme Duval } 28061d7deeeSJérôme Duval } 28161d7deeeSJérôme Duval 28261d7deeeSJérôme Duval return 0; 28361d7deeeSJérôme Duval } 28461d7deeeSJérôme Duval 28561d7deeeSJérôme Duval 286