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;