tablet: added maru tablet device
authorsungmin ha <sungmin82.ha@samsung.com>
Sun, 26 Jul 2015 08:06:10 +0000 (17:06 +0900)
committersung min Ha <sungmin82.ha@samsung.com>
Sun, 26 Jul 2015 08:27:04 +0000 (17:27 +0900)
added mouse operation

Change-Id: I500cff93afccd60cbee2dbb49c9ea6616ee94dab
Signed-off-by: sungmin ha <sungmin82.ha@samsung.com>
15 files changed:
tizen/src/emul_state.c
tizen/src/emulator.c
tizen/src/hw/maru_device_ids.h
tizen/src/hw/virtio/Makefile.objs
tizen/src/hw/virtio/maru_virtio_pci.c
tizen/src/hw/virtio/maru_virtio_tablet.c [new file with mode: 0644]
tizen/src/hw/virtio/maru_virtio_tablet.h [new file with mode: 0644]
tizen/src/skin/maruskin_operation.c
tizen/src/ui/displaybase.cpp
tizen/src/ui/displaybase.h
tizen/src/ui/displayglwidget.cpp
tizen/src/ui/displayglwidget.h
tizen/src/ui/displayswwidget.cpp
tizen/src/ui/displayswwidget.h
tizen/src/ui/mainwindow.cpp

index 399cef5..7774da4 100644 (file)
@@ -243,7 +243,11 @@ char* get_emul_host_ip(void)
 
 int get_max_touch_point(void)
 {
-    return ts->max_finger;
+    if (ts) {
+        return ts->max_finger;
+    } else {
+        return 1;
+    }
 }
 
 /* base port for emualtor vm */
index ce68a53..4909ab2 100644 (file)
@@ -59,6 +59,7 @@ int thread_running = 1; /* Check if we need exit main */
 
 DECLARE_DEBUG_CHANNEL(main);
 
+#define INPUT_TOUCH_PARAMETER "virtio-touchscreen-pci"
 #define ARGS_LIMIT  128
 #define LEN_MARU_KERNEL_CMDLINE 512
 char maru_kernel_cmdline[LEN_MARU_KERNEL_CMDLINE];
@@ -158,6 +159,21 @@ static void print_system_info(void)
     print_system_info_os();
 }
 
