From 92d972cfd83b67961dc63d60c5317ec2651eb256 Mon Sep 17 00:00:00 2001
From: inmarket <andrewh@inmarket.com.au>
Date: Wed, 2 Jul 2014 09:40:01 +1000
Subject: First part new mouse infrastructure

---
 src/ginput/driver_mouse.h | 193 ++++++++++-------------
 src/ginput/mouse.c        | 389 ++++++++++++++++++++++------------------------
 src/ginput/sys_options.h  |  45 +++---
 3 files changed, 297 insertions(+), 330 deletions(-)

diff --git a/src/ginput/driver_mouse.h b/src/ginput/driver_mouse.h
index 21d87dac..c60b9a0e 100644
--- a/src/ginput/driver_mouse.h
+++ b/src/ginput/driver_mouse.h
@@ -19,67 +19,80 @@
 
 #if GINPUT_NEED_MOUSE || defined(__DOXYGEN__)
 
-#include "ginput_lld_mouse_config.h"
-
-// GEVENT_MOUSE or GEVENT_TOUCH - What type of device is this.
-#ifndef GINPUT_MOUSE_EVENT_TYPE
-	#define GINPUT_MOUSE_EVENT_TYPE					GEVENT_MOUSE
-#endif
-
-// TRUE/FALSE - Does the mouse/touch driver require calibration?
-#ifndef GINPUT_MOUSE_NEED_CALIBRATION
-	#define GINPUT_MOUSE_NEED_CALIBRATION			FALSE
-#endif
-
-// TRUE/FALSE - Should the calibration happen at the extremes of the panel?
-#ifndef GINPUT_MOUSE_CALIBRATE_EXTREMES
-	#define GINPUT_MOUSE_CALIBRATE_EXTREMES			FALSE
-#endif
-
-// TRUE/FALSE	- Can the mouse/touch driver itself save calibration data?
-#ifndef GINPUT_MOUSE_LLD_CALIBRATION_LOADSAVE
-	#define GINPUT_MOUSE_LLD_CALIBRATION_LOADSAVE	FALSE
-#endif
-
-// n or -1		- n means to test calibration result (+/- pixels), -1 means not to.
-#ifndef GINPUT_MOUSE_MAX_CALIBRATION_ERROR
-	#define GINPUT_MOUSE_MAX_CALIBRATION_ERROR		-1
-#endif
-
-// n			- How many times to read (and average) per poll
-#ifndef GINPUT_MOUSE_READ_CYCLES
-	#define GINPUT_MOUSE_READ_CYCLES				1
-#endif
-
-// n			 - Millisecs between poll's
-#ifndef GINPUT_MOUSE_POLL_PERIOD
-	#define GINPUT_MOUSE_POLL_PERIOD				25
-#endif
-
-// n			- Movement allowed without discarding the CLICK or CLICKCXT event (+/- pixels)
-#ifndef GINPUT_MOUSE_MAX_CLICK_JITTER
-	#define GINPUT_MOUSE_MAX_CLICK_JITTER			1
-#endif
-
-// n			- Movement allowed without discarding the MOVE event (+/- pixels)
-#ifndef GINPUT_MOUSE_MAX_MOVE_JITTER
-	#define GINPUT_MOUSE_MAX_MOVE_JITTER			0
-#endif
+typedef struct MouseReading {
+	coord_t		x, y, z;
+	uint16_t	buttons;
+	} MouseReading;
 
-// ms			- Millisecs seperating a CLICK from a CXTCLICK
-#ifndef GINPUT_MOUSE_CLICK_TIME
-	#define GINPUT_MOUSE_CLICK_TIME					700
+#if !GINPUT_TOUCH_NOCALIBRATE
+	typedef struct MouseCalibration {
+		float	ax;
+		float	bx;
+		float	cx;
+		float	ay;
+		float	by;
+		float	cy;
+	} MouseCalibration;
 #endif
 
