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:
Stephan Aßmus
2008-11-01 10:48:35 +00:00
parent 4dc9c4a55e
commit 6849a22864
30 changed files with 3929 additions and 560 deletions
+21
View File
@@ -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
+38
View File
@@ -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
+39
View File
@@ -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 */
+1
View File
@@ -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
+4 -1
View File
@@ -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
+103 -18
View File
@@ -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 -4
View File
@@ -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
+1
View File
@@ -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 ;
+11
View File
@@ -0,0 +1,11 @@
SubDir HAIKU_TOP src preferences touchpad ;
UsePrivateHeaders input ;
Preference Touchpad :
TouchpadPref.cpp
TouchpadPrefView.cpp
main.cpp
: be
: Touchpad.rdef
;
+304
View File
@@ -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"
};
+179
View File
@@ -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;
}
+50
View File
@@ -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
+39
View File
@@ -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;
}