+static void set_qemu_input_mode(void)
+{
+    int i;
+    for (i = 0; i < _qemu_argc; ++i) {
+        if (strstr(_qemu_argv[i], INPUT_TOUCH_PARAMETER) != NULL) {
+            /* touchscreen */
+            set_emul_input_touch_enable(true);
+        }
+    }
+
+    if (is_emul_input_touch_enable() != true) {
+        set_emul_input_mouse_enable(true);
+    }
+}
+
 static void print_options_info(void)
 {
     int i;
@@ -339,6 +355,8 @@ static int emulator_main(int argc, char *argv[], char **envp)
     atexit(maru_atexit);
     emulator_add_exit_notifier(&emulator_exit);
 
+    set_qemu_input_mode();
+
     print_system_info();
 
     print_options_info();
index 0942e39..35fa05f 100644 (file)
@@ -53,6 +53,7 @@
 #define PCI_DEVICE_ID_VIRTIO_ROTARY      0x1022
 #define PCI_DEVICE_ID_VIRTIO_ESM         0x1024
 #define PCI_DEVICE_ID_VIRTIO_HWKEY       0x1028
+#define PCI_DEVICE_ID_VIRTIO_TABLET      0x1029
 #define PCI_DEVICE_ID_VIRTIO_EVDI        0x102C
 #define PCI_DEVICE_ID_VIRTIO_SENSOR      0x1034
 #define PCI_DEVICE_ID_VIRTIO_POWER       0x1035
 #define VIRTIO_ID_POWER         40
 #define VIRTIO_ID_VMODEM        41
 #define VIRTIO_ID_ROTARY        42
+#define VIRTIO_ID_TABLET        43
 
 #endif /* MARU_DEVICE_IDS_H_ */
index 026af61..adf0677 100644 (file)
@@ -10,3 +10,4 @@ obj-y += maru_virtio_power.o
 obj-y += maru_virtio_sensor.o
 obj-y += maru_virtio_vmodem.o
 obj-y += maru_virtio_rotary.o
+obj-y += maru_virtio_tablet.o
index 3271a86..61cfc21 100644 (file)
@@ -41,6 +41,7 @@
 #include "maru_virtio_nfc.h"
 #include "maru_virtio_vmodem.h"
 #include "maru_virtio_rotary.h"
+#include "maru_virtio_tablet.h"
 
 typedef struct VirtIOTouchscreenPCI VirtIOTouchscreenPCI;
 typedef struct VirtIOEVDIPCI VirtIOEVDIPCI;
@@ -53,6 +54,7 @@ typedef struct VirtIOPOWERPCI VirtIOPOWERPCI;
 typedef struct VirtIOJACKPCI VirtIOJACKPCI;
 typedef struct VirtIOVModemPCI VirtIOVModemPCI;
 typedef struct VirtIORotaryPCI VirtIORotaryPCI;
+typedef struct VirtIOTabletPCI VirtIOTabletPCI;
 
 /*
  * virtio-touchscreen-pci: This extends VirtioPCIProxy.
@@ -113,6 +115,17 @@ struct VirtIOHWKeyPCI {
 };
 
 /*
+ * virtio-tablet-pci: This extends VirtioPCIProxy.
+ */
+#define TYPE_VIRTIO_TABLET_PCI "virtio-tablet-pci"
+#define VIRTIO_TABLET_PCI(obj) \
+        OBJECT_CHECK(VirtIOTabletPCI, (obj), TYPE_VIRTIO_TABLET_PCI)
+struct VirtIOTabletPCI {
+    VirtIOPCIProxy parent_obj;
+    VirtIOTablet vdev;
+};
+
+/*
  * virtio-sensor-pci: This extends VirtioPCIProxy.
  */
 #define TYPE_VIRTIO_SENSOR_PCI "virtio-sensor-pci"
@@ -358,6 +371,47 @@ static TypeInfo virtio_hwkey_pci_info = {
     .class_init    = virtio_hwkey_pci_class_init,
 };
 
+/* virtio-tablet-pci */
+
+static int virtio_tablet_pci_init(VirtIOPCIProxy *vpci_dev)
+{
+    VirtIOTabletPCI *dev = VIRTIO_TABLET_PCI(vpci_dev);
+    DeviceState *vdev = DEVICE(&dev->vdev);
+
+    qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
+    if (qdev_init(vdev) < 0) {
+        return -1;
+    }
+    return 0;
+}
+
+static void virtio_tablet_pci_class_init(ObjectClass *klass, void *data)
+{
+    VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
+    PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
+
+    k->init = virtio_tablet_pci_init;
+    pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+    pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_TABLET;
+    pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
+    pcidev_k->class_id = PCI_CLASS_OTHERS;
+}
+
+static void virtio_tablet_pci_instance_init(Object *obj)
+{
+    VirtIOTabletPCI *dev = VIRTIO_TABLET_PCI(obj);
+    object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_TABLET);
+    object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
+}
+
+static TypeInfo virtio_tablet_pci_info = {
+    .name          = TYPE_VIRTIO_TABLET_PCI,
+    .parent        = TYPE_VIRTIO_PCI,
+    .instance_size = sizeof(VirtIOTabletPCI),
+    .instance_init = virtio_tablet_pci_instance_init,
+    .class_init    = virtio_tablet_pci_class_init,
+};
+
 /* virtio-evdi-pci */
 
 static Property virtio_evdi_pci_properties[] = {
@@ -671,6 +725,7 @@ static void maru_virtio_pci_register_types(void)
     type_register_static(&virtio_evdi_pci_info);
     type_register_static(&virtio_esm_pci_info);
     type_register_static(&virtio_hwkey_pci_info);
+    type_register_static(&virtio_tablet_pci_info);
     type_register_static(&virtio_keyboard_pci_info);
     type_register_static(&virtio_touchscreen_pci_info);
     type_register_static(&virtio_sensor_pci_info);
diff --git a/tizen/src/hw/virtio/maru_virtio_tablet.c b/tizen/src/hw/virtio/maru_virtio_tablet.c
new file mode 100644 (file)
index 0000000..9c1427f
--- /dev/null
@@ -0,0 +1,264 @@
+/*
+ * Maru Virtio Tablet Device
+ *
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ *  Sungmin Ha <sungmin82.ha@samsung.com>
+ *  Sangho Park <sangho.p@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#include <pthread.h>
+#include "emul_state.h"
+#include "maru_virtio_tablet.h"
+#include "hw/maru_device_ids.h"
+#include "debug_ch.h"
+
+MULTI_DEBUG_CHANNEL(qemu, tablet);
+
+#define DEVICE_NAME "virtio-tablet"
+#define MAX_BUF_COUNT 256
+static int vqidx;
+/*
+ * Tablet event queue
+ */
+typedef struct TabletEventEntry {
+    unsigned int index;
+    EmulTabletEvent tablet;
+
+    QTAILQ_ENTRY(TabletEventEntry) node;
+} TabletEventEntry;
+
+/* the maximum number of Tablet event that can be put into a queue */
+#define MAX_TABLET_EVENT_CNT 256
+
+static TabletEventEntry _events_buf[MAX_TABLET_EVENT_CNT];
+static QTAILQ_HEAD(, TabletEventEntry) events_queue =
+    QTAILQ_HEAD_INITIALIZER(events_queue);
+
+static unsigned int event_ringbuf_cnt; /* _events_buf */
+static unsigned int event_queue_cnt; /* events_queue */
+
+/*
+ * VirtQueueElement queue
+ */
+typedef struct ElementEntry {
+    unsigned int el_index;
+    unsigned int sg_index;
+    VirtQueueElement elem;
+
+    QTAILQ_ENTRY(ElementEntry) node;
+} ElementEntry;
+
+static QTAILQ_HEAD(, ElementEntry) elem_queue =
+    QTAILQ_HEAD_INITIALIZER(elem_queue);
+
+static unsigned int elem_ringbuf_cnt; /* _elem_buf */
+static unsigned int elem_queue_cnt; /* elem_queue */
+
+VirtIOTablet *vtk;
+VirtQueueElement elem_vtk;
+
+/* lock for between communication thread and IO thread */
+static pthread_mutex_t event_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+void maru_tablet_event(int event_type, int x, int y, int btn, int btn_status)
+{
+    TabletEventEntry *entry = NULL;
+
+    if (!vtk) {
+        INFO("Tablet device can not be used.\n");
+        return;
+    }
+
+    if (unlikely(event_queue_cnt >= MAX_TABLET_EVENT_CNT)) {
+        INFO("full tablet event queue, lose event\n", event_queue_cnt);
+
+        qemu_bh_schedule(vtk->bh);
+        return;
+    }
+
+    entry = &(_events_buf[event_ringbuf_cnt % MAX_TABLET_EVENT_CNT]);
+
+    /* tablet event is copied into the queue */
+    entry->tablet.x = x;
+    entry->tablet.y = y;
+    entry->tablet.btn = btn;
+    entry->tablet.btn_status = btn_status;
+    entry->tablet.event_type = event_type;
+
+    pthread_mutex_lock(&event_mutex);
+
+    event_ringbuf_cnt++;
+
+    /* 1 ~ */
+    entry->index = ++event_queue_cnt;
+
+    QTAILQ_INSERT_TAIL(&events_queue, entry, node);
+
+    pthread_mutex_unlock(&event_mutex);
+
+    /* call maru_virtio_tablet_notify */
+    qemu_bh_schedule(vtk->bh);
+
+    TRACE("tablet event (%d) : x=%d, y=%d, btn=%d, btn_status=%d, event_type=%d\n",
+        entry->index, entry->tablet.x, entry->tablet.y, entry->tablet.btn,
+        entry->tablet.btn_status, entry->tablet.event_type);
+}
+
+static void maru_virtio_tablet_handle(VirtIODevice *vdev, VirtQueue *vq)
+{
+    int virt_sg_index = 0;
+
+    TRACE("maru_virtio_tablet_handle\n");
+
+    if (unlikely(virtio_queue_empty(vtk->vq))) {
+        TRACE("virtqueue is empty\n");
+        return;
+    }
+    /* Get a queue buffer which is written by guest side. */
+    do {
+        virt_sg_index = virtqueue_pop(vq, &elem_vtk);
+    } while (virt_sg_index < MAX_BUF_COUNT);
+}
+
+void maru_virtio_tablet_notify(void)
+{
+    TabletEventEntry *event_entry = NULL;
+
+    TRACE("maru_virtio_tablet_notify\n");
+
+    if (unlikely(!virtio_queue_ready(vtk->vq))) {
+        ERR("virtio queue is not ready\n");
+        return;
+    }
+
+    while (true) {
+        if (event_queue_cnt == 0) {
+            TRACE("no event\n");
+            break;
+        }
+
+        /* get tablet event from host queue */
+        event_entry = QTAILQ_FIRST(&events_queue);
+
+        /* copy event into virtio buffer */
+        memcpy(elem_vtk.in_sg[vqidx++].iov_base, &(event_entry->tablet),
+                sizeof(EmulTabletEvent));
+        if (vqidx == MAX_BUF_COUNT) {
+            vqidx = 0;
+        }
+
+        virtqueue_push(vtk->vq, &elem_vtk, sizeof(EmulTabletEvent));
+        virtio_notify(&vtk->vdev, vtk->vq);
+
+        pthread_mutex_lock(&event_mutex);
+
+        /* remove host event */
+        QTAILQ_REMOVE(&events_queue, event_entry, node);
+        event_queue_cnt--;
+
+        pthread_mutex_unlock(&event_mutex);
+    }
+}
+
+static uint32_t virtio_tablet_get_features(
+    VirtIODevice *vdev, uint32_t request_features)
+{
+    return request_features;
+}
+
+static void maru_tablet_bh(void *opaque)
+{
+    maru_virtio_tablet_notify();
+}
+
+static void virtio_tablet_device_realize(DeviceState *dev, Error **errp)
+{
+    INFO("initialize the tablet device\n");
+    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+    vtk = VIRTIO_TABLET(dev);
+
+    if (vdev == NULL) {
+        ERR("failed to initialize the tablet device\n");
+        return;
+    }
+
+    virtio_init(vdev, TYPE_VIRTIO_TABLET, VIRTIO_ID_TABLET, 0);
+
+    vtk->vq = virtio_add_queue(vdev, MAX_BUF_COUNT, maru_virtio_tablet_handle);
+
+    vtk->qdev = dev;
+
+    /* reset the counters */
+    pthread_mutex_lock(&event_mutex);
+    event_queue_cnt = event_ringbuf_cnt = 0;
+    pthread_mutex_unlock(&event_mutex);
+
+    elem_queue_cnt = elem_ringbuf_cnt = 0;
+
+    /* bottom-half */
+    vtk->bh = qemu_bh_new(maru_tablet_bh, vtk);
+}
+
+static void virtio_tablet_device_unrealize(DeviceState *dev, Error **errp)
+{
+    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+
+    INFO("exit the tablet device\n");
+
+    if (vtk->bh) {
+        qemu_bh_delete(vtk->bh);
+    }
+
+    virtio_cleanup(vdev);
+
+    pthread_mutex_destroy(&event_mutex);
+}
+
+static void virtio_tablet_device_reset(VirtIODevice *vdev)
+{
+    INFO("reset tablet device\n");
+    vqidx = 0;
+}
+
+static void virtio_tablet_class_init(ObjectClass *klass, void *data)
+{
+    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
+    vdc->unrealize = virtio_tablet_device_unrealize;
+    vdc->realize = virtio_tablet_device_realize;
+    vdc->reset = virtio_tablet_device_reset;
+    vdc->get_features = virtio_tablet_get_features;
+}
+
+static const TypeInfo virtio_tablet_info = {
+    .name = TYPE_VIRTIO_TABLET,
+    .parent = TYPE_VIRTIO_DEVICE,
+    .instance_size = sizeof(VirtIOTablet),
+    .class_init = virtio_tablet_class_init,
+};
+
+static void virtio_register_types(void)
+{
+    type_register_static(&virtio_tablet_info);
+}
+
+type_init(virtio_register_types)
diff --git a/tizen/src/hw/virtio/maru_virtio_tablet.h b/tizen/src/hw/virtio/maru_virtio_tablet.h
new file mode 100644 (file)
index 0000000..2b35527
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Maru Virtio Tablet Device
+ *
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ *  Sungmin Ha <sungmin82.ha@samsung.com>
+ *  Sangho Park <sangho.p@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#ifndef MARU_TABLET_H_
+#define MARU_TABLET_H_
+
+#include "ui/console.h"
+#include "hw/virtio/virtio.h"
+
+#define TYPE_VIRTIO_TABLET "virtio-tablet-device"
+#define VIRTIO_TABLET(obj) \
+        OBJECT_CHECK(VirtIOTablet, (obj), TYPE_VIRTIO_TABLET)
+
+typedef struct VirtIOTablet
+{
+    VirtIODevice vdev;
+    /* simply a queue into which buffers are posted
+    by the guest for consumption by the host */
+    VirtQueue *vq;
+
+    QEMUBH *bh;
+    DeviceState *qdev;
+} VirtIOTablet;
+
+/* This structure must match the kernel definitions */
+typedef struct EmulTabletEvent {
+    uint8_t event_type;
+    uint32_t x;
+    uint32_t y;
+    uint32_t btn;
+    uint32_t btn_status;
+} EmulTabletEvent;
+
+VirtIODevice *maru_virtio_tablet_init(DeviceState *dev);
+void maru_virtio_tablet_exit(VirtIODevice *vdev);
+
+void maru_tablet_event(int event_type, int x, int y, int btn, int btn_status);
+void maru_virtio_tablet_notify(void);
+
+#endif /* MARU_TABLET_H_ */
index 0fd2b3e..f89edea 100644 (file)
@@ -53,6 +53,7 @@
 #include "ecs/ecs.h"
 #include "hw/virtio/maru_virtio_evdi.h"
 #include "hw/virtio/maru_virtio_rotary.h"
+#include "ui/input.h"
 
 #ifdef CONFIG_HAX
 #include "target-i386/hax-i386.h"
@@ -175,7 +176,23 @@ void do_mouse_event(int button_type, int event_type,
             guest_x = x;
             guest_y = y;
 
-            virtio_touchscreen_event(x, y, z, event_type);
+            if (x != 0) {
+                qemu_input_queue_rel(NULL, INPUT_AXIS_X, x);
+            }
+            if (y != 0) {
+                qemu_input_queue_rel(NULL, INPUT_AXIS_Y, y);
+            }
+            qemu_input_event_sync();
+
+            break;
+        case PS2_DOWN:
+            qemu_input_queue_btn(NULL, INPUT_BUTTON_LEFT, 1);
+            qemu_input_event_sync();
+
+            break;
+        case PS2_UP:
+            qemu_input_queue_btn(NULL, INPUT_BUTTON_LEFT, 0);
+            qemu_input_event_sync();
 
             break;
         default:
index a8ba5fe..6225b8a 100644 (file)
@@ -33,6 +33,7 @@
 
 extern "C" {
 void req_set_sensor_accel_angle(int angle);
+void maru_tablet_event(int event_type, int x, int y, int btn, int btn_status);
 }
 
 #define BLANK_GUIDE_IMAGE_PATH "../images/"
@@ -42,8 +43,8 @@ uint32_t qt5_window_width = 0;
 uint32_t qt5_window_height = 0;
 int qt5_window_angle = 0;
 
-DisplayBase::DisplayBase(DisplayType *displayForm, qreal scaleFactor,
-    QWidget *w) : widget(w)
+DisplayBase::DisplayBase(DisplayType *displayForm, QSize resolution, qreal scaleFactor,
+    QWidget *w) : resolution(resolution), widget(w)
 {
     this->rect = displayForm->getRect();
     this->maskImage = displayForm->getMask();
@@ -56,6 +57,14 @@ DisplayBase::DisplayBase(DisplayType *displayForm, qreal scaleFactor,
     this->gImg = new QImage();
     this->gPxmImg = new QPixmap();
 
+    isMouse = is_emul_input_mouse_enable();
+    if (isMouse) {
+        prevX = 0;
+        prevY = 0;
+        lastMouseTime.tv_sec = 0;
+        mouseStatus = MOUSE_LEAVE;
+    }
+
     loadGuideImg();
 
     MainWindow *win = (MainWindow *)widget->parentWidget();
@@ -238,7 +247,11 @@ void DisplayBase::handleMousePress(QMouseEvent *event)
     if (event->button() == Qt::LeftButton) {
         isDragging = true;
 
-        tsHelper->mousePressed(event, getGuestPos(event->pos()));
+        if (isMouse) {
+            do_mouse_event(1, PS2_PRESS, 0, 0, 0, 0, 0);
+        } else {
+            tsHelper->mousePressed(event, getGuestPos(event->pos()));
+        }
     }
 }
 
@@ -249,45 +262,147 @@ void DisplayBase::handleMouseRelease(QMouseEvent *event)
             isDragging = false;
         }
 
-        tsHelper->mouseReleased(event, getGuestPos(event->pos()));
+        if (isMouse) {
+            do_mouse_event(1, PS2_RELEASE, 0, 0, 0, 0, 0);
+        } else {
+            tsHelper->mouseReleased(event, getGuestPos(event->pos()));
+        }
     }
 }
 
 void DisplayBase::handleMouseMove(QMouseEvent *event)
 {
-    if (isDragging == true) {
-        int hostPosX = event->x();
-        int hostPosY = event->y();
-
-        /* bounds checking */
-        if (hostPosX < 0) {
-            hostPosX = 0;
-            isDragging = false;
-        } else if (hostPosX >= widget->width()) {
-            hostPosX = widget->width() - 1;
-            isDragging = false;
+    if (isMouse) {
+        int event_type = MOUSE_MOVE;
+        int clientX = event->x();
+        int clientY = event->y();
+
+        if (clientX < 0 || clientX > widget->width() ||
+                    clientY < 0 || clientY > widget->height()) {
+            if (isDragging == true) {
+                isDragging = false;
+                qDebug("auto released...");
+                do_mouse_event(1, PS2_RELEASE, 0, 0, 0, 0, 0);
+                return;
+            } else {
+                /* do nothing */
+            }
         }
-
-        if (hostPosY < 0) {
-            hostPosY = 0;
-            isDragging = false;
-        } else if (hostPosY >= widget->height()) {
-            hostPosY = widget->height() - 1;
-            isDragging = false;
+        sendMouseEvent(event_type, clientX, clientY);
+    } else { /* touch device */
+        if (isDragging == true) {
+            int hostPosX = event->x();
+            int hostPosY = event->y();
+
+            /* bounds checking */
+            if (hostPosX < 0) {
+                hostPosX = 0;
+                isDragging = false;
+            } else if (hostPosX >= widget->width()) {
+                hostPosX = widget->width() - 1;
+                isDragging = false;
+            }
+
+            if (hostPosY < 0) {
+                hostPosY = 0;
+                isDragging = false;
+            } else if (hostPosY >= widget->height()) {
+                hostPosY = widget->height() - 1;
+                isDragging = false;
+            }
+
+            if (isDragging == false) {
+                QPoint clientPos(hostPosX, hostPosY);
+                qDebug() << "drag out of touch screen :" << clientPos;
+
+                // TODO: modify event
+                tsHelper->mouseReleased(event, getGuestPos(clientPos));
+            } else {
+                tsHelper->mouseMoved(event, getGuestPos(event->pos()));
+            }
         }
+    }
+}
 
-        if (isDragging == false) {
-            QPoint clientPos(hostPosX, hostPosY);
-            qDebug() << "drag out of touch screen :" << clientPos;
+void DisplayBase::handleMouseInit(QMouseEvent *event)
+{
+    do_mouse_event(1, MOUSE_MOVE, -widget->width()/scaleFactor,
+            -widget->height()/scaleFactor,
+            -widget->width()/scaleFactor,
+            -widget->height()/scaleFactor, 0);
+    prevX = 0;
+    prevY = 0;
+}
 
-            // TODO: modify event
-            tsHelper->mouseReleased(event, getGuestPos(clientPos));
-        } else {
-            tsHelper->mouseMoved(event, getGuestPos(event->pos()));
+void DisplayBase::handleMouseEnter(QEvent *event)
+{
+    if (isMouse) {
+        if (mouseStatus == MOUSE_LEAVE) {
+            mouseStatus = MOUSE_ENTER;
         }
     }
 }
 
+void DisplayBase::handleMouseLeave(QEvent *event)
+{
+    if (isMouse) {
+        mouseStatus = MOUSE_LEAVE;
+    }
+}
+
+void DisplayBase::sendMouseEvent(int eventType, int clientX, int clientY)
+{
+    int xx = clientX / scaleFactor;
+    int yy = clientY / scaleFactor;
+    int absX = xx;
+    int absY = yy;
+
+    /* TODO: x*cos(rad)-y*sin(rad) */
+    switch(rotateAngle) {
+    case 90: /* Reverse Landscape */
+        absX = yy;
+        absY = resolution.height() - xx;
+        break;
+    case 180: /* Reverse Portrait */
+        absX = resolution.width() - xx;
+        absY = resolution.height() - yy;
+        break;
+    case 270: /* Landscape */
+        absX = resolution.width() - yy;
+        absY = xx;
+        break;
+    case 0:
+    default:
+        break;
+    }
+
+    /* Because the TV usb mouse pointer is moved to center after a couple of seconds.
+     * Also the mouse pointer can be entered before emulator skin is initialized.
+     */
+    struct timeval tv;
+    gettimeofday(&tv, NULL);
+    if (tv.tv_sec - lastMouseTime.tv_sec > CURSOR_RESET_TIME || mouseStatus != MOUSE_ENTERED) {
+        maru_tablet_event(INPUT_MOVE, absX, absY, 0, 0);
+        prevX = absX;
+        prevY = absY;
+        mouseStatus = MOUSE_ENTERED;
+    }
+    gettimeofday(&lastMouseTime, NULL);
+
+    prevX = (prevX > resolution.width()) ? resolution.width() : prevX;
+    prevX = (prevX < 0) ? 0 : prevX;
+
+    prevY = (prevY > resolution.height()) ? resolution.height() : prevY;
+    prevY = (prevY < 0) ? 0 : prevY;
+
+    int relX = absX - prevX;
+    int relY = absY - prevY;
+
+    do_mouse_event(1, MOUSE_MOVE, clientX, clientY, relX, relY, 0);
+    prevX = absX;
+    prevY = absY;
+}
+
 DisplayBase::~DisplayBase()
 {
     qDebug("destroy display");
index fd5c0bc..127c892 100644 (file)
@@ -35,6 +35,7 @@
 #include <QLabel>
 #include <QImage>
 #include <QPixmap>
+#include <sys/time.h>
 
 #include "layout/displaytype.h"
 #include "input/touchscreenhelper.h"
@@ -43,6 +44,28 @@ extern "C" {
 void qt5_graphic_hw_invalidate(void);
 }
 
+enum {
+    TOUCH_PRESS = 1,
+    TOUCH_RELEASE = 2,
+    PS2_MOVE = 6,
+    PS2_PRESS = 8,
+    PS2_RELEASE = 9,
+};
+
+enum {
+    MOUSE_LEAVE = 0,
+    MOUSE_ENTER = 1,
+    MOUSE_ENTERED = 2,
+};
+
+/* keep it consistent with emulator-kernel tablet definition */
+enum {
+    INPUT_MOVE = 1,
+    INPUT_BTN = 2,
+};
+
+#define CURSOR_RESET_TIME 6    /* TV spec (sec) */
+
 class DisplayBase
 {
 public:
@@ -63,7 +86,7 @@ public:
     TouchScreenHelper *getTouchScreenHelper();
 
 protected:
-    DisplayBase(DisplayType *displayForm, qreal scaleFactor, QWidget *w);
+    DisplayBase(DisplayType *displayForm, QSize resolution, qreal scaleFactor, QWidget *w);
     virtual ~DisplayBase();
 
     void handlePaint(QPaintEvent *event);
@@ -72,12 +95,26 @@ protected:
     void handleMousePress(QMouseEvent *event);
     void handleMouseRelease(QMouseEvent *event);
     void handleMouseMove(QMouseEvent *event);
+    void handleMouseInit(QMouseEvent *event);
+
+    void handleMouseEnter(QEvent *event);
+    void handleMouseLeave(QEvent *event);
 
     int rotateAngle;
     qreal scaleFactor;
     bool isDragging;
 
 private:
+    void sendMouseEvent(int eventType, int clientX, int clientY);
+
+    QSize resolution;
+    bool isMouse;
+
+    int prevX;
+    int prevY;
+    int mouseStatus;
+    struct timeval lastMouseTime;
+
     QLabel *gLabel;
     QPixmap *gPxmImg;
     QImage *gImg;
index 8eccc9f..28b5f81 100644 (file)
 
 #include "displayglwidget.h"
 
+extern "C" {
+#include "emul_state.h"
+};
+
 DisplayGLWidget::DisplayGLWidget(QWidget *parent, QGLContext *context,
-    DisplayType *displayForm, qreal scaleFactor) :
-    QGLWidget(context, parent), DisplayBase(displayForm, scaleFactor, this)
+    DisplayType *displayForm, QSize resolution, qreal scaleFactor) :
+    QGLWidget(context, parent), DisplayBase(displayForm, resolution, scaleFactor, this)
 {
     setAutoBufferSwap(false);
+    isMouse = is_emul_input_mouse_enable();
+    /* mouse mode */
+    if (isMouse) {
+        setCursor(Qt::BlankCursor);
+        setMouseTracking(true);
+    }
 }
 
 void DisplayGLWidget::initializeGL()
@@ -74,6 +84,16 @@ void DisplayGLWidget::mouseReleaseEvent(QMouseEvent *event)
     handleMouseRelease(event);
 }
 
+void DisplayGLWidget::enterEvent(QEvent *event)
+{
+    handleMouseEnter(event);
+}
+
+void DisplayGLWidget::leaveEvent(QEvent *event)
+{
+    handleMouseLeave(event);
+}
+
 void DisplayGLWidget::mouseMoveEvent(QMouseEvent *event)
 {
     handleMouseMove(event);
index bd2e6a0..f41e083 100644 (file)
@@ -42,7 +42,7 @@ class DisplayGLWidget : public QGLWidget,
 
 public:
     DisplayGLWidget(QWidget *parent, QGLContext *context,
-        DisplayType *displayForm, qreal scaleFactor);
+        DisplayType *displayForm, QSize resolution, qreal scaleFactor);
     ~DisplayGLWidget();
 
 protected:
@@ -54,6 +54,11 @@ protected:
     void mousePressEvent(QMouseEvent *event);
     void mouseReleaseEvent(QMouseEvent *event);
     void mouseMoveEvent(QMouseEvent *event);
+
+    void enterEvent(QEvent *event);
+    void leaveEvent(QEvent *event);
+private:
+    bool isMouse;
 };
 
 #endif // DISPLAYGLWIDGET_H
index 67d2e14..7d1d278 100644 (file)
 #include "displayswwidget.h"
 #include "input/multitouchtracker.h"
 
+extern "C" {
+#include "emul_state.h"
+};
+
 DisplaySWWidget::DisplaySWWidget(QWidget *parent,
-    DisplayType *displayForm, qreal scaleFactor) :
-    QLabel(parent), DisplayBase(displayForm, scaleFactor, this)
+    DisplayType *displayForm, QSize resolution, qreal scaleFactor) :
+    QLabel(parent), DisplayBase(displayForm, resolution, scaleFactor, this)
 {
     this->mtTracker = getTouchScreenHelper()->getMtTracker();
 
@@ -43,6 +47,13 @@ DisplaySWWidget::DisplaySWWidget(QWidget *parent,
         displayForm->getRect().height() * scaleFactor);
     initImage.fill(Qt::black);
     setPixmap(initImage);
+
+    isMouse = is_emul_input_mouse_enable();
+    /* mouse mode */
+    if (isMouse) {
+        setCursor(Qt::BlankCursor);
+        setMouseTracking(true);
+    }
 }
 
 /* override */
@@ -93,6 +104,16 @@ void DisplaySWWidget::mouseMoveEvent(QMouseEvent *event)
     handleMouseMove(event);
 }
 
+void DisplaySWWidget::enterEvent(QEvent *event)
+{
+    handleMouseEnter(event);
+}
+
+void DisplaySWWidget::leaveEvent(QEvent *event)
+{
+    handleMouseLeave(event);
+}
+
 DisplaySWWidget::~DisplaySWWidget()
 {
     /* do nothing */
index f38d3ca..779c7e8 100644 (file)
@@ -42,7 +42,7 @@ class DisplaySWWidget : public QLabel,
 
 public:
     DisplaySWWidget(QWidget *parent,
-        DisplayType *displayForm, qreal scaleFactor);
+        DisplayType *displayForm, QSize resolution, qreal scaleFactor);
     ~DisplaySWWidget();
 
 protected:
@@ -53,8 +53,11 @@ protected:
     void mouseReleaseEvent(QMouseEvent *event);
     void mouseMoveEvent(QMouseEvent *event);
 
+    void enterEvent(QEvent *event);
+    void leaveEvent(QEvent *event);
 private:
     MultiTouchTracker *mtTracker;
+    bool isMouse;
 };
 
 #endif // DISPLAYSWWIDGET_H
index da51172..dcf9599 100644 (file)
@@ -129,7 +129,7 @@ DisplayBase *MainWindow::createDisplay(DisplayType *displayForm)
         QGLContext *context = new QGLContext(format);
 
         displayWidget = new DisplayGLWidget(this, context,
-            displayForm, getUIState()->getScaleFactor());
+            displayForm, uiInfo->resolution, getUIState()->getScaleFactor());
 
         context->setFormat(format);
         context->create(wrapperContext);
@@ -153,7 +153,7 @@ DisplayBase *MainWindow::createDisplay(DisplayType *displayForm)
         swapperThread->start();
     } else { /* off-screen rendering */
         DisplaySWWidget *widget = new DisplaySWWidget(this,
-            displayForm, getUIState()->getScaleFactor());
+            displayForm, uiInfo->resolution, getUIState()->getScaleFactor());
 
         screenWidget = widget;
         displayWidget = widget;