diff --git a/src/action.c b/src/action.c
index 5c47fda..58d8af0 100644
--- a/src/action.c
+++ b/src/action.c
@@ -19,6 +19,7 @@
 
 static double xx=1, yy=1, x0=-1, y0=-1, x1=-1, y1=-1;
 static int mode = 0;
+static enum current_button button = BUTTON_RELEASED;
 
 void
 set_pointer(double x, double y)
@@ -26,6 +27,11 @@ set_pointer(double x, double y)
   xx = x+1; yy = y+1;
   if (xx < 1) xx = 1; else if (xx > screen_width)  xx = screen_width;
   if (yy < 1) yy = 1; else if (yy > screen_height) yy = screen_height;
+  if (mouse_reporting != MOUSE_REPORTING_OFF)
+  {
+    x0 = -1; y0 = -1;
+    mode = 0;
+  }
   if (x0 >= 0 && y0 >= 0)
     select_region((int)xx,(int)yy,(int)x0,(int)y0);
   else
@@ -55,6 +61,11 @@ move_pointer(double x, double y)
   xx += x/20; yy += y/20;
   if (xx < 1) xx = 1; else if (xx > screen_width)  xx = screen_width;
   if (yy < 1) yy = 1; else if (yy > screen_height) yy = screen_height;
+  if (mouse_reporting != MOUSE_REPORTING_OFF)
+  {
+    x0 = -1; y0 = -1;
+    mode = 0;
+  }
   if (x0 >= 0 && y0 >= 0)
     select_mode(mode,(int)xx,(int)yy,(int)x0,(int)y0);
   else
@@ -64,36 +75,85 @@ move_pointer(double x, double y)
 void
 press_left_button(void)
 {
-  if ((int)x1==(int)xx && (int)y1==(int)yy)
+  if (mouse_reporting != MOUSE_REPORTING_OFF)
   {
-    mode = (mode+1)%3;
-    select_mode(mode,(int)xx,(int)yy,(int)xx,(int)yy);
+    button = BUTTON_LEFT;
+    report_pointer((int)xx,(int)yy,button);
   }
   else
   {
-    mode = 0;
-    select_region((int)xx,(int)yy,(int)xx,(int)yy);
+    if ((int)x1==(int)xx && (int)y1==(int)yy)
+    {
+      mode = (mode+1)%3;
+      select_mode(mode,(int)xx,(int)yy,(int)xx,(int)yy);
+    }
+    else
+    {
+      mode = 0;
+      select_region((int)xx,(int)yy,(int)xx,(int)yy);
+    }
+    x0=xx; y0=yy; x1=x0; y1=y0;
   }
-  x0=xx; y0=yy; x1=x0; y1=y0;
 }
 
 void
 release_left_button(void)
 {
+  if (mouse_reporting == MOUSE_REPORTING_X11)
+  {
+    button = BUTTON_RELEASED;
+    report_pointer((int)xx,(int)yy,button);
+  }
   x0=-1; y0=-1;
 }
 
 void
 press_middle_button(void)
 {
-  paste();
+  if (mouse_reporting != MOUSE_REPORTING_OFF)
+  {
+    button = BUTTON_MIDDLE;
+    report_pointer((int)xx,(int)yy,button);
+  }
+  else
+  {
+    paste();
+  }
+}
+
+void
+release_middle_button(void)
+{
+  if (mouse_reporting == MOUSE_REPORTING_X11)
+  {
+    button = BUTTON_RELEASED;
+    report_pointer((int)xx,(int)yy,button);
+  }
 }
 
 void
 press_right_button(void)
 {
-  if (x1>=0 && y1>=0)
-    select_region((int)xx,(int)yy,(int)x1,(int)y1);
+  if (mouse_reporting != MOUSE_REPORTING_OFF)
+  {
+    button = BUTTON_RIGHT;
+    report_pointer((int)xx,(int)yy,button);
+  }
+  else
+  {
+    if (x1>=0 && y1>=0)
+      select_region((int)xx,(int)yy,(int)x1,(int)y1);
+  }
+}
+
+void
+release_right_button(void)
+{
+  if (mouse_reporting == MOUSE_REPORTING_X11)
+  {
+    button = BUTTON_RELEASED;
+    report_pointer((int)xx,(int)yy,button);
+  }
 }
 
 void
diff --git a/src/consolation.h b/src/consolation.h
index f907906..5290d65 100644
--- a/src/consolation.h
+++ b/src/consolation.h
@@ -19,14 +19,30 @@
 
 extern int nodaemon;
 
+enum current_button {
+  BUTTON_LEFT,
+  BUTTON_MIDDLE,
+  BUTTON_RIGHT,
+  BUTTON_RELEASED
+};
+
+enum mouse_reporting_mode {
+  MOUSE_REPORTING_OFF,
+  MOUSE_REPORTING_X10,
+  MOUSE_REPORTING_X11,
+  MOUSE_REPORTING_MODE_COUNT
+};
+
 /* global state */
 
 extern unsigned int screen_width;
 extern unsigned int screen_height;
