Author: czeidler Date: 2011-03-30 11:37:40 +0200 (Wed, 30 Mar 2011) New Revision: 41140 Changeset: https://dev.haiku-os.org/changeset/41140 Modified: haiku/trunk/src/add-ons/kernel/bus_managers/ps2/movement_maker.cpp haiku/trunk/src/add-ons/kernel/bus_managers/ps2/movement_maker.h haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_alps.cpp haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_alps.h haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_synaptics.cpp haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_synaptics.h Log: - 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. Modified: haiku/trunk/src/add-ons/kernel/bus_managers/ps2/movement_maker.cpp =================================================================== --- haiku/trunk/src/add-ons/kernel/bus_managers/ps2/movement_maker.cpp 2011-03-29 22:51:41 UTC (rev 41139) +++ haiku/trunk/src/add-ons/kernel/bus_managers/ps2/movement_maker.cpp 2011-03-30 09:37:40 UTC (rev 41140) @@ -1,12 +1,24 @@ #include "movement_maker.h" -#include <Debug.h> +#include <stdlib.h> + +#include <KernelExport.h> + + #if 1 # define INFO(x...) dprintf(x) #else # define INFO(x...) #endif +// #define TRACE_MOVEMENT_MAKER +#ifdef TRACE_MOVEMENT_MAKER +# define TRACE(x...) dprintf(x) +#else +# define TRACE(x...) +#endif + + typedef union { float value; /* FIXME: Assumes 32 bit int. */ @@ -173,142 +185,460 @@ } + 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 -get_movement(movement_maker *move, uint32 posX, uint32 posY) +TouchpadMovement::Init() { - get_raw_movement(move, posX, posY); + movement_started = false; + scrolling_started = false; + tap_started = false; + valid_edge_motion = false; + double_click = false; +} -// 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); - move->xDelta = move->xDelta * move->speed; - move->yDelta = move->yDelta * move->speed; +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 -get_scrolling(movement_maker *move, uint32 posX, uint32 posY) +TouchpadMovement::_UpdateButtons(mouse_movement *movement) { - int32 stepsX = 0, stepsY = 0; + // 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; - get_raw_movement(move, posX, posY); - compute_acceleration(move, move->scroll_acceleration); + click_last_time = movement->timestamp; + } - if (move->scrolling_xStep > 0) { - move->scrolling_x += move->xDelta; + if (movement->buttons != 0) + movement->clicks = click_count; - stepsX = make_small(move->scrolling_x / move->scrolling_xStep); + buttons_state = movement->buttons; +} - move->scrolling_x -= stepsX * move->scrolling_xStep; - move->xDelta = stepsX; - } else { - move->scrolling_x = 0; - move->xDelta = 0; + +void +TouchpadMovement::_NoTouchToMovement(touch_event *event, + mouse_movement *movement) +{ + uint32 buttons = event->buttons; + + TRACE("ALPS: no touch event\n"); + + scrolling_started = false; + movement_started = false; + + if (tapdrag_started + && (movement->timestamp - tap_time) < TAP_TIMEOUT) { + buttons = 0x01; } - if (move->scrolling_yStep > 0) { - move->scrolling_y += move->yDelta; - stepsY = make_small(move->scrolling_y / move->scrolling_yStep); + // 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"); + } - move->scrolling_y -= stepsY * move->scrolling_yStep; - move->yDelta = -1 * stepsY; - } else { - move->scrolling_y = 0; - move->yDelta = 0; + 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 -start_new_movment(movement_maker *move) +TouchpadMovement::_MoveToMovement(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 isStartOfMovement = false; + float pressure = 0; - move->movementStarted = true; - move->scrolling_x = 0; - move->scrolling_y = 0; + TRACE("ALPS: movement event\n"); + if (!movement_started) { + isStartOfMovement = true; + movement_started = true; + StartNewMovment(); + } + + GetMovement(event->xPosition, event->yPosition); + + movement->xdelta = xDelta; + movement->ydelta = yDelta; + + // 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 { + 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 - 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); } + +/*! 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) +{ + bool isSideScrollingV = false; + bool isSideScrollingH = false; + + // 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; +} Modified: haiku/trunk/src/add-ons/kernel/bus_managers/ps2/movement_maker.h =================================================================== --- haiku/trunk/src/add-ons/kernel/bus_managers/ps2/movement_maker.h 2011-03-29 22:51:41 UTC (rev 41139) +++ haiku/trunk/src/add-ons/kernel/bus_managers/ps2/movement_maker.h 2011-03-30 09:37:40 UTC (rev 41140) @@ -3,38 +3,136 @@ #include <OS.h> +#include <keyboard_mouse_driver.h> +#include <touchpad_settings.h> + float floorf(float x); float ceilf(float x); float sqrtf(float x); int32 make_small(float value); -typedef struct { - int32 xDelta; - int32 yDelta; - int8 acceleration; - int8 speed; +struct touch_event { + uint8 buttons; + uint32 xPosition; + uint32 yPosition; + uint8 zPressure; + // absolut mode (unused) + bool finger; + bool gesture; + // absolut w mode + uint8 wValue; +}; - 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 hardware_specs { + uint16 edgeMotionWidth; + uint16 edgeMotionSpeedFactor; + uint16 areaStartX; + uint16 areaEndX; + uint16 areaStartY; + uint16 areaEndY; -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); + 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 Modified: haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_alps.cpp =================================================================== --- haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_alps.cpp 2011-03-29 22:51:41 UTC (rev 41139) +++ haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_alps.cpp 2011-03-30 09:37:40 UTC (rev 41140) @@ -15,8 +15,6 @@ #include <stdlib.h> #include <string.h> -#include <keyboard_mouse_driver.h> - #include "ps2_service.h" @@ -28,13 +26,6 @@ }; -enum button_ids -{ - kLeftButton = 0x01, - kRightButton = 0x02 -}; - - typedef struct alps_model_info { uint8 id[3]; uint8 firstByte; @@ -55,7 +46,7 @@ // 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 @@ // 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,309 +100,25 @@ // 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 AREA_START_X 40 +#define AREA_END_X 987 +#define AREA_START_Y 40 +#define AREA_END_Y 733 -#define TAP_TIMEOUT 200000 - #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 hardware_specs gHardwareSpecs; -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. -*/ [... truncated: 852 lines follow ...]