Index: uspace/lib/gfx/include/gfx/coord.h
===================================================================
--- uspace/lib/gfx/include/gfx/coord.h	(revision 6c2aba3fef6f293d95c6f25efe30068d7cf8a73f)
+++ uspace/lib/gfx/include/gfx/coord.h	(revision 1388f7f08c41cba76c34b0f31d86da64f7e07c6f)
@@ -43,4 +43,6 @@
 extern void gfx_coord2_subtract(gfx_coord2_t *, gfx_coord2_t *, gfx_coord2_t *);
 extern void gfx_coord2_clip(gfx_coord2_t *, gfx_rect_t *, gfx_coord2_t *);
+extern void gfx_coord2_project(gfx_coord2_t *, gfx_rect_t *, gfx_rect_t *,
+    gfx_coord2_t *);
 extern void gfx_span_points_sort(gfx_coord_t, gfx_coord_t, gfx_coord_t *,
     gfx_coord_t *);
Index: uspace/lib/gfx/src/coord.c
===================================================================
--- uspace/lib/gfx/src/coord.c	(revision 6c2aba3fef6f293d95c6f25efe30068d7cf8a73f)
+++ uspace/lib/gfx/src/coord.c	(revision 1388f7f08c41cba76c34b0f31d86da64f7e07c6f)
@@ -62,4 +62,10 @@
 }
 
+/** Clip point coordinates to be within a rectangle.
+ *
+ * @param a Pixel coordinates
+ * @param clip Clipping rectangle
+ * @param d Place to store clipped coordinates
+ */
 void gfx_coord2_clip(gfx_coord2_t *a, gfx_rect_t *clip, gfx_coord2_t *d)
 {
@@ -74,4 +80,30 @@
 	d->x = max(clip->p0.x, t.x);
 	d->y = max(clip->p0.y, t.y);
+}
+
+/** Transform coordinates via rectangle to rectangle projection.
+ *
+ * Transform pixel coordinate via a projection that maps one rectangle
+ * onto another rectangle. The source rectangle must have both dimensions
+ * greater than one.
+ *
+ * @param a Pixel coordinates
+ * @param srect Source rectangle
+ * @param drect Destination rectangle
+ * @param d Place to store resulting coordinates.
+ */
+void gfx_coord2_project(gfx_coord2_t *a, gfx_rect_t *srect, gfx_rect_t *drect,
+    gfx_coord2_t *d)
+{
+	gfx_rect_t sr;
+	gfx_rect_t dr;
+
+	gfx_rect_points_sort(srect, &sr);
+	gfx_rect_points_sort(drect, &dr);
+
+	d->x = dr.p0.x + (a->x - sr.p0.x) * (dr.p1.x - dr.p0.x - 1) /
+	    (sr.p1.x - sr.p0.x - 1);
+	d->y = dr.p0.y + (a->y - sr.p0.y) * (dr.p1.y - dr.p0.y - 1) /
+	    (sr.p1.y - sr.p0.y - 1);
 }
 
Index: uspace/lib/gfx/test/coord.c
===================================================================
--- uspace/lib/gfx/test/coord.c	(revision 6c2aba3fef6f293d95c6f25efe30068d7cf8a73f)
+++ uspace/lib/gfx/test/coord.c	(revision 1388f7f08c41cba76c34b0f31d86da64f7e07c6f)
@@ -131,4 +131,45 @@
 }
 
+/** gfx_coord2_project projects pixel from one rectangle to another  */
+PCUT_TEST(coord2_project)
+{
+	gfx_coord2_t a, d;
+	gfx_rect_t srect, drect;
+
+	srect.p0.x = 10;
+	srect.p0.y = 10;
+	srect.p1.x = 20 + 1;
+	srect.p1.y = 20 + 1;
+
+	drect.p0.x = 100;
+	drect.p0.y = 100;
+	drect.p1.x = 200 + 1;
+	drect.p1.y = 200 + 1;
+
+	a.x = 10;
+	a.y = 10;
+	gfx_coord2_project(&a, &srect, &drect, &d);
+	PCUT_ASSERT_INT_EQUALS(100, d.x);
+	PCUT_ASSERT_INT_EQUALS(100, d.y);
+
+	a.x = 15;
+	a.y = 15;
+	gfx_coord2_project(&a, &srect, &drect, &d);
+	PCUT_ASSERT_INT_EQUALS(150, d.x);
+	PCUT_ASSERT_INT_EQUALS(150, d.y);
+
+	a.x = 12;
+	a.y = 16;
+	gfx_coord2_project(&a, &srect, &drect, &d);
+	PCUT_ASSERT_INT_EQUALS(120, d.x);
+	PCUT_ASSERT_INT_EQUALS(160, d.y);
+
+	a.x = 20;
+	a.y = 20;
+	gfx_coord2_project(&a, &srect, &drect, &d);
+	PCUT_ASSERT_INT_EQUALS(200, d.x);
+	PCUT_ASSERT_INT_EQUALS(200, d.y);
+}
+
 /** gfx_rect_translate should translate rectangle */
 PCUT_TEST(rect_translate)
