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
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
//
|
||||
// kb_mouse_driver.h
|
||||
//
|
||||
#ifndef _TOUCHPAD_DRIVER_H
|
||||
#define _TOUCHPAD_DRIVER_H
|
||||
|
||||
#include <SupportDefs.h>
|
||||
#include <Drivers.h>
|
||||
|
||||
#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
|
||||
|
||||
@@ -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 <SupportDefs.h>
|
||||
|
||||
|
||||
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 */
|
||||
@@ -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 ;
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
SubDir HAIKU_TOP src add-ons input_server devices touchpad ;
|
||||
|
||||
SetSubDirSupportedPlatformsBeOSCompatible ;
|
||||
|
||||
UsePrivateHeaders input ;
|
||||
|
||||
Addon <input>touchpad :
|
||||
TouchpadInputDevice.cpp
|
||||
: be input_server ;
|
||||
|
||||
Package haiku-inputkit-cvs :
|
||||
<input>touchpad :
|
||||
boot home config add-ons input_server devices ;
|
||||
@@ -0,0 +1,685 @@
|
||||
/*
|
||||
* Copyright 2004-2007, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stefano Ceccherini ([email protected])
|
||||
* Jérôme Duval
|
||||
* Axel Dörfler, [email protected]
|
||||
*/
|
||||
|
||||
|
||||
#include "TouchpadInputDevice.h"
|
||||
#include "kb_mouse_driver.h"
|
||||
#include "kb_mouse_settings.h"
|
||||
#include "touchpad_settings.h"
|
||||
|
||||
#include <Debug.h>
|
||||
#include <Directory.h>
|
||||
#include <Entry.h>
|
||||
#include <File.h>
|
||||
#include <FindDirectory.h>
|
||||
#include <NodeMonitor.h>
|
||||
#include <Path.h>
|
||||
#include <String.h>
|
||||
#include <View.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <new>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 <InputServerDevice.h>
|
||||
#include <InterfaceDefs.h>
|
||||
#include <List.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#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
|
||||
@@ -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
|
||||
;
|
||||
|
||||
@@ -0,0 +1,278 @@
|
||||
#include "movement_maker.h"
|
||||
|
||||
#include <Debug.h>
|
||||
#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;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
#ifndef MOVEMENT_MAKER_H
|
||||
#define MOVEMENT_MAKER_H
|
||||
|
||||
#include <OS.h>
|
||||
|
||||
|
||||
#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
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 <fs/devfs.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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 ([email protected])
|
||||
* Stefano Ceccherini ([email protected])
|
||||
* Axel Dörfler, [email protected]
|
||||
* Marcus Overhagen <[email protected]>
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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 <Drivers.h>
|
||||
#include <string.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#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,
|
||||
};
|
||||
|
||||
@@ -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 ([email protected])
|
||||
* Stefano Ceccherini ([email protected])
|
||||
* Axel Dörfler, [email protected]
|
||||
* Marcus Overhagen <[email protected]>
|
||||
* Clemens Zeidler <[email protected]>
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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 <string.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#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,
|
||||
};
|
||||
@@ -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 <marcus@overhagen.de>
|
||||
* Clemens Zeidler <czeidler@gmx.de>
|
||||
*/
|
||||
|
||||
#ifndef __PS2_STANDART_standart_mouse_H
|
||||
#define __PS2_STANDART_standart_mouse_H
|
||||
|
||||
#include <Drivers.h>
|
||||
|
||||
#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
|
||||
|
||||
@@ -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 <malloc.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#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,
|
||||
};
|
||||
@@ -0,0 +1,126 @@
|
||||
#ifndef SYNAPTICS_H
|
||||
#define SYNAPTICS_H
|
||||
|
||||
#include <KernelExport.h>
|
||||
|
||||
#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
|
||||
@@ -0,0 +1,30 @@
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
#ifndef SYNAPTICS_H
|
||||
#define SYNAPTICS_H
|
||||
|
||||
#include <KernelExport.h>
|
||||
|
||||
#include "ps2_dev.h"
|
||||
|
||||
|
||||
status_t probe_trackpoint(ps2_dev *dev);
|
||||
|
||||
|
||||
#endif
|
||||
@@ -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 ;
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
SubDir HAIKU_TOP src preferences touchpad ;
|
||||
|
||||
UsePrivateHeaders input ;
|
||||
|
||||
Preference Touchpad :
|
||||
TouchpadPref.cpp
|
||||
TouchpadPrefView.cpp
|
||||
main.cpp
|
||||
: be
|
||||
: 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"
|
||||
};
|
||||
@@ -0,0 +1,179 @@
|
||||
#include "TouchpadPref.h"
|
||||
|
||||
#include <List.h>
|
||||
#include <FindDirectory.h>
|
||||
#include <File.h>
|
||||
#include <String.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
#ifndef TouchpadPref_h
|
||||
#define TouchpadPref_h
|
||||
|
||||
#define DEBUG 1
|
||||
#include <Debug.h>
|
||||
|
||||
#include "touchpad_settings.h"
|
||||
#include <Input.h>
|
||||
#include <Path.h>
|
||||
|
||||
#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
|
||||
@@ -0,0 +1,457 @@
|
||||
#include "TouchpadPrefView.h"
|
||||
#include "kb_mouse_driver.h"
|
||||
|
||||
#include <CheckBox.h>
|
||||
#include <Alert.h>
|
||||
#include <Box.h>
|
||||
#include <File.h>
|
||||
#include <FindDirectory.h>
|
||||
#include <GroupLayout.h>
|
||||
#include <GroupView.h>
|
||||
#include <Input.h>
|
||||
#include <SpaceLayoutItem.h>
|
||||
#include <MenuField.h>
|
||||
#include <MenuItem.h>
|
||||
#include <Message.h>
|
||||
#include <Path.h>
|
||||
#include <Screen.h>
|
||||
#include <Window.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
#ifndef TouchpadPrefView_h
|
||||
#define TouchpadPrefView_h
|
||||
|
||||
#include <Bitmap.h>
|
||||
#include <Button.h>
|
||||
#include <CheckBox.h>
|
||||
#include <Invoker.h>
|
||||
#include <Slider.h>
|
||||
#include <View.h>
|
||||
|
||||
#include "TouchpadPref.h"
|
||||
#include "touchpad_settings.h"
|
||||
|
||||
#define DEBUG 1
|
||||
#include <Debug.h>
|
||||
|
||||
#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
|
||||
@@ -0,0 +1,39 @@
|
||||
//Autor: Clemens Zeidler [email protected]
|
||||
//licence: MIT
|
||||
|
||||
#include "TouchpadPrefView.h"
|
||||
#include <Application.h>
|
||||
#include <Window.h>
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
Reference in New Issue
Block a user