+extern enum mouse_reporting_mode mouse_reporting;
 
 /* selection.c */
 
-void set_screen_size(void);
+void set_screen_size_and_mouse_reporting(void);
+void report_pointer(int x, int y, enum current_button button);
 void draw_pointer(int x, int y);
 void select_region(int x, int y, int x2, int y2);
 void select_words(int x, int y, int x2, int y2);
@@ -42,7 +58,9 @@ void move_pointer(double x, double y);
 void press_left_button(void);
 void release_left_button(void);
 void press_middle_button(void);
+void release_middle_button(void);
 void press_right_button(void);
+void release_right_button(void);
 void vertical_axis(double v);

 /* input.c */
diff --git a/src/input.c b/src/input.c
index 74ec072..4a6f99a 100644
--- a/src/input.c
+++ b/src/input.c
@@ -46,6 +46,7 @@
 int nodaemon = false;
 unsigned int screen_width;
 unsigned int screen_height;
+enum mouse_reporting_mode mouse_reporting = MOUSE_REPORTING_OFF;
 
 static struct tools_options options;
 static unsigned int stop = 0;
@@ -92,10 +93,14 @@ handle_pointer_button_event(struct libinput_event *ev)
   case BTN_MIDDLE:
     if (state==LIBINPUT_BUTTON_STATE_PRESSED)
       press_middle_button();
+    else
+      release_middle_button();
     break;
   case BTN_RIGHT:
     if (state==LIBINPUT_BUTTON_STATE_PRESSED)
       press_right_button();
+    else
+      release_right_button();
     break;
   }
 }
@@ -146,7 +151,7 @@ handle_events(struct libinput *li)
   struct libinput_event *ev;
 
   libinput_dispatch(li);
-  set_screen_size();
+  set_screen_size_and_mouse_reporting();
   while ((ev = libinput_get_event(li))) {
 
     switch (libinput_event_get_type(ev)) {
diff --git a/src/selection.c b/src/selection.c
index 6fbfee8..6563c01 100644
--- a/src/selection.c
+++ b/src/selection.c
@@ -22,6 +22,7 @@
 #include <linux/tiocl.h>
 #include <stdint.h>
 #include <linux/kd.h>
+#include <errno.h>
 
 #include "consolation.h"
 
@@ -34,14 +35,38 @@ check_mode(int fd)
 }
 
 void
-set_screen_size(void)
+set_screen_size_and_mouse_reporting(void)
 {
   struct winsize s;
   int fd = open("/dev/tty0",O_RDONLY);
-  if (ioctl(fd, TIOCGWINSZ, &s)) perror("TIOCGWINSZ");
+  if (fd == -1)
+  {
+    perror("open /dev/tty0");
+    return;
+  }
+  if (ioctl(fd, TIOCGWINSZ, &s))
+  {
+    perror("TIOCGWINSZ");
+  }
+  else
+  {
+    screen_width  = s.ws_col;
+    screen_height = s.ws_row;
+  }
+  unsigned char request = TIOCL_GETMOUSEREPORTING;
+  if (ioctl(fd, TIOCLINUX, &request))
+  {
+    perror("TIOCLINUX, TIOCL_GETMOUSEREPORTING");
+    request = MOUSE_REPORTING_OFF;
+  }
+  close(fd);
+  if (request >= MOUSE_REPORTING_MODE_COUNT)
+  {
+    fprintf(stderr, "mouse reporting mode %d not supported\n", (int)request);
+    request = MOUSE_REPORTING_OFF;
+  }
+  mouse_reporting = request;
   close(fd);
-  screen_width  = s.ws_col;
-  screen_height = s.ws_row;
 }
 
 static void
@@ -61,12 +86,27 @@ linux_selection(int xs, int ys, int xe, int ye, int sel_mode)
   s.sel.sel_mode = sel_mode;
   fd = open("/dev/tty0",O_RDONLY);
   if (check_mode(fd))
-    if (ioctl(fd, TIOCLINUX, ((char*)&s)+1)<0)
+  {
+    int err = ioctl(fd, TIOCLINUX, ((char*)&s)+1);
+    if (err<0 && !(errno==EINVAL && (sel_mode&TIOCL_SELMOUSEREPORT)))
+    /* The kernel return EINVAL for TIOCL_SELMOUSEREPORT when
+       TIOCL_GETMOUSEREPORTING reports 0. Unfortunately this cannot be
+       checked without race conditions, so it is simpler to ignore the
+       error.
+     */
       perror("selection: TIOCLINUX");
+  }
   close(fd);
 }
 
 void
+report_pointer(int x, int y, enum current_button button)
+{
+  linux_selection(x, y, x, y, TIOCL_SELCLEAR);
+  linux_selection(x, y, x, y, TIOCL_SELMOUSEREPORT + button );
+}
+
+void
 draw_pointer(int x, int y)
 {
   linux_selection(x, y, x, y, TIOCL_SELPOINTER);
