All of lore.kernel.org
 help / color / mirror / Atom feed
From: Gerd Hoffmann <kraxel@redhat.com>
To: qemu-devel@nongnu.org
Cc: "Paolo Bonzini" <pbonzini@redhat.com>,
	"Gerd Hoffmann" <kraxel@redhat.com>,
	"Marc-André Lureau" <marcandre.lureau@redhat.com>,
	"Markus Armbruster" <armbru@redhat.com>
Subject: [PATCH 3/7] ui/vdagent: add mouse support
Date: Fri, 19 Feb 2021 14:13:45 +0100	[thread overview]
Message-ID: <20210219131349.3993192-4-kraxel@redhat.com> (raw)
In-Reply-To: <20210219131349.3993192-1-kraxel@redhat.com>

This patch adds support for mouse messages to the vdagent
implementation.  This can be enabled/disabled using the new
'mouse' parameter for the vdagent chardev.  Default is on.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 chardev/char.c |   3 ++
 ui/vdagent.c   | 141 +++++++++++++++++++++++++++++++++++++++++++++++++
 qapi/char.json |   4 +-
 3 files changed, 147 insertions(+), 1 deletion(-)

diff --git a/chardev/char.c b/chardev/char.c
index 288efebd1257..ea986dac1bff 100644
--- a/chardev/char.c
+++ b/chardev/char.c
@@ -924,6 +924,9 @@ QemuOptsList qemu_chardev_opts = {
         },{
             .name = "logappend",
             .type = QEMU_OPT_BOOL,
+        },{
+            .name = "mouse",
+            .type = QEMU_OPT_BOOL,
 #ifdef CONFIG_LINUX
         },{
             .name = "tight",
diff --git a/ui/vdagent.c b/ui/vdagent.c
index 9ef4ed3f4dd8..b48b0129b9f2 100644
--- a/ui/vdagent.c
+++ b/ui/vdagent.c
@@ -1,9 +1,14 @@
 #include "qemu/osdep.h"
 #include "include/qemu-common.h"
 #include "chardev/char.h"
+#include "hw/qdev-core.h"
+#include "qemu/option.h"
+#include "ui/console.h"
+#include "ui/input.h"
 #include "trace.h"
 
 #include "qapi/qapi-types-char.h"
+#include "qapi/qapi-types-ui.h"
 
 #include "spice/vd_agent.h"
 
@@ -11,13 +16,25 @@
                      sizeof(VDAgentMessage) + \
                      VD_AGENT_MAX_DATA_SIZE)
 
+#define VDAGENT_MOUSE_DEFAULT true
+
 struct VDAgentChardev {
     Chardev parent;
 
+    /* config */
+    bool mouse;
+
     /* guest vdagent */
     uint32_t caps;
     uint8_t msgbuf[MSGSIZE_MAX];
     uint32_t msgsize;
+
+    /* mouse */
+    DeviceState mouse_dev;
+    uint32_t mouse_x;
+    uint32_t mouse_y;
+    uint32_t mouse_btn;
+    QemuInputHandlerState *mouse_hs;
 };
 typedef struct VDAgentChardev VDAgentChardev;
 
@@ -116,13 +133,105 @@ static void vdagent_send_caps(VDAgentChardev *vd)
     VDAgentMessage *msg = g_malloc0(sizeof(VDAgentMessage) +
                                     sizeof(VDAgentAnnounceCapabilities) +
                                     sizeof(uint32_t));
+    VDAgentAnnounceCapabilities *caps = (void *)msg->data;
 
     msg->type = VD_AGENT_ANNOUNCE_CAPABILITIES;
     msg->size = sizeof(VDAgentAnnounceCapabilities) + sizeof(uint32_t);
+    if (vd->mouse) {
+        caps->caps[0] |= (1 << VD_AGENT_CAP_MOUSE_STATE);
+    }
 
     vdagent_send_msg(vd, msg);
 }
 
