From 6849a22864a9edc90482d16a5fd35f64f671b3b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20A=C3=9Fmus?= Date: Sat, 1 Nov 2008 10:48:35 +0000 Subject: [PATCH] Patch by Clemens Zeilder: * Implemented Synaptics touchpad support in the PS2 bus_manager by refactoring/splitting the structure some and adding touchpad device handling. * Implemented Touchpad input_server device add-on * Created Touchpad preflet for configuring advances Synaptics touchpad options like scroll region (both horizontal and vertical) as well as other neat stuff Thanks a lot, Clemens! git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@28416 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/private/input/kb_mouse_driver.h | 21 + headers/private/input/touchpad_driver.h | 38 + headers/private/input/touchpad_settings.h | 39 + src/add-ons/input_server/devices/Jamfile | 1 + .../input_server/devices/touchpad/Jamfile | 13 + .../devices/touchpad/TouchpadInputDevice.cpp | 685 ++++++++++++++++ .../devices/touchpad/TouchpadInputDevice.h | 51 ++ src/add-ons/kernel/bus_managers/ps2/Jamfile | 5 +- .../kernel/bus_managers/ps2/movement_maker.c | 278 +++++++ .../kernel/bus_managers/ps2/movement_maker.h | 42 + .../kernel/bus_managers/ps2/ps2_common.c | 5 +- .../kernel/bus_managers/ps2/ps2_common.h | 2 +- .../kernel/bus_managers/ps2/ps2_defs.h | 3 +- src/add-ons/kernel/bus_managers/ps2/ps2_dev.c | 121 ++- src/add-ons/kernel/bus_managers/ps2/ps2_dev.h | 19 +- .../kernel/bus_managers/ps2/ps2_mouse.c | 533 ------------ .../bus_managers/ps2/ps2_standart_mouse.c | 494 +++++++++++ .../bus_managers/ps2/ps2_standart_mouse.h | 59 ++ .../kernel/bus_managers/ps2/ps2_synaptics.c | 773 ++++++++++++++++++ .../kernel/bus_managers/ps2/ps2_synaptics.h | 126 +++ .../kernel/bus_managers/ps2/ps2_trackpoint.c | 30 + .../kernel/bus_managers/ps2/ps2_trackpoint.h | 12 + src/preferences/Jamfile | 1 + src/preferences/touchpad/Jamfile | 11 + src/preferences/touchpad/Touchpad.rdef | 304 +++++++ src/preferences/touchpad/TouchpadPref.cpp | 179 ++++ src/preferences/touchpad/TouchpadPref.h | 50 ++ src/preferences/touchpad/TouchpadPrefView.cpp | 457 +++++++++++ src/preferences/touchpad/TouchpadPrefView.h | 98 +++ src/preferences/touchpad/main.cpp | 39 + 30 files changed, 3929 insertions(+), 560 deletions(-) create mode 100644 headers/private/input/touchpad_driver.h create mode 100644 headers/private/input/touchpad_settings.h create mode 100644 src/add-ons/input_server/devices/touchpad/Jamfile create mode 100644 src/add-ons/input_server/devices/touchpad/TouchpadInputDevice.cpp create mode 100644 src/add-ons/input_server/devices/touchpad/TouchpadInputDevice.h create mode 100644 src/add-ons/kernel/bus_managers/ps2/movement_maker.c create mode 100644 src/add-ons/kernel/bus_managers/ps2/movement_maker.h create mode 100644 src/add-ons/kernel/bus_managers/ps2/ps2_standart_mouse.c create mode 100644 src/add-ons/kernel/bus_managers/ps2/ps2_standart_mouse.h create mode 100644 src/add-ons/kernel/bus_managers/ps2/ps2_synaptics.c create mode 100644 src/add-ons/kernel/bus_managers/ps2/ps2_synaptics.h create mode 100644 src/add-ons/kernel/bus_managers/ps2/ps2_trackpoint.c create mode 100644 src/add-ons/kernel/bus_managers/ps2/ps2_trackpoint.h create mode 100644 src/preferences/touchpad/Jamfile create mode 100644 src/preferences/touchpad/Touchpad.rdef create mode 100644 src/preferences/touchpad/TouchpadPref.cpp create mode 100644 src/preferences/touchpad/TouchpadPref.h create mode 100644 src/preferences/touchpad/TouchpadPrefView.cpp create mode 100644 src/preferences/touchpad/TouchpadPrefView.h create mode 100644 src/preferences/touchpad/main.cpp diff --git a/headers/private/input/kb_mouse_driver.h b/headers/private/input/kb_mouse_driver.h index 009a3514cd..f7ef6dd8b3 100644 --- a/headers/private/input/kb_mouse_driver.h +++ b/headers/private/input/kb_mouse_driver.h @@ -62,6 +62,8 @@ enum { MS_GET_CLICKSPEED, MS_SET_CLICKSPEED, MS_NUM_SERIAL_MICE, + MS_IS_TOUCHPAD, + MS_SET_TOUCHPAD_SETTINGS, IIC_WRITE = B_DEVICE_OP_CODES_END + 200, RESTART_SYSTEM, @@ -117,6 +119,25 @@ typedef struct { float tilt_y; } tablet_movement; +#define B_ONE_FINGER 0x01 +#define B_TWO_FINGER 0x02 +#define B_MULTI_FINGER 0x04 +#define B_PEN 0x08 + +typedef struct +{ + uint8 buttons; + uint32 xPosition; + uint32 yPosition; + uint8 zPressure; + uint8 fingers; + bool gesture; + uint8 fingerWidth; + // 1 - 4 normal width + // 5 - 11 very wide finger or palm + // 12 maximum reportable width; extrem wide contact +} touchpad_movement; + #ifdef __cplusplus } #endif diff --git a/headers/private/input/touchpad_driver.h b/headers/private/input/touchpad_driver.h new file mode 100644 index 0000000000..ed8bf3a716 --- /dev/null +++ b/headers/private/input/touchpad_driver.h @@ -0,0 +1,38 @@ +// +// kb_mouse_driver.h +// +#ifndef _TOUCHPAD_DRIVER_H +#define _TOUCHPAD_DRIVER_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define B_ONE_FINGER 0x01 +#define B_TWO_FINGER 0x02 +#define B_MULTI_FINGER 0x04 +#define B_PEN 0x08 + +typedef struct { + uint8 buttons; + uint32 xPosition; + uint32 yPosition; + uint8 zPressure; + uint8 fingers; + bool gesture; + uint8 fingerWidth; + // 1 - 4 normal width + // 5 - 11 very wide finger or palm + // 12 maximum reportable width; extrem wide contact +} touchpad_movement; + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/headers/private/input/touchpad_settings.h b/headers/private/input/touchpad_settings.h new file mode 100644 index 0000000000..c63c9c7376 --- /dev/null +++ b/headers/private/input/touchpad_settings.h @@ -0,0 +1,39 @@ +/* + * Copyright 2001-2008, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef TOUCHPAD_SETTINGS_H +#define TOUCHPAD_SETTINGS_H + +#include + + +typedef struct { + bool scroll_twofinger; + bool scroll_multifinger; + float scroll_rightrange; // from 0 to 1 + float scroll_bottomrange; // from 0 to 1 + uint16 scroll_xstepsize; + uint16 scroll_ystepsize; + uint8 scroll_acceleration; // from 0 to 20 + + uint8 tapgesture_sensibility; // 0 : no tapgesture + // 20: very light tip is enough (default) +} touchpad_settings; + + +const static touchpad_settings kDefaultTouchpadSettings = { + true, + true, + 0.15, + 0.15, + 7, + 10, + 10, + 20 +}; + +#define TOUCHPAD_SETTINGS_FILE "Touchpad_settings" + + +#endif /* TOUCHPAD_SETTINGS_H */ diff --git a/src/add-ons/input_server/devices/Jamfile b/src/add-ons/input_server/devices/Jamfile index 978651f588..d2bf270d89 100644 --- a/src/add-ons/input_server/devices/Jamfile +++ b/src/add-ons/input_server/devices/Jamfile @@ -5,5 +5,6 @@ SubInclude HAIKU_TOP src add-ons input_server devices keyboard ; SubInclude HAIKU_TOP src add-ons input_server devices mouse ; #SubInclude HAIKU_TOP src add-ons input_server devices serial_mouse ; #SubInclude HAIKU_TOP src add-ons input_server devices tablet ; +SubInclude HAIKU_TOP src add-ons input_server devices touchpad ; SubInclude HAIKU_TOP src add-ons input_server devices wacom ; diff --git a/src/add-ons/input_server/devices/touchpad/Jamfile b/src/add-ons/input_server/devices/touchpad/Jamfile new file mode 100644 index 0000000000..89f1396151 --- /dev/null +++ b/src/add-ons/input_server/devices/touchpad/Jamfile @@ -0,0 +1,13 @@ +SubDir HAIKU_TOP src add-ons input_server devices touchpad ; + +SetSubDirSupportedPlatformsBeOSCompatible ; + +UsePrivateHeaders input ; + +Addon touchpad : + TouchpadInputDevice.cpp + : be input_server ; + +Package haiku-inputkit-cvs : + touchpad : + boot home config add-ons input_server devices ; diff --git a/src/add-ons/input_server/devices/touchpad/TouchpadInputDevice.cpp b/src/add-ons/input_server/devices/touchpad/TouchpadInputDevice.cpp new file mode 100644 index 0000000000..812413ca51 --- /dev/null +++ b/src/add-ons/input_server/devices/touchpad/TouchpadInputDevice.cpp @@ -0,0 +1,685 @@ +/* + * Copyright 2004-2007, Haiku. + * Distributed under the terms of the MIT License. + * + * Authors: + * Stefano Ceccherini (stefano.ceccherini@gmail.com) + * Jérôme Duval + * Axel Dörfler, axeld@pinc-software.de + */ + + +#include "TouchpadInputDevice.h" +#include "kb_mouse_driver.h" +#include "kb_mouse_settings.h" +#include "touchpad_settings.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#if DEBUG +FILE *TouchpadInputDevice::sLogFile = NULL; +# define LOG_ERR(text...) LOG(text) +#else +# define LOG(text...) +# define LOG_ERR(text...) fprintf(stderr, text) +#endif + +#define CALLED() LOG("%s\n", __PRETTY_FUNCTION__) + +const static uint32 kMouseThreadPriority = B_FIRST_REAL_TIME_PRIORITY + 4; + +// "/dev/" is automatically prepended by StartMonitoringDevice() +const static char *kTouchpadDevicesDirectoryPS2 = "input/touchpad/ps2"; + + +class TouchpadDevice { + public: + TouchpadDevice(BInputServerDevice& target, const char* path); + ~TouchpadDevice(); + + status_t Start(); + void Stop(); + + status_t UpdateSettings(); + + const char* Path() const { return fPath.String(); } + input_device_ref* DeviceRef() { return &fDeviceRef; } + + bool IsTouchpad() { return fIsTouchpad; } + status_t ReadTouchpadSettingsMsg(BMessage* msg); + status_t UpdateTouchpadSettings(); + + private: + void _Run(); + static status_t _ThreadFunction(void *arg); + + BMessage* _BuildMouseMessage(uint32 what, uint64 when, uint32 buttons, + int32 deltaX, int32 deltaY) const; + void _ComputeAcceleration(const mouse_movement& movements, + int32& deltaX, int32& deltaY) const; + uint32 _RemapButtons(uint32 buttons) const; + + char* _BuildShortName() const; + + status_t GetSettingsPath(BPath &path); + + private: + BInputServerDevice& fTarget; + BString fPath; + int fDevice; + + input_device_ref fDeviceRef; + mouse_settings fSettings; + bool fDeviceRemapsButtons; + + thread_id fThread; + volatile bool fActive; + + bool fIsTouchpad; + touchpad_settings fTouchpadSettings; +}; + + +#if DEBUG +inline void +LOG(const char *fmt, ...) +{ + char buf[1024]; + va_list ap; + va_start(ap, fmt); + vsprintf(buf, fmt, ap); va_end(ap); + fputs(buf, TouchpadInputDevice::sLogFile); fflush(TouchpadInputDevice::sLogFile); +} +#endif + + +extern "C" BInputServerDevice * +instantiate_input_device() +{ + return new (std::nothrow) TouchpadInputDevice(); +} + + +// #pragma mark - + + +TouchpadDevice::TouchpadDevice(BInputServerDevice& target, const char *driverPath) + : + fTarget(target), + fDevice(-1), + fThread(-1), + fActive(false), + fIsTouchpad(false) +{ + fPath = driverPath; + + fDeviceRef.name = _BuildShortName(); + fDeviceRef.type = B_POINTING_DEVICE; + fDeviceRef.cookie = this; + +#ifdef HAIKU_TARGET_PLATFORM_HAIKU + fSettings.map.button[0] = B_PRIMARY_MOUSE_BUTTON; + fSettings.map.button[1] = B_SECONDARY_MOUSE_BUTTON; + fSettings.map.button[2] = B_TERTIARY_MOUSE_BUTTON; +#endif + + fDeviceRemapsButtons = false; +}; + + +TouchpadDevice::~TouchpadDevice() +{ + if (fActive) + Stop(); + + free(fDeviceRef.name); +} + + +status_t +TouchpadDevice::GetSettingsPath(BPath &path) +{ + status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, &path); + if(status < B_OK) + return status; + path.Append(TOUCHPAD_SETTINGS_FILE); + return B_OK; +} + + +status_t +TouchpadDevice::Start() +{ + fDevice = open(fPath.String(), O_RDWR); + if (fDevice < 0) + return errno; + + // touchpad settings + if(ioctl(fDevice, MS_IS_TOUCHPAD, NULL) == B_OK){ + LOG("is touchpad %s\n", fPath.String()); + fIsTouchpad = true; + } + + fTouchpadSettings = kDefaultTouchpadSettings; + + BPath path; + status_t status = GetSettingsPath(path); + BFile settingsFile(path.Path(), B_READ_ONLY); + if(status == B_OK && settingsFile.InitCheck() == B_OK){ + if(settingsFile.Read(&fTouchpadSettings, sizeof(touchpad_settings)) + != sizeof(touchpad_settings)) + { + LOG("failed to load settings\n"); + } + } + + UpdateTouchpadSettings(); + + UpdateSettings(); + + char threadName[B_OS_NAME_LENGTH]; + snprintf(threadName, B_OS_NAME_LENGTH, "%s watcher", fDeviceRef.name); + + fThread = spawn_thread(_ThreadFunction, threadName, + kMouseThreadPriority, (void *)this); + + if (fThread < B_OK) + status = fThread; + else { + fActive = true; + status = resume_thread(fThread); + } + + if (status < B_OK) { + LOG_ERR("%s: can't spawn/resume watching thread: %s\n", + fDeviceRef.name, strerror(status)); + close(fDevice); + return status; + } + + return B_OK; +} + + +void +TouchpadDevice::Stop() +{ + fActive = false; + // this will stop the thread as soon as it reads the next packet + + if (fThread >= B_OK) { + // unblock the thread, which might wait on a semaphore. + suspend_thread(fThread); + resume_thread(fThread); + + status_t dummy; + wait_for_thread(fThread, &dummy); + } + + close(fDevice); +} + + +status_t +TouchpadDevice::UpdateSettings() +{ + CALLED(); + + // retrieve current values + + if (get_mouse_map(&fSettings.map) != B_OK) + LOG_ERR("error when get_mouse_map\n"); + else + fDeviceRemapsButtons = ioctl(fDevice, MS_SET_MAP, &fSettings.map) == B_OK; + + if (get_click_speed(&fSettings.click_speed) != B_OK) + LOG_ERR("error when get_click_speed\n"); + else + ioctl(fDevice, MS_SET_CLICKSPEED, &fSettings.click_speed); + + if (get_mouse_speed(&fSettings.accel.speed) != B_OK) + LOG_ERR("error when get_mouse_speed\n"); + else { + if (get_mouse_acceleration(&fSettings.accel.accel_factor) != B_OK) + LOG_ERR("error when get_mouse_acceleration\n"); + else { + mouse_accel accel; + ioctl(fDevice, MS_GET_ACCEL, &accel); + accel.speed = fSettings.accel.speed; + accel.accel_factor = fSettings.accel.accel_factor; + ioctl(fDevice, MS_SET_ACCEL, &fSettings.accel); + } + } + + if (get_mouse_type(&fSettings.type) != B_OK) + LOG_ERR("error when get_mouse_type\n"); + else + ioctl(fDevice, MS_SET_TYPE, &fSettings.type); + + return B_OK; + +} + + +status_t +TouchpadDevice::ReadTouchpadSettingsMsg(BMessage* msg) +{ + msg->FindBool("scroll_twofinger", &(fTouchpadSettings.scroll_twofinger)); + msg->FindBool("scroll_multifinger", &(fTouchpadSettings.scroll_multifinger)); + msg->FindFloat("scroll_rightrange", &(fTouchpadSettings.scroll_rightrange)); + msg->FindFloat("scroll_bottomrange", &(fTouchpadSettings.scroll_bottomrange)); + msg->FindInt16("scroll_xstepsize", (int16*)&(fTouchpadSettings.scroll_xstepsize)); + msg->FindInt16("scroll_ystepsize", (int16*)&(fTouchpadSettings.scroll_ystepsize)); + msg->FindInt8("scroll_acceleration", (int8*)&(fTouchpadSettings.scroll_acceleration)); + msg->FindInt8("tapgesture_sensibility", (int8*)&(fTouchpadSettings.tapgesture_sensibility)); + + return B_OK; +} + + +status_t +TouchpadDevice::UpdateTouchpadSettings() +{ + if(fIsTouchpad){ + ioctl(fDevice, MS_SET_TOUCHPAD_SETTINGS, &fTouchpadSettings); + return B_OK; + } + return B_ERROR; +} + + +void +TouchpadDevice::_Run() +{ + uint32 lastButtons = 0; + + while (fActive) { + mouse_movement movements; + memset(&movements, 0, sizeof(movements)); + + if (ioctl(fDevice, MS_READ, &movements) != B_OK) + return; + + uint32 buttons = lastButtons ^ movements.buttons; + + uint32 remappedButtons = _RemapButtons(movements.buttons); + int32 deltaX, deltaY; + _ComputeAcceleration(movements, deltaX, deltaY); + + /*LOG("%s: buttons: 0x%lx, x: %ld, y: %ld, clicks:%ld, wheel_x:%ld, wheel_y:%ld\n", + device->device_ref.name, movements.buttons, movements.xdelta, movements.ydelta, + movements.clicks, movements.wheel_xdelta, movements.wheel_ydelta); + LOG("%s: x: %ld, y: %ld\n", device->device_ref.name, deltaX, deltaY);*/ + + BMessage *message = NULL; + + // Send single messages for each event + + if (buttons != 0) { + bool pressedButton = (buttons & movements.buttons) > 0; + BMessage* message = _BuildMouseMessage( + pressedButton ? B_MOUSE_DOWN : B_MOUSE_UP, + movements.timestamp, remappedButtons, deltaX, deltaY); + if (message != NULL) { + if (pressedButton) { + message->AddInt32("clicks", movements.clicks); + LOG("B_MOUSE_DOWN\n"); + } else + LOG("B_MOUSE_UP\n"); + + fTarget.EnqueueMessage(message); + lastButtons = movements.buttons; + } + } + + if (movements.xdelta != 0 || movements.ydelta != 0) { + BMessage* message = _BuildMouseMessage(B_MOUSE_MOVED, + movements.timestamp, remappedButtons, deltaX, deltaY); + if (message != NULL) + fTarget.EnqueueMessage(message); + } + + if ((movements.wheel_ydelta != 0) || (movements.wheel_xdelta != 0)) { + message = new BMessage(B_MOUSE_WHEEL_CHANGED); + if (message == NULL) + continue; + + if (message->AddInt64("when", movements.timestamp) == B_OK + && message->AddFloat("be:wheel_delta_x", movements.wheel_xdelta) == B_OK + && message->AddFloat("be:wheel_delta_y", movements.wheel_ydelta) == B_OK) + fTarget.EnqueueMessage(message); + else + delete message; + } + } +} + + +status_t +TouchpadDevice::_ThreadFunction(void* arg) +{ + TouchpadDevice* device = (TouchpadDevice *)arg; + device->_Run(); + return B_OK; +} + + +BMessage* +TouchpadDevice::_BuildMouseMessage(uint32 what, uint64 when, uint32 buttons, + int32 deltaX, int32 deltaY) const +{ + BMessage* message = new BMessage(what); + if (message == NULL) + return NULL; + + if (message->AddInt64("when", when) < B_OK + || message->AddInt32("buttons", buttons) < B_OK + || message->AddInt32("x", deltaX) < B_OK + || message->AddInt32("y", deltaY) < B_OK) { + delete message; + return NULL; + } + + return message; +} + + +void +TouchpadDevice::_ComputeAcceleration(const mouse_movement& movements, + int32& deltaX, int32& deltaY) const +{ + // basic mouse speed + deltaX = movements.xdelta * fSettings.accel.speed >> 16; + deltaY = movements.ydelta * fSettings.accel.speed >> 16; + + // acceleration + double acceleration = 1; + if (fSettings.accel.accel_factor) { + acceleration = 1 + sqrt(deltaX * deltaX + deltaY * deltaY) + * fSettings.accel.accel_factor / 524288.0; + } + + // make sure that we move at least one pixel (if there was a movement) + if (deltaX > 0) + deltaX = (int32)floor(deltaX * acceleration); + else + deltaX = (int32)ceil(deltaX * acceleration); + + if (deltaY > 0) + deltaY = (int32)floor(deltaY * acceleration); + else + deltaY = (int32)ceil(deltaY * acceleration); +} + + +uint32 +TouchpadDevice::_RemapButtons(uint32 buttons) const +{ + if (fDeviceRemapsButtons) + return buttons; + + uint32 newButtons = 0; + for (int32 i = 0; buttons; i++) { + if (buttons & 0x1) { +#if defined(HAIKU_TARGET_PLATFORM_HAIKU) || defined(HAIKU_TARGET_PLATFORM_DANO) + newButtons |= fSettings.map.button[i]; +#else + if (i == 0) + newButtons |= fSettings.map.left; + if (i == 1) + newButtons |= fSettings.map.right; + if (i == 2) + newButtons |= fSettings.map.middle; +#endif + } + buttons >>= 1; + } + + return newButtons; +} + + +char * +TouchpadDevice::_BuildShortName() const +{ + BString string(fPath); + BString name; + + int32 slash = string.FindLast("/"); + string.CopyInto(name, slash + 1, string.Length() - slash); + //int32 index = atoi(name.String()) + 1; + + BString final = "Touchpad_"; + final+= name; + + LOG("NAME %s, %s\n", final.String(), fPath.String()); + + return strdup(final.String()); +} + + +// #pragma mark - + + +TouchpadInputDevice::TouchpadInputDevice() +{ +#if DEBUG + sLogFile = fopen("/var/log/mouse_device_log.log", "a"); +#endif + CALLED(); + + StartMonitoringDevice(kTouchpadDevicesDirectoryPS2); + + _RecursiveScan(kTouchpadDevicesDirectoryPS2); +} + + +TouchpadInputDevice::~TouchpadInputDevice() +{ + CALLED(); + StopMonitoringDevice(kTouchpadDevicesDirectoryPS2); + + int32 count = fDevices.CountItems(); + while (count-- > 0) { + delete (TouchpadDevice *)fDevices.RemoveItem(count); + } + +#if DEBUG + fclose(sLogFile); +#endif +} + + +status_t +TouchpadInputDevice::InitCheck() +{ + CALLED(); + return BInputServerDevice::InitCheck(); +} + + +status_t +TouchpadInputDevice::Start(const char *name, void *cookie) +{ + LOG("%s(%s)\n", __PRETTY_FUNCTION__, name); + TouchpadDevice* device = (TouchpadDevice*)cookie; + + return device->Start(); +} + + +status_t +TouchpadInputDevice::Stop(const char *name, void *cookie) +{ + LOG("%s(%s)\n", __PRETTY_FUNCTION__, name); + TouchpadDevice* device = (TouchpadDevice*)cookie; + + device->Stop(); + return B_OK; +} + + +status_t +TouchpadInputDevice::Control(const char* name, void* cookie, + uint32 command, BMessage* message) +{ + LOG("%s(%s, code: %lu)\n", __PRETTY_FUNCTION__, name, command); + TouchpadDevice* device = (TouchpadDevice*)cookie; + + if (command == MS_SET_TOUCHPAD_SETTINGS){ + device->ReadTouchpadSettingsMsg(message); + return device->UpdateTouchpadSettings(); + } + + if (command == B_NODE_MONITOR) + return _HandleMonitor(message); + + if (command >= B_MOUSE_TYPE_CHANGED + && command <= B_MOUSE_ACCELERATION_CHANGED) + return device->UpdateSettings(); + + return B_BAD_VALUE; +} + + +// TODO: Test this. USB doesn't work on my machine +status_t +TouchpadInputDevice::_HandleMonitor(BMessage* message) +{ + CALLED(); + + int32 opcode; + if (message->FindInt32("opcode", &opcode) < B_OK) + return B_BAD_VALUE; + + if (opcode != B_ENTRY_CREATED && opcode != B_ENTRY_REMOVED) + return B_OK; + + BEntry entry; + BPath path; + dev_t device; + ino_t directory; + const char *name; + + if (message->FindInt32("device", &device) < B_OK + || message->FindInt64("directory", &directory) < B_OK + || message->FindString("name", &name) < B_OK) + return B_BAD_VALUE; + + entry_ref ref(device, directory, name); + status_t status; + + if ((status = entry.SetTo(&ref)) != B_OK) + return status; + if ((status = entry.GetPath(&path)) != B_OK) + return status; + if ((status = path.InitCheck()) != B_OK) + return status; + + if (opcode == B_ENTRY_CREATED) + status = _AddDevice(path.Path()); + else + status = _RemoveDevice(path.Path()); + + return status; +} + + +TouchpadDevice* +TouchpadInputDevice::_FindDevice(const char *path) +{ + CALLED(); + + for (int32 i = fDevices.CountItems(); i-- > 0;) { + TouchpadDevice* device = (TouchpadDevice*)fDevices.ItemAt(i); + if (!strcmp(device->Path(), path)) + return device; + } + + return NULL; +} + + +status_t +TouchpadInputDevice::_AddDevice(const char *path) +{ + CALLED(); + + TouchpadDevice* device = new (std::nothrow) TouchpadDevice(*this, path); + if (!device) { + LOG("No memory\n"); + return B_NO_MEMORY; + } + + if (!fDevices.AddItem(device)) { + delete device; + return B_NO_MEMORY; + } + + input_device_ref *devices[2]; + devices[0] = device->DeviceRef(); + devices[1] = NULL; + + return RegisterDevices(devices); +} + + +status_t +TouchpadInputDevice::_RemoveDevice(const char *path) +{ + CALLED(); + + TouchpadDevice* device = _FindDevice(path); + if (device == NULL) + return B_ENTRY_NOT_FOUND; + + fDevices.RemoveItem(device); + + input_device_ref *devices[2]; + devices[0] = device->DeviceRef(); + devices[1] = NULL; + + UnregisterDevices(devices); + + delete device; + return B_OK; +} + + +void +TouchpadInputDevice::_RecursiveScan(const char* directory) +{ + CALLED(); + + BEntry entry; + BDirectory dir(directory); + while (dir.GetNextEntry(&entry) == B_OK) { + BPath path; + entry.GetPath(&path); + + if (!strcmp(path.Leaf(), "serial")) { + // skip serial + continue; + } + + if (entry.IsDirectory()) + _RecursiveScan(path.Path()); + else + _AddDevice(path.Path()); + } +} + diff --git a/src/add-ons/input_server/devices/touchpad/TouchpadInputDevice.h b/src/add-ons/input_server/devices/touchpad/TouchpadInputDevice.h new file mode 100644 index 0000000000..217d6266ce --- /dev/null +++ b/src/add-ons/input_server/devices/touchpad/TouchpadInputDevice.h @@ -0,0 +1,51 @@ +/* + * Copyright 2004-2006, Haiku. + * Distributed under the terms of the MIT License. + * + * Authors: + * Stefano Ceccherini + */ +#ifndef MOUSE_INPUT_DEVICE_H +#define MOUSE_INPUT_DEVICE_H + + +#include +#include +#include + +#include +#define DEBUG 1 + +class TouchpadDevice; + +class TouchpadInputDevice : public BInputServerDevice { + public: + TouchpadInputDevice(); + ~TouchpadInputDevice(); + + virtual status_t InitCheck(); + + virtual status_t Start(const char* name, void* cookie); + virtual status_t Stop(const char* name, void* cookie); + + virtual status_t Control(const char* name, void* cookie, + uint32 command, BMessage* message); + + private: + status_t _HandleMonitor(BMessage* message); + void _RecursiveScan(const char* directory); + + TouchpadDevice* _FindDevice(const char* path); + status_t _AddDevice(const char* path); + status_t _RemoveDevice(const char* path); + + BList fDevices; +#ifdef DEBUG +public: + static FILE *sLogFile; +#endif +}; + +extern "C" BInputServerDevice* instantiate_input_device(); + +#endif // MOUSE_INPUT_DEVICE_H diff --git a/src/add-ons/kernel/bus_managers/ps2/Jamfile b/src/add-ons/kernel/bus_managers/ps2/Jamfile index db9d7d00c2..3cfd51fdbb 100644 --- a/src/add-ons/kernel/bus_managers/ps2/Jamfile +++ b/src/add-ons/kernel/bus_managers/ps2/Jamfile @@ -9,6 +9,9 @@ KernelAddon ps2 : ps2_dev.c ps2_keyboard.c ps2_module.c - ps2_mouse.c + ps2_standart_mouse.c + ps2_synaptics.c + ps2_trackpoint.c ps2_service.c + movement_maker.c ; diff --git a/src/add-ons/kernel/bus_managers/ps2/movement_maker.c b/src/add-ons/kernel/bus_managers/ps2/movement_maker.c new file mode 100644 index 0000000000..1a19791fa0 --- /dev/null +++ b/src/add-ons/kernel/bus_managers/ps2/movement_maker.c @@ -0,0 +1,278 @@ +#include "movement_maker.h" + +#include +#if 1 +# define INFO(x...) dprintf(x) +#else +# define INFO(x...) +#endif + +typedef union +{ + float value; + /* FIXME: Assumes 32 bit int. */ + unsigned int word; +} ieee_float_shape_type; + +/* Get a 32 bit int from a float. */ + +#define GET_FLOAT_WORD(i,d) \ +do { \ + ieee_float_shape_type gf_u; \ + gf_u.value = (d); \ + (i) = gf_u.word; \ +} while (0) + +/* Set a float from a 32 bit int. */ + +#define SET_FLOAT_WORD(d,i) \ +do { \ + ieee_float_shape_type sf_u; \ + sf_u.word = (i); \ + (d) = sf_u.value; \ +} while (0) + +static const float huge = 1.0e30; + +float +floorf(float x) +{ + int32 i0,j0; + uint32 i; + GET_FLOAT_WORD(i0,x); + j0 = ((i0>>23)&0xff)-0x7f; + if(j0<23) { + if(j0<0) { /* raise inexact if x != 0 */ + if(huge+x>(float)0.0) {/* return 0*sign(x) if |x|<1 */ + if(i0>=0) {i0=0;} + else if((i0&0x7fffffff)!=0) + { i0=0xbf800000;} + } + } else { + i = (0x007fffff)>>j0; + if((i0&i)==0) return x; /* x is integral */ + if(huge+x>(float)0.0) { /* raise inexact flag */ + if(i0<0) i0 += (0x00800000)>>j0; + i0 &= (~i); + } + } + } else { + if(j0==0x80) return x+x; /* inf or NaN */ + else return x; /* x is integral */ + } + SET_FLOAT_WORD(x,i0); + return x; +} + + +float +ceilf(float x) +{ + int32 i0,j0; + uint32 i; + + GET_FLOAT_WORD(i0,x); + j0 = ((i0>>23)&0xff)-0x7f; + if(j0<23) { + if(j0<0) { /* raise inexact if x != 0 */ + if(huge+x>(float)0.0) {/* return 0*sign(x) if |x|<1 */ + if(i0<0) {i0=0x80000000;} + else if(i0!=0) { i0=0x3f800000;} + } + } else { + i = (0x007fffff)>>j0; + if((i0&i)==0) return x; /* x is integral */ + if(huge+x>(float)0.0) { /* raise inexact flag */ + if(i0>0) i0 += (0x00800000)>>j0; + i0 &= (~i); + } + } + } else { + if(j0==0x80) return x+x; /* inf or NaN */ + else return x; /* x is integral */ + } + SET_FLOAT_WORD(x,i0); + return x; +} + +static const float one = 1.0, tiny=1.0e-30; + +float +sqrtf(float x) +{ + float z; + int32 sign = (int)0x80000000; + int32 ix,s,q,m,t,i; + uint32 r; + + GET_FLOAT_WORD(ix,x); + + /* take care of Inf and NaN */ + if((ix&0x7f800000)==0x7f800000) { + return x*x+x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf + sqrt(-inf)=sNaN */ + } + /* take care of zero */ + if(ix<=0) { + if((ix&(~sign))==0) return x;/* sqrt(+-0) = +-0 */ + else if(ix<0) + return (x-x)/(x-x); /* sqrt(-ve) = sNaN */ + } + /* normalize x */ + m = (ix>>23); + if(m==0) { /* subnormal x */ + for(i=0;(ix&0x00800000)==0;i++) ix<<=1; + m -= i-1; + } + m -= 127; /* unbias exponent */ + ix = (ix&0x007fffff)|0x00800000; + if(m&1) /* odd m, double x to make it even */ + ix += ix; + m >>= 1; /* m = [m/2] */ + + /* generate sqrt(x) bit by bit */ + ix += ix; + q = s = 0; /* q = sqrt(x) */ + r = 0x01000000; /* r = moving bit from right to left */ + + while(r!=0) { + t = s+r; + if(t<=ix) { + s = t+r; + ix -= t; + q += r; + } + ix += ix; + r>>=1; + } + + /* use floating add to find out rounding direction */ + if(ix!=0) { + z = one-tiny; /* trigger inexact flag */ + if (z>=one) { + z = one+tiny; + if (z>one) + q += 2; + else + q += (q&1); + } + } + ix = (q>>1)+0x3f000000; + ix += (m <<23); + SET_FLOAT_WORD(z,ix); + return z; +} + + +int32 +make_small(float value){ + if(value > 0) + return floorf(value); + else + return ceilf(value); +} + + +void +get_raw_movement(movement_maker *move, uint32 posX, uint32 posY) +{ + int16 i; + float meanXOld = 0, meanYOld = 0; + float meanX = 0, meanY = 0; + + // calculate mean + for(i = 0; i < move->n_points; i++){ + meanXOld+= move->historyX[i]; + meanYOld+= move->historyY[i]; + } + if(move->n_points == 0){ + meanXOld = posX; + meanYOld = posY; + } + else{ + meanXOld = meanXOld / move->n_points; + meanYOld = meanYOld / move->n_points; + } + + meanX = (meanXOld + posX) / 2; + meanY = (meanYOld + posY) / 2; + + // fill history + for(i = 0; i < HISTORY_SIZE - 1; i++){ + move->historyX[i] = move->historyX[i + 1]; + move->historyY[i] = move->historyY[i + 1]; + } + move->historyX[HISTORY_SIZE - 1] = meanX; + move->historyY[HISTORY_SIZE - 1] = meanY; + + if(move->n_points < HISTORY_SIZE){ + move->n_points++; + move->xDelta = 0; + move->yDelta = 0; + return; + } + + move->xDelta = make_small((meanX - meanXOld) / 16); + move->yDelta = make_small((meanY - meanYOld) / 16); +} + + +void +compute_acceleration(movement_maker *move, int8 accel_factor) +{ + // acceleration + float acceleration = 1; + if (accel_factor) { + acceleration = 1 + sqrtf(move->xDelta * move->xDelta + move->yDelta * move->yDelta) + * accel_factor / 50.0; + } + + move->xDelta = make_small(move->xDelta * acceleration); + move->yDelta = make_small(move->yDelta * acceleration); +} + + +void +get_movement(movement_maker *move, uint32 posX, uint32 posY) +{ + get_raw_movement(move, posX, posY); + move->xDelta = move->xDelta * move->speed; + move->yDelta = move->yDelta * move->speed; +} + + +void +get_scrolling(movement_maker *move, uint32 posX, uint32 posY) +{ + int32 stepsX = 0, stepsY = 0; + + get_raw_movement(move, posX, posY); + compute_acceleration(move, move->scroll_acceleration); + + move->scrolling_x+= move->xDelta; + move->scrolling_y+= move->yDelta; + + stepsX = make_small(move->scrolling_x / move->scrolling_xStep); + stepsY = make_small(move->scrolling_y / move->scrolling_yStep); + + move->scrolling_x-= stepsX * move->scrolling_xStep; + move->scrolling_y-= stepsY * move->scrolling_yStep; + + move->xDelta = stepsX; + move->yDelta = -1 * stepsY; +} + + +void +start_new_movment(movement_maker *move) +{ + if(move->scrolling_xStep <= 0) + move->scrolling_xStep = 1; + if(move->scrolling_yStep <= 0) + move->scrolling_yStep = 1; + + move->n_points = 0; + move->scrolling_x = 0; + move->scrolling_y = 0; +} + diff --git a/src/add-ons/kernel/bus_managers/ps2/movement_maker.h b/src/add-ons/kernel/bus_managers/ps2/movement_maker.h new file mode 100644 index 0000000000..c31fcf3ecf --- /dev/null +++ b/src/add-ons/kernel/bus_managers/ps2/movement_maker.h @@ -0,0 +1,42 @@ +#ifndef MOVEMENT_MAKER_H +#define MOVEMENT_MAKER_H + +#include + + +#define HISTORY_SIZE 1 + +float floorf(float x); +float ceilf(float x); +float sqrtf(float x); +int32 make_small(float value); + +typedef struct +{ + int32 xDelta; + int32 yDelta; + + int8 acceleration; + int8 speed; + + float scrolling_x; + float scrolling_y; + int32 scrolling_xStep; + int32 scrolling_yStep; + int32 scroll_acceleration; + + uint8 n_points; + float historyX[HISTORY_SIZE]; + float historyY[HISTORY_SIZE]; +} movement_maker; + + + +void get_raw_movement(movement_maker *move, uint32 posX, uint32 posY); +void compute_acceleration(movement_maker *move, int8 accel_factor); +void get_movement(movement_maker *move, uint32 posX, uint32 posY); +void get_scrolling(movement_maker *move, uint32 posX, uint32 posY); +void start_new_movment(movement_maker *move); + + +#endif diff --git a/src/add-ons/kernel/bus_managers/ps2/ps2_common.c b/src/add-ons/kernel/bus_managers/ps2/ps2_common.c index cbbdfe710f..a659f1a805 100644 --- a/src/add-ons/kernel/bus_managers/ps2/ps2_common.c +++ b/src/add-ons/kernel/bus_managers/ps2/ps2_common.c @@ -321,7 +321,7 @@ status_t ps2_init(void) { status_t status; - + TRACE("ps2: init\n"); status = get_module(B_ISA_MODULE_NAME, (module_info **)&gIsa); @@ -361,6 +361,7 @@ ps2_init(void) goto err5; } + ps2_flush(); status = ps2_setup_active_multiplexing(&gActiveMultiplexingEnabled); if (status) { INFO("ps2: setting up active multiplexing failed\n"); @@ -382,7 +383,7 @@ ps2_init(void) ps2_service_notify_device_added(&ps2_device[PS2_DEVICE_MOUSE]); ps2_service_notify_device_added(&ps2_device[PS2_DEVICE_KEYB]); } - + TRACE("ps2: init done!\n"); return B_OK; diff --git a/src/add-ons/kernel/bus_managers/ps2/ps2_common.h b/src/add-ons/kernel/bus_managers/ps2/ps2_common.h index 39eaa5a6b0..cd4ad53929 100644 --- a/src/add-ons/kernel/bus_managers/ps2/ps2_common.h +++ b/src/add-ons/kernel/bus_managers/ps2/ps2_common.h @@ -41,7 +41,7 @@ extern isa_module_info *gIsa; extern device_hooks gKeyboardDeviceHooks; -extern device_hooks gMouseDeviceHooks; +extern device_hooks gPointingDeviceHooks; extern bool gActiveMultiplexingEnabled; extern sem_id gControllerSem; diff --git a/src/add-ons/kernel/bus_managers/ps2/ps2_defs.h b/src/add-ons/kernel/bus_managers/ps2/ps2_defs.h index bacfa8342e..339bb386ca 100644 --- a/src/add-ons/kernel/bus_managers/ps2/ps2_defs.h +++ b/src/add-ons/kernel/bus_managers/ps2/ps2_defs.h @@ -75,7 +75,8 @@ // packet sizes #define PS2_PACKET_STANDARD 3 #define PS2_PACKET_INTELLIMOUSE 4 -#define PS2_MAX_PACKET_SIZE 4 +#define PS2_PACKET_SYNAPTICS 6 +#define PS2_MAX_PACKET_SIZE 6 // Should be equal to the biggest packet size // timeouts diff --git a/src/add-ons/kernel/bus_managers/ps2/ps2_dev.c b/src/add-ons/kernel/bus_managers/ps2/ps2_dev.c index b3d5e59372..896c33915c 100644 --- a/src/add-ons/kernel/bus_managers/ps2/ps2_dev.c +++ b/src/add-ons/kernel/bus_managers/ps2/ps2_dev.c @@ -12,20 +12,88 @@ #include "ps2_dev.h" #include "ps2_service.h" +#include "ps2_standart_mouse.h" +#include "ps2_synaptics.h" +#include "ps2_trackpoint.h" + #include #include ps2_dev ps2_device[PS2_DEVICE_COUNT] = { - { .name = "input/mouse/ps2/0", .active = false, .idx = 0, .result_sem = -1 }, - { .name = "input/mouse/ps2/1", .active = false, .idx = 1, .result_sem = -1 }, - { .name = "input/mouse/ps2/2", .active = false, .idx = 2, .result_sem = -1 }, - { .name = "input/mouse/ps2/3", .active = false, .idx = 3, .result_sem = -1 }, - { .name = "input/keyboard/at/0", .active = false, .result_sem = -1, .flags = PS2_FLAG_KEYB } + { .name = "input/mouse/ps2/0", .active = false, .idx = 0, .result_sem = -1, .command = standart_command_timeout }, + { .name = "input/mouse/ps2/1", .active = false, .idx = 1, .result_sem = -1, .command = standart_command_timeout }, + { .name = "input/mouse/ps2/2", .active = false, .idx = 2, .result_sem = -1, .command = standart_command_timeout }, + { .name = "input/mouse/ps2/3", .active = false, .idx = 3, .result_sem = -1, .command = standart_command_timeout }, + { .name = "input/mouse/ps2/synaptics_passthrough", .active = false, .result_sem = -1, .command = passthrough_command}, + { .name = "input/keyboard/at/0", .active = false, .result_sem = -1, .flags = PS2_FLAG_KEYB, .command = standart_command_timeout } }; +static status_t +ps2_reset_mouse(ps2_dev *dev) +{ + uint8 data[2]; + status_t status; + + TRACE("ps2: ps2_reset_mouse\n"); + + status = ps2_dev_command(dev, PS2_CMD_RESET, NULL, 0, data, 2); + + if (status == B_OK && data[0] != 0xAA && data[1] != 0x00) { + TRACE("ps2: reset mouse failed, response was: 0x%02x 0x%02x\n", data[0], data[1]); + status = B_ERROR; + } else if (status != B_OK) { + TRACE("ps2: reset mouse failed\n"); + } else { + TRACE("ps2: reset mouse success\n"); + } + + return status; +} + + +status_t +ps2_dev_detect_pointing(ps2_dev *dev, device_hooks **hooks) +{ + status_t status = ps2_reset_mouse(dev); + if (status != B_OK) { + INFO("ps2: reset failed\n"); + return B_ERROR; + } + + // probe devices + // the probe function has to set the dev name and the dev packet size + + status = probe_trackpoint(dev); + if (status == B_OK){ + *hooks = &gStandartMouseDeviceHooks; + goto dev_found; + } + + status = probe_synaptics(dev); + if (status == B_OK){ + *hooks = &gSynapticsDeviceHooks; + goto dev_found; + } + + status = probe_standart_mouse(dev); + if (status == B_OK){ + *hooks = &gStandartMouseDeviceHooks; + goto dev_found; + } + + return B_ERROR; + +dev_found: + if(dev == &(ps2_device[PS2_DEVICE_SYN_PASSTHROUGH])){ + synaptics_pt_set_packagesize(dev, dev->packet_size); + } + return B_OK; +} + + status_t ps2_dev_init(void) { @@ -65,12 +133,22 @@ ps2_dev_publish(ps2_dev *dev) if (dev->active) return; - + + if(atomic_get(&dev->flags) & PS2_FLAG_KEYB){ + status = devfs_publish_device(dev->name, &gKeyboardDeviceHooks); + } + else{ + device_hooks *hooks; + status = ps2_dev_detect_pointing(dev, &hooks); + if(status == B_OK){ + status = devfs_publish_device(dev->name, hooks); + } + + //status = devfs_publish_device(dev->name, &gPointingDeviceHooks); + } + dev->active = true; - status = devfs_publish_device(dev->name, (atomic_get(&dev->flags) - & PS2_FLAG_KEYB) ? &gKeyboardDeviceHooks : &gMouseDeviceHooks); - INFO("ps2: devfs_publish_device %s, status = 0x%08lx\n", dev->name, status); } @@ -181,20 +259,13 @@ pass_to_handler: TRACE("ps2: %s not enabled, data 0x%02x dropped\n", dev->name, data); return B_HANDLED_INTERRUPT; } - + return dev->handle_int(dev); } status_t -ps2_dev_command(ps2_dev *dev, uint8 cmd, const uint8 *out, int out_count, uint8 *in, int in_count) -{ - return ps2_dev_command_timeout(dev, cmd, out, out_count, in, in_count, 4000000); -} - - -status_t -ps2_dev_command_timeout(ps2_dev *dev, uint8 cmd, const uint8 *out, int out_count, uint8 *in, int in_count, bigtime_t timeout) +standart_command_timeout(ps2_dev *dev, uint8 cmd, const uint8 *out, int out_count, uint8 *in, int in_count, bigtime_t timeout) { status_t res; bigtime_t start; @@ -301,3 +372,17 @@ ps2_dev_command_timeout(ps2_dev *dev, uint8 cmd, const uint8 *out, int out_count return res; } + +status_t +ps2_dev_command(ps2_dev *dev, uint8 cmd, const uint8 *out, int out_count, uint8 *in, int in_count) +{ + return ps2_dev_command_timeout(dev, cmd, out, out_count, in, in_count, 4000000); +} + + +status_t +ps2_dev_command_timeout(ps2_dev *dev, uint8 cmd, const uint8 *out, int out_count, uint8 *in, int in_count, bigtime_t timeout) +{ + return dev->command(dev, cmd, out, out_count, in, in_count, timeout); +} + diff --git a/src/add-ons/kernel/bus_managers/ps2/ps2_dev.h b/src/add-ons/kernel/bus_managers/ps2/ps2_dev.h index b7838ab72e..c54d2f1d8f 100644 --- a/src/add-ons/kernel/bus_managers/ps2/ps2_dev.h +++ b/src/add-ons/kernel/bus_managers/ps2/ps2_dev.h @@ -15,6 +15,7 @@ typedef struct ps2_dev ps2_dev; #include "ps2_common.h" + typedef struct { bigtime_t time; @@ -26,26 +27,30 @@ struct ps2_dev { const char * name; bool active; - uint32 flags; uint8 idx; sem_id result_sem; + vint32 flags; uint8 * result_buf; int result_buf_idx; int result_buf_cnt; void * cookie; data_history history[2]; - + ps2_dev * parent_dev; + size_t packet_size; + // functions void (*disconnect)(ps2_dev *); int32 (*handle_int)(ps2_dev *); + status_t (*command)(ps2_dev *dev, uint8 cmd, const uint8 *out, int out_count, uint8 *in, int in_count, bigtime_t timeout); }; -#define PS2_DEVICE_COUNT 5 +#define PS2_DEVICE_COUNT 6 extern ps2_dev ps2_device[PS2_DEVICE_COUNT]; #define PS2_DEVICE_MOUSE 0 -#define PS2_DEVICE_KEYB 4 +#define PS2_DEVICE_SYN_PASSTHROUGH 4 +#define PS2_DEVICE_KEYB 5 #define PS2_FLAG_KEYB (1<<0) #define PS2_FLAG_OPEN (1<<1) @@ -55,9 +60,15 @@ extern ps2_dev ps2_device[PS2_DEVICE_COUNT]; #define PS2_FLAG_NACK (1<<5) #define PS2_FLAG_GETID (1<<6) +void ps2_dev_send(ps2_dev *dev, uint8 data); + +status_t ps2_dev_detect_pointing(ps2_dev *dev, device_hooks **hooks); + status_t ps2_dev_init(void); void ps2_dev_exit(void); +status_t standart_command_timeout(ps2_dev *dev, uint8 cmd, const uint8 *out, int out_count, uint8 *in, int in_count, bigtime_t timeout); + status_t ps2_dev_command(ps2_dev *dev, uint8 cmd, const uint8 *out, int out_count, uint8 *in, int in_count); status_t ps2_dev_command_timeout(ps2_dev *dev, uint8 cmd, const uint8 *out, int out_count, uint8 *in, int in_count, bigtime_t timeout); diff --git a/src/add-ons/kernel/bus_managers/ps2/ps2_mouse.c b/src/add-ons/kernel/bus_managers/ps2/ps2_mouse.c index 0468d6f801..e69de29bb2 100644 --- a/src/add-ons/kernel/bus_managers/ps2/ps2_mouse.c +++ b/src/add-ons/kernel/bus_managers/ps2/ps2_mouse.c @@ -1,533 +0,0 @@ -/* - * Copyright 2001-2008 Haiku, Inc. - * Distributed under the terms of the MIT License. - * - * PS/2 mouse device driver - * - * Authors (in chronological order): - * Elad Lahav (elad@eldarshany.com) - * Stefano Ceccherini (burton666@libero.it) - * Axel Dörfler, axeld@pinc-software.de - * Marcus Overhagen - */ - -/* - * A PS/2 mouse is connected to the IBM 8042 controller, and gets its - * name from the IBM PS/2 personal computer, which was the first to - * use this device. All resources are shared between the keyboard, and - * the mouse, referred to as the "Auxiliary Device". - * - * I/O: - * ~~~ - * The controller has 3 I/O registers: - * 1. Status (input), mapped to port 64h - * 2. Control (output), mapped to port 64h - * 3. Data (input/output), mapped to port 60h - * - * Data: - * ~~~~ - * A packet read from the mouse data port is composed of - * three bytes: - * byte 0: status byte, where - * - bit 7: Y overflow (1 = true) - * - bit 6: X overflow (1 = true) - * - bit 5: MSB of Y offset - * - bit 4: MSB of X offset - * - bit 3: Syncronization bit (always 1) - * - bit 2: Middle button (1 = down) - * - bit 1: Right button (1 = down) - * - bit 0: Left button (1 = down) - * byte 1: X position change, since last probed (-127 to +127) - * byte 2: Y position change, since last probed (-127 to +127) - * - * Intellimouse mice send a four byte packet, where the first three - * bytes are the same as standard mice, and the last one reports the - * Z position, which is, usually, the wheel movement. - * - * Interrupts: - * ~~~~~~~~~~ - * The PS/2 mouse device is connected to interrupt 12. - * The controller uses 3 consecutive interrupts to inform the computer - * that it has new data. On the first the data register holds the status - * byte, on the second the X offset, and on the 3rd the Y offset. - */ - -#include -#include -#include - -#include "kb_mouse_driver.h" -#include "packet_buffer.h" -#include "ps2_service.h" - - -#define MOUSE_HISTORY_SIZE 256 - // we record that many mouse packets before we start to drop them - -#define F_MOUSE_TYPE_STANDARD 0x1 -#define F_MOUSE_TYPE_INTELLIMOUSE 0x2 -#define F_MOUSE_TYPE_MASK 0xf - -typedef struct -{ - ps2_dev * dev; - - sem_id mouse_sem; - packet_buffer * mouse_buffer; - bigtime_t click_last_time; - bigtime_t click_speed; - int click_count; - int buttons_state; - int flags; - size_t packet_size; - size_t packet_index; - uint8 packet_buffer[PS2_MAX_PACKET_SIZE]; - -} mouse_cookie; - - -static status_t -ps2_reset_mouse(mouse_cookie *cookie) -{ - uint8 data[2]; - status_t status; - - TRACE("ps2: ps2_reset_mouse\n"); - - status = ps2_dev_command(cookie->dev, PS2_CMD_RESET, NULL, 0, data, 2); - - if (status == B_OK && data[0] != 0xAA && data[1] != 0x00) { - TRACE("ps2: reset mouse failed, response was: 0x%02x 0x%02x\n", data[0], data[1]); - status = B_ERROR; - } else if (status != B_OK) { - TRACE("ps2: reset mouse failed\n"); - } else { - TRACE("ps2: reset mouse success\n"); - } - - return status; -} - - -/** Set sampling rate of the ps2 port. - */ -static inline status_t -ps2_set_sample_rate(mouse_cookie *cookie, uint8 rate) -{ - return ps2_dev_command(cookie->dev, PS2_CMD_SET_SAMPLE_RATE, &rate, 1, NULL, 0); -} - - -/** Converts a packet received by the mouse to a "movement". - */ -static void -ps2_packet_to_movement(mouse_cookie *cookie, uint8 packet[], mouse_movement *pos) -{ - int buttons = packet[0] & 7; - int xDelta = ((packet[0] & 0x10) ? ~0xff : 0) | packet[1]; - int yDelta = ((packet[0] & 0x20) ? ~0xff : 0) | packet[2]; - int xDeltaWheel = 0; - int yDeltaWheel = 0; - bigtime_t currentTime = system_time(); - - if (buttons != 0 && cookie->buttons_state == 0) { - if (cookie->click_last_time + cookie->click_speed > currentTime) - cookie->click_count++; - else - cookie->click_count = 1; - - cookie->click_last_time = currentTime; - } - - cookie->buttons_state = buttons; - - if (cookie->flags & F_MOUSE_TYPE_INTELLIMOUSE) { - yDeltaWheel = packet[3] & 0x07; - if (packet[3] & 0x08) - yDeltaWheel |= ~0x07; - } -/* - if (cookie->flags & F_MOUSE_TYPE_2WHEELS) { - switch (packet[3] & 0x0F) { - case 0x01: yDeltaWheel = +1; break; // wheel 1 down - case 0x0F: yDeltaWheel = -1; break; // wheel 1 up - case 0x02: xDeltaWheel = +1; break; // wheel 2 down - case 0x0E: xDeltaWheel = -1; break; // wheel 2 up - } - } -*/ - -// TRACE("packet: %02x %02x %02x %02x: xd %d, yd %d, 0x%x (%d), w-xd %d, w-yd %d\n", -// packet[0], packet[1], packet[2], packet[3], -// xDelta, yDelta, buttons, cookie->click_count, xDeltaWheel, yDeltaWheel); - - if (pos) { - pos->xdelta = xDelta; - pos->ydelta = yDelta; - pos->buttons = buttons; - pos->clicks = cookie->click_count; - pos->modifiers = 0; - pos->timestamp = currentTime; - pos->wheel_ydelta = yDeltaWheel; - pos->wheel_xdelta = xDeltaWheel; - - TRACE("ps2: ps2_packet_to_movement xdelta: %d, ydelta: %d, buttons %x, clicks: %d, timestamp %Ld\n", - xDelta, yDelta, buttons, cookie->click_count, currentTime); - } -} - - -/** Read a mouse event from the mouse events chain buffer. - */ -static status_t -mouse_read_event(mouse_cookie *cookie, mouse_movement *movement) -{ - uint8 packet[PS2_MAX_PACKET_SIZE]; - status_t status; - - TRACE("ps2: mouse_read_event\n"); - status = acquire_sem_etc(cookie->mouse_sem, 1, B_CAN_INTERRUPT, 0); - if (status < B_OK) - return status; - - if (!cookie->dev->active) { - TRACE("ps2: mouse_read_event: Error device no longer active\n"); - return B_ERROR; - } - - if (packet_buffer_read(cookie->mouse_buffer, packet, cookie->packet_size) != cookie->packet_size) { - TRACE("ps2: error copying buffer\n"); - return B_ERROR; - } - - if (!(packet[0] & 8)) - panic("ps2: got broken data from packet_buffer_read\n"); - - ps2_packet_to_movement(cookie, packet, movement); - return B_OK; -} - - -static void -ps2_mouse_disconnect(ps2_dev *dev) -{ - // the mouse device might not be opened at this point - INFO("ps2: ps2_mouse_disconnect %s\n", dev->name); - if (dev->flags & PS2_FLAG_OPEN) - release_sem(((mouse_cookie *)dev->cookie)->mouse_sem); -} - - -/** Interrupt handler for the mouse device. Called whenever the I/O - * controller generates an interrupt for the PS/2 mouse. Reads mouse - * information from the data port, and stores it, so it can be accessed - * by read() operations. The full data is obtained using 3 consecutive - * calls to the handler, each holds a different byte on the data port. - */ -static int32 -mouse_handle_int(ps2_dev *dev) -{ - mouse_cookie *cookie = dev->cookie; - const uint8 data = dev->history[0].data; - - if (cookie->packet_index == 0 && !(data & 8)) { - INFO("ps2: bad mouse data, trying resync\n"); - return B_HANDLED_INTERRUPT; - } - - // Workarounds for active multiplexing keyboard controllers - // that lose data or send them to the wrong port. - if (cookie->packet_index == 0 && (data & 0xc0)) { - INFO("ps2: strange mouse data, x/y overflow, trying resync\n"); - return B_HANDLED_INTERRUPT; - } - if (cookie->packet_index == 1) { - int xDelta = ((cookie->packet_buffer[0] & 0x10) ? 0xFFFFFF00 : 0) | data; - if (xDelta < -100 || xDelta > 100) { - INFO("ps2: strange mouse data, x-delta %d, trying resync\n", xDelta); - cookie->packet_index = 0; - return B_HANDLED_INTERRUPT; - } - } - if (cookie->packet_index == 2) { - int yDelta = ((cookie->packet_buffer[0] & 0x20) ? 0xFFFFFF00 : 0) | data; - if (yDelta < -100 || yDelta > 100) { - INFO("ps2: strange mouse data, y-delta %d, trying resync\n", yDelta); - cookie->packet_index = 0; - return B_HANDLED_INTERRUPT; - } - } - - cookie->packet_buffer[cookie->packet_index++] = data; - - if (cookie->packet_index != cookie->packet_size) { - // packet not yet complete - return B_HANDLED_INTERRUPT; - } - - // complete packet is assembled - - cookie->packet_index = 0; - - if (packet_buffer_write(cookie->mouse_buffer, cookie->packet_buffer, cookie->packet_size) != cookie->packet_size) { - // buffer is full, drop new data - return B_HANDLED_INTERRUPT; - } - - release_sem_etc(cookie->mouse_sem, 1, B_DO_NOT_RESCHEDULE); - return B_INVOKE_SCHEDULER; -} - - -// #pragma mark - - - -static status_t -probe_mouse(mouse_cookie *cookie) -{ - status_t status; - uint8 deviceId = 0; - - cookie->flags = 0; - - status = ps2_reset_mouse(cookie); - if (status != B_OK) { - INFO("ps2: probe_mouse reset failed\n"); - return B_ERROR; - } - - // get device id - status = ps2_dev_command(cookie->dev, PS2_CMD_GET_DEVICE_ID, NULL, 0, &deviceId, 1); - if (status != B_OK) { - INFO("ps2: probe_mouse get device id failed\n"); - return B_ERROR; - } - - TRACE("ps2: probe_mouse device id: %2x\n", deviceId); - - // check for MS Intellimouse - if (deviceId == 0) { - uint8 alternate_device_id; - status = ps2_set_sample_rate(cookie, 200); - status |= ps2_set_sample_rate(cookie, 100); - status |= ps2_set_sample_rate(cookie, 80); - status |= ps2_dev_command(cookie->dev, PS2_CMD_GET_DEVICE_ID, NULL, 0, &alternate_device_id, 1); - if (status == 0) { - TRACE("ps2: probe_mouse alternate device id: %2x\n", alternate_device_id); - deviceId = alternate_device_id; - } - } - - if (deviceId == PS2_DEV_ID_STANDARD) { - INFO("ps2: probe_mouse Standard PS/2 mouse found\n"); - cookie->flags |= F_MOUSE_TYPE_STANDARD; - } else if (deviceId == PS2_DEV_ID_INTELLIMOUSE) { - INFO("ps2: probe_mouse Extended PS/2 mouse found\n"); - cookie->flags |= F_MOUSE_TYPE_INTELLIMOUSE; - } else { - INFO("ps2: probe_mouse Error unknown device id.\n"); - return B_ERROR; - } - - return B_OK; -} - - -// #pragma mark - -// Device functions - - -static status_t -mouse_open(const char *name, uint32 flags, void **_cookie) -{ - mouse_cookie *cookie; - ps2_dev *dev; - status_t status; - int i; - - TRACE("ps2: mouse_open %s\n", name); - - for (dev = NULL, i = 0; i < PS2_DEVICE_COUNT; i++) { - if (0 == strcmp(ps2_device[i].name, name)) { - dev = &ps2_device[i]; - break; - } - } - - if (dev == NULL) { - TRACE("ps2: dev = NULL\n"); - return B_ERROR; - } - - if (atomic_or(&dev->flags, PS2_FLAG_OPEN) & PS2_FLAG_OPEN) - return B_BUSY; - - cookie = malloc(sizeof(mouse_cookie)); - if (cookie == NULL) - goto err1; - - *_cookie = cookie; - memset(cookie, 0, sizeof(*cookie)); - - cookie->dev = dev; - dev->cookie = cookie; - dev->disconnect = &ps2_mouse_disconnect; - dev->handle_int = &mouse_handle_int; - - // probe mouse also sets cookie->flags - status = probe_mouse(cookie); - if (status != B_OK) { - INFO("ps2: probing mouse %s failed\n", name); - ps2_service_notify_device_removed(dev); - goto err1; - } - - if (cookie->flags & F_MOUSE_TYPE_INTELLIMOUSE) - cookie->packet_size = PS2_PACKET_INTELLIMOUSE; - else - cookie->packet_size = PS2_PACKET_STANDARD; - - cookie->mouse_buffer = create_packet_buffer(MOUSE_HISTORY_SIZE * cookie->packet_size); - if (cookie->mouse_buffer == NULL) { - TRACE("ps2: can't allocate mouse actions buffer\n"); - goto err2; - } - - // create the mouse semaphore, used for synchronization between - // the interrupt handler and the read operation - cookie->mouse_sem = create_sem(0, "ps2_mouse_sem"); - if (cookie->mouse_sem < 0) { - TRACE("ps2: failed creating PS/2 mouse semaphore!\n"); - goto err3; - } - - status = ps2_dev_command(dev, PS2_CMD_ENABLE, NULL, 0, NULL, 0); - if (status < B_OK) { - INFO("ps2: cannot enable mouse %s\n", name); - goto err4; - } - - atomic_or(&dev->flags, PS2_FLAG_ENABLED); - - TRACE("ps2: mouse_open %s success\n", name); - return B_OK; - -err4: - delete_sem(cookie->mouse_sem); -err3: - delete_packet_buffer(cookie->mouse_buffer); -err2: - free(cookie); -err1: - atomic_and(&dev->flags, ~PS2_FLAG_OPEN); - - TRACE("ps2: mouse_open %s failed\n", name); - return B_ERROR; -} - - -static status_t -mouse_close(void *_cookie) -{ - mouse_cookie *cookie = _cookie; - - TRACE("ps2: mouse_close %s enter\n", cookie->dev->name); - - ps2_dev_command_timeout(cookie->dev, PS2_CMD_DISABLE, NULL, 0, NULL, 0, 150000); - - delete_packet_buffer(cookie->mouse_buffer); - delete_sem(cookie->mouse_sem); - - atomic_and(&cookie->dev->flags, ~PS2_FLAG_OPEN); - atomic_and(&cookie->dev->flags, ~PS2_FLAG_ENABLED); - - TRACE("ps2: mouse_close %s done\n", cookie->dev->name); - return B_OK; -} - - -static status_t -mouse_freecookie(void *_cookie) -{ - mouse_cookie *cookie = _cookie; - free(cookie); - return B_OK; -} - - -static status_t -mouse_read(void *cookie, off_t pos, void *buffer, size_t *_length) -{ - *_length = 0; - return B_NOT_ALLOWED; -} - - -static status_t -mouse_write(void *cookie, off_t pos, const void *buffer, size_t *_length) -{ - *_length = 0; - return B_NOT_ALLOWED; -} - - -static status_t -mouse_ioctl(void *_cookie, uint32 op, void *buffer, size_t length) -{ - mouse_cookie *cookie = _cookie; - - switch (op) { - case MS_NUM_EVENTS: - { - int32 count; - TRACE("ps2: ioctl MS_NUM_EVENTS\n"); - get_sem_count(cookie->mouse_sem, &count); - return count; - } - - case MS_READ: - { - mouse_movement movement; - status_t status; - TRACE("ps2: ioctl MS_READ\n"); - if ((status = mouse_read_event(cookie, &movement)) < B_OK) - return status; -// TRACE("%s %d %d %d %d\n", cookie->dev->name, -// movement.xdelta, movement.ydelta, movement.buttons, movement.clicks); - return user_memcpy(buffer, &movement, sizeof(movement)); - } - - case MS_SET_TYPE: - TRACE("ps2: ioctl MS_SET_TYPE not implemented\n"); - return B_BAD_VALUE; - - case MS_SET_MAP: - TRACE("ps2: ioctl MS_SET_MAP (set mouse mapping) not implemented\n"); - return B_BAD_VALUE; - - case MS_GET_ACCEL: - TRACE("ps2: ioctl MS_GET_ACCEL (get mouse acceleration) not implemented\n"); - return B_BAD_VALUE; - - case MS_SET_ACCEL: - TRACE("ps2: ioctl MS_SET_ACCEL (set mouse acceleration) not implemented\n"); - return B_BAD_VALUE; - - case MS_SET_CLICKSPEED: - TRACE("ps2: ioctl MS_SETCLICK (set click speed)\n"); - return user_memcpy(&cookie->click_speed, buffer, sizeof(bigtime_t)); - - default: - TRACE("ps2: ioctl unknown mouse opcode: %ld\n", op); - return B_BAD_VALUE; - } -} - -device_hooks gMouseDeviceHooks = { - mouse_open, - mouse_close, - mouse_freecookie, - mouse_ioctl, - mouse_read, - mouse_write, -}; diff --git a/src/add-ons/kernel/bus_managers/ps2/ps2_standart_mouse.c b/src/add-ons/kernel/bus_managers/ps2/ps2_standart_mouse.c new file mode 100644 index 0000000000..bd2df7bd52 --- /dev/null +++ b/src/add-ons/kernel/bus_managers/ps2/ps2_standart_mouse.c @@ -0,0 +1,494 @@ +/* + * Copyright 2001-2008 Haiku, Inc. + * Distributed under the terms of the MIT License. + * + * PS/2 mouse device driver + * + * Authors (in chronological order): + * Elad Lahav (elad@eldarshany.com) + * Stefano Ceccherini (burton666@libero.it) + * Axel Dörfler, axeld@pinc-software.de + * Marcus Overhagen + * Clemens Zeidler + */ + +/* + * A PS/2 mouse is connected to the IBM 8042 controller, and gets its + * name from the IBM PS/2 personal computer, which was the first to + * use this device. All resources are shared between the keyboard, and + * the mouse, referred to as the "Auxiliary Device". + * + * I/O: + * ~~~ + * The controller has 3 I/O registers: + * 1. Status (input), mapped to port 64h + * 2. Control (output), mapped to port 64h + * 3. Data (input/output), mapped to port 60h + * + * Data: + * ~~~~ + * A packet read from the mouse data port is composed of + * three bytes: + * byte 0: status byte, where + * - bit 7: Y overflow (1 = true) + * - bit 6: X overflow (1 = true) + * - bit 5: MSB of Y offset + * - bit 4: MSB of X offset + * - bit 3: Syncronization bit (always 1) + * - bit 2: Middle button (1 = down) + * - bit 1: Right button (1 = down) + * - bit 0: Left button (1 = down) + * byte 1: X position change, since last probed (-127 to +127) + * byte 2: Y position change, since last probed (-127 to +127) + * + * Intellimouse mice send a four byte packet, where the first three + * bytes are the same as standard mice, and the last one reports the + * Z position, which is, usually, the wheel movement. + * + * Interrupts: + * ~~~~~~~~~~ + * The PS/2 mouse device is connected to interrupt 12. + * The controller uses 3 consecutive interrupts to inform the computer + * that it has new data. On the first the data register holds the status + * byte, on the second the X offset, and on the 3rd the Y offset. + */ + +#include +#include + +#include "kb_mouse_driver.h" +#include "ps2_service.h" +#include "ps2_standart_mouse.h" + + +const char* kStandartMousePath[4] = {"input/mouse/ps2/standart_0", + "input/mouse/ps2/standart_1", + "input/mouse/ps2/standart_2", + "input/mouse/ps2/standart_3"}; +const char* kIntelliMousePath[4] = {"input/mouse/ps2/intelli_0", + "input/mouse/ps2/intelli_1", + "input/mouse/ps2/intelli_2", + "input/mouse/ps2/intelli_3"}; +/** Set sampling rate of the ps2 port. + */ +static inline status_t +ps2_set_sample_rate(ps2_dev *dev, uint8 rate) +{ + return ps2_dev_command(dev, PS2_CMD_SET_SAMPLE_RATE, &rate, 1, NULL, 0); +} + + +/** Converts a packet received by the mouse to a "movement". + */ +static void +ps2_packet_to_movement(standart_mouse_cookie *cookie, uint8 packet[], mouse_movement *pos) +{ + int buttons = packet[0] & 7; + int xDelta = ((packet[0] & 0x10) ? ~0xff : 0) | packet[1]; + int yDelta = ((packet[0] & 0x20) ? ~0xff : 0) | packet[2]; + int xDeltaWheel = 0; + int yDeltaWheel = 0; + bigtime_t currentTime = system_time(); + + if (buttons != 0 && cookie->buttons_state == 0) { + if (cookie->click_last_time + cookie->click_speed > currentTime) + cookie->click_count++; + else + cookie->click_count = 1; + + cookie->click_last_time = currentTime; + } + + cookie->buttons_state = buttons; + + if (cookie->flags & F_pointing_dev_TYPE_INTELLIMOUSE) { + yDeltaWheel = packet[3] & 0x07; + if (packet[3] & 0x08) + yDeltaWheel |= ~0x07; + } +/* + if (cookie->flags & F_standart_mouse_TYPE_2WHEELS) { + switch (packet[3] & 0x0F) { + case 0x01: yDeltaWheel = +1; break; // wheel 1 down + case 0x0F: yDeltaWheel = -1; break; // wheel 1 up + case 0x02: xDeltaWheel = +1; break; // wheel 2 down + case 0x0E: xDeltaWheel = -1; break; // wheel 2 up + } + } +*/ + +// TRACE("packet: %02x %02x %02x %02x: xd %d, yd %d, 0x%x (%d), w-xd %d, w-yd %d\n", +// packet[0], packet[1], packet[2], packet[3], +// xDelta, yDelta, buttons, cookie->click_count, xDeltaWheel, yDeltaWheel); + + if (pos) { + pos->xdelta = xDelta; + pos->ydelta = yDelta; + pos->buttons = buttons; + pos->clicks = cookie->click_count; + pos->modifiers = 0; + pos->timestamp = currentTime; + pos->wheel_ydelta = yDeltaWheel; + pos->wheel_xdelta = xDeltaWheel; + + TRACE("ps2: ps2_packet_to_movement xdelta: %d, ydelta: %d, buttons %x, clicks: %d, timestamp %Ld\n", + xDelta, yDelta, buttons, cookie->click_count, currentTime); + } +} + + +/** Read a mouse event from the mouse events chain buffer. + */ +static status_t +standart_mouse_read_event(standart_mouse_cookie *cookie, mouse_movement *movement) +{ + uint8 packet[PS2_MAX_PACKET_SIZE]; + status_t status; + + TRACE("ps2: standart_mouse_read_event\n"); + + status = acquire_sem_etc(cookie->standart_mouse_sem, 1, B_CAN_INTERRUPT, 0); + TRACE("ps2: standart_mouse_read_event acquired\n"); + if (status < B_OK) + return status; + + if (!cookie->dev->active) { + TRACE("ps2: standart_mouse_read_event: Error device no longer active\n"); + return B_ERROR; + } + + if (packet_buffer_read(cookie->standart_mouse_buffer, packet, cookie->dev->packet_size) != cookie->dev->packet_size) { + TRACE("ps2: error copying buffer\n"); + return B_ERROR; + } + + if (!(packet[0] & 8)) + panic("ps2: got broken data from packet_buffer_read\n"); + + ps2_packet_to_movement(cookie, packet, movement); + return B_OK; +} + + +void +standart_mouse_disconnect(ps2_dev *dev) +{ + // the mouse device might not be opened at this point + INFO("ps2: ps2_standart_mouse_disconnect %s\n", dev->name); + if (dev->flags & PS2_FLAG_OPEN) + release_sem(((standart_mouse_cookie *)dev->cookie)->standart_mouse_sem); +} + + +/** Interrupt handler for the mouse device. Called whenever the I/O + * controller generates an interrupt for the PS/2 mouse. Reads mouse + * information from the data port, and stores it, so it can be accessed + * by read() operations. The full data is obtained using 3 consecutive + * calls to the handler, each holds a different byte on the data port. + */ +int32 +standart_mouse_handle_int(ps2_dev *dev) +{ + standart_mouse_cookie *cookie = (standart_mouse_cookie*)dev->cookie; + const uint8 data = dev->history[0].data; + + TRACE("ps2: standart mouse: %1x\t%1x\t%1x\t%1x\t%1x\t%1x\t%1x\t%1x\n", + data >> 7 & 1, data >> 6 & 1, data >> 5 & 1, + data >> 4 & 1, data >> 3 & 1, data >> 2 & 1, + data >> 1 & 1, data >> 0 & 1); + + if (cookie->packet_index == 0 && !(data & 8)) { + INFO("ps2: bad mouse data, trying resync\n"); + return B_HANDLED_INTERRUPT; + } + + // Workarounds for active multiplexing keyboard controllers + // that lose data or send them to the wrong port. + if (cookie->packet_index == 0 && (data & 0xc0)) { + INFO("ps2: strange mouse data, x/y overflow, trying resync\n"); + return B_HANDLED_INTERRUPT; + } + if (cookie->packet_index == 1) { + int xDelta = ((cookie->packet_buffer[0] & 0x10) ? 0xFFFFFF00 : 0) | data; + if (xDelta < -100 || xDelta > 100) { + INFO("ps2: strange mouse data, x-delta %d, trying resync\n", xDelta); + cookie->packet_index = 0; + return B_HANDLED_INTERRUPT; + } + } + if (cookie->packet_index == 2) { + int yDelta = ((cookie->packet_buffer[0] & 0x20) ? 0xFFFFFF00 : 0) | data; + if (yDelta < -100 || yDelta > 100) { + INFO("ps2: strange mouse data, y-delta %d, trying resync\n", yDelta); + cookie->packet_index = 0; + return B_HANDLED_INTERRUPT; + } + } + + cookie->packet_buffer[cookie->packet_index++] = data; + + if (cookie->packet_index != dev->packet_size) { + // packet not yet complete + return B_HANDLED_INTERRUPT; + } + + // complete packet is assembled + + cookie->packet_index = 0; + if (packet_buffer_write(cookie->standart_mouse_buffer, cookie->packet_buffer, dev->packet_size) != dev->packet_size) { + // buffer is full, drop new data + return B_HANDLED_INTERRUPT; + } + + release_sem_etc(cookie->standart_mouse_sem, 1, B_DO_NOT_RESCHEDULE); + return B_INVOKE_SCHEDULER; +} + + +// #pragma mark - + + +status_t +probe_standart_mouse(ps2_dev * dev) +{ + status_t status; + uint8 deviceId = 0; + + // get device id + status = ps2_dev_command(dev, PS2_CMD_GET_DEVICE_ID, NULL, 0, &deviceId, 1); + if (status != B_OK) { + INFO("ps2: probe_mouse get device id failed\n"); + return B_ERROR; + } + + TRACE("ps2: probe_mouse device id: %2x\n", deviceId); + + // check for MS Intellimouse + if (deviceId == 0) { + uint8 alternate_device_id; + status = ps2_set_sample_rate(dev, 200); + status |= ps2_set_sample_rate(dev, 100); + status |= ps2_set_sample_rate(dev, 80); + status |= ps2_dev_command(dev, PS2_CMD_GET_DEVICE_ID, NULL, 0, &alternate_device_id, 1); + if (status == 0) { + TRACE("ps2: probe_mouse alternate device id: %2x\n", alternate_device_id); + deviceId = alternate_device_id; + } + } + + if (deviceId == PS2_DEV_ID_STANDARD) { + INFO("ps2: probe_mouse Standard PS/2 mouse found\n"); + dev->name = kStandartMousePath[dev->idx]; + dev->packet_size = PS2_PACKET_STANDARD; + } else if (deviceId == PS2_DEV_ID_INTELLIMOUSE) { + dev->name = kIntelliMousePath[dev->idx]; + dev->packet_size = PS2_PACKET_INTELLIMOUSE; + INFO("ps2: probe_mouse Extended PS/2 mouse found\n"); + } else { + INFO("ps2: probe_mouse Error unknown device id.\n"); + return B_ERROR; + } + + return B_OK; +} + + +// #pragma mark - +// Device functions + + +status_t +standart_mouse_open(const char *name, uint32 flags, void **_cookie) +{ + standart_mouse_cookie *cookie; + status_t status; + ps2_dev *dev = NULL; + int i; + + TRACE("ps2: standart_mouse_open %s\n", name); + + for (dev = NULL, i = 0; i < PS2_DEVICE_COUNT; i++) { + if (0 == strcmp(ps2_device[i].name, name)) { + dev = &ps2_device[i]; + break; + } + /*if (0 == strcmp(g_passthrough_dev.name, name)) { + dev = &g_passthrough_dev; + isSynapticsPTDevice = true; + break; + }*/ + } + + if (dev == NULL) { + TRACE("ps2: dev = NULL\n"); + return B_ERROR; + } + + if (atomic_or(&dev->flags, PS2_FLAG_OPEN) & PS2_FLAG_OPEN) + return B_BUSY; + + cookie = malloc(sizeof(standart_mouse_cookie)); + if (cookie == NULL) + goto err1; + + *_cookie = cookie; + memset(cookie, 0, sizeof(*cookie)); + + cookie->dev = dev; + dev->cookie = cookie; + dev->disconnect = &standart_mouse_disconnect; + dev->handle_int = &standart_mouse_handle_int; + + if(strstr(dev->name, "standard_mouse") != NULL){ + cookie->flags = F_pointing_dev_TYPE_STANDARD; + } + if(strstr(dev->name, "intelli_mouse") != NULL){ + cookie->flags = F_pointing_dev_TYPE_INTELLIMOUSE; + } + + cookie->standart_mouse_buffer = create_packet_buffer(standart_mouse_HISTORY_SIZE * dev->packet_size); + if (cookie->standart_mouse_buffer == NULL) { + TRACE("ps2: can't allocate mouse actions buffer\n"); + goto err2; + } + + // create the mouse semaphore, used for synchronization between + // the interrupt handler and the read operation + cookie->standart_mouse_sem = create_sem(0, "ps2_standart_mouse_sem"); + if (cookie->standart_mouse_sem < 0) { + TRACE("ps2: failed creating PS/2 mouse semaphore!\n"); + goto err3; + } + + status = ps2_dev_command(dev, PS2_CMD_ENABLE, NULL, 0, NULL, 0); + if (status < B_OK) { + INFO("ps2: cannot enable mouse %s\n", name); + goto err4; + } + + atomic_or(&dev->flags, PS2_FLAG_ENABLED); + + + TRACE("ps2: standart_mouse_open %s success\n", name); + return B_OK; + +err4: + delete_sem(cookie->standart_mouse_sem); +err3: + delete_packet_buffer(cookie->standart_mouse_buffer); +err2: + free(cookie); +err1: + atomic_and(&dev->flags, ~PS2_FLAG_OPEN); + + TRACE("ps2: standart_mouse_open %s failed\n", name); + return B_ERROR; +} + + +status_t +standart_mouse_close(void *_cookie) +{ + standart_mouse_cookie *cookie = (standart_mouse_cookie*)_cookie; + + TRACE("ps2: standart_mouse_close %s enter\n", cookie->dev->name); + + ps2_dev_command_timeout(cookie->dev, PS2_CMD_DISABLE, NULL, 0, NULL, 0, 150000); + + delete_packet_buffer(cookie->standart_mouse_buffer); + delete_sem(cookie->standart_mouse_sem); + + atomic_and(&cookie->dev->flags, ~PS2_FLAG_OPEN); + atomic_and(&cookie->dev->flags, ~PS2_FLAG_ENABLED); + + TRACE("ps2: standart_mouse_close %s done\n", cookie->dev->name); + return B_OK; +} + + +status_t +standart_mouse_freecookie(void *_cookie) +{ + standart_mouse_cookie *cookie = (standart_mouse_cookie*)_cookie; + free(cookie); + return B_OK; +} + + +static status_t +standart_mouse_read(void *cookie, off_t pos, void *buffer, size_t *_length) +{ + *_length = 0; + return B_NOT_ALLOWED; +} + + +static status_t +standart_mouse_write(void *cookie, off_t pos, const void *buffer, size_t *_length) +{ + *_length = 0; + return B_NOT_ALLOWED; +} + + +status_t +standart_mouse_ioctl(void *_cookie, uint32 op, void *buffer, size_t length) +{ + standart_mouse_cookie *cookie = (standart_mouse_cookie*)_cookie; + + switch (op) { + case MS_NUM_EVENTS: + { + int32 count; + TRACE("ps2: ioctl MS_NUM_EVENTS\n"); + get_sem_count(cookie->standart_mouse_sem, &count); + return count; + } + + case MS_READ: + { + mouse_movement movement; + status_t status; + TRACE("ps2: ioctl MS_READ\n"); + if ((status = standart_mouse_read_event(cookie, &movement)) < B_OK) + return status; +// TRACE("%s %d %d %d %d\n", cookie->dev->name, +// movement.xdelta, movement.ydelta, movement.buttons, movement.clicks); + return user_memcpy(buffer, &movement, sizeof(movement)); + } + + case MS_SET_TYPE: + TRACE("ps2: ioctl MS_SET_TYPE not implemented\n"); + return B_BAD_VALUE; + + case MS_SET_MAP: + TRACE("ps2: ioctl MS_SET_MAP (set mouse mapping) not implemented\n"); + return B_BAD_VALUE; + + case MS_GET_ACCEL: + TRACE("ps2: ioctl MS_GET_ACCEL (get mouse acceleration) not implemented\n"); + return B_BAD_VALUE; + + case MS_SET_ACCEL: + TRACE("ps2: ioctl MS_SET_ACCEL (set mouse acceleration) not implemented\n"); + return B_BAD_VALUE; + + case MS_SET_CLICKSPEED: + TRACE("ps2: ioctl MS_SETCLICK (set click speed)\n"); + return user_memcpy(&cookie->click_speed, buffer, sizeof(bigtime_t)); + + default: + TRACE("ps2: ioctl unknown mouse opcode: %ld\n", op); + return B_BAD_VALUE; + } +} + + +device_hooks gStandartMouseDeviceHooks = { + standart_mouse_open, + standart_mouse_close, + standart_mouse_freecookie, + standart_mouse_ioctl, + standart_mouse_read, + standart_mouse_write, +}; diff --git a/src/add-ons/kernel/bus_managers/ps2/ps2_standart_mouse.h b/src/add-ons/kernel/bus_managers/ps2/ps2_standart_mouse.h new file mode 100644 index 0000000000..630fbb50c9 --- /dev/null +++ b/src/add-ons/kernel/bus_managers/ps2/ps2_standart_mouse.h @@ -0,0 +1,59 @@ +/* + * Copyright 2001-2008 Haiku, Inc. + * Distributed under the terms of the MIT License. + * + * PS/2 mouse device driver + * + * Authors (in chronological order): + * Elad Lahav (elad@eldarshany.com) + * Stefano Ceccherini (burton666@libero.it) + * Axel Dörfler, axeld@pinc-software.de + * Marcus Overhagen + * Clemens Zeidler + */ + +#ifndef __PS2_STANDART_standart_mouse_H +#define __PS2_STANDART_standart_mouse_H + +#include + +#include "packet_buffer.h" + +#define standart_mouse_HISTORY_SIZE 256 + // we record that many mouse packets before we start to drop them + +#define F_pointing_dev_TYPE_STANDARD 0x1 +#define F_pointing_dev_TYPE_INTELLIMOUSE 0x2 + +typedef struct +{ + ps2_dev * dev; + + sem_id standart_mouse_sem; + packet_buffer * standart_mouse_buffer; + bigtime_t click_last_time; + bigtime_t click_speed; + int click_count; + int buttons_state; + int flags; + size_t packet_index; + uint8 packet_buffer[PS2_MAX_PACKET_SIZE]; + +} standart_mouse_cookie; + + +status_t probe_standart_mouse(ps2_dev *dev); + +status_t standart_mouse_open(const char *name, uint32 flags, void **_cookie); +status_t standart_mouse_close(void *_cookie); +status_t standart_mouse_freecookie(void *_cookie); +status_t standart_mouse_ioctl(void *_cookie, uint32 op, void *buffer, size_t length); + +int32 standart_mouse_handle_int(ps2_dev *dev); +void standart_mouse_disconnect(ps2_dev *dev); + +device_hooks gStandartMouseDeviceHooks; + + +#endif + diff --git a/src/add-ons/kernel/bus_managers/ps2/ps2_synaptics.c b/src/add-ons/kernel/bus_managers/ps2/ps2_synaptics.c new file mode 100644 index 0000000000..92f370f6c2 --- /dev/null +++ b/src/add-ons/kernel/bus_managers/ps2/ps2_synaptics.c @@ -0,0 +1,773 @@ +/* + * Copyright 2008 Haiku, Inc. + * Distributed under the terms of the MIT License. + * + * PS/2 synaptics touchpad + * + * Authors (in chronological order): + * Clemens Zeidler (haiku@Clemens-Zeidler.de) + */ + +#include +#include +#include + +#include "ps2_service.h" +#include "ps2_synaptics.h" +#include "kb_mouse_driver.h" + +const char* kSynapticsPath[4] = {"input/touchpad/ps2/synaptics_0", + "input/touchpad/ps2/synaptics_1", + "input/touchpad/ps2/synaptics_2", + "input/touchpad/ps2/synaptics_3"}; + +static touchpad_info g_touchpad_info; +ps2_dev *g_passthrough_dev = &ps2_device[PS2_DEVICE_SYN_PASSTHROUGH]; + + +void +default_settings(touchpad_settings *set) +{ + memcpy(set, &kDefaultTouchpadSettings, sizeof(touchpad_settings)); +} + + +status_t +synaptics_pt_set_packagesize(ps2_dev *dev, uint8 size) +{ + synaptics_cookie* syn_cookie = dev->parent_dev->cookie; + + status_t status = ps2_dev_command(dev->parent_dev, PS2_CMD_DISABLE, NULL, 0, NULL, 0); + if (status < B_OK) { + INFO("SYNAPTICS: cannot disable touchpad %s\n", dev->parent_dev->name); + return B_ERROR; + } + + syn_cookie->packet_index = 0; + + if(size == 4){ + syn_cookie->mode|= SYN_FOUR_BYTE_CHILD; + } + else{ + syn_cookie->mode&= ~SYN_FOUR_BYTE_CHILD; + } + set_touchpad_mode(dev->parent_dev, syn_cookie->mode); + + status = ps2_dev_command(dev->parent_dev, PS2_CMD_ENABLE, NULL, 0, NULL, 0); + if (status < B_OK) { + INFO("SYNAPTICS: cannot enable touchpad %s\n", dev->parent_dev->name); + return B_ERROR; + } + return status; +} + + +status_t +send_touchpad_arg(ps2_dev *dev, uint8 arg){ + return send_touchpad_arg_timeout(dev, arg, 4000000); +} + + +status_t +send_touchpad_arg_timeout(ps2_dev *dev, uint8 arg, bigtime_t timeout){ + int8 i; + uint8 val[8]; + for(i = 0; i < 4; i++){ + val[2*i] = (arg >> (6-2*i)) & 3; + val[2*i + 1] = 0xE8; + } + return ps2_dev_command_timeout(dev, 0xE8, val, 7, NULL, 0, timeout); +} + + +status_t +set_touchpad_mode(ps2_dev *dev, uint8 mode) +{ + uint8 sample_rate = SYN_CHANGE_MODE; + send_touchpad_arg(dev, mode); + return ps2_dev_command(dev, PS2_CMD_SET_SAMPLE_RATE, &sample_rate, 1, NULL, 0); +} + + +status_t +passthrough_command(ps2_dev *dev, uint8 cmd, const uint8 *out, int out_count, uint8 *in, int in_count, bigtime_t timeout) +{ + status_t status; + uint8 pt_cmd = SYN_PASSTHROUGH_CMD; + uint8 val; + uint32 pt_in_count = (in_count + 1) * 6; + uint8 pt_in[pt_in_count]; + int8 i; + + TRACE("SYNAPTICS: passthrough command 0x%x\n", cmd); + + status = ps2_dev_command(dev->parent_dev, PS2_CMD_DISABLE, NULL, 0, NULL, 0); + if(status != B_OK){ + return status; + } + + for (i = -1; i < out_count; i++) { + if (i == -1) { + val = cmd; + } else { + val = out[i]; + } + status = send_touchpad_arg_timeout(dev->parent_dev, val, timeout); + if(status != B_OK){ + return status; + } + if(i != out_count -1){ + status = ps2_dev_command_timeout(dev->parent_dev, PS2_CMD_SET_SAMPLE_RATE, + &pt_cmd, 1, NULL, 0, timeout); + if(status != B_OK){ + return status; + } + } + } + status = ps2_dev_command_timeout(dev->parent_dev, PS2_CMD_SET_SAMPLE_RATE, + &pt_cmd, 1, pt_in, pt_in_count, timeout); + if(status != B_OK){ + return status; + } + + for(i = 0; i < in_count + 1; i++){ + uint8 *inPointer = &(pt_in[i * 6]); + if(!IS_SYN_PT_PACKAGE(inPointer)){ + TRACE("SYNAPTICS: not a pass throught package\n"); + return B_OK; + } + if(i == 0){ + continue; + } + in[i - 1] = pt_in[i * 6 + 1]; + } + + status = ps2_dev_command(dev->parent_dev, PS2_CMD_ENABLE, NULL, 0, NULL, 0); + if(status != B_OK){ + return status; + } + + return B_OK; +} + + +bool +edge_motion(mouse_movement *movement, touch_event *event, bool validStart) +{ + int32 xdelta = 0; + int32 ydelta = 0; + + if(event->xPosition < SYN_AREA_START_X + SYN_EDGE_MOTION_WIDTH){ + xdelta = -SYN_EDGE_MOTION_SPEED; + } + else if(event->xPosition > SYN_AREA_END_X - SYN_EDGE_MOTION_WIDTH){ + xdelta = SYN_EDGE_MOTION_SPEED; + } + + if(event->yPosition < SYN_AREA_START_Y + SYN_EDGE_MOTION_WIDTH){ + ydelta = -SYN_EDGE_MOTION_SPEED; + } + else if(event->yPosition > SYN_AREA_END_Y - SYN_EDGE_MOTION_WIDTH){ + ydelta = SYN_EDGE_MOTION_SPEED; + } + + if(xdelta && validStart){ + movement->xdelta = xdelta; + } + if(ydelta && validStart){ + movement->ydelta = ydelta; + } + + if((xdelta || ydelta) && !validStart){ + return false; + } + return true; +} + + +status_t +touchevent_to_movement(synaptics_cookie* cookie, touch_event *event, mouse_movement *movement) +{ + bool isSideScrollingV = false; + bool isSideScrollingH = false; + bool isInTouch = false; + bool isStartOfMovement = false; + float sens = 0; + bigtime_t currentTime = system_time(); + touchpad_settings * settings = &(cookie->settings); + + if(!movement){ + return B_ERROR; + } + + movement->xdelta = 0; + movement->ydelta = 0; + movement->buttons = 0; + movement->wheel_ydelta = 0; + movement->wheel_xdelta = 0; + movement->modifiers = 0; + movement->clicks = 0; + movement->timestamp = currentTime; + + if((currentTime - cookie->tap_time) > SYN_TAP_TIMEOUT){ + TRACE("SYNAPTICS: tap gesture timed out\n"); + cookie->tap_started = false; + if(!cookie->double_click || (currentTime - cookie->tap_time) > 2 * SYN_TAP_TIMEOUT) + cookie->tap_clicks = 0; + } + + if(event->buttons != 0){ + cookie->tap_clicks = 0; + cookie->tapdrag_started = false; + cookie->tap_started = false; + cookie->valid_edge_motion = false; + } + + if(event->zPressure >= MIN_PRESSURE && event->zPressure < MAX_PRESSURE + && ((event->wValue >=4 && event->wValue <=7) + || event->wValue == 0 || event->wValue == 1) + && (event->xPosition != 0 || event->yPosition != 0)) + { + isInTouch = true; + } + + if(isInTouch) + { + if((SYN_AREA_END_X - SYN_AREA_WIDTH_X * settings->scroll_rightrange + < event->xPosition && !cookie->movement_started + && settings->scroll_rightrange > 0.000001) + || settings->scroll_rightrange > 0.999999) + { + isSideScrollingV = true; + } + if((SYN_AREA_START_Y + SYN_AREA_WIDTH_Y * settings->scroll_bottomrange + > event->yPosition && !cookie->movement_started + && settings->scroll_bottomrange > 0.000001) + || settings->scroll_bottomrange > 0.999999) + { + isSideScrollingH = true; + } + if(isSideScrollingV || isSideScrollingH + ||(event->wValue == 0 && settings->scroll_twofinger) + ||(event->wValue == 1 && settings->scroll_multifinger)) + { + goto scrooling; + } + else{ + cookie->scrolling_started = false; + } + goto movement; + } + else{ + goto notouch; + } + +movement: + TRACE("SYNAPTICS: movement event\n"); + if(!cookie->movement_started){ + isStartOfMovement = true; + cookie->movement_started = true; + start_new_movment(&(cookie->movement_maker)); + } + + get_movement(&(cookie->movement_maker), event->xPosition, event->yPosition); + + movement->xdelta = cookie->movement_maker.xDelta; + movement->ydelta = cookie->movement_maker.yDelta; + + // tap gesture + cookie->tap_delta_x+= cookie->movement_maker.xDelta; + cookie->tap_delta_y+= cookie->movement_maker.yDelta; + + if(cookie->tapdrag_started){ + movement->buttons = 0x01; // left button + movement->clicks = 0; + + cookie->valid_edge_motion = edge_motion(movement, event, cookie->valid_edge_motion); + TRACE("SYNAPTICS: tap drag\n"); + } + else{ + TRACE("SYNAPTICS: movement set buttons\n"); + movement->buttons = event->buttons; + } + + // use only a fraction of pressure range, the max pressure seems to be to high + sens = 20 * (event->zPressure - MIN_PRESSURE) / (MAX_PRESSURE - MIN_PRESSURE - 100); + if(!cookie->tap_started + && isStartOfMovement + && settings->tapgesture_sensibility > (20 - sens)) + { + TRACE("SYNAPTICS: tap started\n"); + cookie->tap_started = true; + cookie->tap_time = system_time(); + cookie->tap_delta_x = 0; + cookie->tap_delta_y = 0; + } + + return B_OK; + +scrooling: + TRACE("SYNAPTICS: scroll event\n"); + cookie->tap_started = false; + cookie->tap_clicks = 0; + cookie->tapdrag_started = false; + cookie->valid_edge_motion = false; + if(!cookie->scrolling_started){ + cookie->scrolling_started = true; + start_new_movment(&(cookie->movement_maker)); + } + get_scrolling(&(cookie->movement_maker), event->xPosition, event->yPosition); + movement->wheel_ydelta = cookie->movement_maker.yDelta; + movement->wheel_xdelta = cookie->movement_maker.xDelta; + + if(isSideScrollingV && !isSideScrollingH){ + movement->wheel_xdelta = 0; + } + else if(isSideScrollingH && !isSideScrollingV){ + movement->wheel_ydelta = 0; + } + return B_OK; + +notouch: + TRACE("SYNAPTICS: no touch event\n"); + cookie->scrolling_started = false; + cookie->movement_started = false; + movement->buttons = event->buttons; + if(event->buttons) + movement->clicks = 1; + + if(cookie->tapdrag_started + && (currentTime - cookie->tap_time) < SYN_TAP_TIMEOUT) + { + movement->buttons = 0x01; + movement->clicks = 0; + } + + // if the movement stopped switch off the dap trag when timeout is expired + if((currentTime - cookie->tap_time) > SYN_TAP_TIMEOUT){ + cookie->tapdrag_started = false; + cookie->valid_edge_motion = false; + TRACE("SYNAPTICS: tap drag gesture timed out\n"); + } + + if(abs(cookie->tap_delta_x) > 15 || abs(cookie->tap_delta_y) > 15){ + cookie->tap_started = false; + cookie->tap_clicks = 0; + } + + if(cookie->tap_started || cookie->double_click) + { + TRACE("SYNAPTICS: tap gesture\n"); + cookie->tap_clicks++; + + if(cookie->tap_clicks > 1){ + TRACE("SYNAPTICS: empty click\n"); + movement->buttons = 0x00; + movement->clicks = 0; + cookie->tap_clicks = 0; + cookie->double_click = true; + } + else{ + movement->buttons = 0x01; + movement->clicks = 1; + cookie->tap_started = false; + cookie->tapdrag_started = true; + cookie->double_click = false; + } + } + + return B_OK; +} + + +status_t +get_synaptics_movment(synaptics_cookie* cookie, mouse_movement *movement) +{ + status_t status; + touch_event event; + uint8 event_buffer[PS2_MAX_PACKET_SIZE]; + uint8 wValue0, wValue1, wValue2, wValue3, wValue; + uint32 val32; + uint32 xTwelfBit, yTwelfBit; + + status = acquire_sem_etc(cookie->synaptics_sem, 1, B_CAN_INTERRUPT, 0); + if (status < B_OK) + return status; + + if (!cookie->dev->active) { + TRACE("SYNAPTICS: read_event: Error device no longer active\n"); + return B_ERROR; + } + + if (packet_buffer_read(cookie->synaptics_ring_buffer, event_buffer, cookie->dev->packet_size) != cookie->dev->packet_size) { + TRACE("SYNAPTICS: error copying buffer\n"); + return B_ERROR; + } + + event.buttons = event_buffer[0] & 3; + event.zPressure = event_buffer[2]; + + if(g_touchpad_info.capExtended){ + wValue0 = event_buffer[3] >> 2 & 1; + wValue1 = event_buffer[0] >> 2 & 1; + wValue2 = event_buffer[0] >> 4 & 1; + wValue3 = event_buffer[0] >> 5 & 1; + + wValue = wValue0; + wValue = wValue | (wValue1 << 1); + wValue = wValue | (wValue2 << 2); + wValue = wValue | (wValue3 << 3); + + event.wValue = wValue; + event.gesture = false; + } + else{ + bool finger = event_buffer[0] >> 5 & 1; + if(finger){ + // finger with normal width + event.wValue = 4; + } + event.gesture = event_buffer[0] >> 2 & 1; + } + + event.xPosition = event_buffer[4]; + event.yPosition = event_buffer[5]; + + val32 = event_buffer[1] & 0x0F; + event.xPosition+= val32 << 8; + val32 = event_buffer[1] >> 4 & 0x0F; + event.yPosition+= val32 << 8; + + xTwelfBit = event_buffer[3] >> 4 & 1; + event.xPosition+= xTwelfBit << 12; + yTwelfBit = event_buffer[3] >> 5 & 1; + event.yPosition+= yTwelfBit << 12; + + status = touchevent_to_movement(cookie, &event, movement); + + return B_OK; +} + + +void +query_capability(ps2_dev *dev) +{ + uint8 val[3]; + send_touchpad_arg(dev, 0x02); + ps2_dev_command(dev, 0xE9, NULL, 0, val, 3); + + g_touchpad_info.capExtended = val[0] >> 7 & 1; + TRACE("SYNAPTICS: extended mode %2x\n", val[0] >> 7 & 1); + TRACE("SYNAPTICS: sleep mode %2x\n", val[2] >> 4 & 1); + g_touchpad_info.capSleep = val[2] >> 4 & 1; + TRACE("SYNAPTICS: four buttons %2x\n", val[2] >> 3 & 1); + g_touchpad_info.capFourButtons = val[2] >> 3 & 1; + TRACE("SYNAPTICS: multi finger %2x\n", val[2] >> 1 & 1); + g_touchpad_info.capMultiFinger = val[2] >> 1 & 1; + TRACE("SYNAPTICS: palm detection %2x\n", val[2] & 1); + g_touchpad_info.capPalmDetection = val[2] & 1; + TRACE("SYNAPTICS: pass through %2x\n", val[2] >> 7 & 1); + g_touchpad_info.capPassThrough = val[2] >> 7 & 1; +} + + +status_t +probe_synaptics(ps2_dev *dev) +{ + uint8 val[3]; + uint8 deviceId; + TRACE("SYNAPTICS: probe\n"); + + send_touchpad_arg(dev, 0x00); + ps2_dev_command(dev, 0xE9, NULL, 0, val, 3); + + g_touchpad_info.minorVersion = val[0]; + deviceId = val[1]; + if(deviceId != SYN_TOUCHPAD){ + TRACE("SYNAPTICS: not found\n"); + return B_ERROR; + } + + TRACE("SYNAPTICS: Touchpad found id:l %2x\n", deviceId); + g_touchpad_info.majorVersion = val[2] & 0x0F; + TRACE("SYNAPTICS: version %d.%d\n", g_touchpad_info.majorVersion, g_touchpad_info.minorVersion); + // version >= 4.0? + if(g_touchpad_info.minorVersion <= 2 && g_touchpad_info.majorVersion <= 3){ + TRACE("SYNAPTICS: too old touchpad not supported\n"); + return B_ERROR; + } + dev->name = kSynapticsPath[dev->idx]; + return B_OK; +} + + +status_t +synaptics_open(const char *name, uint32 flags, void **_cookie) +{ + status_t status; + synaptics_cookie* cookie; + ps2_dev *dev; + int i; + + for (dev = NULL, i = 0; i < PS2_DEVICE_COUNT; i++) { + if (0 == strcmp(ps2_device[i].name, name)) { + dev = &ps2_device[i]; + break; + } + } + + if (dev == NULL) { + TRACE("ps2: dev = NULL\n"); + return B_ERROR; + } + + if (atomic_or(&dev->flags, PS2_FLAG_OPEN) & PS2_FLAG_OPEN) + return B_BUSY; + + cookie = (synaptics_cookie*)malloc(sizeof(synaptics_cookie)); + if (cookie == NULL) + goto err1; + + *_cookie = cookie; + memset(cookie, 0, sizeof(synaptics_cookie)); + + cookie->dev = dev; + dev->cookie = cookie; + dev->disconnect = &synaptics_disconnect; + dev->handle_int = &synaptics_handle_int; + + default_settings(&(cookie->settings)); + + cookie->movement_maker.speed = 1; + cookie->movement_maker.scrolling_xStep = cookie->settings.scroll_xstepsize; + cookie->movement_maker.scrolling_yStep = cookie->settings.scroll_ystepsize; + cookie->movement_maker.scroll_acceleration = cookie->settings.scroll_acceleration; + cookie->movement_started = false; + cookie->scrolling_started = false; + cookie->tap_started = false; + cookie->double_click = false; + cookie->valid_edge_motion = false; + + dev->packet_size = PS2_PACKET_SYNAPTICS; + + cookie->synaptics_ring_buffer = create_packet_buffer(synaptics_HISTORY_SIZE * dev->packet_size); + if (cookie->synaptics_ring_buffer == NULL) { + TRACE("ps2: can't allocate mouse actions buffer\n"); + goto err2; + } + + // create the mouse semaphore, used for synchronization between + // the interrupt handler and the read operation + cookie->synaptics_sem = create_sem(0, "ps2_synaptics_sem"); + if (cookie->synaptics_sem < 0) { + TRACE("SYNAPTICS: failed creating semaphore!\n"); + goto err3; + } + query_capability(dev); + + // create pass through dev + if(g_touchpad_info.capPassThrough){ + TRACE("SYNAPTICS: pass through detected\n"); + g_passthrough_dev->parent_dev = dev; + g_passthrough_dev->idx = dev->idx; + ps2_service_notify_device_added(g_passthrough_dev); + } + + // Set Mode + if(g_touchpad_info.capExtended){ + cookie->mode = SYN_ABSOLUTE_W_MODE; + } + else{ + cookie->mode = SYN_ABSOLUTE_MODE; + } + status = set_touchpad_mode(dev, cookie->mode); + if (status < B_OK) { + INFO("SYNAPTICS: cannot set mode %s\n", name); + goto err4; + } + + status = ps2_dev_command(dev, PS2_CMD_ENABLE, NULL, 0, NULL, 0); + if (status < B_OK) { + INFO("SYNAPTICS: cannot enable touchpad %s\n", name); + goto err4; + } + + atomic_or(&dev->flags, PS2_FLAG_ENABLED); + + TRACE("SYNAPTICS: open %s success\n", name); + return B_OK; + +err4: + delete_sem(cookie->synaptics_sem); +err3: + delete_packet_buffer(cookie->synaptics_ring_buffer); +err2: + free(cookie); +err1: + atomic_and(&dev->flags, ~PS2_FLAG_OPEN); + + TRACE("ps2: standart_mouse_open %s failed\n", name); + return B_ERROR; +} + + +status_t +synaptics_close(void *_cookie) +{ + synaptics_cookie *cookie = _cookie; + + ps2_dev_command_timeout(cookie->dev, PS2_CMD_DISABLE, NULL, 0, NULL, 0, 150000); + + delete_packet_buffer(cookie->synaptics_ring_buffer); + delete_sem(cookie->synaptics_sem); + + atomic_and(&cookie->dev->flags, ~PS2_FLAG_OPEN); + atomic_and(&cookie->dev->flags, ~PS2_FLAG_ENABLED); + + if(g_touchpad_info.capPassThrough){ + ps2_service_notify_device_removed(g_passthrough_dev); + } + + TRACE("SYNAPTICS: close %s done\n", cookie->dev->name); + return B_OK; +} + + +status_t +synaptics_freecookie(void *_cookie) +{ + free(_cookie); + return B_OK; +} + + +static status_t +synaptics_read(void *cookie, off_t pos, void *buffer, size_t *_length) +{ + *_length = 0; + return B_NOT_ALLOWED; +} + + +static status_t +synaptics_write(void *cookie, off_t pos, const void *buffer, size_t *_length) +{ + *_length = 0; + return B_NOT_ALLOWED; +} + + +status_t +synaptics_ioctl(void *_cookie, uint32 op, void *buffer, size_t length) +{ + synaptics_cookie *cookie = _cookie; + mouse_movement movement; + status_t status; + + switch (op) { + case MS_READ: + TRACE("SYNAPTICS: MS_READ get event\n"); + if((status = get_synaptics_movment(cookie, &movement)) != B_OK) + return status; + return user_memcpy(buffer, &movement, sizeof(movement)); + case MS_IS_TOUCHPAD: + TRACE("SYNAPTICS: MS_IS_TOUCHPAD\n"); + return B_OK; + case MS_SET_TOUCHPAD_SETTINGS: + TRACE("SYNAPTICS: MS_SET_TOUCHPAD_SETTINGS"); + user_memcpy(&(cookie->settings), buffer, sizeof(touchpad_settings)); + cookie->movement_maker.scrolling_xStep = cookie->settings.scroll_xstepsize; + cookie->movement_maker.scrolling_yStep = cookie->settings.scroll_ystepsize; + cookie->movement_maker.scroll_acceleration = cookie->settings.scroll_acceleration; + return B_OK; + default: + TRACE("SYNAPTICS: unknown opcode: %ld\n", op); + return B_BAD_VALUE; + } +} + + +int32 +synaptics_handle_int(ps2_dev *dev) +{ + synaptics_cookie *cookie = dev->cookie; + uint8 val; + + val = cookie->dev->history[0].data; + + if ((cookie->packet_index == 0 || cookie->packet_index == 3) && val & 8) { + INFO("SYNAPTICS: bad mouse data, trying resync\n"); + cookie->packet_index = 0; + goto unhandled; + } + if(cookie->packet_index == 0 && val >> 6 != 0x02){ + TRACE("SYNAPTICS: first package begins not with bit 1, 0\n"); + goto unhandled; + } + if(cookie->packet_index == 3 && val >> 6 != 0x03){ + TRACE("SYNAPTICS: third package begins not with bit 1, 1\n"); + cookie->packet_index = 0; + goto unhandled; + } + cookie->packet_buffer[cookie->packet_index] = val; + + cookie->packet_index++; + if(cookie->packet_index >= 6){ + cookie->packet_index = 0; + + // check if package is a pass through package if true pass it + // too the pass through interrupt handle + if(g_passthrough_dev->active + && g_passthrough_dev->handle_int != NULL + && IS_SYN_PT_PACKAGE(cookie->packet_buffer)) + { + status_t status; + + g_passthrough_dev->history[0].data = cookie->packet_buffer[1]; + g_passthrough_dev->handle_int(g_passthrough_dev); + g_passthrough_dev->history[0].data = cookie->packet_buffer[4]; + g_passthrough_dev->handle_int(g_passthrough_dev); + g_passthrough_dev->history[0].data = cookie->packet_buffer[5]; + status = g_passthrough_dev->handle_int(g_passthrough_dev); + + if(cookie->dev->packet_size == 4){ + g_passthrough_dev->history[0].data = cookie->packet_buffer[2]; + status = g_passthrough_dev->handle_int(g_passthrough_dev); + } + return status; + } + + if (packet_buffer_write(cookie->synaptics_ring_buffer, cookie->packet_buffer, cookie->dev->packet_size) != cookie->dev->packet_size) { + // buffer is full, drop new data + return B_HANDLED_INTERRUPT; + } + release_sem_etc(cookie->synaptics_sem, 1, B_DO_NOT_RESCHEDULE); + + return B_INVOKE_SCHEDULER; + } + + return B_HANDLED_INTERRUPT; +unhandled: + return B_UNHANDLED_INTERRUPT; +} + + +void +synaptics_disconnect(ps2_dev *dev) +{ + synaptics_cookie *cookie = dev->cookie; + // the mouse device might not be opened at this point + INFO("ps2: ps2_standart_mouse_disconnect %s\n", dev->name); + if (dev->flags & PS2_FLAG_OPEN) + release_sem(cookie->synaptics_sem); +} + + +device_hooks gSynapticsDeviceHooks = { + synaptics_open, + synaptics_close, + synaptics_freecookie, + synaptics_ioctl, + synaptics_read, + synaptics_write, +}; diff --git a/src/add-ons/kernel/bus_managers/ps2/ps2_synaptics.h b/src/add-ons/kernel/bus_managers/ps2/ps2_synaptics.h new file mode 100644 index 0000000000..6ac828f420 --- /dev/null +++ b/src/add-ons/kernel/bus_managers/ps2/ps2_synaptics.h @@ -0,0 +1,126 @@ +#ifndef SYNAPTICS_H +#define SYNAPTICS_H + +#include + +#include "kb_mouse_driver.h" +#include "movement_maker.h" +#include "packet_buffer.h" +#include "touchpad_settings.h" + + +#define SYN_TOUCHPAD 0x47 +// Synaptics modes +#define SYN_ABSOLUTE_MODE 0x80 +// Absolute plus w mode +#define SYN_ABSOLUTE_W_MODE 0x81 +#define SYN_FOUR_BYTE_CHILD (1 << 1) +// Low power sleep mode +#define SYN_SLEEP_MODE 0x0C +// Synaptics Passthrough port +#define SYN_CHANGE_MODE 0x14 +#define SYN_PASSTHROUGH_CMD 0x28 + + +// synaptics touchpad proportions +#define SYN_EDGE_MOTION_WIDTH 50 +#define SYN_EDGE_MOTION_SPEED 5 +#define SYN_AREA_OFFSET 40 // increase the touchpad size a little bit +#define SYN_AREA_START_X (1472 - SYN_AREA_OFFSET) +#define SYN_AREA_END_X (5472 + SYN_AREA_OFFSET) +#define SYN_AREA_WIDTH_X (SYN_AREA_END_X - SYN_AREA_START_X) +#define SYN_AREA_START_Y (1408 - SYN_AREA_OFFSET) +#define SYN_AREA_END_Y (4448 + SYN_AREA_OFFSET) +#define SYN_AREA_WIDTH_Y (SYN_AREA_END_Y - SYN_AREA_START_Y) + +#define SYN_TAP_TIMEOUT 200000 + +#define MIN_PRESSURE 30 +#define MAX_PRESSURE 200 + +#define synaptics_HISTORY_SIZE 256 + +// no touchpad / left / right button pressed +#define IS_SYN_PT_PACKAGE(val) ((val[0] & 0xFC) == 0x84 && (val[3] & 0xCC) == 0xc4) + + +typedef struct +{ + uint8 majorVersion; + uint8 minorVersion; + + bool capExtended; + bool capSleep; + bool capFourButtons; + bool capMultiFinger; + bool capPalmDetection; + bool capPassThrough; + +} touchpad_info; + + +typedef struct +{ + uint8 buttons; + uint32 xPosition; + uint32 yPosition; + uint8 zPressure; + // absolut mode + bool finger; + bool gesture; + // absolut w mode + uint8 wValue; +} touch_event; + + +typedef struct +{ + ps2_dev * dev; + + sem_id synaptics_sem; + packet_buffer * synaptics_ring_buffer; + size_t packet_index; + uint8 packet_buffer[PS2_PACKET_SYNAPTICS]; + uint8 mode; + + movement_maker movement_maker; + bool movement_started; + bool scrolling_started; + bool tap_started; + bigtime_t tap_time; + int32 tap_delta_x; + int32 tap_delta_y; + int32 tap_clicks; + bool tapdrag_started; + bool valid_edge_motion; + bool double_click; + + touchpad_settings settings; +} synaptics_cookie; + + +void default_settings(touchpad_settings *settings); + +status_t synaptics_pt_set_packagesize(ps2_dev *dev, uint8 size); +status_t send_touchpad_arg(ps2_dev *dev, uint8 arg); +status_t send_touchpad_arg_timeout(ps2_dev *dev, uint8 arg, bigtime_t timeout); +status_t set_touchpad_mode(ps2_dev *dev, uint8 mode); +status_t passthrough_command(ps2_dev *dev, uint8 cmd, const uint8 *out, int out_count, uint8 *in, int in_count, bigtime_t timeout); + +bool edge_motion(mouse_movement *movement, touch_event *event, bool validStart); +status_t touchevent_to_movement(synaptics_cookie* cookie, touch_event *event, mouse_movement *movement); +status_t get_synaptics_movment(synaptics_cookie* cookie, mouse_movement *movement); +void query_capability(ps2_dev *dev); +status_t probe_synaptics(ps2_dev *dev); + +status_t synaptics_open(const char *name, uint32 flags, void **_cookie); +status_t synaptics_close(void *_cookie); +status_t synaptics_freecookie(void *_cookie); +status_t synaptics_ioctl(void *_cookie, uint32 op, void *buffer, size_t length); + +int32 synaptics_handle_int(ps2_dev *dev); +void synaptics_disconnect(ps2_dev *dev); + +device_hooks gSynapticsDeviceHooks; + +#endif diff --git a/src/add-ons/kernel/bus_managers/ps2/ps2_trackpoint.c b/src/add-ons/kernel/bus_managers/ps2/ps2_trackpoint.c new file mode 100644 index 0000000000..a10e93d8b3 --- /dev/null +++ b/src/add-ons/kernel/bus_managers/ps2/ps2_trackpoint.c @@ -0,0 +1,30 @@ +#include +#include + +#include "kb_mouse_driver.h" +#include "ps2_trackpoint.h" + +const char* kTrackpointPath[4] = {"input/mouse/ps2/ibm_trackpoint_0", + "input/mouse/ps2/ibm_trackpoint_1", + "input/mouse/ps2/ibm_trackpoint_2", + "input/mouse/ps2/ibm_trackpoint_3"}; + + +status_t +probe_trackpoint(ps2_dev *dev) +{ + uint8 val[2]; + + TRACE("TRACKPOINT: probe\n"); + ps2_dev_command(dev, 0xE1, NULL, 0, val, 2); + + if(val[0] != 0x01){ + TRACE("TRACKPOINT: not found\n"); + return B_ERROR; + } + dev->name = kTrackpointPath[dev->idx]; + dev->packet_size = 3; + TRACE("TRACKPOINT: version 0x%x found\n", val[1]); + + return B_OK; +} diff --git a/src/add-ons/kernel/bus_managers/ps2/ps2_trackpoint.h b/src/add-ons/kernel/bus_managers/ps2/ps2_trackpoint.h new file mode 100644 index 0000000000..2ac7e5e099 --- /dev/null +++ b/src/add-ons/kernel/bus_managers/ps2/ps2_trackpoint.h @@ -0,0 +1,12 @@ +#ifndef SYNAPTICS_H +#define SYNAPTICS_H + +#include + +#include "ps2_dev.h" + + +status_t probe_trackpoint(ps2_dev *dev); + + +#endif diff --git a/src/preferences/Jamfile b/src/preferences/Jamfile index 550d509a83..62e5e31912 100644 --- a/src/preferences/Jamfile +++ b/src/preferences/Jamfile @@ -20,4 +20,5 @@ SubInclude HAIKU_TOP src preferences screen ; SubInclude HAIKU_TOP src preferences screensaver ; SubInclude HAIKU_TOP src preferences sounds ; SubInclude HAIKU_TOP src preferences time ; +SubInclude HAIKU_TOP src preferences touchpad ; SubInclude HAIKU_TOP src preferences virtualmemory ; diff --git a/src/preferences/touchpad/Jamfile b/src/preferences/touchpad/Jamfile new file mode 100644 index 0000000000..b801d58f0b --- /dev/null +++ b/src/preferences/touchpad/Jamfile @@ -0,0 +1,11 @@ +SubDir HAIKU_TOP src preferences touchpad ; + +UsePrivateHeaders input ; + +Preference Touchpad : + TouchpadPref.cpp + TouchpadPrefView.cpp + main.cpp + : be + : Touchpad.rdef + ; diff --git a/src/preferences/touchpad/Touchpad.rdef b/src/preferences/touchpad/Touchpad.rdef new file mode 100644 index 0000000000..715a20fb64 --- /dev/null +++ b/src/preferences/touchpad/Touchpad.rdef @@ -0,0 +1,304 @@ + +resource app_signature "application/x-vnd.Haiku-Touchpad"; + +resource app_flags B_SINGLE_LAUNCH; + +resource app_version { + major = 1, + middle = 0, + minor = 0, + + /* 0 = development 1 = alpha 2 = beta + 3 = gamma 4 = golden master 5 = final */ + variety = 2, + + internal = 0, + + short_info = "Touchpad", + long_info = "Touchpad ©2002-2008 Haiku" +}; + +#ifdef HAIKU_TARGET_PLATFORM_HAIKU + +resource vector_icon { + $"6E636966080301000002000202AC6DA33A810CBCBF0CAEA9C248C4E546BB2A00" + $"01000000FF010000FF020016023D2328BA287D3B40A23E5D334837CE48FA2500" + $"69FF01020116023E40000000000000003E400048000048000000FBFFC0020106" + $"02B832FBBACA8D3ACA8DB832FB48D3BB493902FFBEBEBE0001000005BE05FC01" + $"0100007D0604033E2C3C2436263E222E2E282E342E2802082C4CB5EDC39ABA27" + $"C5B7BFBFC883BD60C754C19AC9715052C4C9C842C722C5E9544EC6B5C656C90E" + $"C3FDC7B7C08BC992C179C558BF5C4038C21FBDBFBDE5BBA232BD5BBB83BC04B9" + $"2ABE5DB6FB42B7FDBF8AB5A4C1E30208475443544B54C6EB50C660C6ABC777C5" + $"9456C487C803C508C9DBC33056405842543E42334E3536312C3A3036283EB628" + $"C223B628C2232A4A344AB80EC27CBE0FC50F0604EE2E383838323638383B3635" + $"333B332F3304032F3049304930433A36BA1DBE14413141330606FE0B4659C487" + $"59C36B59C5605954C8E9C6D7C95AC91CC837CBD7C4FBCB67C614CC30C41DCAE7" + $"C289CBC8C2FAC983C1D75443080A070105000A0101001001178400040A000302" + $"01031001178422040A020101000A030102000A0001041001178100040A060104" + $"123FE3AA0000000000003FDFFC41DB9540107701178100040A04010300" +}; + +#else // HAIKU_TARGET_PLATFORM_HAIKU + +resource large_icon { + $"FFFFFFFFFFFF000000000000000000000EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFF00000E0F0F0F0F0F0F0F0E0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFF00000E0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FF000E0FFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FF000EFFFFFFFFFFFF00111717180000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FF00000E0FFFFFFF00111717181717180000FFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFF00000E0F00111817171817180A3F170000FFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFF0000111717181717180A3F171718170000FFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFF00111717181717180A3F171718171718170000FFFFFFFFFFFFFFFF" + $"FFFFFFFF00111717181717180A3F171718171718171817170000FFFFFFFFFFFF" + $"FFFFFF00111717181717180A3F17171817171817183F171718170000FFFFFFFF" + $"FFFF003F1717181717180A3F1717181717181718171C3F171718110A00FFFFFF" + $"FFFF003F3F171718170B3F171700001817171817183F171718110A0B00FFFFFF" + $"FFFF0011113F3F170B3F1717005B5B001817171817181717110B0B0000FFFFFF" + $"FFFF00111111113F0A18171700DA5B5B00171817171817110B0A000B000FFFFF" + $"FFFF000A0B1111110A3F3F002B2CDA5B001717181718110A0B000A0B000FFFFF" + $"FFFF0011110A0B110A1111002B2FEB001817181717110B0B000A0B000F0FFFFF" + $"FFFF00111111110A0B11002B2B2F2F0017181717110B0B000A0B000F0F0EFFFF" + $"FFFFFF00001111111100002B2F2F003F3F1717110B0B000A0B000F0F0EFFFFFF" + $"FFFFFFFFFF00001111002B2CEB2F0011113F110A0B000A0B000F0F0FFFFFFFFF" + $"FFFFFF000000FF0000002B2F2F000A1111110B0B000A0B000F0F0EFFFFFFFFFF" + $"FFFF005B5B5B00FF002B2CEB2F00110A0B110A000B0B000F0E0FFFFFFFFFFFFF" + $"FF005B5B5BDA00FF002B2F2F00111111110A000B0B000E0F0FFFFFFFFFFFFFFF" + $"FF002B2CDA5B5B002B2CEB2F0000001111110B0A000F0F0FFFFFFFFFFFFFFFFF" + $"FFFF002B2CDA5B2B2CEB2F00FFFFFF0000110A000F0F0FFFFFFFFFFFFFFFFFFF" + $"FFFF002B2BDA5B2C2B2FEB00FFFFFFFFFF00000E0F0FFFFFFFFFFFFFFFFFFFFF" + $"FFFFFF002B2C2B2B2F2F00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFF002B2C2B2B2F2F00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFF002B2CEB2F00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFF002B2CEB2F00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFF002B2F000E0F0F0F0F0F0F0F0F0FFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFFFF0000000E0F0F0F0F0F0F0F0F0F0FFFFFFFFFFFFFFFFFFFFFFFFFFF" +}; + +resource mini_icon { + $"FF00000000000E0F0FFFFFFFFFFFFFFF" + $"000F0F0F000000FFFFFFFFFFFFFFFFFF" + $"000FFF001717180000FFFFFFFFFFFFFF" + $"FF0000171718170B3F0000FFFFFFFFFF" + $"FF00171718170B3F1717180000FFFFFF" + $"003F3F17170B3F17171817171800FFFF" + $"000A113F0A3F001717181717110B00FF" + $"00110A0B11005B00171817110B0A00FF" + $"000011110A002F003F17110B0A000FFF" + $"FFFF0000002F000A11110B0A000FFFFF" + $"FF00FFFF002F00110A0B0A000FFFFFFF" + $"002B00002F0000000A0B000FFFFFFFFF" + $"002B5B2CEB00FFFF00000EFFFFFFFFFF" + $"FF002B2F00FFFFFFFFFFFFFFFFFFFFFF" + $"FF002B2F00FFFFFFFFFFFFFFFFFFFFFF" + $"FFFF00000E0F0F0F0FFFFFFFFFFFFFFF" +}; + +#endif // HAIKU_TARGET_PLATFORM_HAIKU + +resource(601, "double_click_bmap") #'bits' array { + $"424D06070000000000003A000000280000000E0000001E000000010018000000" + $"0000CC060000130B0000130B00000000000000000000FFFFFFFFD8D8D8000000" + $"0000000000000000000000000000000000000000000000000000000000000000" + $"00D8D8D800000000008080808080808080808080808080808080808080808080" + $"808080808080808080808080800000000000000000B8B8B8FFFFFFB8B8B8B8B8" + $"B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B880808000000000000000" + $"00B8B8B8FFFFFFB8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8" + $"B8B88080800000000000000000B8B8B8FFFFFFB8B8B8B8B8B8B8B8B8B8B8B8B8" + $"B8B8B8B8B8B8B8B8B8B8B8B8B8B88080800000000000000000B8B8B8FFFFFFB8" + $"B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8808080000000" + $"0000000000B8B8B8FFFFFFB8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8" + $"B8B8B8B8B8B87F7F7F0000000000000000B8B8B8FFFFFFB8B8B8B8B8B8B8B8B8" + $"B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B88080800000000000000000B8B8B8" + $"FFFFFFB8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B88080" + $"800000000000000000B8B8B8FFFFFFB8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8" + $"B8B8B8B8B8B8B8B8B8B88080800000000000000000B8B8B8FFFFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80808000000000000000" + $"0080808080808080808080808080808080808080808080808080808080808080" + $"80808080800000000000000000B8B8B8FFFFFFB8B8B8B8B8B8C0C0C0808080FF" + $"FFFFC0C0C0B8B8B8B8B8B8B8B8B88080800000000000000000B8B8B8FFFFFFB8" + $"B8B8B8B8B8C0C0C0808080FFFFFFC0C0C0B8B8B8B8B8B8B8B8B8808080000000" + $"0000000000B8B8B8FFFFFFB8B8B8B8B8B8C0C0C0808080FFFFFFC0C0C0B8B8B8" + $"B8B8B8B8B8B88080800000000000000000B8B8B8FFFFFFFFFFFFFFFFFFFFFFFF" + $"808080FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8080800000000000000000B8B8B8" + $"B8B8B8B8B8B8B8B8B8B8B8B8808080B8B8B8B8B8B8B8B8B8B8B8B8B8B8B88080" + $"800000000000D8D8D80000000000000000000000000000005858580000000000" + $"00000000000000000000000000D8D8D80000D8D8D8D8D8D8D8D8D8D8D8D8D8D8" + $"D8000000000000000000D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D80000D8D8" + $"D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8000000D8D8D8D8D8D8D8D8D8D8D8D8D8" + $"D8D8D8D8D8D8D8D80000D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8000000D8" + $"D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D80000D8D8D8D8D8D8D8D8D8D8" + $"D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8" + $"0000D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8" + $"D8D8D8D8D8D8D8D8D8D8D8D80000D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8" + $"989898D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D80000D8D8D8D8D8D8" + $"D8D8D8D8D8D8D8D8D8989898989898989898D8D8D8D8D8D8D8D8D8D8D8D8D8D8" + $"D8D8D8D80000D8D8D8D8D8D8D8D8D8D8D8D89898989898989898989898989898" + $"98D8D8D8D8D8D8D8D8D8D8D8D8D8D8D80000D8D8D8D8D8D8D8D8D8D8D8D8D8D8" + $"D8D8D8D8989898D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D80000D8D8" + $"D8D8D8D8D8D8D8D8D8D8D8D8D8989898989898989898D8D8D8D8D8D8D8D8D8D8" + $"D8D8D8D8D8D8D8D80000D8D8D8D8D8D8D8D8D8D8D8D898989898989898989898" + $"9898989898D8D8D8D8D8D8D8D8D8D8D8D8D8D8D80000D8D8D8D8D8D8D8D8D898" + $"9898989898989898989898989898989898989898D8D8D8D8D8D8D8D8D8D8D8D8" + $"0000000000000000000000000000000000000000000000000000000000000000" + $"0000000000000000000000000000000000000000000000000000000000000000" + $"0000000000000000000000000000000000000000000000000000000000000000" + $"0000000000000000000000000000000000000000000000000000000000000000" + $"0000000000000000000000000000000000000000000000000000000000000000" + $"0000000000000000000000000000000000000000000000000000000000000000" + $"0000000000000000000000000000000000000000000000000000000000000000" + $"0000000000000000000000000000000000000000000000000000000000000000" + $"0000000000000000000000000000000000000000000000000000000000000000" + $"0000000000000000000000000000000000000000000000000000000000000000" + $"0000000000000000000000000000000000000000000000000000000000000000" + $"0000000000000000000000000000000000000000000000000000000000000000" + $"0000000000000000000000000000000000000000000000000000000000000000" + $"000000000000" +}; + +resource(602, "speed_bmap") #'bits' array { + $"424DE8080000000000003A000000280000001900000016000000010018000000" + $"0000AE080000130B0000130B00000000000000000000FFFFFFFFD8D8D8D8D8D8" + $"D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8" + $"D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8" + $"D8D8D8D8D800D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8" + $"D8D8D8D8D8D8D8D8D8D800000000000000000000000000000000000000000000" + $"0000000000000000000000000000D8D8D800D8D8D8D8D8D8D8D8D8D8D8D8D8D8" + $"D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D800000080808080808080808080" + $"808080808080808080808080808080808080808080808080808000000000D8D8" + $"D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D800" + $"0000B8B8B8FFFFFFB8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8" + $"B8B8B880808000000000D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8" + $"D8D8D8D8D8D8D8D8D8D8D8000000B8B8B8FFFFFFB8B8B8B8B8B8B8B8B8B8B8B8" + $"B8B8B8B8B8B8B8B8B8B8B8B8B8B8B880808000000000D8D8D8D8D8D8D8D8D8D8" + $"D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8000000B8B8B8FFFFFF" + $"B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B88080800000" + $"0000D8D8D8D8D8D8D8D8D8989898D8D8D8989898989898989898989898D8D8D8" + $"D8D8D8000000B8B8B8FFFFFFB8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8" + $"B8B8B8B8B8B8B880808000000000D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8" + $"D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8000000B8B8B8FFFFFFB8B8B8B8B8B8B8B8" + $"B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B880808000000000D8D8D8D8D8D8" + $"D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8000000B8B8" + $"B8FFFFFFB8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B880" + $"808000000000989898D8D8D89898989898989898989898989898989898989898" + $"98D8D8D8D8D8D8000000B8B8B8FFFFFFB8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8" + $"B8B8B8B8B8B8B8B8B8B8B87F7F7F00000000D8D8D8D8D8D8D8D8D8D8D8D8D8D8" + $"D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8000000B8B8B8FFFFFFB8B8B8B8" + $"B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B880808000000000D8D8" + $"D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D800" + $"0000B8B8B8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFF80808000000000D8D8D8D8D8D8D8D8D8989898D8D8D898989898989898" + $"9898989898D8D8D8D8D8D8000000808080808080808080808080808080808080" + $"80808080808080808080808080808080808000000000D8D8D8D8D8D8D8D8D8D8" + $"D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8000000B8B8B8FFFFFF" + $"B8B8B8B8B8B8C0C0C0808080FFFFFFC0C0C0B8B8B8B8B8B8B8B8B88080800000" + $"0000D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8" + $"D8D8D8000000B8B8B8FFFFFFB8B8B8B8B8B8C0C0C0808080FFFFFFC0C0C0B8B8" + $"B8B8B8B8B8B8B880808000000000D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8" + $"D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8000000B8B8B8FFFFFFB8B8B8B8B8B8C0C0" + $"C0808080FFFFFFC0C0C0B8B8B8B8B8B8B8B8B880808000000000D8D8D8D8D8D8" + $"D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8000000B8B8" + $"B8FFFFFFFFFFFFFFFFFFFFFFFF808080FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80" + $"808000000000D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8" + $"D8D8D8D8D8D8D8000000B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8808080B8B8B8B8" + $"B8B8B8B8B8B8B8B8B8B8B880808000000000D8D8D8D8D8D8D8D8D8D8D8D8D8D8" + $"D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D800000000000000000000" + $"0000000000585858000000000000000000000000000000000000D8D8D800D8D8" + $"D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8" + $"D8D8D8D8D8D8D8D8D8D8D8D8D8D8000000000000000000D8D8D8D8D8D8D8D8D8" + $"D8D8D8D8D8D8D8D8D800D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8" + $"D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8000000" + $"D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D800D8D8D8D8D8D8D8D8D8D8" + $"D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8" + $"D8D8D8D8D8D8D8D8D8000000D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8" + $"D800000000000000000000000000000000000000000000000000000000000000" + $"0000000000000000000000000000000000000000000000000000000000000000" + $"0000000000000000000000000000000000000000000000000000000000000000" + $"0000000000000000000000000000000000000000000000000000000000000000" + $"0000000000000000000000000000000000000000000000000000000000000000" + $"0000000000000000000000000000000000000000000000000000000000000000" + $"0000000000000000000000000000000000000000000000000000000000000000" + $"0000000000000000000000000000000000000000000000000000000000000000" + $"0000000000000000000000000000000000000000000000000000000000000000" + $"0000000000000000000000000000000000000000000000000000000000000000" + $"0000000000000000000000000000000000000000000000000000000000000000" + $"0000000000000000000000000000000000000000000000000000000000000000" + $"0000000000000000000000000000000000000000000000000000000000000000" + $"0000000000000000000000000000000000000000000000000000000000000000" + $"0000000000000000000000000000000000000000000000000000000000000000" + $"0000000000000000000000000000000000000000000000000000000000000000" + $"0000000000000000000000000000000000000000000000000000000000000000" + $"0000000000000000" +}; + +resource(603, "acceleration_bmap") #'bits' array { + $"424D83080000000000003A000000280000001900000015000000010018000000" + $"000049080000130B0000130B00000000F8410000F841FFFFFFFFD8D8D8D8D8D8" + $"D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D80000" + $"0000000000000000000000000000000000000000000000000000000000000000" + $"0000D8D8D800D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8" + $"D8D8D8D8D8D8D800000080808080808080808080808080808080808080808080" + $"808080808080808080808080808000000000D8D8D8D8D8D8D8D8D8D8D8D8D8D8" + $"D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8000000B8B8B8FFFFFFB8B8B8B8" + $"B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B880808000000000D8D8" + $"D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D800" + $"0000B8B8B8FFFFFFB8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8" + $"B8B8B880808000000000D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8" + $"D8D8D8D8D8D8D8D8D8D8D8000000B8B8B8FFFFFFB8B8B8B8B8B8B8B8B8B8B8B8" + $"B8B8B8B8B8B8B8B8B8B8B8B8B8B8B880808000000000D8D8D8D8D8D8D8D8D898" + $"9898D8D8D8989898989898989898989898D8D8D8D8D8D8000000B8B8B8FFFFFF" + $"B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B88080800000" + $"0000D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8" + $"D8D8D8000000B8B8B8FFFFFFB8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8" + $"B8B8B8B8B8B8B880808000000000D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8" + $"D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8000000B8B8B8FFFFFFB8B8B8B8B8B8B8B8" + $"B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B87F7F7F00000000989898D8D8D8" + $"989898989898989898989898989898989898989898D8D8D8D8D8D8000000B8B8" + $"B8FFFFFFB8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B880" + $"808000000000D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8" + $"D8D8D8D8D8D8D8000000B8B8B8FFFFFFB8B8B8B8B8B8B8B8B8B8B8B8B8B8B8B8" + $"B8B8B8B8B8B8B8B8B8B8B87F7F7F00000000D8D8D8D8D8D8D8D8D8D8D8D8D8D8" + $"D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8000000B8B8B8FFFFFFFFFFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80808000000000D8D8" + $"D8D8D8D8D8D8D8989898D8D8D8989898989898989898989898D8D8D8D8D8D800" + $"0000808080808080808080808080808080808080808080808080808080808080" + $"80808080808000000000D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8" + $"D8D8D8D8D8D8D8D8D8D8D8000000B8B8B8FFFFFFB8B8B8B8B8B8C0C0C0808080" + $"FFFFFFC0C0C0B8B8B8B8B8B8B8B8B880808000000000D8D8D8D8D8D8D8D8D8D8" + $"D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8000000B8B8B8FFFFFF" + $"B8B8B8B8B8B8C0C0C0808080FFFFFFC0C0C0B8B8B8B8B8B8B8B8B88080800000" + $"0000D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8" + $"D8D8D8000000B8B8B8FFFFFFB8B8B8B8B8B8C0C0C0808080FFFFFFC0C0C0B8B8" + $"B8B8B8B8B8B8B880808000000000D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8" + $"D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8000000B8B8B8FFFFFFFFFFFFFFFFFFFFFF" + $"FF808080FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80808000000000D8D8D8D8D8D8" + $"D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8000000B8B8" + $"B8B8B8B8B8B8B8B8B8B8B8B8B8808080B8B8B8B8B8B8B8B8B8B8B8B8B8B8B880" + $"808000000000D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8" + $"D8D8D8D8D8D8D8D8D8D800000000000000000000000000000058585800000000" + $"0000000000000000000000000000D8D8D800D8D8D8D8D8D8D8D8D8D8D8D8D8D8" + $"D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8" + $"D8D8000000000000000000D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D800D8D8" + $"D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8" + $"D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8000000D8D8D8D8D8D8D8D8D8D8D8D8" + $"D8D8D8D8D8D8D8D8D800D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8" + $"D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8000000" + $"D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D800000090413D3D3DFF0000" + $"80420000984100008042000008423D0000FF0000804200000C42000080420000" + $"4842003D00FF0000804200004C42000080420000844200003DFF000082420000" + $"004000008242000090413E3E3EFF000082420000984100008242000008423E00" + $"00FF0000824200000C420000824200004842003E00FF0000824200004C420000" + $"82420000844200003EFF000084420000004000008442000090413F3F3FFF0000" + $"84420000984100008442000008423F0000FF0000844200000C42000084420000" + $"4842003F00FF0000844200004C42000084420000844200003FFF000086420000" + $"00400000864200009041404040FF000086420000984100008642000008424000" + $"00FF0000864200000C420000864200004842004000FF0000864200004C420000" + $"864200008442000040FF00008842000000400000884200009041414141FF0000" + $"8842000098410000884200000842410000FF0000884200000C42000088420000" + $"4842004100FF0000884200004C420000884200008442000041FF00008A420000" + $"004000008A4200009041424242FF00008A420000984100008A42000008424200" + $"00FF00008A4200000C4200008A4200004842004200FF00008A4200004C420000" + $"8A4200008442000042FF00008C420000004000008C4200009041434343FF0000" + $"8C420000984100008C4200000842430000FF00008C4200000C4200008C420000" + $"484200" +}; diff --git a/src/preferences/touchpad/TouchpadPref.cpp b/src/preferences/touchpad/TouchpadPref.cpp new file mode 100644 index 0000000000..28f78e1d47 --- /dev/null +++ b/src/preferences/touchpad/TouchpadPref.cpp @@ -0,0 +1,179 @@ +#include "TouchpadPref.h" + +#include +#include +#include +#include + +#include "kb_mouse_driver.h" + + +TouchpadPref::TouchpadPref() +{ + fConnected = false; + // default center position + fWindowPosition.x = -1; + fWindowPosition.y = -1; + + ConnectToTouchPad(); + + if(LoadSettings() != B_OK){ + Defaults(); + } + fStartSettings = fSettings; +} + + +TouchpadPref::~TouchpadPref() +{ + if(fConnected){ + delete fTouchPad; + } + SaveSettings(); +} + + +void +TouchpadPref::Revert() +{ + fSettings = fStartSettings; +} + + +status_t +TouchpadPref::UpdateSettings() +{ + LOG("UpdateSettings of device %s\n", fTouchPad->Name()); + if(!fConnected){ + return B_ERROR; + } + + BMessage msg; + msg.AddBool("scroll_twofinger", fSettings.scroll_twofinger); + msg.AddBool("scroll_multifinger", fSettings.scroll_multifinger); + msg.AddFloat("scroll_rightrange", fSettings.scroll_rightrange); + msg.AddFloat("scroll_bottomrange", fSettings.scroll_bottomrange); + msg.AddInt16("scroll_xstepsize", fSettings.scroll_xstepsize); + msg.AddInt16("scroll_ystepsize", fSettings.scroll_ystepsize); + msg.AddInt8("scroll_acceleration", fSettings.scroll_acceleration); + msg.AddInt8("tapgesture_sensibility", fSettings.tapgesture_sensibility); + return fTouchPad->Control(MS_SET_TOUCHPAD_SETTINGS, &msg); +} + + +void +TouchpadPref::Defaults() +{ + fSettings = kDefaultTouchpadSettings; +} + + +status_t +TouchpadPref::GetSettingsPath(BPath &path) +{ + status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, &path); + if(status < B_OK) + return status; + path.Append(TOUCHPAD_SETTINGS_FILE); + return B_OK; +} + + +status_t +TouchpadPref::LoadSettings() +{ + BPath path; + status_t status = GetSettingsPath(path); + if(status != B_OK) + return status; + + BFile settingsFile(path.Path(), B_READ_ONLY); + status = settingsFile.InitCheck(); + if(status != B_OK) + return status; + + if(settingsFile.Read(&fSettings, sizeof(touchpad_settings)) + != sizeof(touchpad_settings)) + { + LOG("failed to load settings\n"); + return B_ERROR; + } + + if(settingsFile.Read(&fWindowPosition, sizeof(BPoint)) + != sizeof(BPoint)) + { + LOG("failed to load settings\n"); + return B_ERROR; + } + return B_OK; +} + + +status_t +TouchpadPref::SaveSettings() +{ + BPath path; + status_t status = GetSettingsPath(path); + if(status != B_OK) + return status; + + BFile settingsFile(path.Path(), B_READ_WRITE | B_CREATE_FILE); + status = settingsFile.InitCheck(); + if(status != B_OK) + return status; + + if(settingsFile.Write(&fSettings, sizeof(touchpad_settings)) + != sizeof(touchpad_settings)) + { + LOG("can't save settings\n"); + return B_ERROR; + } + + if(settingsFile.Write(&fWindowPosition, sizeof(BPoint)) + != sizeof(BPoint)) + { + LOG("can't save window position\n"); + return B_ERROR; + } + return B_OK; +} + + +status_t +TouchpadPref::ConnectToTouchPad() +{ + BList devList; + status_t status = get_input_devices(&devList); + if(status != B_OK){ + return status; + } + int32 i = 0; + while(true){ + BInputDevice * dev = (BInputDevice*)devList.ItemAt(i); + if(!dev) + break; + i++; + + LOG("input device %s\n", dev->Name()); + + bool isTouchpad = false; + BString name = dev->Name(); + + if(name.FindFirst("Touchpad") != B_ERROR + && dev->Type() == B_POINTING_DEVICE + && !fConnected) + { + isTouchpad = true; + fConnected = true; + fTouchPad = dev; + } + else{ + delete dev; + } + } + if(fConnected) + return B_OK; + + LOG("touchpad input device NOT found\n"); + return B_ENTRY_NOT_FOUND; +} diff --git a/src/preferences/touchpad/TouchpadPref.h b/src/preferences/touchpad/TouchpadPref.h new file mode 100644 index 0000000000..c2e4db0353 --- /dev/null +++ b/src/preferences/touchpad/TouchpadPref.h @@ -0,0 +1,50 @@ +#ifndef TouchpadPref_h +#define TouchpadPref_h + +#define DEBUG 1 +#include + +#include "touchpad_settings.h" +#include +#include + +#if DEBUG +# define LOG(text...) PRINT((text)) +#else +# define LOG(text...) +#endif + + +// draw a touchpad +class TouchpadPref +{ + public: + TouchpadPref(); + ~TouchpadPref(); + + void Revert(); + void Defaults(); + + BPoint WindowPosition(){return fWindowPosition;} + void SetWindowPosition(BPoint position){ + fWindowPosition = position;} + + touchpad_settings * GetSettings(){return &fSettings;} + status_t UpdateSettings(); + private: + status_t GetSettingsPath(BPath &path); + status_t LoadSettings(); + status_t SaveSettings(); + + status_t ConnectToTouchPad(); + + bool fConnected; + BInputDevice * fTouchPad; + + touchpad_settings fSettings; + touchpad_settings fStartSettings; + BPoint fWindowPosition; +}; + + +#endif \ No newline at end of file diff --git a/src/preferences/touchpad/TouchpadPrefView.cpp b/src/preferences/touchpad/TouchpadPrefView.cpp new file mode 100644 index 0000000000..e49b5a9f24 --- /dev/null +++ b/src/preferences/touchpad/TouchpadPrefView.cpp @@ -0,0 +1,457 @@ +#include "TouchpadPrefView.h" +#include "kb_mouse_driver.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +const uint32 SCROLL_X_DRAG = 'sxdr'; +const uint32 SCROLL_Y_DRAG = 'sydr'; + + +TouchpadView::TouchpadView(BRect frame) + :BView(frame, "TouchpadView", B_FOLLOW_NONE, B_WILL_DRAW) +{ + fXTracking = false; + fYTracking = false; + fOffScreenView = NULL; + fOffScreenBitmap = NULL; + + fPrefRect = frame; + fPadRect = fPrefRect; + fPadRect.InsetBy(10, 10); + fXScrollRange = fPadRect.Width(); + fYScrollRange = fPadRect.Height(); + +} + + +TouchpadView::~TouchpadView() +{ + if(fOffScreenBitmap){ + delete fOffScreenBitmap; + } +} + + +void +TouchpadView::Draw(BRect updateRect) +{ + DrawSliders(); + +} + + +void +TouchpadView::MouseDown(BPoint point) +{ + if(fXScrollDragZone.Contains(point)) + { + fXTracking = true; + fOldXScrollRange = fXScrollRange; + SetMouseEventMask( B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS ); + } + + if(fYScrollDragZone.Contains(point)) + { + fYTracking = true; + fOldYScrollRange = fYScrollRange; + SetMouseEventMask( B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS ); + } +} + + +void +TouchpadView::MouseUp(BPoint point) +{ + if(fXTracking || fYTracking){ + fXTracking = false; + fYTracking = false; + int32 result = 0; + if(GetRightScrollRatio() > 0.7 || GetBottomScrollRatio() > 0.7){ + BAlert *alert = new BAlert("ReallyChangeScrollArea", + "The new scroll area is very small. Do you really want to change the scroll area?", "Ok", "Cancel", + NULL, + B_WIDTH_AS_USUAL, + B_WARNING_ALERT); + result = alert->Go(); + } + if(result == 0){ + BMessage msg(SCROLL_AREA_CHANGED); + Invoke(&msg); + } + else{ + fXScrollRange = fOldXScrollRange; + fYScrollRange = fOldYScrollRange; + DrawSliders(); + } + } +} + + +void +TouchpadView::AttachedToWindow() +{ + if (!fOffScreenView) { + fOffScreenView = new BView(Bounds(), "", B_FOLLOW_ALL, B_WILL_DRAW); + } + if (!fOffScreenBitmap) { + fOffScreenBitmap = new BBitmap(Bounds(), B_CMAP8, true, false); + + if (fOffScreenBitmap && fOffScreenView) + fOffScreenBitmap->AddChild(fOffScreenView); + + } +} + + +void +TouchpadView::SetValues(float rightRange, float bottomRange) +{ + fXScrollRange = fPadRect.Width() * (1 - rightRange); + fYScrollRange = fPadRect.Height() * (1 - bottomRange); + Invalidate(); +} + + +void +TouchpadView::GetPreferredSize(float *width, float *height) +{ + *width = fPrefRect.Width(); + *height = fPrefRect.Height(); +} + + +void +TouchpadView::MouseMoved(BPoint point, uint32 transit, const BMessage *message) +{ + if(fXTracking){ + if(point.x > fPadRect.right){ + fXScrollRange = fPadRect.Width(); + } + else if(point.x < fPadRect.left){ + fXScrollRange = 0; + } + else{ + fXScrollRange = point.x - fPadRect.left; + } + DrawSliders(); + } + + if(fYTracking){ + if(point.y > fPadRect.bottom){ + fYScrollRange = fPadRect.Height(); + } + else if(point.y < fPadRect.top){ + fYScrollRange = 0; + } + else{ + fYScrollRange = point.y - fPadRect.top; + } + DrawSliders(); + } +} + + + +void +TouchpadView::DrawSliders() +{ + BView *view = NULL; + if(fOffScreenView){ + view = fOffScreenView; + } + else{ + view = this; + } + + if (LockLooper()) { + if (fOffScreenBitmap->Lock()) { + view->SetHighColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + view->FillRect(Bounds()); + view->SetHighColor(100, 100, 100); + view->FillRoundRect(fPadRect, 4, 4); + + int32 dragSize = 3; //half drag size + + // scroll areas + view->SetHighColor(145, 100, 100); + BRect rightRect(fPadRect.left + fXScrollRange, fPadRect.top, + fPadRect.right, fPadRect.bottom); + view->FillRoundRect(rightRect, 4, 4); + + BRect bottomRect(fPadRect.left, fPadRect.top + fYScrollRange, + fPadRect.right, fPadRect.bottom); + view->FillRoundRect(bottomRect, 4, 4); + + // Stroke Rect + view->SetHighColor(100, 100, 100); + view->SetPenSize(2); + view->StrokeRoundRect(fPadRect, 4, 4); + + // x scroll range line + view->SetHighColor(200, 0, 0); + view->StrokeLine(BPoint(fPadRect.left + fXScrollRange, fPadRect.top), + BPoint(fPadRect.left + fXScrollRange, fPadRect.bottom)); + + fXScrollDragZone = BRect(fPadRect.left + fXScrollRange - dragSize, + fPadRect.top - dragSize, + fPadRect.left + fXScrollRange + dragSize, + fPadRect.bottom + dragSize); + fXScrollDragZone1 = BRect(fPadRect.left + fXScrollRange - dragSize, + fPadRect.top - dragSize, + fPadRect.left + fXScrollRange + dragSize, + fPadRect.top + dragSize); + view->FillRect(fXScrollDragZone1); + fXScrollDragZone2 = BRect(fPadRect.left + fXScrollRange - dragSize, + fPadRect.bottom - dragSize, + fPadRect.left + fXScrollRange + dragSize, + fPadRect.bottom + dragSize); + view->FillRect(fXScrollDragZone2); + + // y scroll range line + view->StrokeLine(BPoint(fPadRect.left, fPadRect.top + fYScrollRange), + BPoint(fPadRect.right, fPadRect.top + fYScrollRange)); + + fYScrollDragZone = BRect(fPadRect.left - dragSize, + fPadRect.top + fYScrollRange - dragSize, + fPadRect.right + dragSize, + fPadRect.top + fYScrollRange + dragSize); + fYScrollDragZone1 = BRect(fPadRect.left - dragSize, + fPadRect.top + fYScrollRange - dragSize, + fPadRect.left + dragSize, + fPadRect.top + fYScrollRange + dragSize); + view->FillRect(fYScrollDragZone1); + fYScrollDragZone2 = BRect(fPadRect.right - dragSize, + fPadRect.top + fYScrollRange - dragSize, + fPadRect.right + dragSize, + fPadRect.top + fYScrollRange + dragSize); + view->FillRect(fYScrollDragZone2); + + fOffScreenView->Sync(); + fOffScreenBitmap->Unlock(); + DrawBitmap(fOffScreenBitmap, B_ORIGIN); + + + } + UnlockLooper(); + } +} + +// -------TouchpadPrefView---------- +TouchpadPrefView::TouchpadPrefView(BRect frame, const char *name) + :BView(frame, name, B_FOLLOW_ALL_SIDES, 0) +{ + SetupView(); + // set view values + SetValues(fTouchpadPref.GetSettings()); +} + + + +TouchpadPrefView::~TouchpadPrefView() +{ + delete fTouchpadView; +} + + +void +TouchpadPrefView::MessageReceived(BMessage *msg) +{ + touchpad_settings *settings = fTouchpadPref.GetSettings(); + switch(msg->what) { + case SCROLL_AREA_CHANGED: + settings->scroll_rightrange = fTouchpadView->GetRightScrollRatio(); + settings->scroll_bottomrange = fTouchpadView->GetBottomScrollRatio(); + fRevertButton->SetEnabled(true); + fTouchpadPref.UpdateSettings(); + break; + case SCROLL_CONTROL_CHANGED: + settings->scroll_twofinger = (fTwoFingerBox->Value() == B_CONTROL_ON) ? true : false; + settings->scroll_multifinger = (fMultiFingerBox->Value() == B_CONTROL_ON) ? true : false; + settings->scroll_acceleration = fScrollAccelSlider->Value(); + settings->scroll_xstepsize = (20 - fScrollStepXSlider->Value()) * 3; + settings->scroll_ystepsize = (20 - fScrollStepYSlider->Value()) * 3; + fRevertButton->SetEnabled(true); + fTouchpadPref.UpdateSettings(); + break; + case TAP_CONTROL_CHANGED: + settings->tapgesture_sensibility = fTapSlider->Value(); + fRevertButton->SetEnabled(true); + fTouchpadPref.UpdateSettings(); + break; + case DEFAULT_SETTINGS: + fTouchpadPref.Defaults(); + fRevertButton->SetEnabled(true); + fTouchpadPref.UpdateSettings(); + SetValues(settings); + break; + case REVERT_SETTINGS: + fTouchpadPref.Revert(); + fTouchpadPref.UpdateSettings(); + fRevertButton->SetEnabled(false); + SetValues(settings); + break; + default: + BView::MessageReceived(msg); + } + +} + + +void +TouchpadPrefView::AttachedToWindow() +{ + fTouchpadView->SetTarget(this); + fTwoFingerBox->SetTarget(this); + fMultiFingerBox->SetTarget(this); + fScrollStepXSlider->SetTarget(this); + fScrollStepYSlider->SetTarget(this); + fScrollAccelSlider->SetTarget(this); + fTapSlider->SetTarget(this); + fDefaultButton->SetTarget(this); + fRevertButton->SetTarget(this); + BSize size = PreferredSize(); + Window()->ResizeTo(size.width, size.height); + + BRect rect = BScreen().Frame(); + BRect windowFrame = Window()->Frame(); + BPoint position = fTouchpadPref.WindowPosition(); + // center window on screen if it had a bad position + if(position.x < 0 && position.y < 0){ + position.x = (rect.Width() - windowFrame.Width()) / 2; + position.y = (rect.Height() - windowFrame.Height()) / 2; + } + Window()->MoveTo(position); +} + + +void +TouchpadPrefView::DetachedFromWindow(void) +{ + fTouchpadPref.SetWindowPosition(Window()->Frame().LeftTop()); +} + + +void +TouchpadPrefView::SetupView() +{ + SetLayout(new BGroupLayout(B_VERTICAL)); + BRect rect = Bounds(); + rect.InsetBy(5, 5); + BBox *scrollBox = new BBox(rect, "Touchpad"); + scrollBox->SetLabel("Scrolling"); + SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + + fTouchpadView = new TouchpadView(BRect(0,0,130,120)); + fTouchpadView->SetExplicitMaxSize(BSize(130, 120)); + + // Create the "Mouse Speed" slider... + fScrollAccelSlider = new BSlider(rect, "scroll_accel", "Scroll Acceleration", + new BMessage(SCROLL_CONTROL_CHANGED), 0, 20); + fScrollAccelSlider->SetHashMarks(B_HASH_MARKS_BOTTOM); + fScrollAccelSlider->SetHashMarkCount(7); + fScrollAccelSlider->SetLimitLabels("Slow", "Fast"); + + fScrollStepXSlider = new BSlider(rect, "scroll_stepX", "Horizontal Scroll Stepsize", + new BMessage(SCROLL_CONTROL_CHANGED), 0, 20); + fScrollStepXSlider->SetHashMarks(B_HASH_MARKS_BOTTOM); + fScrollStepXSlider->SetHashMarkCount(7); + fScrollStepXSlider->SetLimitLabels("Wide", "Small"); + + fScrollStepYSlider = new BSlider(rect, "scroll_stepY", "Vertical Scroll Stepsize", + new BMessage(SCROLL_CONTROL_CHANGED), 0, 20); + fScrollStepYSlider->SetHashMarks(B_HASH_MARKS_BOTTOM); + fScrollStepYSlider->SetHashMarkCount(7); + fScrollStepYSlider->SetLimitLabels("Wide", "Small"); + + fTwoFingerBox = new BCheckBox("Two Finger Scrolling", new BMessage(SCROLL_CONTROL_CHANGED)); + fMultiFingerBox = new BCheckBox("Multi Finger Scrolling", new BMessage(SCROLL_CONTROL_CHANGED)); + + BGroupView* scrollPrefLeftLayout = new BGroupView(B_VERTICAL); + scrollPrefLeftLayout->AddChild(fTouchpadView); + scrollPrefLeftLayout->AddChild(fTwoFingerBox); + scrollPrefLeftLayout->AddChild(fMultiFingerBox); + + BGroupView* scrollPrefRightLayout = new BGroupView(B_VERTICAL); + scrollPrefRightLayout->AddChild(fScrollAccelSlider); + scrollPrefRightLayout->AddChild(fScrollStepXSlider); + scrollPrefRightLayout->AddChild(fScrollStepYSlider); + + BGroupLayout* scrollPrefLayout = new BGroupLayout(B_HORIZONTAL); + scrollPrefLayout->SetSpacing(10); + scrollPrefLayout->SetInsets(10, scrollBox->TopBorderOffset() * 2 + 10, 10, 10); + scrollBox->SetLayout(scrollPrefLayout); + + scrollPrefLayout->AddView(scrollPrefLeftLayout); + scrollPrefLayout->AddItem(BSpaceLayoutItem::CreateVerticalStrut(15)); + scrollPrefLayout->AddView(scrollPrefRightLayout); + + BBox *tapBox = new BBox(rect, "tapbox"); + tapBox->SetLabel("Tap Gesture"); + + BGroupLayout* tapPrefLayout = new BGroupLayout(B_HORIZONTAL); + tapPrefLayout->SetInsets(10, tapBox->TopBorderOffset() * 2 + 10, 10, 10); + tapBox->SetLayout(tapPrefLayout); + + fTapSlider = new BSlider(rect, "tap_sens", "Tap Click Sensitivity", + new BMessage(TAP_CONTROL_CHANGED), 0, 20); + fTapSlider->SetHashMarks(B_HASH_MARKS_BOTTOM); + fTapSlider->SetHashMarkCount(7); + fTapSlider->SetLimitLabels("Off", "High"); + + tapPrefLayout->AddView(fTapSlider); + + BGroupView* buttonView = new BGroupView(B_HORIZONTAL); + fDefaultButton = new BButton("Defaults", + new BMessage(DEFAULT_SETTINGS)); + + buttonView->AddChild(fDefaultButton); + buttonView->GetLayout()->AddItem(BSpaceLayoutItem::CreateHorizontalStrut(7)); + fRevertButton = new BButton("Revert", + new BMessage(REVERT_SETTINGS)); + fRevertButton->SetEnabled(false); + buttonView->AddChild(fRevertButton); + buttonView->GetLayout()->AddItem(BSpaceLayoutItem::CreateGlue()); + + BGroupLayout* layout = new BGroupLayout(B_VERTICAL); + layout->SetInsets(10, 10, 10, 10); + layout->SetSpacing(10); + BView* rootView = new BView("root view", 0, layout); + AddChild(rootView); + rootView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + + layout->AddView(scrollBox); + layout->AddView(tapBox); + layout->AddView(buttonView); + +} + + +void +TouchpadPrefView::SetValues(touchpad_settings *settings) +{ + fTouchpadView->SetValues(settings->scroll_rightrange, settings->scroll_bottomrange); + fTwoFingerBox->SetValue(settings->scroll_twofinger ? B_CONTROL_ON : B_CONTROL_OFF); + fMultiFingerBox->SetValue(settings->scroll_multifinger ? B_CONTROL_ON : B_CONTROL_OFF); + fScrollStepXSlider->SetValue(20 - settings->scroll_xstepsize / 2); + fScrollStepYSlider->SetValue(20 - settings->scroll_ystepsize / 2); + fScrollAccelSlider->SetValue(settings->scroll_acceleration); + fTapSlider->SetValue(settings->tapgesture_sensibility); +} + diff --git a/src/preferences/touchpad/TouchpadPrefView.h b/src/preferences/touchpad/TouchpadPrefView.h new file mode 100644 index 0000000000..d8b956a70c --- /dev/null +++ b/src/preferences/touchpad/TouchpadPrefView.h @@ -0,0 +1,98 @@ +#ifndef TouchpadPrefView_h +#define TouchpadPrefView_h + +#include +#include +#include +#include +#include +#include + +#include "TouchpadPref.h" +#include "touchpad_settings.h" + +#define DEBUG 1 +#include + +#if DEBUG +# define LOG(text...) PRINT((text)) +#else +# define LOG(text...) +#endif + +const uint SCROLL_AREA_CHANGED = '&sac'; +const uint SCROLL_CONTROL_CHANGED = '&scc'; +const uint TAP_CONTROL_CHANGED = '&tcc'; +const uint DEFAULT_SETTINGS = '&dse'; +const uint REVERT_SETTINGS = '&rse'; + + +// draw a touchpad +class TouchpadView : public BView, public BInvoker +{ + public: + TouchpadView(BRect frame); + ~TouchpadView(); + virtual void Draw(BRect updateRect); + virtual void MouseDown(BPoint point); + virtual void MouseUp(BPoint point); + virtual void MouseMoved(BPoint point, uint32 transit, const BMessage *message); + + virtual void AttachedToWindow(); + virtual void GetPreferredSize(float *width, float *height); + + void SetValues(float rightRange, float bottomRange); + float GetRightScrollRatio(){ return (1 - fXScrollRange / fPadRect.Width()); }; + float GetBottomScrollRatio(){ return (1 - fYScrollRange / fPadRect.Height()); }; + private: + + virtual void DrawSliders(); + BRect fPrefRect; + BRect fPadRect; + BRect fXScrollDragZone; + BRect fXScrollDragZone1; + BRect fXScrollDragZone2; + float fXScrollRange; + float fOldXScrollRange; + BRect fYScrollDragZone; + BRect fYScrollDragZone1; + BRect fYScrollDragZone2; + float fYScrollRange; + float fOldYScrollRange; + + bool fXTracking; + bool fYTracking; + BView *fOffScreenView; + BBitmap *fOffScreenBitmap; +}; + + +class TouchpadPrefView : public BView +{ + public: + TouchpadPrefView(BRect frame, const char *name); + ~TouchpadPrefView(); + virtual void MessageReceived(BMessage *msg); + virtual void AttachedToWindow(); + virtual void DetachedFromWindow(void); + void SetupView(); + + void SetValues(touchpad_settings *settings); + + private: + // visual the touchpad + TouchpadView* fTouchpadView; + BCheckBox* fTwoFingerBox; + BCheckBox* fMultiFingerBox; + BSlider* fScrollStepXSlider; + BSlider* fScrollStepYSlider; + BSlider* fScrollAccelSlider; + BSlider* fTapSlider; + BButton* fDefaultButton; + BButton* fRevertButton; + + TouchpadPref fTouchpadPref; +}; + + +#endif \ No newline at end of file diff --git a/src/preferences/touchpad/main.cpp b/src/preferences/touchpad/main.cpp new file mode 100644 index 0000000000..0e9144cca1 --- /dev/null +++ b/src/preferences/touchpad/main.cpp @@ -0,0 +1,39 @@ +//Autor: Clemens Zeidler czeidler@gmx.de +//licence: MIT + +#include "TouchpadPrefView.h" +#include +#include + + +class TouchpadPrefWindow : public BWindow +{ + public: + TouchpadPrefWindow(BRect frame, + const char *title, + window_type type, + uint32 flags) + :BWindow(frame, title, type, flags) + {}; + + virtual bool TouchpadPrefWindow::QuitRequested() + { + be_app->PostMessage(B_QUIT_REQUESTED); + return true; + }; +}; + + +int +main(int argc, char* argv[]) +{ + BApplication *app = new BApplication("application/touchpadpref"); + TouchpadPrefWindow *window = new TouchpadPrefWindow(BRect(50, 50, 450, 350),"Touchpad", B_TITLED_WINDOW, + B_NOT_RESIZABLE | B_NOT_ZOOMABLE | B_AVOID_FRONT | B_ASYNCHRONOUS_CONTROLS); + window->AddChild(new TouchpadPrefView(window->Bounds(), "TouchpadPrefView")); + window->Show(); + app->Run(); + + delete app; + return 0; +} \ No newline at end of file