Index: uspace/srv/hid/display/input.c
===================================================================
--- uspace/srv/hid/display/input.c	(revision 6c2aba3fef6f293d95c6f25efe30068d7cf8a73f)
+++ uspace/srv/hid/display/input.c	(revision 1388f7f08c41cba76c34b0f31d86da64f7e07c6f)
@@ -97,7 +97,16 @@
     unsigned max_x, unsigned max_y)
 {
-	printf("ds_input_ev_abs_move x=%u y=%u mx=%u my=%u\n",
-	    x, y, max_x, max_y);
-	return EOK;
+	ds_display_t *disp = (ds_display_t *) input->user;
+	ptd_event_t event;
+
+	event.type = PTD_ABS_MOVE;
+	event.apos.x = x;
+	event.apos.y = y;
+	event.abounds.p0.x = 0;
+	event.abounds.p0.y = 0;
+	event.abounds.p1.x = max_x + 1;
+	event.abounds.p1.y = max_y + 1;
+
+	return ds_display_post_ptd_event(disp, &event);
 }
 
Index: uspace/srv/hid/display/seat.c
===================================================================
--- uspace/srv/hid/display/seat.c	(revision 6c2aba3fef6f293d95c6f25efe30068d7cf8a73f)
+++ uspace/srv/hid/display/seat.c	(revision 1388f7f08c41cba76c34b0f31d86da64f7e07c6f)
@@ -256,4 +256,5 @@
  * @return EOK on success or an error code
  */
+#include <stdio.h>
 errno_t ds_seat_post_ptd_event(ds_seat_t *seat, ptd_event_t *event)
 {
@@ -306,4 +307,32 @@
 	}
 
+	if (event->type == PTD_ABS_MOVE) {
+		/*
+		 * Project input device area onto display area. Technically
+		 * we probably want to project onto the area of a particular
+		 * display device. The tricky part is figuring out which
+		 * display device the input device is associated with.
+		 */
+		gfx_coord2_project(&event->apos, &event->abounds,
+		    &disp->rect, &npos);
+
+		gfx_coord2_clip(&npos, &disp->rect, &npos);
+
+		(void) ds_seat_clear_pointer(seat);
+		seat->pntpos = npos;
+
+		pevent.pos_id = 0;
+		pevent.type = POS_UPDATE;
+		pevent.btn_num = 0;
+		pevent.hpos = seat->pntpos.x;
+		pevent.vpos = seat->pntpos.y;
+
+		rc = ds_seat_post_pos_event(seat, &pevent);
+		if (rc != EOK)
+			return rc;
+
+		(void) ds_seat_draw_pointer(seat);
+	}
+
 	return EOK;
 }
Index: uspace/srv/hid/display/types/display/ptd_event.h
===================================================================
--- uspace/srv/hid/display/types/display/ptd_event.h	(revision 6c2aba3fef6f293d95c6f25efe30068d7cf8a73f)
+++ uspace/srv/hid/display/types/display/ptd_event.h	(revision 1388f7f08c41cba76c34b0f31d86da64f7e07c6f)
@@ -40,4 +40,5 @@
 typedef enum {
 	PTD_MOVE,
+	PTD_ABS_MOVE,
 	PTD_PRESS,
 	PTD_RELEASE
@@ -51,4 +52,8 @@
 	/** Relative move vector for PTD_MOVE */
 	gfx_coord2_t dmove;
+	/** Absolute position for PTD_ABS_MOVE */
+	gfx_coord2_t apos;
+	/** Absolute position bounds for PTD_ABS_MOVE */
+	gfx_rect_t abounds;
 } ptd_event_t;
 