+/* ------------------------------------------------------------------ */
+/* mouse events                                                       */
+
+static void vdagent_send_mouse(VDAgentChardev *vd)
+{
+    VDAgentMessage *msg = g_malloc0(sizeof(VDAgentMessage) +
+                                    sizeof(VDAgentMouseState));
+    VDAgentMouseState *mouse = (void *)msg->data;
+
+    msg->type = VD_AGENT_MOUSE_STATE;
+    msg->size = sizeof(VDAgentMouseState);
+
+    mouse->x       = vd->mouse_x;
+    mouse->y       = vd->mouse_y;
+    mouse->buttons = vd->mouse_btn;
+
+    vdagent_send_msg(vd, msg);
+}
+
+static void vdagent_pointer_event(DeviceState *dev, QemuConsole *src,
+                                  InputEvent *evt)
+{
+    static const int bmap[INPUT_BUTTON__MAX] = {
+        [INPUT_BUTTON_LEFT]        = VD_AGENT_LBUTTON_MASK,
+        [INPUT_BUTTON_RIGHT]       = VD_AGENT_RBUTTON_MASK,
+        [INPUT_BUTTON_MIDDLE]      = VD_AGENT_MBUTTON_MASK,
+        [INPUT_BUTTON_WHEEL_UP]    = VD_AGENT_UBUTTON_MASK,
+        [INPUT_BUTTON_WHEEL_DOWN]  = VD_AGENT_DBUTTON_MASK,
+#if 0
+        [INPUT_BUTTON_SIDE]        = VD_AGENT_SBUTTON_MASK,
+        [INPUT_BUTTON_EXTRA]       = VD_AGENT_EBUTTON_MASK,
+#endif
+    };
+
+    VDAgentChardev *vd = container_of(dev, struct VDAgentChardev, mouse_dev);
+    InputMoveEvent *move;
+    InputBtnEvent *btn;
+    uint32_t xres, yres;
+
+    switch (evt->type) {
+    case INPUT_EVENT_KIND_ABS:
+        move = evt->u.abs.data;
+        xres = qemu_console_get_width(src, 1024);
+        yres = qemu_console_get_height(src, 768);
+        if (move->axis == INPUT_AXIS_X) {
+            vd->mouse_x = qemu_input_scale_axis(move->value,
+                                                INPUT_EVENT_ABS_MIN,
+                                                INPUT_EVENT_ABS_MAX,
+                                                0, xres);
+        } else if (move->axis == INPUT_AXIS_Y) {
+            vd->mouse_y = qemu_input_scale_axis(move->value,
+                                                INPUT_EVENT_ABS_MIN,
+                                                INPUT_EVENT_ABS_MAX,
+                                                0, yres);
+        }
+        break;
+
+    case INPUT_EVENT_KIND_BTN:
+        btn = evt->u.btn.data;
+        if (btn->down) {
+            vd->mouse_btn |= bmap[btn->button];
+        } else {
+            vd->mouse_btn &= ~bmap[btn->button];
+        }
+        break;
+
+    default:
+        /* keep gcc happy */
+        break;
+    }
+}
+
+static void vdagent_pointer_sync(DeviceState *dev)
+{
+    VDAgentChardev *vd = container_of(dev, struct VDAgentChardev, mouse_dev);
+
+    if (vd->caps & (1 << VD_AGENT_CAP_MOUSE_STATE)) {
+        vdagent_send_mouse(vd);
+    }
+}
+
+static QemuInputHandler vdagent_mouse_handler = {
+    .name  = "vdagent mouse",
+    .mask  = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_ABS,
+    .event = vdagent_pointer_event,
+    .sync  = vdagent_pointer_sync,
+};
+
 /* ------------------------------------------------------------------ */
 /* chardev backend                                                    */
 
@@ -131,6 +240,19 @@ static void vdagent_chr_open(Chardev *chr,
                              bool *be_opened,
                              Error **errp)
 {
+    VDAgentChardev *vd = VDAGENT_CHARDEV(chr);
+    ChardevVDAgent *cfg = backend->u.vdagent.data;
+
+    vd->mouse = VDAGENT_MOUSE_DEFAULT;
+    if (cfg->has_mouse) {
+        vd->mouse = cfg->mouse;
+    }
+
+    if (vd->mouse) {
+        vd->mouse_hs = qemu_input_handler_register(&vd->mouse_dev,
+                                                   &vdagent_mouse_handler);
+    }
+
     *be_opened = true;
 }
 
@@ -149,6 +271,9 @@ static void vdagent_chr_recv_caps(VDAgentChardev *vd, VDAgentMessage *msg)
     if (caps->request) {
         vdagent_send_caps(vd);
     }
