# Build library
add_library(touchmouse SHARED ${LIBSRC})
-# Build demo
-add_executable(consoledemo examples/consoledemo.c)
if(WIN32)
target_link_libraries(touchmouse setupapi)
- target_link_libraries(consoledemo touchmouse setupapi)
-elseif(NOT APPLE)
- target_link_libraries(consoledemo touchmouse usb-1.0 pthread rt)
-else()
- target_link_libraries(consoledemo touchmouse)
endif()
+
+# Build examples
+add_subdirectory(examples)
+
--- /dev/null
+
+add_subdirectory(consoledemo)
+add_subdirectory(qtview)
+
--- /dev/null
+
+add_executable(consoledemo consoledemo.c)
+if(WIN32)
+ target_link_libraries(consoledemo touchmouse setupapi)
+elseif(NOT APPLE)
+ target_link_libraries(consoledemo touchmouse usb-1.0 pthread rt)
+else()
+ target_link_libraries(consoledemo touchmouse)
+endif()
+
}
// Poll device for image updates.
- int i;
+ int i = 0;
while(i < 100) {
res = touchmouse_process_events_timeout(dev, -1); // -1 means infinite timeout
i++;
--- /dev/null
+
+find_package(Qt4 REQUIRED QtCore QtGui)
+include(${QT_USE_FILE})
+include_directories(${QT_INCLUDES})
+
+set (QTVIEW_HEADERS mousepoller.h mouseviewer.h)
+set (QTVIEW_SOURCES mousepoller.cpp mouseviewer.cpp main.cpp)
+
+QT4_WRAP_CPP(QTVIEW_MOC_OUTFILES ${QTVIEW_HEADERS} )
+
+add_executable(qtview ${QTVIEW_SOURCES} ${QTVIEW_MOC_OUTFILES})
+if(WIN32)
+ target_link_libraries(qtview touchmouse ${QT_LIBRARIES} setupapi)
+elseif(NOT APPLE)
+ target_link_libraries(qtview touchmouse ${QT_LIBRARIES} usb-1.0 pthread rt)
+else()
+ target_link_libraries(qtview touchmouse ${QT_LIBRARIES})
+endif()
+
+
--- /dev/null
+#include <QApplication>
+#include "mousepoller.h"
+#include "mouseviewer.h"
+
+int main(int argc, char** argv) {
+ QApplication* app = new QApplication(argc, argv);
+
+ MousePoller* poller = new MousePoller();
+
+ MouseViewer* viewer = new MouseViewer();
+ QObject::connect(poller, SIGNAL(mouseUpdate(QByteArray,QDateTime)),
+ viewer, SLOT(imageUpdate(QByteArray,QDateTime)));
+ viewer->resize(15 * 12, 13 * 12 );
+ viewer->show();
+ poller->startPolling();
+
+ int retval = app->exec();
+ poller->stopPolling();
+ return retval;
+}
--- /dev/null
+#include "mousepoller.h"
+#include <QTimer>
+#include <libtouchmouse/libtouchmouse.h>
+#include <QDebug>
+
+MousePoller::MousePoller(int index, QObject* parent) : QObject(parent) {
+ touchmouse_okay = false;
+ timer = new QTimer(this);
+ timer->setInterval(1);
+ connect(timer, SIGNAL(timeout()),
+ this, SLOT(pollMouse()));
+ int res;
+ res = touchmouse_init();
+ if (res != 0) {
+ qDebug() << "Failed to initialize libtouchmouse";
+ }
+ int devs_found = 0;
+ touchmouse_device_info* devs = touchmouse_enumerate_devices();
+ touchmouse_device_info* d = devs;
+ while(d) {
+ d = d->next;
+ devs_found++;
+ }
+ if (devs_found < index) {
+ qDebug() << "Didn't see enough Touchmouse devices to open device" << index;
+ touchmouse_free_enumeration(devs);
+ return;
+ }
+ dev = NULL;
+ d = devs;
+ for(int i = 0; i < index ; i++) {
+ d = d->next;
+ }
+ res = touchmouse_open(&dev, d);
+ touchmouse_free_enumeration(devs);
+ if (res != 0) {
+ qDebug() << "Failed to open Touchmouse device";
+ return;
+ }
+ res = touchmouse_set_image_update_callback(dev, MousePoller::callback);
+ if (res != 0) {
+ qDebug() << "Failed to set Touchmouse device to full updates mode";
+ return;
+ }
+ res = touchmouse_set_device_userdata(dev, this);
+ if (res != 0) {
+ qDebug() << "Failed to set device userdata";
+ return;
+ }
+ touchmouse_okay = true;
+}
+
+MousePoller::~MousePoller() {
+ touchmouse_close(dev);
+ touchmouse_shutdown();
+}
+
+void MousePoller::callback(touchmouse_callback_info *cbdata) {
+ //qDebug() << "static callback triggered";
+ MousePoller* poller = static_cast<MousePoller*>(cbdata->userdata);
+ poller->memberCallback(cbdata);
+}
+
+void MousePoller::memberCallback(touchmouse_callback_info *cbdata) {
+ QByteArray ba((const char*)cbdata->image, 195);
+ // TODO: aggregate timestamps using mouse clock for precision.
+ QDateTime timestamp = QDateTime::currentDateTime();
+ emit mouseUpdate(ba, timestamp);
+}
+
+void MousePoller::pollMouse() {
+ int res;
+ res = touchmouse_process_events_timeout(dev, 0);
+ if (res < 0) {
+ if (res != -1) // -1 is returned on recoverable errors, -2 is a fatal hid_read failure
+ // TODO: make an error enumeration
+ touchmouse_okay = false;
+ }
+}
+
+void MousePoller::startPolling() {
+ if (touchmouse_okay) {
+ int res;
+ res = touchmouse_set_device_mode(dev, TOUCHMOUSE_RAW_IMAGE);
+ if (res != 0) {
+ qDebug() << "Failed to enable full image updates";
+ touchmouse_okay = false;
+ return;
+ }
+ timer->start();
+ } else {
+ qDebug() << "MousePoller::startPolling() called, but libtouchmouse not okay";
+ }
+}
+
+void MousePoller::stopPolling() {
+ if (touchmouse_okay) {
+ int res;
+ res = touchmouse_set_device_mode(dev, TOUCHMOUSE_DEFAULT);
+ if (res != 0) {
+ qDebug() << "Failed to disable full image updates";
+ touchmouse_okay = false;
+ return;
+ }
+ timer->stop();
+ } else {
+ qDebug() << "MousePoller::stopPolling() called, but libtouchmouse not okay";
+ }
+}
+
--- /dev/null
+#ifndef __MOUSEPOLLER_H__
+#define __MOUSEPOLLER_H__
+
+#include <QObject>
+#include <QByteArray>
+#include <QDateTime>
+#include <libtouchmouse/libtouchmouse.h>
+
+class QTimer;
+
+class MousePoller : public QObject {
+ Q_OBJECT
+public:
+ MousePoller(int index = 0, QObject* parent = 0);
+ ~MousePoller();
+ static void callback(touchmouse_callback_info *cbdata);
+ void memberCallback(touchmouse_callback_info* cbdata);
+
+public slots:
+ void startPolling();
+ void stopPolling();
+ void pollMouse();
+
+signals:
+ void mouseUpdate(QByteArray image, QDateTime timestamp);
+
+private:
+ QTimer* timer;
+ touchmouse_device *dev;
+ bool touchmouse_okay;
+};
+
+#endif // __MOUSEPOLLER_H__
--- /dev/null
+#include "mousethread.h"
+
+MouseThread::MouseThread(QObject* parent) : QThread(parent) {
+ shutdownRequested = false;
+ moveToThread(this);
+}
+
+
--- /dev/null
+#ifndef __MOUSETHREAD_H__
+#define __MOUSETHREAD_H__
+
+#include <QThread>
+
+class MouseThread : public QThread {
+ Q_OBJECT
+public:
+ MouseThread(QObject* parent = 0);
+ ~MouseThread();
+
+ void run();
+public slots:
+ void shutdown();
+private:
+ bool shutdownRequested;
+};
+
+#endif // __MOUSETHREAD_H__
+
--- /dev/null
+#include "mouseviewer.h"
+#include <QPainter>
+#include <QPaintEvent>
+#include <QDebug>
+
+MouseViewer::MouseViewer(QWidget* parent) : QWidget(parent) {
+ lastImage.resize(195);
+ // Blank initial image
+ for(int i = 0 ; i < 195; i++) {
+ lastImage[i] = 0;
+ }
+}
+
+MouseViewer::~MouseViewer() {
+
+}
+
+void MouseViewer::paintEvent(QPaintEvent* e) {
+ Q_UNUSED(e)
+ QPainter p(this);
+ if (lastImage.size() == 195) {
+ for(int row = 0; row < 13; row++) {
+ for(int col = 0; col < 15 ; col++) {
+ unsigned char value = uchar(lastImage[row*15 + col]);
+ QColor c(value, value, value);
+ p.setBrush(c);
+ p.drawRect(width() * col / 15, height() * row / 13, width() / 15, height() / 13);
+ }
+ }
+ } else {
+ qDebug() << "paintEvent, but no image yet";
+ }
+}
+
+void MouseViewer::imageUpdate(QByteArray image, QDateTime timestamp) {
+ // Ignoring timestamp, lah de dah
+ lastImage = image;
+ update();
+}
--- /dev/null
+#ifndef __MOUSEVIEWER_H__
+#define __MOUSEVIEWER_H__
+
+#include <QWidget>
+#include <QByteArray>
+#include <QDateTime>
+
+class QPaintEvent;
+
+class MouseViewer : public QWidget {
+ Q_OBJECT
+public:
+ MouseViewer(QWidget* parent = 0);
+ ~MouseViewer();
+ void paintEvent(QPaintEvent* e);
+public slots:
+ void imageUpdate(QByteArray image, QDateTime timestamp);
+private:
+ QByteArray lastImage;
+};
+
+#endif // __MOUSEVIEWER_H__
#endif
#endif
+#ifdef __cplusplus
+extern "C" {
+#endif
+
// Types:
struct touchmouse_device_;
typedef struct touchmouse_device_ touchmouse_device;
// milliseconds > 0 means "fetch data. Trigger a callback if the data arrives within <arg> milliseconds, otherwise return."
TOUCHMOUSEAPI int touchmouse_process_events_timeout(touchmouse_device *dev, int milliseconds);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* __LIBTOUCHMOUSE_H__ */
uint64_t deadline;
if(milliseconds == -1) {
deadline = (uint64_t)(-1);
+ printf("Got infinite timeout\n");
} else {
deadline = mono_timer_nanos() + (milliseconds * 1000000);
}
res = hid_read_timeout(dev->dev, data, 255, (deadline - nanos) / 1000000 );
if (res < 0 ) {
fprintf(stderr, "hid_read() failed: %d\n", res);
- return -1;
+ return -2;
} else if (res > 0) {
// Dump contents of transfer
- printf("Got reply: %d bytes:", res);
- int j;
- for(j = 0; j < res; j++) {
- printf(" %02X", data[j]);
- }
- printf("\n");
+ //printf("Got reply: %d bytes:", res);
+ //int j;
+ //for(j = 0; j < res; j++) {
+ // printf(" %02X", data[j]);
+ //}
+ //printf("\n");
// Interpret contents.
report* r = (report*)data;
// We only care about report ID 39 (0x27), which should be 32 bytes long
if (res == 32 && r->report_id == 0x27) {
- printf("Timestamp: %02X\t%02X bytes:", r->timestamp, r->length - 1);
+ //printf("Timestamp: %02X\t%02X bytes:", r->timestamp, r->length - 1);
int t;
- for(t = 0; t < r->length - 1; t++) {
- printf(" %02X", r->data[t]);
- }
- printf("\n");
+ //for(t = 0; t < r->length - 1; t++) {
+ // printf(" %02X", r->data[t]);
+ //}
+ //printf("\n");
// Reset the decoder if we've seen one timestamp already from earlier
// transfers, and this one doesn't match.
if (first_timestamp_read && r->timestamp != last_timestamp) {
return 0;
}
if (res == DECODER_ERROR) {
- fprintf(stderr, "Caught error in decoder, aborting!\n");
+ fprintf(stderr, "Caught error in decoder, aborting decode!\n");
reset_decoder(dev);
return -1;
}
return 0;
}
if (res == DECODER_ERROR) {
- fprintf(stderr, "Caught error in decoder, aborting!\n");
+ fprintf(stderr, "Caught error in decoder, aborting decode!\n");
reset_decoder(dev);
return -1;
}