diff --git a/backends/msmouse.c b/backends/msmouse.c
index 035b7b4..3f35e7e 100644
--- a/backends/msmouse.c
+++ b/backends/msmouse.c
@@ -29,10 +29,16 @@
 #define MSMOUSE_LO6(n) ((n) & 0x3f)
 #define MSMOUSE_HI2(n) (((n) & 0xc0) >> 6)
 
+typedef struct MSMouseState {
+    CharDriverState chr;
+
+    int buttons_state;
+} MSMouseState;
+
 static void msmouse_event(void *opaque,
                           int dx, int dy, int dz, int buttons_state)
 {
-    CharDriverState *chr = (CharDriverState *)opaque;
+    MSMouseState *s = opaque;
 
     unsigned char bytes[4] = { 0x40, 0x00, 0x00, 0x00 };
 
@@ -49,7 +55,16 @@ static void msmouse_event(void *opaque,
     /* We always send the packet of, so that we do not have to keep track
        of previous state of the middle button. This can potentially confuse
        some very old drivers for two button mice though. */
-    qemu_chr_be_write(chr, bytes, 4);
+    qemu_chr_be_write(&s->chr, bytes, 4);
+
+    s->buttons_state = buttons_state;
+}
+
+static int msmouse_get_buttons_state(void *opaque)
+{
+    MSMouseState *s = opaque;
+
+    return s->buttons_state;
 }
 
 static int msmouse_chr_write (struct CharDriverState *s, const uint8_t *buf, int len)
@@ -65,13 +80,14 @@ static void msmouse_chr_close (struct CharDriverState *chr)
 
 static const MouseOps msmouse_mouse_ops = {
     .put_event = msmouse_event,
+    .get_buttons_state = msmouse_get_buttons_state,
 };
 
 CharDriverState *qemu_chr_open_msmouse(void)
 {
     CharDriverState *chr;
 
-    chr = g_malloc0(sizeof(CharDriverState));
+    chr = g_malloc0(sizeof(MSMouseState));
     chr->chr_write = msmouse_chr_write;
     chr->chr_close = msmouse_chr_close;
     chr->explicit_be_open = true;
diff --git a/hw/char/escc.c b/hw/char/escc.c
index f6592cb..1ac4d9e 100644
--- a/hw/char/escc.c
+++ b/hw/char/escc.c
@@ -88,6 +88,7 @@ typedef struct ChannelState {
     SERIOQueue queue;
     CharDriverState *chr;
     int e0_mode, led_mode, caps_lock_mode, num_lock_mode;
+    int buttons_state;
     int disabled;
     int clock;
     uint32_t vmstate_dummy;
@@ -304,6 +305,7 @@ static void escc_reset_chn(ChannelState *s)
     s->rxint = s->txint = 0;
     s->rxint_under_svc = s->txint_under_svc = 0;
     s->e0_mode = s->led_mode = s->caps_lock_mode = s->num_lock_mode = 0;
+    s->buttons_state = 0;
     clear_queue(s);
 }
 
@@ -813,6 +815,7 @@ static void sunmouse_event(void *opaque,
     trace_escc_sunmouse_event(dx, dy, buttons_state);
     ch = 0x80 | 0x7; /* protocol start byte, no buttons pressed */
 
+    s->buttons_state = buttons_state;
     if (buttons_state & MOUSE_EVENT_LBUTTON)
         ch ^= 0x4;
     if (buttons_state & MOUSE_EVENT_MBUTTON)
@@ -846,6 +849,13 @@ static void sunmouse_event(void *opaque,
     put_queue(s, 0);
 }
 
+static int sunmouse_get_buttons_state(void *opaque)
+{
+    ChannelState *s = opaque;
+
+    return s->buttons_state;
+}
+
 void slavio_serial_ms_kbd_init(hwaddr base, qemu_irq irq,
                                int disabled, int clock, int it_shift)
 {
@@ -869,6 +879,7 @@ void slavio_serial_ms_kbd_init(hwaddr base, qemu_irq irq,
 
 static const MouseOps sunmouse_mouse_ops = {
     .put_event = sunmouse_event,
+    .get_buttons_state = sunmouse_get_buttons_state,
 };
 
 static int escc_init1(SysBusDevice *dev)
diff --git a/hw/display/ads7846.c b/hw/display/ads7846.c
index 9026d97..d8d05e6 100644
--- a/hw/display/ads7846.c
+++ b/hw/display/ads7846.c
@@ -108,6 +108,13 @@ static void ads7846_ts_event(void *opaque,
     }
 }
 
+static int ads7846_ts_get_buttons_state(void *opaque)
+{
+    ADS7846State *s = opaque;
+
+    return s->pressure;
+}
+
 static int ads7856_post_load(void *opaque, int version_id)
 {
     ADS7846State *s = opaque;
@@ -135,6 +142,7 @@ static const VMStateDescription vmstate_ads7846 = {
 
 static const MouseOps ads7846_ts_ops = {
     .put_event = ads7846_ts_event,
+    .get_buttons_state = ads7846_ts_get_buttons_state,
 };
 
 static int ads7846_init(SSISlave *dev)
diff --git a/hw/display/xenfb.c b/hw/display/xenfb.c
index 14dac45..0d27377 100644
--- a/hw/display/xenfb.c
+++ b/hw/display/xenfb.c
@@ -64,6 +64,7 @@ struct XenInput {
     int extended;
     QEMUPutMouseEntry *qmouse;
 };
+typedef struct XenInput XenInput;
 
 #define UP_QUEUE 8
 
@@ -342,6 +343,13 @@ static void xenfb_mouse_event(void *opaque,
     xenfb->button_state = button_state;
 }
 
+static int xenfb_mouse_get_buttons_state(void *opaque)
+{
+    XenInput *in = opaque;
+
+    return in->button_state;
+}
+
 static int input_init(struct XenDevice *xendev)
 {
     xenstore_write_be_int(xendev, "feature-abs-pointer", 1);
@@ -368,6 +376,7 @@ static int input_initialise(struct XenDevice *xendev)
 
 static const MouseOps xenfb_mouse_ops = {
     .put_event = xenfb_mouse_event,
+    .get_buttons_state = xenfb_mouse_get_buttons_state,
 };
 
 static void input_connected(struct XenDevice *xendev)
diff --git a/hw/input/adb.c b/hw/input/adb.c
index 88edf57..e12d978 100644
--- a/hw/input/adb.c
+++ b/hw/input/adb.c
@@ -404,6 +404,12 @@ static void adb_mouse_event(void *opaque,
     s->buttons_state = buttons_state;
 }
 
+static int adb_mouse_get_buttons_state(void *opaque)
+{
+    MouseState *s = opaque;
+
+    return s->buttons_state;
+}
 
 static int adb_mouse_poll(ADBDevice *d, uint8_t *obuf)
 {
@@ -531,6 +537,7 @@ static const VMStateDescription vmstate_adb_mouse = {
 
 static const MouseOps adb_mouse_ops = {
     .put_event = adb_mouse_event,
+    .get_buttons_state = adb_mouse_get_buttons_state,
 };
 
 static void adb_mouse_realizefn(DeviceState *dev, Error **errp)
diff --git a/hw/input/hid.c b/hw/input/hid.c
index 4cdc8a9..ebe6276 100644
--- a/hw/input/hid.c
+++ b/hw/input/hid.c
@@ -158,6 +158,18 @@ static void hid_pointer_event(void *opaque,
     hs->event(hs);
 }
 
+static int hid_pointer_get_buttons_state(void *opaque)
+{
+    HIDState *hs = opaque;
+    int index;
+    HIDPointerEvent *e;
+
+    index = (hs->n ? hs->head : hs->head - 1);
+    e = &hs->ptr.queue[index & QUEUE_MASK];
+
+    return e->buttons_state;
+}
+
 static void hid_keyboard_event(void *opaque, int keycode)
 {
     HIDState *hs = opaque;
@@ -427,6 +439,7 @@ void hid_free(HIDState *hs)
 
 static const MouseOps hid_mouse_ops = {
     .put_event = hid_pointer_event,
+    .get_buttons_state = hid_pointer_get_buttons_state,
 };
 
 void hid_init(HIDState *hs, int kind, HIDEventFunc event)
diff --git a/hw/input/ps2.c b/hw/input/ps2.c
index 743e380..a4de407 100644
--- a/hw/input/ps2.c
+++ b/hw/input/ps2.c
@@ -391,6 +391,13 @@ void ps2_mouse_fake_event(void *opaque)
     ps2_mouse_event(opaque, 1, 0, 0, 0);
 }
 
+static int ps2_mouse_get_buttons_state(void *opaque)
+{
+    PS2MouseState *s = opaque;
+
+    return s->mouse_buttons;
+}
+
 void ps2_write_mouse(void *opaque, int val)
 {
     PS2MouseState *s = (PS2MouseState *)opaque;
@@ -665,6 +672,7 @@ void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg)
 
 static const MouseOps ps2_mouse_ops = {
     .put_event = ps2_mouse_event,
+    .get_buttons_state = ps2_mouse_get_buttons_state,
 };
 
 void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg)
diff --git a/hw/input/tsc2005.c b/hw/input/tsc2005.c
index 69b543c..ed9f405 100644
--- a/hw/input/tsc2005.c
+++ b/hw/input/tsc2005.c
@@ -432,6 +432,13 @@ static void tsc2005_touchscreen_event(void *opaque,
         tsc2005_pin_update(s);
 }
 
+static int tsc2005_touchscreen_get_buttons_state(void *opaque)
+{
+    TSC2005State *s = opaque;
+
+    return s->pressure;
+}
+
 static void tsc2005_save(QEMUFile *f, void *opaque)
 {
     TSC2005State *s = (TSC2005State *) opaque;
@@ -521,6 +528,7 @@ static int tsc2005_load(QEMUFile *f, void *opaque, int version_id)
 
 static const MouseOps tsc2005_touchscreen_ops = {
     .put_event = tsc2005_touchscreen_event,
+    .get_buttons_state = tsc2005_touchscreen_get_buttons_state,
 };
 
 void *tsc2005_init(qemu_irq pintdav)
diff --git a/hw/input/tsc210x.c b/hw/input/tsc210x.c
index 66e18fb..593b90d 100644
--- a/hw/input/tsc210x.c
+++ b/hw/input/tsc210x.c
@@ -988,6 +988,13 @@ static void tsc210x_touchscreen_event(void *opaque,
         tsc210x_pin_update(s);
 }
 
+static int tsc210x_touchscreen_get_buttons_state(void *opaque)
+{
+    TSC210xState *s = opaque;
+
+    return s->pressure;
+}
+
 static void tsc210x_i2s_swallow(TSC210xState *s)
 {
     if (s->dac_voice[0])
@@ -1102,6 +1109,7 @@ static int tsc210x_load(QEMUFile *f, void *opaque, int version_id)
 
 static const MouseOps tsc210x_touchscreen_ops = {
     .put_event = tsc210x_touchscreen_event,
+    .get_buttons_state = tsc210x_touchscreen_get_buttons_state,
 };
 
 uWireSlave *tsc2102_init(qemu_irq pint)
diff --git a/hw/input/vmmouse.c b/hw/input/vmmouse.c
index ec13a8b..dd20f1d 100644
--- a/hw/input/vmmouse.c
+++ b/hw/input/vmmouse.c
@@ -106,6 +106,16 @@ static void vmmouse_mouse_event(void *opaque, int x, int y, int dz, int buttons_
     i8042_isa_mouse_fake_event(s->ps2_mouse);
 }
 
+static int vmmouse_get_buttons_state(void *opaque)
+{
+    VMMouseState *s = opaque;
+
+    if (s->nb_queue < 4) {
+        return 0;
+    }
+    return s->queue[s->nb_queue - 4];
+}
+
 static void vmmouse_remove_handler(VMMouseState *s)
 {
     if (s->entry) {
@@ -116,6 +126,7 @@ static void vmmouse_remove_handler(VMMouseState *s)
 
 static const MouseOps vmmouse_mouse_ops = {
     .put_event = vmmouse_mouse_event,
+    .get_buttons_state = vmmouse_get_buttons_state,
 };
 
 static void vmmouse_update_handler(VMMouseState *s, uint8_t absolute)
diff --git a/hw/usb/dev-wacom.c b/hw/usb/dev-wacom.c
index 90b7fee..76f75bb 100644
--- a/hw/usb/dev-wacom.c
+++ b/hw/usb/dev-wacom.c
@@ -155,6 +155,13 @@ static void usb_wacom_event(void *opaque,
     usb_wakeup(s->intr, 0);
 }
 
+static int usb_mouse_get_buttons_state(void *opaque)
+{
+    USBWacomState *s = opaque;
+
+    return s->buttons_state;
+}
+
 static inline int int_clamp(int val, int vmin, int vmax)
 {
     if (val < vmin)
@@ -167,6 +174,7 @@ static inline int int_clamp(int val, int vmin, int vmax)
 
 static const MouseOps usb_mouse_ops = {
     .put_event = usb_mouse_event,
+    .get_buttons_state = usb_mouse_get_buttons_state,
 };
 
 static int usb_mouse_poll(USBWacomState *s, uint8_t *buf, int len)
@@ -209,6 +217,7 @@ static int usb_mouse_poll(USBWacomState *s, uint8_t *buf, int len)
 
 static const MouseOps usb_wacom_ops = {
     .put_event = usb_wacom_event,
+    .get_buttons_state = usb_mouse_get_buttons_state,
 };
 
 static int usb_wacom_poll(USBWacomState *s, uint8_t *buf, int len)
diff --git a/include/ui/console.h b/include/ui/console.h
index 30b0451..2ac6403 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -29,13 +29,16 @@ typedef void QEMUPutKBDEvent(void *opaque, int keycode);
 typedef void QEMUPutLEDEvent(void *opaque, int ledstate);
 typedef void QEMUPutMouseEvent(void *opaque, int dx, int dy, int dz,
                                int buttons_state);
+typedef int QEMUGetMouseButtonsState(void *opaque);
 
 /**
  * MouseOps:
  * @put_event: Signals a mouse event to a backend.
+ * @get_buttons_state: Retrieves mouse buttons state from a backend.
  */
 typedef struct MouseOps {
     QEMUPutMouseEvent *put_event;
+    QEMUGetMouseButtonsState *get_buttons_state;
 } MouseOps;
 
 typedef struct QEMUPutMouseEntry QEMUPutMouseEntry;
