diff --git a/hw/kdrive/linux/tslib.c b/hw/kdrive/linux/tslib.c index c4caff9..3b9174b 100644 --- a/hw/kdrive/linux/tslib.c +++ b/hw/kdrive/linux/tslib.c @@ -100,8 +100,6 @@ { KdMouseInfo *mi = closure; struct ts_sample event; - long x, y; - unsigned long flags; if (tslib_raw_event_hook) { @@ -116,14 +114,107 @@ return; } +#define SCROLL_TIMEOUT 200 /* after this many ms of holding, we drag, not scroll */ +#define SCROLL_RSQ 400 /* sqrt(thismuch) pixel motion triggers scrolling */ +#define SCROLL_THRESHOLD 8 /* Once we're scrolling, need to move at least this many pixels to react */ while (ts_read(tsDev, &event, 1) == 1) { - flags = (event.pressure) ? KD_BUTTON_1 : 0; - x = event.x; - y = event.y; - - KdEnqueueMouseEvent (mi, flags, x, y); + // click/drag if + // 1. release event comes before timeout AND we stayed in a small area. + // In this case press, release events are both sent at release + // 2. release event comes after the timeout. + // In this case, press comes at timeout, release comes at release + // Scroll happens in all other cases. These are large, fast motions: + // 1. release event comes before timeout, but there was + // considerable motion. + // In this case, the scrolling starts at the original press + // location, as soon as we leave the area + // + // In other words: + // 1. As soon as we leave the area, scroll + // 2. As soon as we timeout, drag + // 3. If we release before #1 or #2 happen, click + // 4. No events before one of these occurs + static int pressedNow = 0; + static int wherePressedX, wherePressedY; + static int scrollLastX, scrollLastY; + static CARD32 whenPressed; + static int scrolling, dragging; + if( event.pressure ) + { + if( !pressedNow ) + { + // first press + whenPressed = GetTimeInMillis(); + wherePressedX = scrollLastX = event.x; + wherePressedY = scrollLastY = event.y; + scrolling = dragging = FALSE; + } + else + { + // still pressed + if(!scrolling && !dragging) + { + if(GetTimeInMillis() - whenPressed > SCROLL_TIMEOUT) + dragging = TRUE; + else + { + unsigned int dx = event.x - wherePressedX; + unsigned int dy = event.y - wherePressedY; + if(dx*dx + dy*dy > SCROLL_RSQ) + scrolling = TRUE; + } + } + if(scrolling) + { + int dx = event.x - scrollLastX; + int dy = event.y - scrollLastY; + unsigned int dx2 = dx*dx; + unsigned int dy2 = dy*dy; + + if(dx2 > SCROLL_THRESHOLD*SCROLL_THRESHOLD || + dy2 > SCROLL_THRESHOLD*SCROLL_THRESHOLD) + { + if( dy2 >= dx2 ) + { + if(dy > 0) + KdEnqueueMouseEvent (mi, KD_BUTTON_4, wherePressedX, wherePressedY); + else + KdEnqueueMouseEvent (mi, KD_BUTTON_5, wherePressedX, wherePressedY); + } + else + { + if(dx > 0) + KdEnqueueMouseEvent (mi, KD_BUTTON_6, wherePressedX, wherePressedY); + else + KdEnqueueMouseEvent (mi, KD_BUTTON_7, wherePressedX, wherePressedY); + } + KdEnqueueMouseEvent (mi, 0, wherePressedX, wherePressedY); + + scrollLastX = event.x; + scrollLastY = event.y; + } + + } + else if(dragging) + { + KdEnqueueMouseEvent (mi, KD_BUTTON_1, event.x, event.y); + } + + } + } + else + { + // release event + // If we haven't sent a press event yet, do that + if(!scrolling && !dragging) + KdEnqueueMouseEvent (mi, KD_BUTTON_1, event.x, event.y); + if(!scrolling) + KdEnqueueMouseEvent (mi, 0, event.x, event.y); + } + + pressedNow = event.pressure; } } diff --git a/hw/kdrive/src/kdrive.h b/hw/kdrive/src/kdrive.h index 04078a0..3259fbc 100644 --- a/hw/kdrive/src/kdrive.h +++ b/hw/kdrive/src/kdrive.h @@ -728,6 +728,8 @@ KdEnqueueKeyboardEvent(unsigned char scan_code, #define KD_BUTTON_3 0x04 #define KD_BUTTON_4 0x08 #define KD_BUTTON_5 0x10 +#define KD_BUTTON_6 0x20 +#define KD_BUTTON_7 0x40 #define KD_MOUSE_DELTA 0x80000000 void diff --git a/hw/kdrive/src/kinput.c b/hw/kdrive/src/kinput.c index a655181..f1f4db2 100644 --- a/hw/kdrive/src/kinput.c +++ b/hw/kdrive/src/kinput.c @@ -1484,7 +1484,7 @@ KdEnqueueMouseEvent(KdMouseInfo *mi, unsigned long flags, int rx, int ry) buttons = flags; - for (button = KD_BUTTON_1, n = 0; button <= KD_BUTTON_5; button <<= 1, n++) + for (button = KD_BUTTON_1, n = 0; button <= KD_BUTTON_7; button <<= 1, n++) { if ((mi->buttonState & button) ^ (buttons & button)) {