-// true/false	- Whether the mouse driver internally handles screen rotation
-#ifndef GINPUT_MOUSE_NO_ROTATION
-	#define GINPUT_MOUSE_NO_ROTATION				FALSE
-#endif
+typedef struct MouseInstance {
+	struct MouseInstance *				next;				// The next mouse instance
+	const struct MOUSEVMT *				vmt;				// The mouse VMT
+	MouseReading						r;					// The current position and state
+	uint16_t							flags;				// Flags
+			#define GMOUSE_FLG_ACTIVE			0x0001				// Mouse is currently active
+			#define GMOUSE_FLG_DYNAMIC			0x0002				// Mouse is dynamically allocated
+			#define GMOUSE_FLG_CLICK_TIMER		0x0004				// Currently timing a click event
+			#define GMOUSE_FLG_INDELTA			0x0008				// Currently in a up/down transition test
+			#define GMOUSE_FLG_CLIP				0x0010				// Clip reading to the display
+			#define GMOUSE_FLG_CALIBRATE		0x0020				// Calibrate readings
+			#define GMOUSE_FLG_CAL_INPROGRESS	0x0040				// Calibrate is currently in progress
+			#define GMOUSE_FLG_CAL_SAVED		0x0080				// Calibration has been saved
+			#define GMOUSE_FLG_FINGERMODE		0x0100				// Mouse is currently in finger mode
+	point								clickpos;			// The position of the last click event
+	systemticks_t						clicktime;			// The time of the last click event
+	GDisplay *							display;			// The display the mouse is associated with
+	void *								param;				// A variable for private driver use
+	#if !GINPUT_TOUCH_NOCALIBRATE
+		GMouseCalibrationSaveRoutine	fnsavecal;			// The calibration load routine
+		GMouseCalibrationLoadRoutine	fnloadcal;			// The calibration save routine
+		MouseCalibration				caldata;			// The calibration data
+	#endif
+} MouseInstance;
+
+typedef struct MouseJitter {
+	coord_t		calibrate;									// Maximum error for a calibration to succeed
+	coord_t		click;										// Movement allowed without discarding the CLICK or CLICKCXT event
+	coord_t		move;										// Movement allowed without discarding the MOVE event
+} MouseJitter;
+
+typedef struct MOUSEVMT {
+	uint16_t	flags;										// Device flags
+		#define GMOUSE_VFLG_TOUCH			0x0001			// This is a touch device (rather than a mouse). Button 1 is calculated from z value.
+		#define GMOUSE_VFLG_NOPOLL			0x0002			// Do not poll this device - it is purely interrupt driven
+		#define GMOUSE_VFLG_SELFROTATION	0x0004			// This device returns readings that are aligned with the display orientation
+		#define GMOUSE_VFLG_DEFAULTFINGER	0x0008			// Default to finger mode
+		#define GMOUSE_VFLG_CALIBRATE		0x0010			// This device requires calibration
+		#define GMOUSE_VFLG_CAL_EXTREMES	0x0020			// Use edge to edge calibration
+		#define GMOUSE_VFLG_CAL_TEST		0x0040			// Test the results of the calibration
+		#define GMOUSE_VFLG_ONLY_DOWN		0x0100			// This device returns a valid position only when the mouse is down
+		#define GMOUSE_VFLG_POORUPDOWN		0x0200			// Position readings during up/down are unreliable
+	coord_t		z_max;										// TOUCH: Maximum possible z value (fully touched)
+	coord_t		z_min;										// TOUCH: Minimum possible z value (touch off screen). Note may also be > z_max
+	coord_t		z_touchon;									// TOUCH: z values between z_max and this are a solid touch on
+	coord_t		z_touchoff;									// TOUCH: z values between z_min and this are a solid touch off
+
+	MouseJitter	pen_jitter;									// PEN MODE: Jitter settings
+	MouseJitter	finger_jitter;								// FINGER MODE: Jitter settings
+
+	void (*init)((MouseInstance *pmouse);							// Required
+	void (*get)(MouseInstance *pmouse, MouseReading *prd);			// Required
+	void (*cal_save)(MouseInstance *pmouse, void *buf, size_t sz);	// Optional
+	const char *(*cal_load)(MouseInstance *pmouse);					// Optional: Can return NULL if no data is saved.
+																	// 			 Buffer is gfxFree()'d afterwards.
+} MOUSEVMT;
 
-typedef struct MouseReading_t {
-	coord_t		x, y, z;
-	uint16_t	buttons;
-	} MouseReading;
+#include "ginput_lld_mouse_config.h"
 
 /*===========================================================================*/
 /* External declarations.                                                    */
@@ -88,70 +101,33 @@ typedef struct MouseReading_t {
 #ifdef __cplusplus
 extern "C" {
 #endif
-
 	/**
-	 * @brief   Initialise the mouse/touch.
+	 * @brief	Get a new empty mouse instance and assign it this VMT and display
+	 * @note	This routine is provided to low level drivers by the high level code.
+	 * @note	This routine is designed for displays that have their own dedicated mouse
+	 * 			eg. Win32, X, uGFXnet.
+	 * 			The display driver will during initialisation call this routine to associate
+	 * 			itself with a mouse.
 	 *
 	 * @notapi
 	 */
-	void ginput_lld_mouse_init(void);
+	MouseInstance *ginputMouseGetNewMouseForDisplay(const MOUSEVMT *vmt, GDisplay *g);
 
 	/**
-	 * @brief   Read the mouse/touch position.
-	 *
-	 * @param[in] pt	A pointer to the structure to fill
-	 *
-	 * @note			For drivers that don't support returning a position
-	 *					when the touch is up (most touch devices), it should
-	 *					return the previous position with the new Z value.
-	 *					The z value is the pressure for those touch devices
-	 *					that support it (-100 to 100 where > 0 is touched)
-	 *					or, 0 or 100 for those drivers that don't.
+	 * @brief	Release a mouse
+	 * @note	This routine is provided to low level drivers by the high level code.
+	 * @note	This routine is designed for displays that have their own dedicated mouse
+	 * 			eg. Win32, X, uGFXnet.
+	 * 			When the display has finished with the mouse it can release it.
 	 *
 	 * @notapi
 	 */
-	void ginput_lld_mouse_get_reading(MouseReading *pt);
-
-	#if GINPUT_MOUSE_LLD_CALIBRATION_LOADSAVE
-		/**
-		 * @brief   Load calibration data from a storage area on the touch controller.
-		 *
-		 * @param[in] instance	The mouse instance number
-		 *
-		 * @note	The instance parameter is currently always 0 as we only support
-		 * 			one mouse/touch device at a time.
-		 * @note	This routine should only be provided if the driver has its own
-		 * 			storage area where calibration data can be stored. The drivers
-		 * 			option.h file should define GINPUT_MOUSE_LLD_CALIBRATION_LOADSAVE = TRUE
-		 * 			if it supports this.
-		 *
-		 * @notapi
-		 */
-		const char *ginput_lld_mouse_calibration_load(uint16_t instance);
-		/**
-		 * @brief   Save calibration data to a storage area on the touch controller.
-		 *
-		 * @param[in] instance	The mouse instance number
-		 * @param[in] calbuf	The calibration data to be saved
-		 * @param[in] sz		The size of the calibration data
-		 *
-		 * @note	The instance parameter is currently always 0 as we only support
-		 * 			one mouse/touch device at a time.
-		 * @note	This routine should only be provided if the driver has its own
-		 * 			storage area where calibration data can be stored. The drivers
-		 * 			option.h file should define GINPUT_MOUSE_LLD_CALIBRATION_LOADSAVE = TRUE
-		 * 			if it supports this.
-		 *
-		 * @notapi
-		 */
-		void ginput_lld_mouse_calibration_save(uint16_t instance, const uint8_t *calbuf, size_t sz);
-	#endif
+	void ginputMouseGetNewMouseForDisplay(MouseIntance *pmouse);
 
 	/**
 	 * @brief	Wakeup the high level code so that it attempts another read
 	 *
 	 * @note	This routine is provided to low level drivers by the high level code
-	 * @note	Particularly useful if GINPUT_MOUSE_POLL_PERIOD = TIME_INFINITE
 	 *
 	 * @notapi
 	 */
@@ -161,7 +137,6 @@ extern "C" {
 	 * @brief	Wakeup the high level code so that it attempts another read
 	 *
 	 * @note	This routine is provided to low level drivers by the high level code
-	 * @note	Particularly useful if GINPUT_MOUSE_POLL_PERIOD = TIME_INFINITE
 	 *
 	 * @iclass
 	 * @notapi
@@ -172,7 +147,7 @@ extern "C" {
 }
 #endif
 
-#endif /* GINPUT_NEED_MOUSE || GINPUT_NEED_TOUCH */
+#endif /* GINPUT_NEED_MOUSE */
 
 #endif /* _LLD_GINPUT_MOUSE_H */
 /** @} */
diff --git a/src/ginput/mouse.c b/src/ginput/mouse.c
index f7842e33..1f1a18fe 100644
--- a/src/ginput/mouse.c
+++ b/src/ginput/mouse.c
@@ -19,7 +19,7 @@
 
 #include "src/ginput/driver_mouse.h"
 
-#if GINPUT_MOUSE_NEED_CALIBRATION
+#if !GINPUT_TOUCH_NOCALIBRATE
 	#if !defined(GFX_USE_GDISP) || !GFX_USE_GDISP
 		#error "GINPUT: GFX_USE_GDISP must be defined when mouse or touch calibration is required"
 	#endif
@@ -38,87 +38,12 @@
 		#define GINPUT_MOUSE_CALIBRATION_POINTS		4
 	#endif
 
-	typedef struct Calibration_t {
-		float	ax;
-		float	bx;
-		float	cx;
-		float	ay;
-		float	by;
-		float	cy;
-	} Calibration;
-#endif
-
-typedef struct MousePoint_t {
-	coord_t		x, y;
-} MousePoint;
+endif
 
 static GTIMER_DECL(MouseTimer);
 
-static struct MouseConfig_t {
-	MouseReading					t;
-	MousePoint						movepos;
-	MousePoint						clickpos;
-	systemticks_t					clicktime;
-	uint16_t						last_buttons;
-	uint16_t						flags;
-			#define FLG_INIT_DONE		0x8000
-			#define FLG_CLICK_TIMER		0x0001
-			#define FLG_IN_CAL			0x0010
-			#define FLG_CAL_OK			0x0020
-			#define FLG_CAL_SAVED		0x0040
-			#define FLG_CAL_FREE		0x0080
-			#define FLG_CAL_RAW			0x0100
-	#if GINPUT_MOUSE_NEED_CALIBRATION
-		GMouseCalibrationSaveRoutine	fnsavecal;
-		GMouseCalibrationLoadRoutine	fnloadcal;
-		Calibration						caldata;
-	#endif
-	GDisplay *							display;
-} MouseConfig;
-
-void _tsOrientClip(MouseReading *pt, GDisplay *g, bool_t doClip) {
-	coord_t		w, h;
-
-	w = gdispGGetWidth(g);
-	h = gdispGGetHeight(g);
-
-	#if GDISP_NEED_CONTROL && !GINPUT_MOUSE_NO_ROTATION
-		switch(gdispGGetOrientation(g)) {
-			case GDISP_ROTATE_0:
-				break;
-			case GDISP_ROTATE_90:
-				{
-					coord_t t = pt->x;
-					pt->x = w - 1 - pt->y;
-					pt->y = t;
-				}
-				break;
-			case GDISP_ROTATE_180:
-				pt->x = w - 1 - pt->x;
-				pt->y = h - 1 - pt->y;
-				break;
-			case GDISP_ROTATE_270:
-				{
-					coord_t t = pt->y;
-					pt->y = h - 1 - pt->x;
-					pt->x = t;
-				}
-				break;
-			default:
-				break;
-		}
-	#endif
-
-	if (doClip) {
-		if (pt->x < 0)	pt->x = 0;
-		else if (pt->x >= w) pt->x = w-1;
-		if (pt->y < 0)	pt->y = 0;
-		else if (pt->y >= h) pt->y = h-1;
-	}
-}
-
-#if GINPUT_MOUSE_NEED_CALIBRATION
-	static inline void _tsSetIdentity(Calibration *c) {
+#if !GINPUT_TOUCH_NOCALIBRATE
+	static inline void _tsSetIdentity(MouseCalibration *c) {
 		c->ax = 1;
 		c->bx = 0;
 		c->cx = 0;
@@ -127,7 +52,7 @@ void _tsOrientClip(MouseReading *pt, GDisplay *g, bool_t doClip) {
 		c->cy = 0;
 	}
 
-	static inline void _tsDrawCross(const MousePoint *pp) {
+	static inline void _tsDrawCross(const point *pp) {
 		gdispGDrawLine(MouseConfig.display, pp->x-15, pp->y, pp->x-2, pp->y, White);
 		gdispGDrawLine(MouseConfig.display, pp->x+2, pp->y, pp->x+15, pp->y, White);
 		gdispGDrawLine(MouseConfig.display, pp->x, pp->y-15, pp->x, pp->y-2, White);
@@ -250,143 +175,208 @@ void _tsOrientClip(MouseReading *pt, GDisplay *g, bool_t doClip) {
 	}
 #endif
 
-#if GINPUT_MOUSE_READ_CYCLES > 1
-	static void get_raw_reading(MouseReading *pt) {
-		int32_t x, y, z;
-		unsigned i;
-
-		x = y = z = 0;
-		for(i = 0; i < GINPUT_MOUSE_READ_CYCLES; i++) {
-			ginput_lld_mouse_get_reading(pt);
-			x += pt->x;
-			y += pt->y;
-			z += pt->z;
+static void DoMouseReading(MouseInstance *pm) {
+	MouseReading	r;
+
+	pm->vmt->get(pm, &r);
+
+	// If touch then calculate button 1 from z
+	if ((pm->vmt->flags & GMOUSE_VFLG_TOUCH)) {
+		if (pm->vmt->z_min <= pm->vmt->z_max) {
+			if (r.z >= pm->vmt->z_touchon)			r.buttons |= GINPUT_MOUSE_BTN_LEFT;
+			else if (r.z <= pm->vmt->z_touchoff)	r.buttons &= ~GINPUT_MOUSE_BTN_LEFT;
+			else									return;				// bad reading
+		} else {
+			if (r.z <= pm->vmt->z_touchon)			r.buttons |= GINPUT_MOUSE_BTN_LEFT;
+			else if (r.z >= pm->vmt->z_touchoff)	r.buttons &= ~GINPUT_MOUSE_BTN_LEFT;
+			else									return;				// bad reading
 		}
+	}
+
+	// Double check up & down events if needed
+	if ((pm->vmt->flags & GMOUSE_VFLG_POORUPDOWN)) {
+		// Are we in a transition test
+		if ((pm->flags & GMOUSE_FLG_INDELTA)) {
+			if (!((r.buttons ^ pm->r.buttons) & GINPUT_MOUSE_BTN_LEFT)) {
+				// Transition failed
+				pm->flags &= ~GMOUSE_FLG_INDELTA;
+				return;
+			}
+			// Transition succeeded
+			pm->flags &= ~GMOUSE_FLG_INDELTA;
 
-		/* Take the average of the readings */
-		pt->x = x / GINPUT_MOUSE_READ_CYCLES;
-		pt->y = y / GINPUT_MOUSE_READ_CYCLES;
-		pt->z = z / GINPUT_MOUSE_READ_CYCLES;
+		// Should we start a transition test
+		} else if (((r.buttons ^ pm->r.buttons) & GINPUT_MOUSE_BTN_LEFT)) {
+			pm->flags |= GMOUSE_FLG_INDELTA;
+			return;
+		}
 	}
-#else
-	#define get_raw_reading(pt)		ginput_lld_mouse_get_reading(pt)
-#endif
 
-static void get_calibrated_reading(MouseReading *pt) {
-	get_raw_reading(pt);
+	// If the mouse is up we may need to keep our previous position
+	if ((pm->vmt->flags & GMOUSE_VFLG_ONLY_DOWN) && !(r.buttons & GINPUT_MOUSE_BTN_LEFT)) {
+		r.x = pm->r.x;
+		r.y = pm->r.y;
 
-	#if GINPUT_MOUSE_NEED_CALIBRATION
-		_tsTransform(pt, &MouseConfig.caldata);
-	#endif
+	} else {
+		coord_t			w, h;
 
-	_tsOrientClip(pt, MouseConfig.display, !(MouseConfig.flags & FLG_CAL_RAW));
-}
+		#if !GINPUT_TOUCH_NOCALIBRATE
+			// Do we need to calibrate the reading?
+			if ((pm->flags & GMOUSE_FLG_CALIBRATE))
+				_tsTransform(&r, &MouseConfig.caldata);
+		#endif
 
-static void MousePoll(void *param) {
-	(void) param;
-	GSourceListener	*psl;
-	GEventMouse		*pe;
-	unsigned 		meta;
-	uint16_t		upbtns, dnbtns;
-	uint32_t		cdiff;
-	uint32_t		mdiff;
-
-	// Save the last mouse state
-	MouseConfig.last_buttons = MouseConfig.t.buttons;
-
-	// Get the new mouse reading
-	get_calibrated_reading(&MouseConfig.t);
-
-	// Calculate out new event meta value and handle CLICK and CXTCLICK
-	dnbtns = MouseConfig.t.buttons & ~MouseConfig.last_buttons;
-	upbtns = ~MouseConfig.t.buttons & MouseConfig.last_buttons;
-	meta = GMETA_NONE;
-
-	// As the touch moves up we need to return a point at the old position because some
-	//	controllers return garbage with the mouse up
-	if ((upbtns & GINPUT_MOUSE_BTN_LEFT)) {
-		MouseConfig.t.x = MouseConfig.movepos.x;
-		MouseConfig.t.y = MouseConfig.movepos.y;
-	}
+		// We now need display information
+		w = gdispGGetWidth(g);
+		h = gdispGGetHeight(g);
 
-	// Calculate the position difference from our movement reference (update the reference if out of range)
-	mdiff = (MouseConfig.t.x - MouseConfig.movepos.x) * (MouseConfig.t.x - MouseConfig.movepos.x) +
-		(MouseConfig.t.y - MouseConfig.movepos.y) * (MouseConfig.t.y - MouseConfig.movepos.y);
-	if (mdiff > GINPUT_MOUSE_MAX_MOVE_JITTER * GINPUT_MOUSE_MAX_MOVE_JITTER) {
-		MouseConfig.movepos.x = MouseConfig.t.x;
-		MouseConfig.movepos.y = MouseConfig.t.y;
-	}
-	
-	// Check if the click has moved outside the click area and if so cancel the click
-	if ((MouseConfig.flags & FLG_CLICK_TIMER)) {
-		cdiff = (MouseConfig.t.x - MouseConfig.clickpos.x) * (MouseConfig.t.x - MouseConfig.clickpos.x) +
-			(MouseConfig.t.y - MouseConfig.clickpos.y) * (MouseConfig.t.y - MouseConfig.clickpos.y);
-		if (cdiff > GINPUT_MOUSE_MAX_CLICK_JITTER * GINPUT_MOUSE_MAX_CLICK_JITTER)
-			MouseConfig.flags &= ~FLG_CLICK_TIMER;
-	}
+		#if GDISP_NEED_CONTROL
+			// Do we need to rotate the reading to match the display
+			if (!(pm->vmt->flags & GMOUSE_VFLG_SELFROTATION)) {
+				coord_t		t;
+
+				switch(gdispGGetOrientation(g)) {
+					case GDISP_ROTATE_0:
+						break;
+					case GDISP_ROTATE_90:
+						t = r.x;
+						r.x = w - 1 - r.y;
+						r.y = t;
+						break;
+					case GDISP_ROTATE_180:
+						r.x = w - 1 - r.x;
+						r.y = h - 1 - r.y;
+						break;
+					case GDISP_ROTATE_270:
+						t = r.y;
+						r.y = h - 1 - r.x;
+						r.x = t;
+						break;
+					default:
+						break;
+				}
+			}
+		#endif
 
-	// Mouse down
-	if ((dnbtns & (GINPUT_MOUSE_BTN_LEFT|GINPUT_MOUSE_BTN_RIGHT))) {
-		MouseConfig.clickpos.x = MouseConfig.t.x;
-		MouseConfig.clickpos.y = MouseConfig.t.y;
-		MouseConfig.clicktime = gfxSystemTicks();
-		MouseConfig.flags |= FLG_CLICK_TIMER;
-		if ((dnbtns & GINPUT_MOUSE_BTN_LEFT))
-			meta |= GMETA_MOUSE_DOWN;
+		// Do we need to clip the reading to the display
+		if ((pm->flags & GMOUSE_FLG_CLIP)) {
+			if (r.x < 0)		r.x = 0;
+			else if (r.x >= w)	r.x = w-1;
+			if (r.y < 0)		r.y = 0;
+			else if (r.y >= h)	r.y = h-1;
+		}
 	}
 
-	// Mouse up
-	if ((upbtns & (GINPUT_MOUSE_BTN_LEFT|GINPUT_MOUSE_BTN_RIGHT))) {
-		if ((upbtns & GINPUT_MOUSE_BTN_LEFT))
-			meta |= GMETA_MOUSE_UP;
-		if ((MouseConfig.flags & FLG_CLICK_TIMER)) {
-			if ((upbtns & GINPUT_MOUSE_BTN_LEFT)
-					#if GINPUT_MOUSE_CLICK_TIME != TIME_INFINITE
-						&& gfxSystemTicks() - MouseConfig.clicktime < gfxMillisecondsToTicks(GINPUT_MOUSE_CLICK_TIME)
-					#endif
-					)
-				meta |= GMETA_MOUSE_CLICK;
-			else
-				meta |= GMETA_MOUSE_CXTCLICK;
-			MouseConfig.flags &= ~FLG_CLICK_TIMER;
+	{
+		MouseJitter		*pj;
+		uint32_t		diff;
+
+		// Are we in pen or finger mode
+		pj = (pm->flags & GMOUSE_FLG_FINGERMODE) ? &pm->vmt->finger_jitter : &pm->vmt->pen_jitter;
+
+		// Is this just movement jitter
+		if (pj->move > 0) {
+			diff = (uint32_t)(r.x - pm->r.x) * (uint32_t)(r.x - pm->r.x) + (uint32_t)(r.y - pm->r.y) * (uint32_t)(r.y - pm->r.y);
+			if (diff > (uint32_t)pj->move * (uint32_t)pj->move) {
+				r.x = pm->r.x;
+				r.y = pm->r.y;
+			}
+		}
+
+		// Check if the click has moved outside the click area and if so cancel the click
+		if (pj->click > 0 && (pm->flags & GMOUSE_FLG_CLICK_TIMER)) {
+			diff = (uint32_t)(r.x - pm->clickpos.x) * (uint32_t)(r.x - pm->clickpos.x) + (uint32_t)(r.y - pm->clickpos.y) * (uint32_t)(r.y - pm->clickpos.y);
+			if (diff > (uint32_t)pj->click * (uint32_t)pj->click)
+				pm->flags &= ~GMOUSE_FLG_CLICK_TIMER;
 		}
 	}
 
-	// Send the event to the listeners that are interested.
-	psl = 0;
-	while ((psl = geventGetSourceListener((GSourceHandle)(&MouseConfig), psl))) {
-		if (!(pe = (GEventMouse *)geventGetEventBuffer(psl))) {
-			// This listener is missing - save the meta events that have happened
-			psl->srcflags |= meta;
-			continue;
+	{
+		GSourceListener	*psl;
+		GEventMouse		*pe;
+		unsigned 		meta;
+		uint16_t		upbtns, dnbtns;
+
+		// Calculate out new event meta value and handle CLICK and CXTCLICK
+		dnbtns = r.buttons & ~pm->r.buttons;
+		upbtns = ~r.buttons & pm->r.buttons;
+		meta = GMETA_NONE;
+
+		// Mouse down
+		if ((dnbtns & (GINPUT_MOUSE_BTN_LEFT|GINPUT_MOUSE_BTN_RIGHT))) {
+			pm->clickpos.x = r.x;
+			pm->clickpos.y = r.y;
+			pm->clicktime = gfxSystemTicks();
+			pm->flags |= GMOUSE_FLG_CLICK_TIMER;
+			if ((dnbtns & GINPUT_MOUSE_BTN_LEFT))
+				meta |= GMETA_MOUSE_DOWN;
+		}
+
+		// Mouse up
+		if ((upbtns & (GINPUT_MOUSE_BTN_LEFT|GINPUT_MOUSE_BTN_RIGHT))) {
+			if ((upbtns & GINPUT_MOUSE_BTN_LEFT))
+				meta |= GMETA_MOUSE_UP;
+			if ((pm->flags & GMOUSE_FLG_CLICK_TIMER)) {
+				if ((upbtns & GINPUT_MOUSE_BTN_LEFT)
+						#if GINPUT_TOUCH_CLICK_TIME != TIME_INFINITE
+							&& gfxSystemTicks() - pm->clicktime < gfxMillisecondsToTicks(GINPUT_TOUCH_CLICK_TIME)
+						#endif
+						)
+					meta |= GMETA_MOUSE_CLICK;
+				else
+					meta |= GMETA_MOUSE_CXTCLICK;
+				pm->flags &= ~GMOUSE_FLG_CLICK_TIMER;
+			}
 		}
 
-		// If we haven't really moved (and there are no meta events) don't bother sending the event
-		if (mdiff <= GINPUT_MOUSE_MAX_MOVE_JITTER * GINPUT_MOUSE_MAX_MOVE_JITTER && !psl->srcflags
-				&& !meta && MouseConfig.last_buttons == MouseConfig.t.buttons && !(psl->listenflags & GLISTEN_MOUSENOFILTER))
-			continue;
-
-		// Send the event if we are listening for it
-		if (((MouseConfig.t.buttons & GINPUT_MOUSE_BTN_LEFT) && (psl->listenflags & GLISTEN_MOUSEDOWNMOVES))
-				|| (!(MouseConfig.t.buttons & GINPUT_MOUSE_BTN_LEFT) && (psl->listenflags & GLISTEN_MOUSEUPMOVES))
-				|| (meta && (psl->listenflags & GLISTEN_MOUSEMETA))) {
-			pe->type = GINPUT_MOUSE_EVENT_TYPE;
-			pe->instance = 0;
-			pe->x = MouseConfig.t.x;
-			pe->y = MouseConfig.t.y;
-			pe->z = MouseConfig.t.z;
-			pe->current_buttons = MouseConfig.t.buttons;
-			pe->last_buttons = MouseConfig.last_buttons;
-			pe->meta = meta;
-			if (psl->srcflags) {
-				pe->current_buttons |= GINPUT_MISSED_MOUSE_EVENT;
-				pe->meta |= psl->srcflags;
-				psl->srcflags = 0;
+		// Send the event to the listeners that are interested.
+		psl = 0;
+		while ((psl = geventGetSourceListener((GSourceHandle)(&MouseConfig), psl))) {
+			if (!(pe = (GEventMouse *)geventGetEventBuffer(psl))) {
+				// This listener is missing - save the meta events that have happened
+				psl->srcflags |= meta;
+				continue;
+			}
+
+			// If we haven't really moved (and there are no meta events) don't bother sending the event
+			if (!meta && !psl->srcflags && !(psl->listenflags & GLISTEN_MOUSENOFILTER)
+					&& r.x == pm->r.x && r.y == pm->r.y	&& r.buttons == pm->r.buttons)
+				continue;
+
+			// Send the event if we are listening for it
+			if (((r.buttons & GINPUT_MOUSE_BTN_LEFT) && (psl->listenflags & GLISTEN_MOUSEDOWNMOVES))
+					|| (!(r.buttons & GINPUT_MOUSE_BTN_LEFT) && (psl->listenflags & GLISTEN_MOUSEUPMOVES))
+					|| (meta && (psl->listenflags & GLISTEN_MOUSEMETA))) {
+				pe->type = GINPUT_MOUSE_EVENT_TYPE;
+				pe->instance = 0;
+				pe->x = r.x;
+				pe->y = r.y;
+				pe->z = r.z;
+				pe->current_buttons = r.buttons;
+				pe->last_buttons = pm->r.buttons;
+				pe->meta = meta;
+				if (psl->srcflags) {
+					pe->current_buttons |= GINPUT_MISSED_MOUSE_EVENT;
+					pe->meta |= psl->srcflags;
+					psl->srcflags = 0;
+				}
+				pe->display = pm->display;
+				geventSendEvent(psl);
 			}
-			pe->display = MouseConfig.display;
-			geventSendEvent(psl);
 		}
 	}
+
+	// Finally save the results
+	pm->r.x = r.x;
+	pm->r.y = r.y;
+	pm->r.z = r.z;
+	pm->r.buttons = r.buttons;
+}
+
+static void MousePoll(void *param) {
+	(void) param;
+	
+	DoMouseReading(stuff in here);
 }
 
 GSourceHandle ginputGetMouse(uint16_t instance) {
@@ -481,7 +471,8 @@ bool_t ginputGetMouseStatus(uint16_t instance, GEventMouse *pe) {
 }
 
 bool_t ginputCalibrateMouse(uint16_t instance) {
-	#if !GINPUT_MOUSE_NEED_CALIBRATION
+	#if GINPUT_TOUCH_NOCALIBRATE
+
 		(void) instance;
 		
 		return FALSE;
diff --git a/src/ginput/sys_options.h b/src/ginput/sys_options.h
index c606262b..7ccc7b78 100644
--- a/src/ginput/sys_options.h
+++ b/src/ginput/sys_options.h
@@ -73,40 +73,41 @@
  * @{
  */
 	/**
-	 * @brief   Use a custom board definition for the mouse/touch driver even if a board definition exists.
+	 * @brief   Turn off touch mouse support.
 	 * @details	Defaults to FALSE
-	 * @details	If TRUE, add ginput_lld_mouse_board.h to your project directory and customise it.
-	 * @note	Not all GINPUT mouse/touch low level drivers use board definition files.
+	 * @note	Touch device handling requires a lot of code. If your mouse doesn't require it
+	 * 			this can be turned off to save a lot of space.
 	 */
-	#ifndef GINPUT_MOUSE_USE_CUSTOM_BOARD
-		#define GINPUT_MOUSE_USE_CUSTOM_BOARD		FALSE
+	#ifndef GINPUT_TOUCH_NOTOUCH
+		#define GINPUT_TOUCH_NOTOUCH					FALSE
 	#endif
 	/**
-	 * @brief   Use a custom board definition for the keyboard driver even if a board definition exists.
+	 * @brief   Turn off calibration support.
 	 * @details	Defaults to FALSE
-	 * @details	If TRUE, add ginput_lld_keyboard_board.h to your project directory and customise it.
-	 * @note	Not all GINPUT keyboard low level drivers use board definition files.
+	 * @note	Calibration requires a lot of code. If your mouse doesn't require it
+	 * 			this can be turned off to save a lot of space.
 	 */
-	#ifndef GINPUT_KEYBOARD_USE_CUSTOM_BOARD
-		#define GINPUT_KEYBOARD_USE_CUSTOM_BOARD	FALSE
+	#ifndef GINPUT_TOUCH_NOCALIBRATE
+		#define GINPUT_TOUCH_NOCALIBRATE				FALSE
 	#endif
 	/**
-	 * @brief   Use a custom board definition for the toggle driver even if a board definition exists.
-	 * @details	Defaults to FALSE
-	 * @details	If TRUE, add ginput_lld_toggle_board.h to your project directory and customise it.
-	 * @note	Not all GINPUT toggle low level drivers use board definition files.
+	 * @brief   Milliseconds between mouse polls.
+	 * @details	Defaults to 25 millseconds
+	 * @note	How often mice should be polled. More often leads to smoother mouse movement
+	 * 			but increases CPU usage. If no mouse drivers need polling the poll is not
+	 * 			started.
 	 */
-	#ifndef GINPUT_TOGGLE_USE_CUSTOM_BOARD
-		#define GINPUT_TOGGLE_USE_CUSTOM_BOARD		FALSE
+	#ifndef GINPUT_MOUSE_POLL_PERIOD
+		#define GINPUT_MOUSE_POLL_PERIOD				25
 	#endif
+
 	/**
-	 * @brief   Use a custom board definition for the dial driver even if a board definition exists.
-	 * @details	Defaults to FALSE
-	 * @details	If TRUE, add ginput_lld_dial_board.h to your project directory and customise it.
-	 * @note	Not all GINPUT dial low level drivers use board definition files.
+	 * @brief   Milliseconds separating a CLICK from a CXTCLICK.
+	 * @details	Defaults to 700 millseconds
+	 * @note	How long it takes for a click to turn into a CXTCLICK on a touch device.
 	 */
-	#ifndef GINPUT_DIAL_USE_CUSTOM_BOARD
-		#define GINPUT_DIAL_USE_CUSTOM_BOARD		FALSE
+	#ifndef GINPUT_TOUCH_CLICK_TIME
+		#define GINPUT_TOUCH_CLICK_TIME					700
 	#endif
 /** @} */
 
-- 
cgit v1.2.3