- ALPS and synaptics are sharing the same code to generate mouse events now. The movement generation is calibrated on the synaptics touchpad, though.

ALPS movements are fine now, hope the synaptics is still working. Please test! There are still some leftovers form switching from a c struct to a c++ 
class will fix that later.
- Support ALPS devices with passthrough.
- ALPS is still disabled because tap and edge motion is not working yet. The 
problem is that synaptics generates more helper events which makes this a lot
easier to implement. My plan is to emulate this events to imitate the synatics touchpad.



git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@41140 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Clemens Zeidler 2011-03-30 09:37:40 +00:00
parent f011dde511
commit c152c70b46
6 changed files with 656 additions and 810 deletions

View File

@ -1,12 +1,24 @@
#include "movement_maker.h"
#include <Debug.h>
#include <stdlib.h>
#include <KernelExport.h>
#if 1
# define INFO(x...) dprintf(x)
#else
# define INFO(x...)
#endif
// #define TRACE_MOVEMENT_MAKER
#ifdef TRACE_MOVEMENT_MAKER
# define TRACE(x...) dprintf(x)
#else
# define TRACE(x...)
#endif
typedef union {
float value;
/* FIXME: Assumes 32 bit int. */
@ -173,142 +185,460 @@ make_small(float value)
}
void
get_raw_movement(movement_maker *move, uint32 posX, uint32 posY)
MovementMaker::SetSettings(touchpad_settings* settings)
{
fSettings = settings;
}
void
MovementMaker::SetSpecs(hardware_specs* specs)
{
fSpecs = specs;
fAreaWidth = fSpecs->areaEndX - fSpecs->areaStartX;
fAreaHeight = fSpecs->areaEndY - fSpecs->areaStartY;
// calibrated on the synaptics touchpad
fSpeed = 4100 / fAreaWidth;
fSmallMovement = 3 / fSpeed;
}
void
MovementMaker::StartNewMovment()
{
if (fSettings->scroll_xstepsize <= 0)
fSettings->scroll_xstepsize = 1;
if (fSettings->scroll_ystepsize <= 0)
fSettings->scroll_ystepsize = 1;
movementStarted = true;
scrolling_x = 0;
scrolling_y = 0;
}
void
MovementMaker::GetMovement(uint32 posX, uint32 posY)
{
_GetRawMovement(posX, posY);
// INFO("SYN: pos: %lu x %lu, delta: %ld x %ld, sums: %ld x %ld\n",
// posX, posY, xDelta, yDelta,
// deltaSumX, deltaSumY);
xDelta = xDelta;
yDelta = yDelta;
}
void
MovementMaker::GetScrolling(uint32 posX, uint32 posY)
{
int32 stepsX = 0, stepsY = 0;
_GetRawMovement(posX, posY);
_ComputeAcceleration(fSettings->scroll_acceleration);
if (fSettings->scroll_xstepsize > 0) {
scrolling_x += xDelta;
stepsX = make_small(scrolling_x / fSettings->scroll_xstepsize);
scrolling_x -= stepsX * fSettings->scroll_xstepsize;
xDelta = stepsX;
} else {
scrolling_x = 0;
xDelta = 0;
}
if (fSettings->scroll_ystepsize > 0) {
scrolling_y += yDelta;
stepsY = make_small(scrolling_y / fSettings->scroll_ystepsize);
scrolling_y -= stepsY * fSettings->scroll_ystepsize;
yDelta = -1 * stepsY;
} else {
scrolling_y = 0;
yDelta = 0;
}
}
void
MovementMaker::_GetRawMovement(uint32 posX, uint32 posY)
{
// calibrated on the synaptics touchpad
posX = posX * float(SYN_WIDTH) / fAreaWidth;
posY = posY * float(SYN_HEIGHT) / fAreaHeight;
const float acceleration = 0.8;
const float translation = 12.0;
int diff;
float xDelta, yDelta;
if (move->movementStarted) {
move->movementStarted = false;
if (movementStarted) {
movementStarted = false;
// init delta tracking
move->previousX = posX;
move->previousY = posY;
previousX = posX;
previousY = posY;
// deltas are automatically reset
}
// accumulate delta and store current pos, reset if pos did not change
diff = posX - move->previousX;
diff = posX - previousX;
// lessen the effect of small diffs
if ((diff > -3 && diff < -1) || (diff > 1 && diff < 3))
if ((diff > -fSmallMovement && diff < -1)
|| (diff > 1 && diff < fSmallMovement)) {
diff /= 2;
}
if (diff == 0)
move->deltaSumX = 0.0;
deltaSumX = 0.0;
else
move->deltaSumX += diff;
deltaSumX += diff;
diff = posY - move->previousY;
diff = posY - previousY;
// lessen the effect of small diffs
if ((diff > -3 && diff < -1) || (diff > 1 && diff < 3))
if ((diff > -fSmallMovement && diff < -1)
|| (diff > 1 && diff < fSmallMovement)) {
diff /= 2;
}
if (diff == 0)
move->deltaSumY = 0.0;
deltaSumY = 0.0;
else
move->deltaSumY += diff;
deltaSumY += diff;
move->previousX = posX;
move->previousY = posY;
previousX = posX;
previousY = posY;
// compute current delta and reset accumulated delta if
// abs() is greater than 1
xDelta = move->deltaSumX / translation;
yDelta = move->deltaSumY / translation;
xDelta = deltaSumX / translation;
yDelta = deltaSumY / translation;
if (xDelta > 1.0) {
move->deltaSumX = 0.0;
deltaSumX = 0.0;
xDelta = 1.0 + (xDelta - 1.0) * acceleration;
} else if (xDelta < -1.0) {
move->deltaSumX = 0.0;
deltaSumX = 0.0;
xDelta = -1.0 + (xDelta + 1.0) * acceleration;
}
if (yDelta > 1.0) {
move->deltaSumY = 0.0;
deltaSumY = 0.0;
yDelta = 1.0 + (yDelta - 1.0) * acceleration;
} else if (yDelta < -1.0) {
move->deltaSumY = 0.0;
deltaSumY = 0.0;
yDelta = -1.0 + (yDelta + 1.0) * acceleration;
}
move->xDelta = make_small(xDelta);
move->yDelta = make_small(yDelta);
xDelta = make_small(xDelta);
yDelta = make_small(yDelta);
}
void
compute_acceleration(movement_maker *move, int8 accel_factor)
MovementMaker::_ComputeAcceleration(int8 accel_factor)
{
// acceleration
float acceleration = 1;
if (accel_factor != 0) {
acceleration = 1 + sqrtf(move->xDelta * move->xDelta
+ move->yDelta * move->yDelta) * accel_factor / 50.0;
acceleration = 1 + sqrtf(xDelta * xDelta
+ yDelta * yDelta) * accel_factor / 50.0;
}
move->xDelta = make_small(move->xDelta * acceleration);
move->yDelta = make_small(move->yDelta * acceleration);
xDelta = make_small(xDelta * acceleration);
yDelta = make_small(yDelta * acceleration);
}
// #pragma mark -
#define TAP_TIMEOUT 200000
void
TouchpadMovement::Init()
{
movement_started = false;
scrolling_started = false;
tap_started = false;
valid_edge_motion = false;
double_click = false;
}
status_t
TouchpadMovement::EventToMovement(touch_event *event, mouse_movement *movement)
{
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 = system_time();
if ((movement->timestamp - tap_time) > TAP_TIMEOUT) {
TRACE("ALPS: tap gesture timed out\n");
tap_started = false;
if (!double_click
|| (movement->timestamp - tap_time) > 2 * TAP_TIMEOUT) {
tap_clicks = 0;
}
}
if (event->buttons & kLeftButton) {
tap_clicks = 0;
tapdrag_started = false;
tap_started = false;
valid_edge_motion = false;
}
if (event->zPressure >= fSpecs->minPressure
&& event->zPressure < fSpecs->maxPressure
&& ((event->wValue >= 4 && event->wValue <= 7)
|| event->wValue == 0 || event->wValue == 1)
&& (event->xPosition != 0 || event->yPosition != 0)) {
// The touch pad is in touch with at least one finger
if (!_CheckScrollingToMovement(event, movement))
_MoveToMovement(event, movement);
} else
_NoTouchToMovement(event, movement);
return B_OK;
}
bool
TouchpadMovement::_EdgeMotion(mouse_movement *movement, touch_event *event,
bool validStart)
{
int32 xdelta = 0;
int32 ydelta = 0;
if (event->xPosition < fSpecs->areaStartX + fSpecs->edgeMotionWidth)
xdelta = -fSpecs->edgeMotionSpeedFactor * fSpeed;
else if (event->xPosition > uint16(
fSpecs->areaEndX - fSpecs->edgeMotionWidth)) {
xdelta = fSpecs->edgeMotionSpeedFactor * fSpeed;
}
if (event->yPosition < fSpecs->areaStartY + fSpecs->edgeMotionWidth)
ydelta = -fSpecs->edgeMotionSpeedFactor * fSpeed;
else if (event->yPosition > uint16(
fSpecs->areaEndY - fSpecs->edgeMotionWidth)) {
ydelta = fSpecs->edgeMotionSpeedFactor * fSpeed;
}
if (xdelta && validStart)
movement->xdelta = xdelta;
if (ydelta && validStart)
movement->ydelta = ydelta;
if ((xdelta || ydelta) && !validStart)
return false;
return true;
}
/*! If a button has been clicked (movement->buttons must be set accordingly),
this function updates the click_count, as well as the
\a movement's clicks field.
Also, it sets the button state from movement->buttons.
*/
void
TouchpadMovement::_UpdateButtons(mouse_movement *movement)
{
// set click count correctly according to double click timeout
if (movement->buttons != 0 && buttons_state == 0) {
if (click_last_time + click_speed > movement->timestamp)
click_count++;
else
click_count = 1;
click_last_time = movement->timestamp;
}
if (movement->buttons != 0)
movement->clicks = click_count;
buttons_state = movement->buttons;
}
void
get_movement(movement_maker *move, uint32 posX, uint32 posY)
TouchpadMovement::_NoTouchToMovement(touch_event *event,
mouse_movement *movement)
{
get_raw_movement(move, posX, posY);
uint32 buttons = event->buttons;
// INFO("SYN: pos: %lu x %lu, delta: %ld x %ld, sums: %ld x %ld\n",
// posX, posY, move->xDelta, move->yDelta,
// move->deltaSumX, move->deltaSumY);
TRACE("ALPS: no touch event\n");
move->xDelta = move->xDelta * move->speed;
move->yDelta = move->yDelta * move->speed;
scrolling_started = false;
movement_started = false;
if (tapdrag_started
&& (movement->timestamp - tap_time) < TAP_TIMEOUT) {
buttons = 0x01;
}
// if the movement stopped switch off the tap drag when timeout is expired
if ((movement->timestamp - tap_time) > TAP_TIMEOUT) {
tapdrag_started = false;
valid_edge_motion = false;
TRACE("ALPS: tap drag gesture timed out\n");
}
if (abs(tap_delta_x) > 15 || abs(tap_delta_y) > 15) {
tap_started = false;
tap_clicks = 0;
}
if (tap_started || double_click) {
TRACE("ALPS: tap gesture\n");
tap_clicks++;
if (tap_clicks > 1) {
TRACE("ALPS: empty click\n");
buttons = 0x00;
tap_clicks = 0;
double_click = true;
} else {
buttons = 0x01;
tap_started = false;
tapdrag_started = true;
double_click = false;
}
}
movement->buttons = buttons;
_UpdateButtons(movement);
}
void
get_scrolling(movement_maker *move, uint32 posX, uint32 posY)
TouchpadMovement::_MoveToMovement(touch_event *event, mouse_movement *movement)
{
int32 stepsX = 0, stepsY = 0;
bool isStartOfMovement = false;
float pressure = 0;
get_raw_movement(move, posX, posY);
compute_acceleration(move, move->scroll_acceleration);
TRACE("ALPS: movement event\n");
if (!movement_started) {
isStartOfMovement = true;
movement_started = true;
StartNewMovment();
}
if (move->scrolling_xStep > 0) {
move->scrolling_x += move->xDelta;
GetMovement(event->xPosition, event->yPosition);
stepsX = make_small(move->scrolling_x / move->scrolling_xStep);
movement->xdelta = xDelta;
movement->ydelta = yDelta;
move->scrolling_x -= stepsX * move->scrolling_xStep;
move->xDelta = stepsX;
// tap gesture
tap_delta_x += xDelta;
tap_delta_y += yDelta;
if (tapdrag_started) {
movement->buttons = kLeftButton;
movement->clicks = 0;
valid_edge_motion = _EdgeMotion(movement, event, valid_edge_motion);
TRACE("ALPS: tap drag\n");
} else {
move->scrolling_x = 0;
move->xDelta = 0;
TRACE("ALPS: movement set buttons\n");
movement->buttons = event->buttons;
}
if (move->scrolling_yStep > 0) {
move->scrolling_y += move->yDelta;
stepsY = make_small(move->scrolling_y / move->scrolling_yStep);
move->scrolling_y -= stepsY * move->scrolling_yStep;
move->yDelta = -1 * stepsY;
} else {
move->scrolling_y = 0;
move->yDelta = 0;
// use only a fraction of pressure range, the max pressure seems to be
// to high
pressure = 20 * (event->zPressure - fSpecs->minPressure)
/ (fSpecs->realMaxPressure - fSpecs->minPressure);
if (!tap_started
&& isStartOfMovement
&& fSettings->tapgesture_sensibility > 0.
&& fSettings->tapgesture_sensibility > (20 - pressure)) {
TRACE("ALPS: tap started\n");
tap_started = true;
tap_time = system_time();
tap_delta_x = 0;
tap_delta_y = 0;
}
_UpdateButtons(movement);
}
void
start_new_movment(movement_maker *move)
/*! Checks if this is a scrolling event or not, and also actually does the
scrolling work if it is.
\return \c true if this was a scrolling event, \c false if not.
*/
bool
TouchpadMovement::_CheckScrollingToMovement(touch_event *event,
mouse_movement *movement)
{
if (move->scrolling_xStep <= 0)
move->scrolling_xStep = 1;
if (move->scrolling_yStep <= 0)
move->scrolling_yStep = 1;
bool isSideScrollingV = false;
bool isSideScrollingH = false;
move->movementStarted = true;
move->scrolling_x = 0;
move->scrolling_y = 0;
// if a button is pressed don't allow to scroll, we likely be in a drag
// action
if (buttons_state != 0)
return false;
if ((fSpecs->areaEndX - fAreaWidth * fSettings->scroll_rightrange
< event->xPosition && !movement_started
&& fSettings->scroll_rightrange > 0.000001)
|| fSettings->scroll_rightrange > 0.999999) {
isSideScrollingV = true;
}
if ((fSpecs->areaStartY + fAreaHeight * fSettings->scroll_bottomrange
> event->yPosition && !movement_started
&& fSettings->scroll_bottomrange > 0.000001)
|| fSettings->scroll_bottomrange > 0.999999) {
isSideScrollingH = true;
}
if ((event->wValue == 0 || event->wValue == 1)
&& fSettings->scroll_twofinger) {
// two finger scrolling is enabled
isSideScrollingV = true;
isSideScrollingH = fSettings->scroll_twofinger_horizontal;
}
if (!isSideScrollingV && !isSideScrollingH) {
scrolling_started = false;
return false;
}
TRACE("ALPS: scroll event\n");
tap_started = false;
tap_clicks = 0;
tapdrag_started = false;
valid_edge_motion = false;
if (!scrolling_started) {
scrolling_started = true;
StartNewMovment();
}
GetScrolling(event->xPosition, event->yPosition);
movement->wheel_ydelta = yDelta;
movement->wheel_xdelta = xDelta;
if (isSideScrollingV && !isSideScrollingH)
movement->wheel_xdelta = 0;
else if (isSideScrollingH && !isSideScrollingV)
movement->wheel_ydelta = 0;
buttons_state = movement->buttons;
return true;
}

View File

@ -3,38 +3,136 @@
#include <OS.h>
#include <keyboard_mouse_driver.h>
#include <touchpad_settings.h>
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;
bool movementStarted;
uint32 previousX;
uint32 previousY;
int32 deltaSumX;
int32 deltaSumY;
} movement_maker;
struct touch_event {
uint8 buttons;
uint32 xPosition;
uint32 yPosition;
uint8 zPressure;
// absolut mode (unused)
bool finger;
bool gesture;
// absolut w mode
uint8 wValue;
};
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);
struct hardware_specs {
uint16 edgeMotionWidth;
uint16 edgeMotionSpeedFactor;
uint16 areaStartX;
uint16 areaEndX;
uint16 areaStartY;
uint16 areaEndY;
uint16 minPressure;
// the value you reach when you hammer really hard on the touchpad
uint16 realMaxPressure;
uint16 maxPressure;
};
/*! The raw movement calculation is calibrated on ths synaptics touchpad. */
// increase the touchpad size a little bit
#define SYN_AREA_TOP_LEFT_OFFSET 40
#define SYN_AREA_BOTTOM_RIGHT_OFFSET 60
#define SYN_AREA_START_X (1472 - SYN_AREA_TOP_LEFT_OFFSET)
#define SYN_AREA_END_X (5472 + SYN_AREA_BOTTOM_RIGHT_OFFSET)
#define SYN_WIDTH (SYN_AREA_END_X - SYN_AREA_START_X)
#define SYN_AREA_START_Y (1408 - SYN_AREA_TOP_LEFT_OFFSET)
#define SYN_AREA_END_Y (4448 + SYN_AREA_BOTTOM_RIGHT_OFFSET)
#define SYN_HEIGHT (SYN_AREA_END_Y - SYN_AREA_START_Y)
class MovementMaker {
public:
void SetSettings(touchpad_settings* settings);
void SetSpecs(hardware_specs* specs);
int32 xDelta;
int32 yDelta;
float scrolling_x;
float scrolling_y;
protected:
void StartNewMovment();
void GetMovement(uint32 posX, uint32 posY);
void GetScrolling(uint32 posX, uint32 posY);
touchpad_settings* fSettings;
hardware_specs* fSpecs;
int8 fSpeed;
int16 fAreaWidth;
int16 fAreaHeight;
private:
void _GetRawMovement(uint32 posX, uint32 posY);
void _ComputeAcceleration(int8 accel_factor);
bool movementStarted;
uint32 previousX;
uint32 previousY;
int32 deltaSumX;
int32 deltaSumY;
int8 fSmallMovement;
};
enum button_ids
{
kLeftButton = 0x01,
kRightButton = 0x02
};
class TouchpadMovement : public MovementMaker {
public:
void Init();
status_t EventToMovement(touch_event *event,
mouse_movement *movement);
bigtime_t click_speed;
private:
bool _EdgeMotion(mouse_movement *movement,
touch_event *event, bool validStart);
inline void _UpdateButtons(mouse_movement *movement);
inline void _NoTouchToMovement(touch_event *event,
mouse_movement *movement);
inline void _MoveToMovement(touch_event *event,
mouse_movement *movement);
inline bool _CheckScrollingToMovement(touch_event *event,
mouse_movement *movement);
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;
bigtime_t click_last_time;
int32 click_count;
uint32 buttons_state;
};
#endif

View File

@ -15,8 +15,6 @@
#include <stdlib.h>
#include <string.h>
#include <keyboard_mouse_driver.h>
#include "ps2_service.h"
@ -28,13 +26,6 @@ const char* kALPSPath[4] = {
};
enum button_ids
{
kLeftButton = 0x01,
kRightButton = 0x02
};
typedef struct alps_model_info {
uint8 id[3];
uint8 firstByte;
@ -55,7 +46,7 @@ typedef struct alps_model_info {
// 6-byte ALPS packet
static const struct alps_model_info gALPSModelInfos[] = {
// {{0x32, 0x02, 0x14}, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT},
{{0x32, 0x02, 0x14}, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT},
// Toshiba Salellite Pro M10
// {{0x33, 0x02, 0x0a}, 0x88, 0xf8, ALPS_OLDPROTO},
// UMAX-530T
@ -65,29 +56,29 @@ static const struct alps_model_info gALPSModelInfos[] = {
// HP ze1115
{{0x63, 0x02, 0x0a}, 0xf8, 0xf8, 0},
{{0x63, 0x02, 0x14}, 0xf8, 0xf8, 0},
// {{0x63, 0x02, 0x28}, 0xf8, 0xf8, ALPS_FW_BK_2},
{{0x63, 0x02, 0x28}, 0xf8, 0xf8, ALPS_FW_BK_2},
// Fujitsu Siemens S6010
// {{0x63, 0x02, 0x3c}, 0x8f, 0x8f, ALPS_WHEEL},
// Toshiba Satellite S2400-103
// {{0x63, 0x02, 0x50}, 0xef, 0xef, ALPS_FW_BK_1},
{{0x63, 0x02, 0x50}, 0xef, 0xef, ALPS_FW_BK_1},
// NEC Versa L320
{{0x63, 0x02, 0x64}, 0xf8, 0xf8, 0},
// {{0x63, 0x03, 0xc8}, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT},
{{0x63, 0x03, 0xc8}, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT},
// Dell Latitude D800
{{0x73, 0x00, 0x0a}, 0xf8, 0xf8, ALPS_DUALPOINT},
// ThinkPad R61 8918-5QG, x301
{{0x73, 0x02, 0x0a}, 0xf8, 0xf8, 0},
// {{0x73, 0x02, 0x14}, 0xf8, 0xf8, ALPS_FW_BK_2},
{{0x73, 0x02, 0x14}, 0xf8, 0xf8, ALPS_FW_BK_2},
// Ahtec Laptop
// {{0x20, 0x02, 0x0e}, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT},
{{0x20, 0x02, 0x0e}, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT},
// XXX
// {{0x22, 0x02, 0x0a}, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT},
// {{0x22, 0x02, 0x14}, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT},
{{0x22, 0x02, 0x0a}, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT},
{{0x22, 0x02, 0x14}, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT},
// Dell Latitude D600
// {{0x62, 0x02, 0x14}, 0xcf, 0xcf, ALPS_PASS | ALPS_DUALPOINT
// | ALPS_PS2_INTERLEAVED},
// Dell Latitude E5500, E6400, E6500, Precision M4400
// {{0x73, 0x02, 0x50}, 0xcf, 0xcf, ALPS_FOUR_BUTTONS},
{{0x73, 0x02, 0x50}, 0xcf, 0xcf, ALPS_FOUR_BUTTONS},
// Dell Vostro 1400
// {{0x52, 0x01, 0x14}, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT
// | ALPS_PS2_INTERLEAVED},
@ -109,307 +100,23 @@ static alps_model_info* sFoundModel = NULL;
// touchpad proportions
#define SPEED_FACTOR 5
#define EDGE_MOTION_WIDTH 10
#define EDGE_MOTION_SPEED (5 * SPEED_FACTOR)
#define EDGE_MOTION_WIDTH 45
#define EDGE_MOTION_SPEED 4
// increase the touchpad size a little bit
#define AREA_START_X 50
#define AREA_END_X 985
#define AREA_WIDTH_X (AREA_END_X - AREA_START_X)
#define AREA_START_Y 45
#define AREA_END_Y 735
#define AREA_WIDTH_Y (AREA_END_Y - AREA_START_Y)
#define TAP_TIMEOUT 200000
#define AREA_START_X 40
#define AREA_END_X 987
#define AREA_START_Y 40
#define AREA_END_Y 733
#define MIN_PRESSURE 15
#define REAL_MAX_PRESSURE 70
#define MAX_PRESSURE 115
#define ALPS_HISTORY_SIZE 256
typedef struct {
uint8 buttons;
uint32 xPosition;
uint32 yPosition;
uint8 zPressure;
// absolut mode
bool finger;
// absolut w mode
uint8 wValue;
} touch_event;
static bool
edge_motion(mouse_movement *movement, touch_event *event, bool validStart)
{
int32 xdelta = 0;
int32 ydelta = 0;
if (event->xPosition < AREA_START_X + EDGE_MOTION_WIDTH)
xdelta = -EDGE_MOTION_SPEED;
else if (event->xPosition > AREA_END_X - EDGE_MOTION_WIDTH)
xdelta = EDGE_MOTION_SPEED;
if (event->yPosition < AREA_START_Y + EDGE_MOTION_WIDTH)
ydelta = -EDGE_MOTION_SPEED;
else if (event->yPosition > AREA_END_Y - EDGE_MOTION_WIDTH)
ydelta = EDGE_MOTION_SPEED;
if (xdelta && validStart)
movement->xdelta = xdelta;
if (ydelta && validStart)
movement->ydelta = ydelta;
if ((xdelta || ydelta) && !validStart)
return false;
return true;
}
/*! If a button has been clicked (movement->buttons must be set accordingly),
this function updates the click_count of the \a cookie, as well as the
\a movement's clicks field.
Also, it sets the cookie's button state from movement->buttons.
*/
static inline void
update_buttons(alps_cookie *cookie, mouse_movement *movement)
{
// set click count correctly according to double click timeout
if (movement->buttons != 0 && cookie->buttons_state == 0) {
if (cookie->click_last_time + cookie->click_speed > movement->timestamp)
cookie->click_count++;
else
cookie->click_count = 1;
cookie->click_last_time = movement->timestamp;
}
if (movement->buttons != 0)
movement->clicks = cookie->click_count;
cookie->buttons_state = movement->buttons;
}
static inline void
no_touch_to_movement(alps_cookie *cookie, touch_event *event,
mouse_movement *movement)
{
uint32 buttons = event->buttons;
TRACE("ALPS: no touch event\n");
cookie->scrolling_started = false;
cookie->movement_started = false;
if (cookie->tapdrag_started
&& (movement->timestamp - cookie->tap_time) < TAP_TIMEOUT) {
buttons = 0x01;
}
// if the movement stopped switch off the tap drag when timeout is expired
if ((movement->timestamp - cookie->tap_time) > TAP_TIMEOUT) {
cookie->tapdrag_started = false;
cookie->valid_edge_motion = false;
TRACE("ALPS: 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("ALPS: tap gesture\n");
cookie->tap_clicks++;
if (cookie->tap_clicks > 1) {
TRACE("ALPS: empty click\n");
buttons = 0x00;
cookie->tap_clicks = 0;
cookie->double_click = true;
} else {
buttons = 0x01;
cookie->tap_started = false;
cookie->tapdrag_started = true;
cookie->double_click = false;
}
}
movement->buttons = buttons;
update_buttons(cookie, movement);
}
static inline void
move_to_movement(alps_cookie *cookie, touch_event *event,
mouse_movement *movement)
{
touchpad_settings *settings = &cookie->settings;
bool isStartOfMovement = false;
float pressure = 0;
TRACE("ALPS: movement event\n");
if (!cookie->movement_started) {
isStartOfMovement = true;
cookie->movement_started = true;
start_new_movment(&cookie->movementMaker);
}
get_movement(&cookie->movementMaker, event->xPosition, event->yPosition);
movement->xdelta = cookie->movementMaker.xDelta;
movement->ydelta = cookie->movementMaker.yDelta;
// tap gesture
cookie->tap_delta_x += cookie->movementMaker.xDelta;
cookie->tap_delta_y += cookie->movementMaker.yDelta;
if (cookie->tapdrag_started) {
movement->buttons = kLeftButton;
movement->clicks = 0;
cookie->valid_edge_motion = edge_motion(movement, event,
cookie->valid_edge_motion);
TRACE("ALPS: tap drag\n");
} else {
TRACE("ALPS: movement set buttons\n");
movement->buttons = event->buttons;
}
// use only a fraction of pressure range, the max pressure seems to be
// to high
pressure = 20 * (event->zPressure - MIN_PRESSURE)
/ (MAX_PRESSURE - MIN_PRESSURE - 40);
if (!cookie->tap_started
&& isStartOfMovement
&& settings->tapgesture_sensibility > 0.
&& settings->tapgesture_sensibility > (20 - pressure)) {
TRACE("ALPS: tap started\n");
cookie->tap_started = true;
cookie->tap_time = system_time();
cookie->tap_delta_x = 0;
cookie->tap_delta_y = 0;
}
update_buttons(cookie, movement);
}
/*! Checks if this is a scrolling event or not, and also actually does the
scrolling work if it is.
\return \c true if this was a scrolling event, \c false if not.
*/
static inline bool
check_scrolling_to_movement(alps_cookie *cookie, touch_event *event,
mouse_movement *movement)
{
touchpad_settings *settings = &cookie->settings;
bool isSideScrollingV = false;
bool isSideScrollingH = false;
// if a button is pressed don't allow to scroll, we likely be in a drag
// action
if (cookie->buttons_state != 0)
return false;
if ((AREA_END_X - AREA_WIDTH_X * settings->scroll_rightrange
< event->xPosition && !cookie->movement_started
&& settings->scroll_rightrange > 0.000001)
|| settings->scroll_rightrange > 0.999999) {
isSideScrollingV = true;
}
if ((AREA_START_Y + AREA_WIDTH_Y * settings->scroll_bottomrange
> event->yPosition && !cookie->movement_started
&& settings->scroll_bottomrange > 0.000001)
|| settings->scroll_bottomrange > 0.999999) {
isSideScrollingH = true;
}
if ((event->wValue == 0 || event->wValue == 1)
&& settings->scroll_twofinger) {
// two finger scrolling is enabled
isSideScrollingV = true;
isSideScrollingH = settings->scroll_twofinger_horizontal;
}
if (!isSideScrollingV && !isSideScrollingH) {
cookie->scrolling_started = false;
return false;
}
TRACE("ALPS: 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->movementMaker);
}
get_scrolling(&cookie->movementMaker, event->xPosition,
event->yPosition);
movement->wheel_ydelta = cookie->movementMaker.yDelta;
movement->wheel_xdelta = cookie->movementMaker.xDelta;
if (isSideScrollingV && !isSideScrollingH)
movement->wheel_xdelta = 0;
else if (isSideScrollingH && !isSideScrollingV)
movement->wheel_ydelta = 0;
cookie->buttons_state = movement->buttons;
return true;
}
static status_t
event_to_movement(alps_cookie *cookie, touch_event *event,
mouse_movement *movement)
{
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 = system_time();
if ((movement->timestamp - cookie->tap_time) > TAP_TIMEOUT) {
TRACE("ALPS: tap gesture timed out\n");
cookie->tap_started = false;
if (!cookie->double_click
|| (movement->timestamp - cookie->tap_time) > 2 * TAP_TIMEOUT) {
cookie->tap_clicks = 0;
}
}
if (event->buttons & kLeftButton) {
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)) {
// The touch pad is in touch with at least one finger
if (!check_scrolling_to_movement(cookie, event, movement))
move_to_movement(cookie, event, movement);
} else
no_touch_to_movement(cookie, event, movement);
return B_OK;
}
static hardware_specs gHardwareSpecs;
/* Data taken from linux driver:
@ -450,7 +157,7 @@ get_alps_movment(alps_cookie *cookie, mouse_movement *movement)
return B_ERROR;
}
event.buttons = event_buffer[3] & 3;
event.buttons = event_buffer[3] & 7;
event.zPressure = event_buffer[5];
// finger on touchpad
@ -461,11 +168,16 @@ get_alps_movment(alps_cookie *cookie, mouse_movement *movement)
event.wValue = 3;
}
// tabgesture
// tab gesture
if (event_buffer[2] & 0x1) {
event.zPressure = 80;
event.zPressure = 60;
event.wValue = 4;
}
// if hardware tab gesture is off a z pressure of 16 is reported
//if (cookie->previousZ == 0 && event.wValue == 4 && event.zPressure == 16)
// event.zPressure = 60;
cookie->previousZ = event.zPressure;
event.xPosition = event_buffer[1] | ((event_buffer[2] & 0x78) << 4);
event.yPosition = event_buffer[4] | ((event_buffer[3] & 0x70) << 3);
@ -481,23 +193,24 @@ if (event.yPosition > maxY)
maxY = event.yPosition;
if (event.zPressure > maxZ)
maxZ = event.zPressure;
dprintf("x %i %i, y %i %i, z %i %i, fin %i ges %i\n", minX, maxX, minY, maxY,
maxZ, event.zPressure, event_buffer[2] & 0x2, event_buffer[2] & 0x1);
bigtime_t time = system_time();
dprintf("x %i %i, y %i %i, z %i %i, time %i, fin %i ges %i\n", minX, maxX, minY, maxY,
maxZ, event.zPressure, time, event_buffer[2] & 0x2,
event_buffer[2] & 0x1);
// debug end
event.yPosition = AREA_END_Y - event.yPosition;
status = event_to_movement(cookie, &event, movement);
// check for trackpoint even (z pressure 127)
if (sFoundModel->flags & ALPS_DUALPOINT && event.zPressure == 127) {
movement->xdelta = event.xPosition > 383 ? event.xPosition - 768
: event.xPosition;
event.yPosition = AREA_END_Y - event.yPosition;
movement->ydelta = event.yPosition > 255
? event.yPosition - 512 : event.yPosition;
event.yPosition = AREA_END_Y - event.yPosition;
movement->wheel_xdelta = 0;
movement->wheel_ydelta = 0;
movement->buttons = event.buttons;
} else {
event.yPosition = AREA_END_Y - (event.yPosition - AREA_START_Y);
status = cookie->movementMaker.EventToMovement(&event, movement);
}
return status;
}
@ -513,10 +226,11 @@ default_settings(touchpad_settings *set)
status_t
probe_alps(ps2_dev* dev)
{
return B_ERROR;
int i;
uint8 val[3];
TRACE("ALPS: probe\n");
return B_ERROR;
val[0] = 0;
if (ps2_dev_command(dev, PS2_MOUSE_CMD_SET_RES, val, 1, NULL, 0) != B_OK
|| ps2_dev_command(dev, PS2_MOUSE_CMD_SET_SCALE11, NULL, 0, NULL, 0)
@ -571,15 +285,48 @@ return B_ERROR;
}
status_t
switch_hardware_tab(ps2_dev* dev, bool on)
{
uint8 val[3];
uint8 arg = 0x00;
uint8 command = PS2_MOUSE_CMD_SET_RES;
if (on) {
arg = 0x0A;
command = PS2_MOUSE_CMD_SET_RATE;
}
if (ps2_dev_command(dev, PS2_MOUSE_CMD_GET_INFO, NULL, 0, val, 3) != B_OK
|| ps2_dev_command(dev, PS2_CMD_DISABLE, NULL, 0, NULL, 0) != B_OK
|| ps2_dev_command(dev, PS2_CMD_DISABLE, NULL, 0, NULL, 0) != B_OK
|| ps2_dev_command(dev, command, &arg, 1, NULL, 0) != B_OK)
return B_ERROR;
return B_OK;
}
status_t
enable_passthrough(ps2_dev* dev, bool on)
{
uint8 command = PS2_MOUSE_CMD_SET_SCALE11;
if (on)
command = PS2_MOUSE_CMD_SET_SCALE21;
if (ps2_dev_command(dev, command, NULL, 0, NULL, 0) != B_OK
|| ps2_dev_command(dev, command, NULL, 0, NULL, 0) != B_OK
|| ps2_dev_command(dev, command, NULL, 0, NULL, 0) != B_OK
|| ps2_dev_command(dev, PS2_CMD_DISABLE, NULL, 0, NULL, 0) != B_OK)
return B_ERROR;
return B_OK;
}
status_t
alps_open(const char *name, uint32 flags, void **_cookie)
{
alps_cookie *cookie;
ps2_dev *dev;
ps2_dev* dev;
int i;
uint8 val[3];
uint8 arg;
for (dev = NULL, i = 0; i < PS2_DEVICE_COUNT; i++) {
if (0 == strcmp(ps2_device[i].name, name)) {
dev = &ps2_device[i];
@ -595,12 +342,12 @@ alps_open(const char *name, uint32 flags, void **_cookie)
if (atomic_or(&dev->flags, PS2_FLAG_OPEN) & PS2_FLAG_OPEN)
return B_BUSY;
cookie = (alps_cookie*)malloc(sizeof(alps_cookie));
alps_cookie* cookie = (alps_cookie*)malloc(sizeof(alps_cookie));
if (cookie == NULL)
goto err1;
cookie->movementMaker.Init();
cookie->previousZ = 0;
*_cookie = cookie;
memset(cookie, 0, sizeof(alps_cookie));
cookie->dev = dev;
dev->cookie = cookie;
@ -609,21 +356,25 @@ alps_open(const char *name, uint32 flags, void **_cookie)
default_settings(&cookie->settings);
cookie->movementMaker.speed = 1 * SPEED_FACTOR;
cookie->movementMaker.scrolling_xStep = cookie->settings.scroll_xstepsize;
cookie->movementMaker.scrolling_yStep = cookie->settings.scroll_ystepsize;
cookie->movementMaker.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;
gHardwareSpecs.edgeMotionWidth = EDGE_MOTION_WIDTH;
gHardwareSpecs.edgeMotionSpeedFactor = EDGE_MOTION_SPEED;
gHardwareSpecs.areaStartX = AREA_START_X;
gHardwareSpecs.areaEndX = AREA_END_X;
gHardwareSpecs.areaStartY = AREA_START_Y;
gHardwareSpecs.areaEndY = AREA_END_Y;
gHardwareSpecs.minPressure = MIN_PRESSURE;
gHardwareSpecs.realMaxPressure = REAL_MAX_PRESSURE;
gHardwareSpecs.maxPressure = MAX_PRESSURE;
cookie->movementMaker.SetSettings(&cookie->settings);
cookie->movementMaker.SetSpecs(&gHardwareSpecs);
dev->packet_size = PS2_PACKET_ALPS;
cookie->ring_buffer
= create_packet_buffer(ALPS_HISTORY_SIZE * dev->packet_size);
cookie->ring_buffer = create_packet_buffer(
ALPS_HISTORY_SIZE * dev->packet_size);
if (cookie->ring_buffer == NULL) {
TRACE("ALPS: can't allocate mouse actions buffer\n");
goto err2;
@ -636,12 +387,12 @@ alps_open(const char *name, uint32 flags, void **_cookie)
goto err3;
}
if ((sFoundModel->flags & ALPS_PASS) != 0
&& enable_passthrough(dev, true) != B_OK)
goto err4;
// switch tap mode off
arg = 0x00;
if (ps2_dev_command(dev, PS2_MOUSE_CMD_GET_INFO, NULL, 0, val, 3) != B_OK
|| ps2_dev_command(dev, PS2_CMD_DISABLE, NULL, 0, NULL, 0) != B_OK
|| ps2_dev_command(dev, PS2_CMD_DISABLE, NULL, 0, NULL, 0) != B_OK
|| ps2_dev_command(dev, PS2_MOUSE_CMD_SET_RES, &arg, 1, NULL, 0) != B_OK)
if (switch_hardware_tab(dev, true) != B_OK)
goto err4;
// init the alps device to absolut mode
@ -652,6 +403,10 @@ alps_open(const char *name, uint32 flags, void **_cookie)
|| ps2_dev_command(dev, PS2_CMD_ENABLE, NULL, 0, NULL, 0) != B_OK)
goto err4;
if ((sFoundModel->flags & ALPS_PASS) != 0
&& enable_passthrough(dev, false) != B_OK)
goto err4;
if (ps2_dev_command(dev, PS2_MOUSE_CMD_SET_STREAM, NULL, 0, NULL, 0) != B_OK)
goto err4;
@ -735,17 +490,12 @@ alps_ioctl(void *_cookie, uint32 op, void *buffer, size_t length)
case MS_SET_TOUCHPAD_SETTINGS:
TRACE("ALPS: MS_SET_TOUCHPAD_SETTINGS");
user_memcpy(&cookie->settings, buffer, sizeof(touchpad_settings));
cookie->movementMaker.scrolling_xStep
= cookie->settings.scroll_xstepsize;
cookie->movementMaker.scrolling_yStep
= cookie->settings.scroll_ystepsize;
cookie->movementMaker.scroll_acceleration
= cookie->settings.scroll_acceleration;
return B_OK;
case MS_SET_CLICKSPEED:
TRACE("ALPS: ioctl MS_SETCLICK (set click speed)\n");
return user_memcpy(&cookie->click_speed, buffer, sizeof(bigtime_t));
return user_memcpy(&cookie->movementMaker.click_speed, buffer,
sizeof(bigtime_t));
default:
TRACE("ALPS: unknown opcode: %ld\n", op);
@ -777,8 +527,6 @@ alps_handle_int(ps2_dev *dev)
uint8 val;
val = cookie->dev->history[0].data;
//dprintf("%i %i %i %i %i %i %i %i\n", (val >> 7) & 0x1, (val >> 6) & 0x1, (val >> 5) & 0x1, (val >> 4) & 0x1, (val >> 3) & 0x1,
// (val >> 2) & 0x1, (val >> 1) & 0x1, (val >> 0) & 0x1);
if (cookie->packet_index == 0
&& (val & sFoundModel->maskFirstByte) != sFoundModel->firstByte) {
INFO("ALPS: bad header, trying resync\n");

View File

@ -19,22 +19,8 @@ struct packet_buffer* ring_buffer;
uint8 buffer[PS2_PACKET_ALPS];
uint8 mode;
movement_maker movementMaker;
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;
bigtime_t click_last_time;
bigtime_t click_speed;
int32 click_count;
uint32 buttons_state;
uint8 previousZ;
TouchpadMovement movementMaker;
touchpad_settings settings;
} alps_cookie;

View File

@ -13,7 +13,6 @@
#include "ps2_synaptics.h"
#include <malloc.h>
#include <string.h>
#include <stdlib.h>
@ -22,6 +21,19 @@
#include "ps2_service.h"
// synaptics touchpad proportions
#define SYN_EDGE_MOTION_WIDTH 50
#define SYN_EDGE_MOTION_SPEED 5
#define SYN_AREA_OFFSET 40
#define MIN_PRESSURE 30
#define REAL_MAX_PRESSURE 100
#define MAX_PRESSURE 200
static hardware_specs gHardwareSpecs;
const char* kSynapticsPath[4] = {
"input/touchpad/ps2/synaptics_0",
"input/touchpad/ps2/synaptics_1",
@ -71,278 +83,6 @@ set_touchpad_mode(ps2_dev *dev, uint8 mode)
}
static 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;
}
/*! If a button has been clicked (movement->buttons must be set accordingly),
this function updates the click_count of the \a cookie, as well as the
\a movement's clicks field.
Also, it sets the cookie's button state from movement->buttons.
*/
static inline void
update_buttons(synaptics_cookie *cookie, mouse_movement *movement)
{
// set click count correctly according to double click timeout
if (movement->buttons != 0 && cookie->buttons_state == 0) {
if (cookie->click_last_time + cookie->click_speed > movement->timestamp)
cookie->click_count++;
else
cookie->click_count = 1;
cookie->click_last_time = movement->timestamp;
}
if (movement->buttons != 0)
movement->clicks = cookie->click_count;
cookie->buttons_state = movement->buttons;
}
static inline void
no_touch_to_movement(synaptics_cookie *cookie, touch_event *event,
mouse_movement *movement)
{
uint32 buttons = event->buttons;
TRACE("SYNAPTICS: no touch event\n");
cookie->scrolling_started = false;
cookie->movement_started = false;
if (cookie->tapdrag_started
&& (movement->timestamp - cookie->tap_time) < SYN_TAP_TIMEOUT) {
buttons = 0x01;
}
// if the movement stopped switch off the tap drag when timeout is expired
if ((movement->timestamp - 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");
buttons = 0x00;
cookie->tap_clicks = 0;
cookie->double_click = true;
} else {
buttons = 0x01;
cookie->tap_started = false;
cookie->tapdrag_started = true;
cookie->double_click = false;
}
}
movement->buttons = buttons;
update_buttons(cookie, movement);
}
static inline void
move_to_movement(synaptics_cookie *cookie, touch_event *event,
mouse_movement *movement)
{
touchpad_settings *settings = &cookie->settings;
bool isStartOfMovement = false;
float pressure = 0;
TRACE("SYNAPTICS: movement event\n");
if (!cookie->movement_started) {
isStartOfMovement = true;
cookie->movement_started = true;
start_new_movment(&cookie->movementMaker);
}
get_movement(&cookie->movementMaker, event->xPosition, event->yPosition);
movement->xdelta = cookie->movementMaker.xDelta;
movement->ydelta = cookie->movementMaker.yDelta;
// tap gesture
cookie->tap_delta_x += cookie->movementMaker.xDelta;
cookie->tap_delta_y += cookie->movementMaker.yDelta;
if (cookie->tapdrag_started) {
movement->buttons = kLeftButton;
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
pressure = 20 * (event->zPressure - MIN_PRESSURE)
/ (MAX_PRESSURE - MIN_PRESSURE - 100);
if (!cookie->tap_started
&& isStartOfMovement
&& settings->tapgesture_sensibility > 0.
&& settings->tapgesture_sensibility > (20 - pressure)) {
TRACE("SYNAPTICS: tap started\n");
cookie->tap_started = true;
cookie->tap_time = system_time();
cookie->tap_delta_x = 0;
cookie->tap_delta_y = 0;
}
update_buttons(cookie, movement);
}
/*! Checks if this is a scrolling event or not, and also actually does the
scrolling work if it is.
\return \c true if this was a scrolling event, \c false if not.
*/
static inline bool
check_scrolling_to_movement(synaptics_cookie *cookie, touch_event *event,
mouse_movement *movement)
{
touchpad_settings *settings = &cookie->settings;
bool isSideScrollingV = false;
bool isSideScrollingH = false;
// if a button is pressed don't allow to scroll, we likely be in a drag
// action
if (cookie->buttons_state != 0)
return false;
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 ((event->wValue == 0 || event->wValue == 1)
&& settings->scroll_twofinger) {
// two finger scrolling is enabled
isSideScrollingV = true;
isSideScrollingH = settings->scroll_twofinger_horizontal;
}
if (!isSideScrollingV && !isSideScrollingH) {
cookie->scrolling_started = false;
return false;
}
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->movementMaker);
}
get_scrolling(&cookie->movementMaker, event->xPosition,
event->yPosition);
movement->wheel_ydelta = cookie->movementMaker.yDelta;
movement->wheel_xdelta = cookie->movementMaker.xDelta;
if (isSideScrollingV && !isSideScrollingH)
movement->wheel_xdelta = 0;
else if (isSideScrollingH && !isSideScrollingV)
movement->wheel_ydelta = 0;
cookie->buttons_state = movement->buttons;
return true;
}
static status_t
event_to_movement(synaptics_cookie *cookie, touch_event *event,
mouse_movement *movement)
{
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 = system_time();
if ((movement->timestamp - cookie->tap_time) > SYN_TAP_TIMEOUT) {
TRACE("SYNAPTICS: tap gesture timed out\n");
cookie->tap_started = false;
if (!cookie->double_click
|| (movement->timestamp - cookie->tap_time) > 2 * SYN_TAP_TIMEOUT) {
cookie->tap_clicks = 0;
}
}
if (event->buttons & kLeftButton) {
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)) {
// The touch pad is in touch with at least one finger
if (!check_scrolling_to_movement(cookie, event, movement))
move_to_movement(cookie, event, movement);
} else
no_touch_to_movement(cookie, event, movement);
return B_OK;
}
static status_t
get_synaptics_movment(synaptics_cookie *cookie, mouse_movement *movement)
{
@ -406,7 +146,7 @@ get_synaptics_movment(synaptics_cookie *cookie, mouse_movement *movement)
yTwelfBit = event_buffer[3] >> 5 & 1;
event.yPosition += yTwelfBit << 12;
status = event_to_movement(cookie, &event, movement);
status = cookie->movementMaker.EventToMovement(&event, movement);
return status;
}
@ -592,9 +332,8 @@ synaptics_open(const char *name, uint32 flags, void **_cookie)
cookie = (synaptics_cookie*)malloc(sizeof(synaptics_cookie));
if (cookie == NULL)
goto err1;
cookie->movementMaker.Init();
*_cookie = cookie;
memset(cookie, 0, sizeof(synaptics_cookie));
cookie->dev = dev;
dev->cookie = cookie;
@ -603,16 +342,20 @@ synaptics_open(const char *name, uint32 flags, void **_cookie)
default_settings(&cookie->settings);
cookie->movementMaker.speed = 1;
cookie->movementMaker.scrolling_xStep = cookie->settings.scroll_xstepsize;
cookie->movementMaker.scrolling_yStep = cookie->settings.scroll_ystepsize;
cookie->movementMaker.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;
gHardwareSpecs.edgeMotionWidth = SYN_EDGE_MOTION_WIDTH;
gHardwareSpecs.edgeMotionSpeedFactor = SYN_EDGE_MOTION_SPEED;
gHardwareSpecs.areaStartX = SYN_AREA_START_X;
gHardwareSpecs.areaEndX = SYN_AREA_END_X;
gHardwareSpecs.areaStartY = SYN_AREA_START_Y;
gHardwareSpecs.areaEndY = SYN_AREA_END_Y;
gHardwareSpecs.minPressure = MIN_PRESSURE;
gHardwareSpecs.realMaxPressure = REAL_MAX_PRESSURE;
gHardwareSpecs.maxPressure = MAX_PRESSURE;
cookie->movementMaker.SetSettings(&cookie->settings);
cookie->movementMaker.SetSpecs(&gHardwareSpecs);
dev->packet_size = PS2_PACKET_SYNAPTICS;
@ -754,17 +497,12 @@ synaptics_ioctl(void *_cookie, uint32 op, void *buffer, size_t length)
case MS_SET_TOUCHPAD_SETTINGS:
TRACE("SYNAPTICS: MS_SET_TOUCHPAD_SETTINGS");
user_memcpy(&cookie->settings, buffer, sizeof(touchpad_settings));
cookie->movementMaker.scrolling_xStep
= cookie->settings.scroll_xstepsize;
cookie->movementMaker.scrolling_yStep
= cookie->settings.scroll_ystepsize;
cookie->movementMaker.scroll_acceleration
= cookie->settings.scroll_acceleration;
return B_OK;
case MS_SET_CLICKSPEED:
TRACE("SYNAPTICS: ioctl MS_SETCLICK (set click speed)\n");
return user_memcpy(&cookie->click_speed, buffer, sizeof(bigtime_t));
return user_memcpy(&cookie->movementMaker.click_speed, buffer,
sizeof(bigtime_t));
default:
TRACE("SYNAPTICS: unknown opcode: %ld\n", op);

View File

@ -31,25 +31,6 @@
#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_TOP_LEFT_OFFSET 40
#define SYN_AREA_BOTTOM_RIGHT_OFFSET 60
#define SYN_AREA_START_X (1472 - SYN_AREA_TOP_LEFT_OFFSET)
#define SYN_AREA_END_X (5472 + SYN_AREA_BOTTOM_RIGHT_OFFSET)
#define SYN_AREA_WIDTH_X (SYN_AREA_END_X - SYN_AREA_START_X)
#define SYN_AREA_START_Y (1408 - SYN_AREA_TOP_LEFT_OFFSET)
#define SYN_AREA_END_Y (4448 + SYN_AREA_BOTTOM_RIGHT_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
@ -70,26 +51,6 @@ typedef struct {
} touchpad_info;
enum button_ids
{
kLeftButton = 0x01,
kRightButton = 0x02
};
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;
@ -99,22 +60,7 @@ struct packet_buffer* synaptics_ring_buffer;
uint8 buffer[PS2_PACKET_SYNAPTICS];
uint8 mode;
movement_maker movementMaker;
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;
bigtime_t click_last_time;
bigtime_t click_speed;
int32 click_count;
uint32 buttons_state;
TouchpadMovement movementMaker;
touchpad_settings settings;
} synaptics_cookie;