Exemplo n.º 1
0
static void
handle_touch_event (GdkWindow           *window,
                    const MirTouchEvent *mir_touch_event)
{
  const MirInputEvent *mir_input_event = mir_touch_event_input_event (mir_touch_event);
  guint n = mir_touch_event_point_count (mir_touch_event);
  GdkEvent *gdk_event;
  guint i;

  for (i = 0; i < n; i++)
    {
      MirTouchAction action = mir_touch_event_action (mir_touch_event, i);
      if (action == mir_touch_action_up)
        gdk_event = gdk_event_new (GDK_TOUCH_END);
      else if (action == mir_touch_action_down)
        gdk_event = gdk_event_new (GDK_TOUCH_BEGIN);
      else
        gdk_event = gdk_event_new (GDK_TOUCH_UPDATE);

      gdk_event->touch.window = window;
      gdk_event->touch.sequence = GINT_TO_POINTER (mir_touch_event_id (mir_touch_event, i));
      gdk_event->touch.time = mir_input_event_get_event_time (mir_input_event);
      gdk_event->touch.state = get_modifier_state (mir_touch_event_modifiers (mir_touch_event), 0);
      gdk_event->touch.x = mir_touch_event_axis_value (mir_touch_event, i, mir_touch_axis_x);
      gdk_event->touch.y = mir_touch_event_axis_value (mir_touch_event, i, mir_touch_axis_y);
      gdk_event->touch.x_root = mir_touch_event_axis_value (mir_touch_event, i, mir_touch_axis_x);
      gdk_event->touch.y_root = mir_touch_event_axis_value (mir_touch_event, i, mir_touch_axis_y);
      gdk_event->touch.emulating_pointer = TRUE;
      gdk_event_set_pointer_emulated (gdk_event, TRUE);

      send_event (window, get_pointer (window), gdk_event);
    }
}
Exemplo n.º 2
0
// This is the core of the touch validator. Given a valid event 'last_ev' which was the last_event to be dispatched
// this function must dispatch events such that 'ev' is a valid event to dispatch.
// Our requirements for touch validity are simple:
//     1. A touch point (unique per ID) can not vanish without being released.
//     2. A touch point can not appear without coming down.
// Our algorithm to ensure a candidate event can be dispatched is as follows:
//
//     First we look at the last event to build a set of expected touch ID's. That is to say
// each touch point in the last event which did not have touch_action_up (signifying its dissapearance)
// is expected to be in the candidate event. Likewise we go through the candidate event can produce a set of events
// we have found.
//
//     We now check for expected events which were not found, e.g. touch points which are missing a release.
// For each of these touch points we can take the coordinates for these points from the last event
// and dispatch an event which releases the missing point.
//
//     Now we check for found touch points which were not expected. If these show up with mir_touch_action_down
// things are fine. On the other hand if they show up with mir_touch_action_change then a touch point
// has appeared before its gone down and thus we must inject an event signifying this touch going down.
void mi::Validator::ensure_stream_validity_locked(std::lock_guard<std::mutex> const&,
    MirTouchEvent const* ev, MirTouchEvent const* last_ev)
{
    TouchSet expected;
    for (size_t i = 0; i < mir_touch_event_point_count(last_ev); i++)
    {
        auto action = mir_touch_event_action(last_ev, i);
        if (action == mir_touch_action_up)
            continue;
        expected.insert(mir_touch_event_id(last_ev, i));
    }

    TouchSet found;
    for (size_t i = 0; i < mir_touch_event_point_count(ev); i++)
    {
        auto id = mir_touch_event_id(ev, i);
        found.insert(id);
    }

    // Insert missing touch releases
    auto last_ev_copy =
        remove_old_releases_from(reinterpret_cast<MirEvent const*>(last_ev));
    for (auto const& expected_id : expected)
    {
        if (found.find(expected_id) == found.end())
        {
            auto inject_ev = add_missing_up(last_ev_copy.get(), expected_id);
            dispatch_valid_event(*inject_ev);
            last_ev_copy = remove_old_releases_from(inject_ev.get());
        }
    }

    for (size_t i = 0; i < mir_touch_event_point_count(ev); i++)
    {
        auto id = mir_touch_event_id(ev, i);
        if (expected.find(id) == expected.end() &&
            mir_touch_event_action(ev, i) != mir_touch_action_down)
        {
            
            auto inject_ev = add_missing_down(last_ev_copy.get(), ev, id);
            dispatch_valid_event(*inject_ev);
            last_ev_copy = std::move(inject_ev);
        }
    }
}
Exemplo n.º 3
0
void QMirClientInput::dispatchTouchEvent(QMirClientWindow *window, const MirInputEvent *ev)
{
    const MirTouchEvent *tev = mir_input_event_get_touch_event(ev);

    // FIXME(loicm) Max pressure is device specific. That one is for the Samsung Galaxy Nexus. That
    //     needs to be fixed as soon as the compat input lib adds query support.
    const float kMaxPressure = 1.28;
    const QRect kWindowGeometry = window->geometry();
    QList<QWindowSystemInterface::TouchPoint> touchPoints;


    // TODO: Is it worth setting the Qt::TouchPointStationary ones? Currently they are left
    //       as Qt::TouchPointMoved
    const unsigned int kPointerCount = mir_touch_event_point_count(tev);
    touchPoints.reserve(int(kPointerCount));
    for (unsigned int i = 0; i < kPointerCount; ++i) {
        QWindowSystemInterface::TouchPoint touchPoint;

        const float kX = mir_touch_event_axis_value(tev, i, mir_touch_axis_x) + kWindowGeometry.x();
        const float kY = mir_touch_event_axis_value(tev, i, mir_touch_axis_y) + kWindowGeometry.y(); // see bug lp:1346633 workaround comments elsewhere
        const float kW = mir_touch_event_axis_value(tev, i, mir_touch_axis_touch_major);
        const float kH = mir_touch_event_axis_value(tev, i, mir_touch_axis_touch_minor);
        const float kP = mir_touch_event_axis_value(tev, i, mir_touch_axis_pressure);
        touchPoint.id = mir_touch_event_id(tev, i);
        touchPoint.normalPosition = QPointF(kX / kWindowGeometry.width(), kY / kWindowGeometry.height());
        touchPoint.area = QRectF(kX - (kW / 2.0), kY - (kH / 2.0), kW, kH);
        touchPoint.pressure = kP / kMaxPressure;

        MirTouchAction touch_action = mir_touch_event_action(tev, i);
        switch (touch_action)
        {
        case mir_touch_action_down:
            mLastInputWindow = window;
            touchPoint.state = Qt::TouchPointPressed;
            break;
        case mir_touch_action_up:
            touchPoint.state = Qt::TouchPointReleased;
            break;
        case mir_touch_action_change:
            touchPoint.state = Qt::TouchPointMoved;
            break;
        default:
            Q_UNREACHABLE();
        }

        touchPoints.append(touchPoint);
    }

    ulong timestamp = mir_input_event_get_event_time(ev) / 1000000;
    QWindowSystemInterface::handleTouchEvent(window->window(), timestamp,
            mTouchDevice, touchPoints);
}
Exemplo n.º 4
0
TEST_F(InputEventBuilder, makes_valid_touch_event)
{
    unsigned touch_count = 3;
    MirTouchId touch_ids[] = {7, 9, 4};
    MirTouchAction actions[] = { mir_touch_action_up, mir_touch_action_change, mir_touch_action_change};
    MirTouchTooltype tooltypes[] = {mir_touch_tooltype_unknown, mir_touch_tooltype_finger, mir_touch_tooltype_stylus};
    float x_axis_values[] = { 7, 14.3, 19.6 };
    float y_axis_values[] = { 3, 9, 11 };
    float pressure_values[] = {3, 9, 14.6};
    float touch_major_values[] = {11, 9, 14};
    float touch_minor_values[] = {13, 3, 9.13};
    float size_values[] = {4, 9, 6};

   auto ev = mev::make_event(device_id, timestamp,
       mac, modifiers);
   for (unsigned i = 0; i < touch_count; i++)
   {
       mev::add_touch(*ev, touch_ids[i], actions[i], tooltypes[i], x_axis_values[i], y_axis_values[i],
           pressure_values[i], touch_major_values[i], touch_minor_values[i], size_values[i]);
   }
   auto e = ev.get();

   EXPECT_EQ(mir_event_type_input, mir_event_get_type(e));
   auto ie = mir_event_get_input_event(e);
   EXPECT_EQ(mir_input_event_type_touch, mir_input_event_get_type(ie));
   auto tev = mir_input_event_get_touch_event(ie);
   EXPECT_EQ(modifiers, mir_touch_event_modifiers(tev));
   EXPECT_EQ(touch_count, mir_touch_event_point_count(tev));
   EXPECT_EQ(mac, mir_touch_event_get_cookie(tev).mac);
   EXPECT_EQ(timestamp.count(), mir_touch_event_get_cookie(tev).timestamp);

   for (unsigned i = 0; i < touch_count; i++)
   {
       EXPECT_EQ(touch_ids[i], mir_touch_event_id(tev, i));
       EXPECT_EQ(actions[i], mir_touch_event_action(tev, i));
       EXPECT_EQ(tooltypes[i], mir_touch_event_tooltype(tev, i));
       EXPECT_EQ(x_axis_values[i], mir_touch_event_axis_value(tev, i, mir_touch_axis_x));
       EXPECT_EQ(y_axis_values[i], mir_touch_event_axis_value(tev, i, mir_touch_axis_y));
       EXPECT_EQ(pressure_values[i], mir_touch_event_axis_value(tev, i, mir_touch_axis_pressure));
       EXPECT_EQ(touch_major_values[i], mir_touch_event_axis_value(tev, i, mir_touch_axis_touch_major));
       EXPECT_EQ(touch_minor_values[i], mir_touch_event_axis_value(tev, i, mir_touch_axis_touch_minor));
       EXPECT_EQ(size_values[i], mir_touch_event_axis_value(tev, i, mir_touch_axis_size));
   }   
}
Exemplo n.º 5
0
bool me::WindowManager::handle_touch_event(MirTouchEvent const* tev)
{
    bool handled = false;
    geometry::Point cursor = average_pointer(tev);

    auto const& modifiers = mir_touch_event_modifiers(tev);

    int fingers = mir_touch_event_point_count(tev);

    if (fingers > max_fingers)
        max_fingers = fingers;

    auto const surf = focus_controller->focused_surface();
    if (surf &&
        (modifiers & mir_input_event_modifier_alt ||
         fingers >= 3))
    {
        geometry::Displacement pinch_dir;
        auto pinch_diam =
            measure_pinch(tev, pinch_dir);

        // Start of a gesture: When the latest finger/button goes down
        if (any_touches_went_down(tev))
        {
            click = cursor;
            save_edges(*surf, click);
            handled = true;
        }
        else if(max_fingers <= 3)  // Avoid accidental movement
        {
            geometry::Displacement drag = cursor - old_cursor;

            surf->move_to(old_pos + drag);

            if (fingers == 3)
            {  // Resize by pinch/zoom
                float diam_delta = pinch_diam - old_pinch_diam;
                /*
                 * Resize vector (dx,dy) has length=diam_delta and
                 * direction=pinch_dir, so solve for (dx,dy)...
                 */
                float lenlen = diam_delta * diam_delta;
                int x = pinch_dir.dx.as_int();
                int y = pinch_dir.dy.as_int();
                int xx = x * x;
                int yy = y * y;
                int xxyy = xx + yy;
                int dx = sqrtf(lenlen * xx / xxyy);
                int dy = sqrtf(lenlen * yy / xxyy);
                if (diam_delta < 0.0f)
                {
                    dx = -dx;
                    dy = -dy;
                }

                int width = old_size.width.as_int() + dx;
                int height = old_size.height.as_int() + dy;
                surf->resize({width, height});
            }

            handled = true;
        }

        old_pos = surf->top_left();
        old_size = surf->size();
        old_pinch_diam = pinch_diam;
    }

    auto gesture_ended = last_touch_released(tev);

    if (max_fingers == 4 && gesture_ended)
    { // Four fingers released
        geometry::Displacement dir = cursor - click;
        if (abs(dir.dx.as_int()) >= min_swipe_distance)
        {
            focus_controller->focus_next_session();
            if (auto const surface = focus_controller->focused_surface())
                focus_controller->raise({surface});
            handled = true;
        }
    }

    if (fingers == 1 && gesture_ended)
        max_fingers = 0;

    old_cursor = cursor;
    return handled;
}