+    if (vd->caps & (1 << VD_AGENT_CAP_MOUSE_STATE) && vd->mouse_hs) {
+        qemu_input_handler_activate(vd->mouse_hs);
+    }
 }
 
 static uint32_t vdagent_chr_recv(VDAgentChardev *vd)
@@ -208,18 +333,34 @@ static void vdagent_chr_set_fe_open(struct Chardev *chr, int fe_open)
         /* reset state */
         vd->msgsize = 0;
         vd->caps = 0;
+        if (vd->mouse_hs) {
+            qemu_input_handler_deactivate(vd->mouse_hs);
+        }
         return;
     }
 
     trace_vdagent_open();
 }
 
+static void vdagent_chr_parse(QemuOpts *opts, ChardevBackend *backend,
+                              Error **errp)
+{
+    ChardevVDAgent *cfg;
+
+    backend->type = CHARDEV_BACKEND_KIND_VDAGENT;
+    cfg = backend->u.vdagent.data = g_new0(ChardevVDAgent, 1);
+    qemu_chr_parse_common(opts, qapi_ChardevVDAgent_base(cfg));
+    cfg->has_mouse = true;
+    cfg->mouse = qemu_opt_get_bool(opts, "mouse", VDAGENT_MOUSE_DEFAULT);
+}
+
 /* ------------------------------------------------------------------ */
 
 static void vdagent_chr_class_init(ObjectClass *oc, void *data)
 {
     ChardevClass *cc = CHARDEV_CLASS(oc);
 
+    cc->parse            = vdagent_chr_parse;
     cc->open             = vdagent_chr_open;
     cc->chr_write        = vdagent_chr_write;
     cc->chr_set_fe_open  = vdagent_chr_set_fe_open;
diff --git a/qapi/char.json b/qapi/char.json
index 62e161aea343..d8e96b772523 100644
--- a/qapi/char.json
+++ b/qapi/char.json
@@ -395,10 +395,12 @@
 #
 # Configuration info for vdagent.
 #
+# @mouse: enable/disable mouse, default is enabled.
+#
 # Since: 6.0
 ##
 { 'struct': 'ChardevVDAgent',
-  'data': { },
+  'data': { '*mouse'    : 'bool' },
   'base': 'ChardevCommon' }
 
 ##
-- 
2.29.2



  parent reply	other threads:[~2021-02-19 13:20 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-02-19 13:13 [PATCH 0/7] ui: add vdagent implementation and clipboard support Gerd Hoffmann
2021-02-19 13:13 ` [PATCH 1/7] ui: add clipboard infrastructure Gerd Hoffmann
2021-02-19 13:13 ` [PATCH 2/7] ui/vdagent: core infrastructure Gerd Hoffmann
2021-02-25 18:24   ` Marc-André Lureau
2021-02-19 13:13 ` Gerd Hoffmann [this message]
2021-02-19 13:13 ` [PATCH 4/7] ui/vdagent: add clipboard support Gerd Hoffmann
2021-02-25 18:37   ` Marc-André Lureau
2021-02-19 13:13 ` [PATCH 5/7] ui/vnc: " Gerd Hoffmann
2021-02-25 19:09   ` Marc-André Lureau
2021-03-03 12:13     ` Gerd Hoffmann
2021-03-03 14:27       ` Marc-André Lureau
2021-03-04  8:58         ` Gerd Hoffmann
2021-03-04 10:07           ` Gerd Hoffmann
2021-02-19 13:13 ` [PATCH 6/7] ui/gtk: move struct GtkDisplayState to ui/gtk.h Gerd Hoffmann
2021-02-19 13:13 ` [PATCH 7/7] ui/gtk: add clipboard support Gerd Hoffmann
2021-02-25 19:45   ` Marc-André Lureau
2021-03-03 12:20     ` Gerd Hoffmann
2021-03-03 13:54       ` Marc-André Lureau
2021-03-04  9:04         ` Gerd Hoffmann
2021-02-19 13:36 ` [PATCH 0/7] ui: add vdagent implementation and " no-reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210219131349.3993192-4-kraxel@redhat.com \
    --to=kraxel@redhat.com \
    --cc=armbru@redhat.com \
    --cc=marcandre.lureau@redhat.com \
    --cc=pbonzini@redhat.com \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.