From c152c70b467536ee3e54c43674f70e1f849c4532 Mon Sep 17 00:00:00 2001 From: Clemens Zeidler Date: Wed, 30 Mar 2011 09:37:40 +0000 Subject: [PATCH] - 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 --- .../bus_managers/ps2/movement_maker.cpp | 464 +++++++++++++++--- .../kernel/bus_managers/ps2/movement_maker.h | 144 +++++- .../kernel/bus_managers/ps2/ps2_alps.cpp | 460 ++++------------- .../kernel/bus_managers/ps2/ps2_alps.h | 18 +- .../kernel/bus_managers/ps2/ps2_synaptics.cpp | 324 ++---------- .../kernel/bus_managers/ps2/ps2_synaptics.h | 56 +-- 6 files changed, 656 insertions(+), 810 deletions(-) diff --git a/src/add-ons/kernel/bus_managers/ps2/movement_maker.cpp b/src/add-ons/kernel/bus_managers/ps2/movement_maker.cpp index 4c350a9588..60d1e9164b 100644 --- a/src/add-ons/kernel/bus_managers/ps2/movement_maker.cpp +++ b/src/add-ons/kernel/bus_managers/ps2/movement_maker.cpp @@ -1,12 +1,24 @@ #include "movement_maker.h" -#include +#include + +#include + + #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; } - diff --git a/src/add-ons/kernel/bus_managers/ps2/movement_maker.h b/src/add-ons/kernel/bus_managers/ps2/movement_maker.h index 9f92e77ef1..a5813297e9 100644 --- a/src/add-ons/kernel/bus_managers/ps2/movement_maker.h +++ b/src/add-ons/kernel/bus_managers/ps2/movement_maker.h @@ -3,38 +3,136 @@ #include +#include +#include + 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 diff --git a/src/add-ons/kernel/bus_managers/ps2/ps2_alps.cpp b/src/add-ons/kernel/bus_managers/ps2/ps2_alps.cpp index cb5b73b2f4..d02bece9b4 100644 --- a/src/add-ons/kernel/bus_managers/ps2/ps2_alps.cpp +++ b/src/add-ons/kernel/bus_managers/ps2/ps2_alps.cpp @@ -15,8 +15,6 @@ #include #include -#include - #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"); diff --git a/src/add-ons/kernel/bus_managers/ps2/ps2_alps.h b/src/add-ons/kernel/bus_managers/ps2/ps2_alps.h index 8cb6165923..bd74665aab 100644 --- a/src/add-ons/kernel/bus_managers/ps2/ps2_alps.h +++ b/src/add-ons/kernel/bus_managers/ps2/ps2_alps.h @@ -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; diff --git a/src/add-ons/kernel/bus_managers/ps2/ps2_synaptics.cpp b/src/add-ons/kernel/bus_managers/ps2/ps2_synaptics.cpp index 2c6a4e9c03..a3776754cc 100644 --- a/src/add-ons/kernel/bus_managers/ps2/ps2_synaptics.cpp +++ b/src/add-ons/kernel/bus_managers/ps2/ps2_synaptics.cpp @@ -13,7 +13,6 @@ #include "ps2_synaptics.h" -#include #include #include @@ -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); diff --git a/src/add-ons/kernel/bus_managers/ps2/ps2_synaptics.h b/src/add-ons/kernel/bus_managers/ps2/ps2_synaptics.h index 8cb30ef619..1483bbd506 100644 --- a/src/add-ons/kernel/bus_managers/ps2/ps2_synaptics.h +++ b/src/add-ons/kernel/bus_managers/ps2/ps2_synaptics.h @@ -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;