diff --git a/src/wayland/autotests/server/test_tablet_interface.cpp b/src/wayland/autotests/server/test_tablet_interface.cpp index 0fe2aea0dc..4021cb5b40 100644 --- a/src/wayland/autotests/server/test_tablet_interface.cpp +++ b/src/wayland/autotests/server/test_tablet_interface.cpp @@ -18,6 +18,7 @@ #include "KWayland/Client/event_queue.h" #include "KWayland/Client/registry.h" #include "KWayland/Client/seat.h" +#include "KWayland/Client/surface.h" #include "qwayland-tablet-unstable-v2.h" @@ -32,6 +33,42 @@ public: } }; +class TabletPad : public QObject, public QtWayland::zwp_tablet_pad_v2 +{ + Q_OBJECT +public: + TabletPad(::zwp_tablet_pad_v2 *t) + : QtWayland::zwp_tablet_pad_v2(t) + { + } + + void zwp_tablet_pad_v2_done() override { + Q_ASSERT(!doneCalled); + doneCalled = true; + } + + void zwp_tablet_pad_v2_buttons(uint32_t buttons) override { + Q_ASSERT(buttons == 1); + } + + void zwp_tablet_pad_v2_enter(uint32_t /*serial*/, struct ::zwp_tablet_v2 */*tablet*/, struct ::wl_surface *surface) override { + m_currentSurface = surface; + } + + void zwp_tablet_pad_v2_button(uint32_t /*time*/, uint32_t button, uint32_t state) override { + buttonStates[m_currentSurface][button] = state; + Q_EMIT buttonReceived(); + } + + ::wl_surface *m_currentSurface = nullptr; + + bool doneCalled = false; + QHash<::wl_surface *, QHash> buttonStates; + +Q_SIGNALS: + void buttonReceived(); +}; + class Tool : public QObject, public QtWayland::zwp_tablet_tool_v2 { Q_OBJECT @@ -76,10 +113,18 @@ public: Q_EMIT toolAdded(); } + void zwp_tablet_seat_v2_pad_added(struct ::zwp_tablet_pad_v2 *id) override + { + m_pads << new TabletPad(id); + Q_EMIT padAdded(); + } + QVector m_tablets; + QVector m_pads; QVector m_tools; Q_SIGNALS: + void padAdded(); void toolAdded(); void tabletAdded(); }; @@ -96,6 +141,7 @@ public: private Q_SLOTS: void initTestCase(); void testAdd(); + void testAddPad(); void testInteractSimple(); void testInteractSurfaceChange(); @@ -112,8 +158,10 @@ private: TabletSeat *m_tabletSeatClient = nullptr; TabletManagerV2Interface *m_tabletManager; + QVector m_surfacesClient; TabletV2Interface *m_tablet; + TabletPadV2Interface *m_tabletPad = nullptr; TabletToolV2Interface *m_tool; QVector m_surfaces; @@ -178,7 +226,7 @@ void TestTabletInterface::initTestCase() QSignalSpy surfaceSpy(m_serverCompositor, &CompositorInterface::surfaceCreated); for (int i = 0; i < 3; ++i) { - m_clientCompositor->createSurface(this); + m_surfacesClient += m_clientCompositor->createSurface(this); } QVERIFY(surfaceSpy.count() < 3 && surfaceSpy.wait(200)); QVERIFY(m_surfaces.count() == 3); @@ -230,6 +278,32 @@ void TestTabletInterface::testAdd() m_tool->setCurrentSurface(nullptr); } +void TestTabletInterface::testAddPad() +{ + TabletSeatV2Interface *seatInterface = m_tabletManager->seat(m_seat); + QVERIFY(seatInterface); + + QSignalSpy tabletPadSpy(m_tabletSeatClient, &TabletSeat::padAdded); + m_tabletPad = seatInterface->addTabletPad(QStringLiteral("my tablet pad"), QStringLiteral("tabletpad"), {QStringLiteral("/test/event33")}, 1, 1, 1, 1, 0, m_tablet); + QVERIFY(m_tabletPad); + QVERIFY(tabletPadSpy.wait() || tabletPadSpy.count() == 1); + QCOMPARE(m_tabletSeatClient->m_pads.count(), 1); + QVERIFY(m_tabletSeatClient->m_pads[0]); + + QVERIFY(m_tabletPad->ring(0)); + QVERIFY(m_tabletPad->strip(0)); + + QCOMPARE(m_surfaces.count(), 3); + QVERIFY(m_tabletSeatClient->m_pads[0]->buttonStates.isEmpty()); + QSignalSpy buttonSpy(m_tabletSeatClient->m_pads[0], &TabletPad::buttonReceived); + m_tabletPad->setCurrentSurface(m_surfaces[0], m_tablet); + m_tabletPad->sendButton(123, 0, QtWayland::zwp_tablet_pad_v2::button_state_pressed); + QVERIFY(buttonSpy.count() || buttonSpy.wait(100)); + QCOMPARE(m_tabletSeatClient->m_pads[0]->doneCalled, true); + QCOMPARE(m_tabletSeatClient->m_pads[0]->buttonStates.count(), 1); + QCOMPARE(m_tabletSeatClient->m_pads[0]->buttonStates[*m_surfacesClient[0]][0], QtWayland::zwp_tablet_pad_v2::button_state_pressed); +} + static uint s_serial = 0; void TestTabletInterface::testInteractSimple() { diff --git a/src/wayland/tablet_v2_interface.cpp b/src/wayland/tablet_v2_interface.cpp index 9faeeddd08..315ae5d286 100644 --- a/src/wayland/tablet_v2_interface.cpp +++ b/src/wayland/tablet_v2_interface.cpp @@ -46,6 +46,7 @@ public: } TabletV2Interface *const q; + TabletPadV2Interface *m_pad = nullptr; const uint32_t m_vendorId; const uint32_t m_productId; const QString m_name; @@ -76,6 +77,11 @@ void TabletV2Interface::sendRemoved() } } +TabletPadV2Interface *TabletV2Interface::pad() const +{ + return d->m_pad; +} + class TabletCursorV2Private { public: @@ -327,6 +333,280 @@ void TabletToolV2Interface::sendRemoved() } } +class TabletPadRingV2InterfacePrivate : public QtWaylandServer::zwp_tablet_pad_ring_v2 +{ +public: + TabletPadRingV2InterfacePrivate(TabletPadRingV2Interface *q) + : zwp_tablet_pad_ring_v2() + , q(q) + { + } + + wl_resource *resourceForSurface(SurfaceInterface *surface) const + { + ClientConnection *client = surface->client(); + Resource *r = resourceMap().value(*client); + return r ? r->handle : nullptr; + } + + void zwp_tablet_pad_ring_v2_destroy(Resource *resource) override { + wl_resource_destroy(resource->handle); + if (m_pad->isRemoved() && resourceMap().isEmpty()) { + delete q; + } + } + TabletPadRingV2Interface *const q; + TabletPadV2Interface *m_pad; +}; + +TabletPadRingV2Interface::TabletPadRingV2Interface(QObject *parent) + : QObject(parent) + , d(new TabletPadRingV2InterfacePrivate(this)) +{ +} + +TabletPadRingV2Interface::~TabletPadRingV2Interface() = default; + +void TabletPadRingV2Interface::sendAngle(qreal angle) +{ + d->send_angle(d->resourceForSurface(d->m_pad->currentSurface()), wl_fixed_from_double(angle)); +} + +void TabletPadRingV2Interface::sendFrame(quint32 time) +{ + d->send_frame(d->resourceForSurface(d->m_pad->currentSurface()), time); +} + +void TabletPadRingV2Interface::sendSource(Source source) +{ + d->send_source(d->resourceForSurface(d->m_pad->currentSurface()), source); +} + +void TabletPadRingV2Interface::sendStop() +{ + d->send_stop(d->resourceForSurface(d->m_pad->currentSurface())); +} + +class TabletPadStripV2InterfacePrivate : public QtWaylandServer::zwp_tablet_pad_strip_v2 +{ +public: + TabletPadStripV2InterfacePrivate(TabletPadStripV2Interface *q) + : zwp_tablet_pad_strip_v2() + , q(q) + { + } + + wl_resource *resourceForSurface(SurfaceInterface *surface) const + { + ClientConnection *client = surface->client(); + Resource *r = resourceMap().value(*client); + return r ? r->handle : nullptr; + } + + void zwp_tablet_pad_strip_v2_destroy(Resource *resource) override { + wl_resource_destroy(resource->handle); + if (m_pad->isRemoved() && resourceMap().isEmpty()) { + delete q; + } + } + TabletPadV2Interface *m_pad = nullptr; + TabletPadStripV2Interface *const q; +}; + +TabletPadStripV2Interface::TabletPadStripV2Interface(QObject *parent) + : QObject(parent) + , d(new TabletPadStripV2InterfacePrivate(this)) +{ +} + +TabletPadStripV2Interface::~TabletPadStripV2Interface() = default; + +void TabletPadStripV2Interface::sendFrame(quint32 time) +{ + d->send_frame(d->resourceForSurface(d->m_pad->currentSurface()), time); +} + +void TabletPadStripV2Interface::sendPosition(quint32 position) +{ + d->send_position(d->resourceForSurface(d->m_pad->currentSurface()), position); +} + +void TabletPadStripV2Interface::sendSource(Source source) +{ + d->send_source(d->resourceForSurface(d->m_pad->currentSurface()), source); +} + +void TabletPadStripV2Interface::sendStop() +{ + d->send_stop(d->resourceForSurface(d->m_pad->currentSurface())); +} + +class TabletPadGroupV2InterfacePrivate : public QtWaylandServer::zwp_tablet_pad_group_v2 +{ +public: + TabletPadGroupV2InterfacePrivate(quint32 currentMode, TabletPadGroupV2Interface *q) + : zwp_tablet_pad_group_v2() + , q(q) + , m_currentMode(currentMode) + { + } + + wl_resource *resourceForSurface(SurfaceInterface *surface) const + { + ClientConnection *client = surface->client(); + Resource *r = resourceMap().value(*client); + return r ? r->handle : nullptr; + } + + void zwp_tablet_pad_group_v2_destroy(Resource * resource) override { + wl_resource_destroy(resource->handle); + if (m_pad->isRemoved() && resourceMap().isEmpty()) { + delete q; + } + } + + TabletPadGroupV2Interface *const q; + TabletPadV2Interface *m_pad = nullptr; + quint32 m_currentMode; +}; + +TabletPadGroupV2Interface::TabletPadGroupV2Interface(quint32 currentMode, QObject *parent) + : QObject(parent) + , d(new TabletPadGroupV2InterfacePrivate(currentMode, this)) +{ +} + +TabletPadGroupV2Interface::~TabletPadGroupV2Interface() = default; + +void TabletPadGroupV2Interface::sendModeSwitch(quint32 time, quint32 serial, quint32 mode) +{ + d->m_currentMode = mode; + d->send_mode_switch(d->resourceForSurface(d->m_pad->currentSurface()), time, serial, mode); +} + +class TabletPadV2InterfacePrivate : public QtWaylandServer::zwp_tablet_pad_v2 +{ +public: + TabletPadV2InterfacePrivate(const QString &path, quint32 buttons, quint32 rings, quint32 strips, quint32 modes, quint32 currentMode, Display *display, TabletPadV2Interface *q) + : zwp_tablet_pad_v2() + , q(q) + , m_path(path) + , m_buttons(buttons) + , m_modes(modes) + , m_padGroup(new TabletPadGroupV2Interface(currentMode, q)) + , m_display(display) + { + for (uint i = 0; i < buttons; ++i) { + m_buttons[i] = i; + } + + m_padGroup->d->m_pad = q; + m_rings.reserve(rings); + for (quint32 i = 0; i < rings; ++i) { + m_rings += new TabletPadRingV2Interface(q); + m_rings.constLast()->d->m_pad = q; + } + + m_strips.reserve(strips); + for (quint32 i = 0; i < strips; ++i) { + m_strips += new TabletPadStripV2Interface(q); + m_strips.constLast()->d->m_pad = q; + } + } + + void zwp_tablet_pad_v2_destroy(Resource *resource) override { + wl_resource_destroy(resource->handle); + if (m_removed && resourceMap().isEmpty()) { + delete q; + } + } + + void zwp_tablet_pad_v2_set_feedback(Resource *resource, quint32 button, const QString &description, quint32 serial) override { + Q_EMIT q->feedback(m_display->getConnection(resource->client()), button, description, serial); + } + + wl_resource *resourceForSurface(SurfaceInterface *surface) const + { + ClientConnection *client = surface->client(); + Resource *r = resourceMap().value(*client); + return r ? r->handle : nullptr; + } + + TabletPadV2Interface *const q; + + const QString m_path; + QVector m_buttons; + const int m_modes; + + QVector m_rings; + QVector m_strips; + TabletPadGroupV2Interface *const m_padGroup; + TabletSeatV2Interface *m_seat = nullptr; + SurfaceInterface *m_currentSurface = nullptr; + bool m_removed = false; + Display *const m_display; +}; + +TabletPadV2Interface::TabletPadV2Interface(const QString &path, quint32 buttons, quint32 rings, quint32 strips, quint32 modes, quint32 currentMode, Display *display, QObject *parent) + : QObject(parent) + , d(new TabletPadV2InterfacePrivate(path, buttons, rings, strips, modes, currentMode, display, this)) +{ +} + +TabletPadV2Interface::~TabletPadV2Interface() = default; + +void TabletPadV2Interface::sendButton(quint32 time, quint32 button, bool pressed) +{ + d->send_button(d->resourceForSurface(currentSurface()), time, button, pressed); +} + +void TabletPadV2Interface::sendRemoved() +{ + d->m_removed = true; + for (auto resource : d->resourceMap()) { + d->send_removed(resource->handle); + } +} + +TabletPadRingV2Interface *TabletPadV2Interface::ring(uint at) const +{ + return d->m_rings[at]; +} + +TabletPadStripV2Interface *TabletPadV2Interface::strip(uint at) const +{ + return d->m_strips[at]; +} + +bool TabletPadV2Interface::isRemoved() const +{ + return d->m_removed; +} + +void TabletPadV2Interface::setCurrentSurface(SurfaceInterface *surface, TabletV2Interface *tablet) +{ + if (surface == d->m_currentSurface) { + return; + } + + if (d->m_currentSurface) { + d->send_leave(d->m_display->nextSerial(), surface->resource()); + } + + d->m_currentSurface = surface; + if (surface) { + wl_resource *tabletResource = tablet->d->resourceForSurface(surface); + + d->send_enter(d->resourceForSurface(surface), d->m_display->nextSerial(), tabletResource, surface->resource()); + d->m_padGroup->sendModeSwitch(0, d->m_display->nextSerial(), d->m_padGroup->d->m_currentMode); + } +} + +SurfaceInterface *TabletPadV2Interface::currentSurface() const +{ + return d->m_currentSurface; +} + class TabletSeatV2InterfacePrivate : public QtWaylandServer::zwp_tablet_seat_v2 { public: @@ -339,8 +619,12 @@ public: void zwp_tablet_seat_v2_bind_resource(Resource *resource) override { - for (auto iface : qAsConst(m_tablets)) { - sendTabletAdded(resource, iface); + for (auto tablet : qAsConst(m_tablets)) { + sendTabletAdded(resource, tablet); + } + + for (auto pad : qAsConst(m_pads)) { + sendPadAdded(resource, pad); } for (auto *tool : qAsConst(m_tools)) { @@ -384,9 +668,40 @@ public: tablet->d->send_done(tabletResource); } + void sendPadAdded(Resource *resource, TabletPadV2Interface *pad) + { + if (pad->d->m_removed) + return; + + wl_resource *tabletResource = pad->d->add(resource->client(), resource->version())->handle; + send_pad_added(resource->handle, tabletResource); + + pad->d->send_buttons(tabletResource, pad->d->m_buttons.size()); + pad->d->send_path(tabletResource, pad->d->m_path); + + auto groupResource = pad->d->m_padGroup->d->add(resource->client(), resource->version()); + pad->d->send_group(tabletResource, groupResource->handle); + pad->d->m_padGroup->d->send_modes(groupResource->handle, pad->d->m_modes); + + pad->d->m_padGroup->d->send_buttons(groupResource->handle, QByteArray::fromRawData(reinterpret_cast(pad->d->m_buttons.data()), pad->d->m_buttons.size() * sizeof(quint32))); + + for (auto ring : pad->d->m_rings) { + auto ringResource = ring->d->add(resource->client(), resource->version()); + pad->d->m_padGroup->d->send_ring(groupResource->handle, ringResource->handle); + } + + for (auto strip : pad->d->m_strips) { + auto stripResource = strip->d->add(resource->client(), resource->version()); + pad->d->m_padGroup->d->send_strip(groupResource->handle, stripResource->handle); + } + pad->d->m_padGroup->d->send_done(groupResource->handle); + pad->d->send_done(tabletResource); + } + TabletSeatV2Interface *const q; QVector m_tools; QHash m_tablets; + QHash m_pads; Display *const m_display; }; @@ -425,6 +740,8 @@ TabletV2Interface *TabletSeatV2Interface::addTablet(uint32_t vendorId, uint32_t const QString &name, const QStringList &paths) { + Q_ASSERT(!d->m_tablets.contains(sysname)); + auto iface = new TabletV2Interface(vendorId, productId, name, paths, this); for (QtWaylandServer::zwp_tablet_seat_v2::Resource *r : d->resourceMap()) { @@ -435,12 +752,32 @@ TabletV2Interface *TabletSeatV2Interface::addTablet(uint32_t vendorId, uint32_t return iface; } -void TabletSeatV2Interface::removeTablet(const QString &sysname) +TabletPadV2Interface *TabletSeatV2Interface::addTabletPad(const QString &sysname, const QString &name, const QStringList &paths, quint32 buttons, quint32 rings, quint32 strips, quint32 modes, quint32 currentMode, TabletV2Interface *tablet) +{ + Q_UNUSED(name); + auto iface = new TabletPadV2Interface(paths.at(0), buttons, rings, strips, modes, currentMode, d->m_display, this); + iface->d->m_seat = this; + for (auto r : d->resourceMap()) { + d->sendPadAdded(r, iface); + } + + tablet->d->m_pad = iface; + + d->m_pads[sysname] = iface; + return iface; +} + +void TabletSeatV2Interface::removeDevice(const QString &sysname) { auto tablet = d->m_tablets.take(sysname); if (tablet) { tablet->sendRemoved(); } + + auto pad = d->m_pads.take(sysname); + if (pad) { + pad->sendRemoved(); + } } TabletToolV2Interface *TabletSeatV2Interface::toolByHardwareId(quint64 hardwareId) const @@ -461,9 +798,10 @@ TabletToolV2Interface *TabletSeatV2Interface::toolByHardwareSerial(quint64 hardw return nullptr; } -TabletV2Interface *TabletSeatV2Interface::tabletByName(const QString &name) const +TabletPadV2Interface * TabletSeatV2Interface::padByName(const QString &name) const { - return d->m_tablets.value(name); + Q_ASSERT(d->m_pads.contains(name)); + return d->m_pads.value(name); } class TabletManagerV2InterfacePrivate : public QtWaylandServer::zwp_tablet_manager_v2 @@ -508,6 +846,11 @@ TabletSeatV2Interface *TabletManagerV2Interface::seat(SeatInterface *seat) const return d->get(seat); } +bool TabletSeatV2Interface::isClientSupported(ClientConnection *client) const +{ + return d->resourceMap().value(*client); +} + TabletManagerV2Interface::~TabletManagerV2Interface() = default; } // namespace KWaylandServer diff --git a/src/wayland/tablet_v2_interface.h b/src/wayland/tablet_v2_interface.h index 9245eef850..7e87d03e3e 100644 --- a/src/wayland/tablet_v2_interface.h +++ b/src/wayland/tablet_v2_interface.h @@ -14,6 +14,7 @@ namespace KWaylandServer { +class ClientConnection; class Display; class SeatInterface; class SurfaceInterface; @@ -25,6 +26,14 @@ class TabletSeatV2InterfacePrivate; class TabletToolV2InterfacePrivate; class TabletV2Interface; class TabletV2InterfacePrivate; +class TabletPadV2Interface; +class TabletPadV2InterfacePrivate; +class TabletPadRingV2Interface; +class TabletPadRingV2InterfacePrivate; +class TabletPadStripV2Interface; +class TabletPadStripV2InterfacePrivate; +class TabletPadGroupV2Interface; +class TabletPadGroupV2InterfacePrivate; /** * This is an implementation of wayland-protocols/unstable/tablet/tablet-unstable-v2.xml @@ -130,6 +139,95 @@ private: friend class TabletToolV2InterfacePrivate; }; +class KWAYLANDSERVER_EXPORT TabletPadV2Interface : public QObject +{ + Q_OBJECT +public: + virtual ~TabletPadV2Interface(); + + TabletPadRingV2Interface *ring(uint at) const; + TabletPadStripV2Interface *strip(uint at) const; + void sendButton(quint32 time, quint32 button, bool pressed); + + void sendRemoved(); + bool isRemoved() const; + + void setCurrentSurface(SurfaceInterface *surface, TabletV2Interface *tablet); + SurfaceInterface *currentSurface() const; + +Q_SIGNALS: + void feedback(KWaylandServer::ClientConnection *client, quint32 button, const QString &description, quint32 serial); + +private: + friend class TabletSeatV2Interface; + friend class TabletSeatV2InterfacePrivate; + explicit TabletPadV2Interface(const QString &path, quint32 buttons, quint32 rings, quint32 strips, quint32 modes, quint32 currentMode, Display *display, QObject *parent); + QScopedPointer d; +}; + +class KWAYLANDSERVER_EXPORT TabletPadRingV2Interface : public QObject +{ + Q_OBJECT +public: + virtual ~TabletPadRingV2Interface(); + + enum Source { + SourceFinger = 1, // finger + }; + Q_ENUM(Source) + + void sendSource(Source source); + void sendAngle(qreal angle); + void sendStop(); + void sendFrame(quint32 time); + +private: + friend class TabletPadGroupV2Interface; + friend class TabletPadV2InterfacePrivate; + friend class TabletSeatV2InterfacePrivate; + explicit TabletPadRingV2Interface(QObject *parent); + QScopedPointer d; +}; + +class KWAYLANDSERVER_EXPORT TabletPadStripV2Interface : public QObject +{ + Q_OBJECT +public: + virtual ~TabletPadStripV2Interface(); + + enum Source { + SourceFinger = 1, // finger + }; + + void sendSource(Source source); + void sendPosition(quint32 position); + void sendFrame(quint32 time); + void sendStop(); + +private: + friend class TabletPadGroupV2Interface; + friend class TabletPadV2InterfacePrivate; + friend class TabletSeatV2InterfacePrivate; + explicit TabletPadStripV2Interface(QObject *parent); + QScopedPointer d; +}; + +class KWAYLANDSERVER_EXPORT TabletPadGroupV2Interface : public QObject +{ + Q_OBJECT +public: + virtual ~TabletPadGroupV2Interface(); + + void sendModeSwitch(quint32 time, quint32 serial, quint32 mode); + +private: + friend class TabletPadV2Interface; + friend class TabletPadV2InterfacePrivate; + friend class TabletSeatV2InterfacePrivate; + explicit TabletPadGroupV2Interface(quint32 currentMode, QObject *parent); + QScopedPointer d; +}; + class KWAYLANDSERVER_EXPORT TabletV2Interface : public QObject { Q_OBJECT @@ -141,11 +239,13 @@ public: */ bool isSurfaceSupported(SurfaceInterface *surface) const; + TabletPadV2Interface *pad() const; void sendRemoved(); private: friend class TabletSeatV2Interface; friend class TabletSeatV2InterfacePrivate; + friend class TabletPadV2Interface; friend class TabletToolV2Interface; explicit TabletV2Interface(quint32 vendorId, quint32 productId, const QString &name, const QStringList &paths, QObject *parent); QScopedPointer d; @@ -158,13 +258,16 @@ public: virtual ~TabletSeatV2Interface(); TabletV2Interface *addTablet(quint32 vendorId, quint32 productId, const QString &sysname, const QString &name, const QStringList &paths); + TabletPadV2Interface *addTabletPad(const QString &sysname, const QString &name, const QStringList &paths, quint32 buttons, quint32 rings, quint32 strips, quint32 modes, quint32 currentMode, TabletV2Interface *tablet); TabletToolV2Interface *addTool(TabletToolV2Interface::Type type, quint64 hardwareSerial, quint64 hardwareId, const QVector &capabilities); TabletToolV2Interface *toolByHardwareId(quint64 hardwareId) const; TabletToolV2Interface *toolByHardwareSerial(quint64 hardwareSerial) const; - TabletV2Interface *tabletByName(const QString &sysname) const; + TabletPadV2Interface *padByName(const QString &sysname) const; - void removeTablet(const QString &sysname); + void removeDevice(const QString &sysname); + + bool isClientSupported(ClientConnection *client) const; private: friend class TabletManagerV2InterfacePrivate;