aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorinmarket <andrewh@inmarket.com.au>2014-09-25 17:44:16 +1000
committerinmarket <andrewh@inmarket.com.au>2014-09-25 17:44:16 +1000
commit10dc968427ed1ec846342dd1932b273acea414bd (patch)
treeedcae422757a97d55360a110e72b10f4d7288905 /src
parent33200c1a9787254532394e6877ec403ed4b89db8 (diff)
downloaduGFX-10dc968427ed1ec846342dd1932b273acea414bd.tar.gz
uGFX-10dc968427ed1ec846342dd1932b273acea414bd.tar.bz2
uGFX-10dc968427ed1ec846342dd1932b273acea414bd.zip
New mouse updates. Just need a driver now.
Diffstat (limited to 'src')
-rw-r--r--src/ginput/driver_mouse.h48
-rw-r--r--src/ginput/ginput_mouse.c1056
-rw-r--r--src/ginput/ginput_mouse.h150
-rw-r--r--src/ginput/sys_options.h84
-rw-r--r--src/ginput/sys_rules.h15
-rw-r--r--src/gwin/gwin_widget.c16
-rw-r--r--src/gwin/gwin_widget.h4
7 files changed, 786 insertions, 587 deletions
diff --git a/src/ginput/driver_mouse.h b/src/ginput/driver_mouse.h
index a0f0f807..ababfef8 100644
--- a/src/ginput/driver_mouse.h
+++ b/src/ginput/driver_mouse.h
@@ -42,21 +42,17 @@ typedef struct GMouse {
GDriver d; // The driver overheads and vmt
GMouseReading r; // The current position and state
uint16_t flags; // Flags
- #define GMOUSE_FLG_ACTIVE 0x0001 // Mouse is currently active
- #define GMOUSE_FLG_CLICK_TIMER 0x0002 // Currently timing a click event
- #define GMOUSE_FLG_INDELTA 0x0004 // Currently in a up/down transition test
- #define GMOUSE_FLG_CLIP 0x0008 // Clip reading to the display
- #define GMOUSE_FLG_CALIBRATE 0x0010 // Calibrate readings
- #define GMOUSE_FLG_CAL_INPROGRESS 0x0020 // Calibrate is currently in progress
- #define GMOUSE_FLG_CAL_SAVED 0x0040 // Calibration has been saved
- #define GMOUSE_FLG_FINGERMODE 0x0080 // Mouse is currently in finger mode
- #define GMOUSE_FLG_NEEDREAD 0x0100 // The mouse needs reading
+ #define GMOUSE_FLG_CLICK_TIMER 0x0001 // Currently timing a click
+ #define GMOUSE_FLG_INDELTA 0x0002 // Currently in a up/down transition test
+ #define GMOUSE_FLG_CLIP 0x0004 // Clip reading to the display
+ #define GMOUSE_FLG_CALIBRATE 0x0008 // Calibrate readings
+ #define GMOUSE_FLG_IN_CAL 0x0010 // Currently in calibration routine
+ #define GMOUSE_FLG_FINGERMODE 0x0020 // Mouse is currently in finger mode
+ #define GMOUSE_FLG_NEEDREAD 0x0040 // The mouse needs reading
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
#if !GINPUT_TOUCH_NOCALIBRATE
- GMouseCalibrationSaveRoutine fnsavecal; // The calibration load routine
- GMouseCalibrationLoadRoutine fnloadcal; // The calibration save routine
GMouseCalibration caldata; // The calibration data
#endif
// Other driver specific fields may follow.
@@ -77,8 +73,10 @@ typedef struct GMouseVMT {
#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_CAL_LOADFREE 0x0080 // Call gfxFree on the buffer returned by the VMT calload() routine.
#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
+ #define GMOUSE_VFLG_DYNAMICONLY 0x8000 // This mouse driver should not be statically initialized eg Win32
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
@@ -87,10 +85,11 @@ typedef struct GMouseVMT {
GMouseJitter pen_jitter; // PEN MODE: Jitter settings
GMouseJitter finger_jitter; // FINGER MODE: Jitter settings
- bool_t (*init)(GMouse *m); // Required
+ bool_t (*init)(GMouse *m, unsigned driverinstance); // Required
+ void (*deinit)(GMouse *m); // Optional
void (*get)(GMouse *m, GMouseReading *prd); // Required
void (*calsave)(GMouse *m, void *buf, size_t sz); // Optional
- const char *(*calload)(GMouse *m); // Optional: Can return NULL if no data is saved. Buffer is automatically gfxFree()'d afterwards.
+ const char *(*calload)(GMouse *m, size_t sz); // Optional: Can return NULL if no data is saved.
} GMouseVMT;
#define gmvmt(m) ((const GMouseVMT const *)((m)->d.vmt))
@@ -99,17 +98,36 @@ typedef struct GMouseVMT {
/* External declarations. */
/*===========================================================================*/
+// If we are not using multiple mice then hard-code the VMT name
+#if !defined(GINPUT_MOUSE_DRIVER_LIST)
+ #undef GMOUSE_DRIVER_VMT
+ #define GMOUSE_DRIVER_VMT GMOUSEVMT_OnlyOne
+#endif
+
#ifdef __cplusplus
extern "C" {
#endif
/**
+ * @brief Routines needed by the general driver VMT
+ * @note These routines are provided by the high level code for
+ * use in the GMouseVMT.d structure.
+ *
+ * @notapi
+ * @{
+ */
+ bool_t _gmouseInitDriver(GDriver *g, unsigned driverinstance, unsigned systeminstance);
+ void _gmousePostInitDriver(GDriver *g);
+ void _gmouseDeInitDriver(GDriver *g);
+ /** @} */
+
+ /**
* @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
*
* @notapi
*/
- void ginputMouseWakeup(GMouse *m);
+ void _gmouseWakeup(GMouse *m);
/**
* @brief Wakeup the high level code so that it attempts another read
@@ -119,7 +137,7 @@ extern "C" {
* @iclass
* @notapi
*/
- void ginputMouseWakeupI(GMouse *m);
+ void _gmouseWakeupI(GMouse *m);
#ifdef __cplusplus
}
diff --git a/src/ginput/ginput_mouse.c b/src/ginput/ginput_mouse.c
index ee6f51b6..f33a74e0 100644
--- a/src/ginput/ginput_mouse.c
+++ b/src/ginput/ginput_mouse.c
@@ -8,71 +8,340 @@
/**
* @file src/ginput/ginput_mouse.c
* @brief GINPUT mouse/touch code.
- *
- * @defgroup Mouse Mouse
- * @ingroup GINPUT
- * @{
*/
#include "gfx.h"
-#if (GFX_USE_GINPUT && GINPUT_NEED_MOUSE) || defined(__DOXYGEN__)
+#if GFX_USE_GINPUT && GINPUT_NEED_MOUSE
+
+// Local Settings
+#define CALIBRATION_POLL_PERIOD 20 // milliseconds
+#define CALIBRATION_MINPRESS_PERIOD 300 // milliseconds
+#define CALIBRATION_MAXPRESS_PERIOD 5000 // milliseconds
+
+#define CALIBRATION_FONT "* Double"
+#define CALIBRATION_FONT2 "* Narrow"
+#define CALIBRATION_BACKGROUND Blue
+
+#define CALIBRATION_CROSS_COLOR1 White
+#define CALIBRATION_CROSS_COLOR2 RGB2COLOR(184,158,131)
+#define CALIBRATION_CROSS_INNERGAP 2
+#define CALIBRATION_CROSS_RADIUS 15
+
+#define CALIBRATION_TITLE "Calibration"
+#define CALIBRATION_TITLE_Y 5
+#define CALIBRATION_TITLE_HEIGHT 30
+#define CALIBRATION_TITLE_COLOR White
+#define CALIBRATION_TITLE_BACKGROUND Blue
+
+#define CALIBRATION_ERROR_TEXT "Failed - Please try again!"
+#define CALIBRATION_ERROR_COLOR Red
+#define CALIBRATION_ERROR_BACKGROUND Yellow
+#define CALIBRATION_ERROR_Y 35
+#define CALIBRATION_ERROR_HEIGHT 40
+// Get the mouse driver interface
#include "driver_mouse.h"
+// The mouse poll timer
+static GTIMER_DECL(MouseTimer);
+
+// Calibration application
#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"
+ #if GINPUT_TOUCH_USER_CALIBRATION_LOAD
+ #include <string.h> // Required for memcpy
#endif
- #include <string.h> // Required for memcpy
+ static inline void CalibrationTransform(GMouseReading *pt, const GMouseCalibration *c) {
+ pt->x = (coord_t) (c->ax * pt->x + c->bx * pt->y + c->cx);
+ pt->y = (coord_t) (c->ay * pt->x + c->by * pt->y + c->cy);
+ }
+#endif
- #define CALIBRATION_FONT "* Double"
- #define CALIBRATION_FONT2 "* Narrow"
- #define CALIBRATION_TEXT "Calibration"
- #define CALIBRATION_ERROR_TEXT "Failed - Please try again!"
- #define CALIBRATION_SAME_TEXT "Error: Same Reading - Check Driver!"
- #define CALIBRATION_BACKGROUND Blue
- #define CALIBRATION_COLOR1 White
- #define CALIBRATION_COLOR2 RGB2COLOR(184,158,131)
+static void SendMouseEvent(GSourceListener *psl, GMouse *m, GMouseReading *r) {
+ GEventMouse *pe;
-#endif
+ // If there is no event buffer just mark a missed event
+ if (!(pe = (GEventMouse *)geventGetEventBuffer(psl))) {
+ // This listener is missing - save the meta events that have happened
+ psl->srcflags |= ((r->buttons & GMETA_MASK)|GINPUT_MISSED_MOUSE_EVENT);
+ return;
+ }
-static GTIMER_DECL(MouseTimer);
+ // If we haven't really moved (and there are no meta events) don't bother sending the event
+ if (!(r->buttons & GMETA_MASK) && !psl->srcflags && !(psl->listenflags & GLISTEN_MOUSENOFILTER)
+ && r->x == m->r.x && r->y == m->r.y && (r->buttons & GINPUT_MOUSE_BTN_MASK) == (m->r.buttons & GINPUT_MOUSE_BTN_MASK))
+ return;
-#if !GINPUT_TOUCH_NOCALIBRATE
- /*
- static inline void CalibrationSetIdentity(MouseCalibration *c) {
- c->ax = 1;
- c->bx = 0;
- c->cx = 0;
- c->ay = 0;
- c->by = 1;
- c->cy = 0;
+ // Send the event only 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))
+ && !((r->buttons & GMETA_MASK) && (psl->listenflags & GLISTEN_MOUSEMETA)))
+ return;
+
+ #if !GINPUT_TOUCH_NOTOUCH
+ pe->type = (gmvmt(m)->d.flags & GMOUSE_VFLG_TOUCH) ? GEVENT_TOUCH : GEVENT_MOUSE;
+ #else
+ pe->type = GEVENT_MOUSE;
+ #endif
+ pe->x = r->x;
+ pe->y = r->y;
+ pe->z = r->z;
+ pe->buttons = r->buttons | psl->srcflags;
+ psl->srcflags = 0;
+ pe->display = m->display;
+ geventSendEvent(psl);
+}
+
+static void GetMouseReading(GMouse *m) {
+ GMouseReading r;
+
+ // Step 1 - Get the Raw Reading
+ {
+ m->flags &= ~GMOUSE_FLG_NEEDREAD;
+ gmvmt(m)->get(m, &r);
}
- */
- static inline void CalibrationCrossDraw(GMouse *m, const point *pp) {
- gdispGDrawLine(m->display, pp->x-15, pp->y, pp->x-2, pp->y, CALIBRATION_COLOR1);
- gdispGDrawLine(m->display, pp->x+2, pp->y, pp->x+15, pp->y, CALIBRATION_COLOR1);
- gdispGDrawLine(m->display, pp->x, pp->y-15, pp->x, pp->y-2, CALIBRATION_COLOR1);
- gdispGDrawLine(m->display, pp->x, pp->y+2, pp->x, pp->y+15, CALIBRATION_COLOR1);
- gdispGDrawLine(m->display, pp->x-15, pp->y+15, pp->x-7, pp->y+15, CALIBRATION_COLOR2);
- gdispGDrawLine(m->display, pp->x-15, pp->y+7, pp->x-15, pp->y+15, CALIBRATION_COLOR2);
- gdispGDrawLine(m->display, pp->x-15, pp->y-15, pp->x-7, pp->y-15, CALIBRATION_COLOR2);
- gdispGDrawLine(m->display, pp->x-15, pp->y-7, pp->x-15, pp->y-15, CALIBRATION_COLOR2);
- gdispGDrawLine(m->display, pp->x+7, pp->y+15, pp->x+15, pp->y+15, CALIBRATION_COLOR2);
- gdispGDrawLine(m->display, pp->x+15, pp->y+7, pp->x+15, pp->y+15, CALIBRATION_COLOR2);
- gdispGDrawLine(m->display, pp->x+7, pp->y-15, pp->x+15, pp->y-15, CALIBRATION_COLOR2);
- gdispGDrawLine(m->display, pp->x+15, pp->y-15, pp->x+15, pp->y-7, CALIBRATION_COLOR2);
+ // Step 2 - Handle touch and button 0 debouncing
+ {
+ // Clean off button garbage
+ r.buttons &= GINPUT_MOUSE_BTN_MASK;
+
+ #if !GINPUT_TOUCH_NOTOUCH
+ // If touch then calculate button 0 from z
+ if ((gmvmt(m)->d.flags & GMOUSE_VFLG_TOUCH)) {
+ if (gmvmt(m)->z_min <= gmvmt(m)->z_max) {
+ if (r.z >= gmvmt(m)->z_touchon) r.buttons |= GINPUT_MOUSE_BTN_LEFT;
+ else if (r.z <= gmvmt(m)->z_touchoff) r.buttons &= ~GINPUT_MOUSE_BTN_LEFT;
+ else return; // bad transitional reading
+ } else {
+ if (r.z <= gmvmt(m)->z_touchon) r.buttons |= GINPUT_MOUSE_BTN_LEFT;
+ else if (r.z >= gmvmt(m)->z_touchoff) r.buttons &= ~GINPUT_MOUSE_BTN_LEFT;
+ else return; // bad transitional reading
+ }
+ }
+
+ // Devices with poor button 0 transitioning need debouncing
+ if ((gmvmt(m)->d.flags & GMOUSE_VFLG_POORUPDOWN)) {
+ // Are we in a transition test
+ if ((m->flags & GMOUSE_FLG_INDELTA)) {
+ if (!((r.buttons ^ m->r.buttons) & GINPUT_MOUSE_BTN_LEFT)) {
+ // Transition failed
+ m->flags &= ~GMOUSE_FLG_INDELTA;
+ return;
+ }
+ // Transition succeeded
+ m->flags &= ~GMOUSE_FLG_INDELTA;
+
+ // Should we start a transition test
+ } else if (((r.buttons ^ m->r.buttons) & GINPUT_MOUSE_BTN_LEFT)) {
+ m->flags |= GMOUSE_FLG_INDELTA;
+ return;
+ }
+ }
+ #endif
+
+ #if !GINPUT_TOUCH_NOCALIBRATE_GUI
+ // Stop here with just the raw x,y reading during calibration
+ if ((m->flags & GMOUSE_FLG_IN_CAL)) {
+ if ((r.buttons & GINPUT_MOUSE_BTN_LEFT)) {
+ m->r.x = r.x;
+ m->r.y = r.y;
+ }
+ m->r.buttons = r.buttons;
+ return;
+ }
+ #endif
}
- static inline void CalibrationCrossClear(GMouse *m, const point *pp) {
- gdispGFillArea(m->display, pp->x - 15, pp->y - 15, 32, 32, CALIBRATION_BACKGROUND);
+ // Step 3 - Apply calibration, rotation and display clipping
+ {
+ // If the mouse is up we may need to keep our previous position
+ if ((gmvmt(m)->d.flags & GMOUSE_VFLG_ONLY_DOWN) && !(r.buttons & GINPUT_MOUSE_BTN_LEFT)) {
+ r.x = m->r.x;
+ r.y = m->r.y;
+
+ } else {
+
+ #if !GINPUT_TOUCH_NOCALIBRATE
+ // Do we need to calibrate the reading?
+ if ((m->flags & GMOUSE_FLG_CALIBRATE))
+ CalibrationTransform(&r, &m->caldata);
+ #endif
+
+ // We can't clip or rotate if we don't have a display
+ if (m->display) {
+ coord_t w, h;
+
+ // We now need display information
+ w = gdispGGetWidth(m->display);
+ h = gdispGGetHeight(m->display);
+
+ #if GDISP_NEED_CONTROL
+ // Do we need to rotate the reading to match the display
+ if (!(gmvmt(m)->d.flags & GMOUSE_VFLG_SELFROTATION)) {
+ coord_t t;
+
+ switch(gdispGGetOrientation(m->display)) {
+ 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
+
+ // Do we need to clip the reading to the display
+ if ((m->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;
+ }
+ }
+ }
}
- static inline void CalibrationTransform(GMouseReading *pt, const GMouseCalibration *c) {
- pt->x = (coord_t) (c->ax * pt->x + c->bx * pt->y + c->cx);
- pt->y = (coord_t) (c->ay * pt->x + c->by * pt->y + c->cy);
+ // Step 4 - Apply jitter detection
+ #if !GINPUT_TOUCH_NOTOUCH
+ {
+ const GMouseJitter *pj;
+ uint32_t diff;
+
+ // Are we in pen or finger mode
+ pj = (m->flags & GMOUSE_FLG_FINGERMODE) ? &gmvmt(m)->finger_jitter : &gmvmt(m)->pen_jitter;
+
+ // Is this just movement jitter
+ if (pj->move > 0) {
+ diff = (uint32_t)(r.x - m->r.x) * (uint32_t)(r.x - m->r.x) + (uint32_t)(r.y - m->r.y) * (uint32_t)(r.y - m->r.y);
+ if (diff > (uint32_t)pj->move * (uint32_t)pj->move) {
+ r.x = m->r.x;
+ r.y = m->r.y;
+ }
+ }
+
+ // Check if the click has moved outside the click area and if so cancel the click
+ if (pj->click > 0 && (m->flags & GMOUSE_FLG_CLICK_TIMER)) {
+ diff = (uint32_t)(r.x - m->clickpos.x) * (uint32_t)(r.x - m->clickpos.x) + (uint32_t)(r.y - m->clickpos.y) * (uint32_t)(r.y - m->clickpos.y);
+ if (diff > (uint32_t)pj->click * (uint32_t)pj->click)
+ m->flags &= ~GMOUSE_FLG_CLICK_TIMER;
+ }
+ }
+ #endif
+
+ // Step 5 - Click, context-click and other meta event detection
+ {
+ uint16_t upbtns, dnbtns;
+
+ // Calculate button transitions
+ dnbtns = r.buttons & ~m->r.buttons;
+ upbtns = ~r.buttons & m->r.buttons;
+
+ // Left mouse down generates the Mouse-down meta event
+ if ((dnbtns & GINPUT_MOUSE_BTN_LEFT))
+ r.buttons |= GMETA_MOUSE_DOWN;
+
+ // Left mouse up generates the Mouse-up meta event
+ if ((upbtns & GINPUT_MOUSE_BTN_LEFT))
+ r.buttons |= GMETA_MOUSE_UP;
+
+ // Left/Right mouse down starts the click timer
+ if ((dnbtns & (GINPUT_MOUSE_BTN_LEFT|GINPUT_MOUSE_BTN_RIGHT))) {
+ m->clickpos.x = r.x;
+ m->clickpos.y = r.y;
+ m->clicktime = gfxSystemTicks();
+ m->flags |= GMOUSE_FLG_CLICK_TIMER;
+ }
+
+ // Left/Right mouse up with the click timer still running may generate a click or context click
+ if ((upbtns & (GINPUT_MOUSE_BTN_LEFT|GINPUT_MOUSE_BTN_RIGHT)) && (m->flags & GMOUSE_FLG_CLICK_TIMER)) {
+ m->flags &= ~GMOUSE_FLG_CLICK_TIMER;
+ m->clicktime = gfxSystemTicks() - m->clicktime;
+
+ // Was this a short click?
+ if (m->clicktime <= gfxMillisecondsToTicks(GINPUT_MOUSE_CLICK_TIME)) {
+ if ((upbtns & GINPUT_MOUSE_BTN_RIGHT))
+ r.buttons |= GMETA_MOUSE_CXTCLICK;
+ if ((upbtns & GINPUT_MOUSE_BTN_LEFT))
+ r.buttons |= GMETA_MOUSE_CLICK;
+ }
+
+ #if !GINPUT_TOUCH_NOTOUCH
+ // Was this a long click on a touch device?
+ if ((gmvmt(m)->d.flags & GMOUSE_VFLG_TOUCH) && m->clicktime >= gfxMillisecondsToTicks(GINPUT_TOUCH_CXTCLICK_TIME))
+ r.buttons |= GMETA_MOUSE_CXTCLICK;
+ #endif
+ }
+ }
+
+ // Step 6 - Send the event to the listeners that are interested.
+ {
+ GSourceListener *psl;
+
+ // Send to the "All Mice" source listeners
+ psl = 0;
+ while ((psl = geventGetSourceListener((GSourceHandle)&MouseTimer, psl)))
+ SendMouseEvent(psl, m, &r);
+
+ // Send to the mouse specific source listeners
+ psl = 0;
+ while ((psl = geventGetSourceListener((GSourceHandle)m, psl)))
+ SendMouseEvent(psl, m, &r);
+ }
+
+ // Step 7 - Finally save the results
+ m->r.x = r.x;
+ m->r.y = r.y;
+ m->r.z = r.z;
+ m->r.buttons = r.buttons;
+}
+
+static void MousePoll(void *param) {
+ GMouse * m;
+ (void) param;
+
+ for(m = (GMouse *)gdriverGetNext(GDRIVER_TYPE_MOUSE, 0); m; m = (GMouse *)gdriverGetNext(GDRIVER_TYPE_MOUSE, (GDriver *)m)) {
+ if (!(gmvmt(m)->d.flags & GMOUSE_VFLG_NOPOLL) || (m->flags & GMOUSE_FLG_NEEDREAD))
+ GetMouseReading(m);
+ }
+}
+
+// Calibration user interface
+#if !GINPUT_TOUCH_NOCALIBRATE_GUI
+ #if !defined(GFX_USE_GDISP) || !GFX_USE_GDISP
+ #error "GINPUT: GFX_USE_GDISP must be defined when calibration is required"
+ #endif
+
+ static inline void CalibrationCrossDraw(GMouse *m, const point *pp) {
+ gdispGDrawLine(m->display, pp->x-CALIBRATION_CROSS_RADIUS, pp->y, pp->x-CALIBRATION_CROSS_INNERGAP, pp->y, CALIBRATION_CROSS_COLOR1);
+ gdispGDrawLine(m->display, pp->x+CALIBRATION_CROSS_INNERGAP, pp->y, pp->x+CALIBRATION_CROSS_RADIUS, pp->y, CALIBRATION_CROSS_COLOR1);
+ gdispGDrawLine(m->display, pp->x, pp->y-CALIBRATION_CROSS_RADIUS, pp->x, pp->y-CALIBRATION_CROSS_INNERGAP, CALIBRATION_CROSS_COLOR1);
+ gdispGDrawLine(m->display, pp->x, pp->y+CALIBRATION_CROSS_INNERGAP, pp->x, pp->y+CALIBRATION_CROSS_RADIUS, CALIBRATION_CROSS_COLOR1);
+ gdispGDrawLine(m->display, pp->x-CALIBRATION_CROSS_RADIUS, pp->y+CALIBRATION_CROSS_RADIUS, pp->x-CALIBRATION_CROSS_RADIUS/2, pp->y+CALIBRATION_CROSS_RADIUS, CALIBRATION_CROSS_COLOR2);
+ gdispGDrawLine(m->display, pp->x-CALIBRATION_CROSS_RADIUS, pp->y+CALIBRATION_CROSS_RADIUS/2, pp->x-CALIBRATION_CROSS_RADIUS, pp->y+CALIBRATION_CROSS_RADIUS, CALIBRATION_CROSS_COLOR2);
+ gdispGDrawLine(m->display, pp->x-CALIBRATION_CROSS_RADIUS, pp->y-CALIBRATION_CROSS_RADIUS, pp->x-CALIBRATION_CROSS_RADIUS/2, pp->y-CALIBRATION_CROSS_RADIUS, CALIBRATION_CROSS_COLOR2);
+ gdispGDrawLine(m->display, pp->x-CALIBRATION_CROSS_RADIUS, pp->y-CALIBRATION_CROSS_RADIUS/2, pp->x-CALIBRATION_CROSS_RADIUS, pp->y-CALIBRATION_CROSS_RADIUS, CALIBRATION_CROSS_COLOR2);
+ gdispGDrawLine(m->display, pp->x+CALIBRATION_CROSS_RADIUS/2, pp->y+CALIBRATION_CROSS_RADIUS, pp->x+CALIBRATION_CROSS_RADIUS, pp->y+CALIBRATION_CROSS_RADIUS, CALIBRATION_CROSS_COLOR2);
+ gdispGDrawLine(m->display, pp->x+CALIBRATION_CROSS_RADIUS, pp->y+CALIBRATION_CROSS_RADIUS/2, pp->x+CALIBRATION_CROSS_RADIUS, pp->y+CALIBRATION_CROSS_RADIUS, CALIBRATION_CROSS_COLOR2);
+ gdispGDrawLine(m->display, pp->x+CALIBRATION_CROSS_RADIUS/2, pp->y-CALIBRATION_CROSS_RADIUS, pp->x+CALIBRATION_CROSS_RADIUS, pp->y-CALIBRATION_CROSS_RADIUS, CALIBRATION_CROSS_COLOR2);
+ gdispGDrawLine(m->display, pp->x+CALIBRATION_CROSS_RADIUS, pp->y-CALIBRATION_CROSS_RADIUS, pp->x+CALIBRATION_CROSS_RADIUS, pp->y-CALIBRATION_CROSS_RADIUS/2, CALIBRATION_CROSS_COLOR2);
+ }
+
+ static inline void CalibrationCrossClear(GMouse *m, const point *pp) {
+ gdispGFillArea(m->display, pp->x - CALIBRATION_CROSS_RADIUS, pp->y - CALIBRATION_CROSS_RADIUS, CALIBRATION_CROSS_RADIUS*2, CALIBRATION_CROSS_RADIUS*2, CALIBRATION_BACKGROUND);
}
static inline void CalibrationCalculate(GMouse *m, const point *cross, const point *points) {
@@ -165,220 +434,178 @@ static GTIMER_DECL(MouseTimer);
- c1 * ((float)points[0].x * (float)points[2].y - (float)points[2].x * (float)points[0].y)
+ c2 * ((float)points[0].x * (float)points[1].y - (float)points[1].x * (float)points[0].y)) / dx;
}
-#endif
-
-static void GetMouseReading(GMouse *m) {
- GMouseReading r;
- // Get the raw reading.
- gmvmt(m)->get(m, &r);
- m->flags &= ~GMOUSE_FLG_NEEDREAD;
+ static void CalibrateMouse(GMouse *m) {
+ coord_t w, h;
+ point cross[4]; // The locations of the test points on the display
+ point points[4]; // The x, y readings obtained from the mouse for each test point
+ font_t font1, font2;
- // If touch then calculate button 0 from z
- if ((gmvmt(m)->d.flags & GMOUSE_VFLG_TOUCH)) {
- if (gmvmt(m)->z_min <= gmvmt(m)->z_max) {
- if (r.z >= gmvmt(m)->z_touchon) r.buttons |= GINPUT_MOUSE_BTN_LEFT;
- else if (r.z <= gmvmt(m)->z_touchoff) r.buttons &= ~GINPUT_MOUSE_BTN_LEFT;
- else return; // bad transitional reading
- } else {
- if (r.z <= gmvmt(m)->z_touchon) r.buttons |= GINPUT_MOUSE_BTN_LEFT;
- else if (r.z >= gmvmt(m)->z_touchoff) r.buttons &= ~GINPUT_MOUSE_BTN_LEFT;
- else return; // bad transitional reading
- }
- }
-
- // Double check up & down events if needed
- if ((gmvmt(m)->d.flags & GMOUSE_VFLG_POORUPDOWN)) {
- // Are we in a transition test
- if ((m->flags & GMOUSE_FLG_INDELTA)) {
- if (!((r.buttons ^ m->r.buttons) & GINPUT_MOUSE_BTN_LEFT)) {
- // Transition failed
- m->flags &= ~GMOUSE_FLG_INDELTA;
- return;
- }
- // Transition succeeded
- m->flags &= ~GMOUSE_FLG_INDELTA;
-
- // Should we start a transition test
- } else if (((r.buttons ^ m->r.buttons) & GINPUT_MOUSE_BTN_LEFT)) {
- m->flags |= GMOUSE_FLG_INDELTA;
- return;
- }
- }
-
- // If the mouse is up we may need to keep our previous position
- if ((gmvmt(m)->d.flags & GMOUSE_VFLG_ONLY_DOWN) && !(r.buttons & GINPUT_MOUSE_BTN_LEFT)) {
- r.x = m->r.x;
- r.y = m->r.y;
-
- } else {
- coord_t w, h;
-
- #if !GINPUT_TOUCH_NOCALIBRATE
- // Do we need to calibrate the reading?
- if ((m->flags & GMOUSE_FLG_CALIBRATE))
- CalibrationTransform(&r, &m->caldata);
+ font1 = gdispOpenFont(CALIBRATION_FONT);
+ font2 = gdispOpenFont(CALIBRATION_FONT2);
+ w = gdispGGetWidth(m->display);
+ h = gdispGGetHeight(m->display);
+ #if GDISP_NEED_CLIP
+ gdispGSetClip(m->display, 0, 0, w, h);
#endif
- // We can't clip or rotate if we don't have a display
- if (m->display) {
+ // Ensure we get minimaly processed readings for the calibration
+ m->flags |= GMOUSE_FLG_IN_CAL;
+
+ // Set up our calibration locations
+ if ((gmvmt(m)->d.flags & GMOUSE_VFLG_CAL_EXTREMES)) {
+ cross[0].x = 0; cross[0].y = 0;
+ cross[1].x = w-1; cross[1].y = 0;
+ cross[2].x = w-1; cross[2].y = h-1;
+ cross[3].x = w/2; cross[3].y = h/2;
+ } else {
+ cross[0].x = w/4; cross[0].y = h/4;
+ cross[1].x = w-w/4; cross[1].y = h/4;
+ cross[2].x = w-w/4; cross[2].y = h-h/4;
+ cross[3].x = w/2; cross[3].y = h/2;
+ }
+
+ // Perform calibration until we get a valid result
+ while(1) {
+
+ // Set up the calibration display
+ gdispGClear(m->display, Blue);
+ gdispGFillStringBox(m->display,
+ 0, CALIBRATION_TITLE_Y, w, CALIBRATION_TITLE_HEIGHT,
+ CALIBRATION_TITLE, font1, CALIBRATION_TITLE_COLOR, CALIBRATION_TITLE_BACKGROUND,
+ justifyCenter);
+
+ // Calculate the calibration
+ {
+ unsigned i, maxpoints;
+
+ maxpoints = (gmvmt(m)->d.flags & GMOUSE_VFLG_CAL_TEST) ? 4 : 3;
+
+ // Loop through the calibration points
+ for(i = 0; i < maxpoints; i++) {
+ int32_t px, py;
+ unsigned j;
+
+ // Draw the current calibration point
+ CalibrationCrossDraw(m, &cross[i]);
+
+ // Get a valid "point pressed" average reading
+ do {
+ // Wait for the mouse to be pressed
+ while(!(m->r.buttons & GINPUT_MOUSE_BTN_LEFT))
+ gfxSleepMilliseconds(CALIBRATION_POLL_PERIOD);
+
+ // Sum samples taken every CALIBRATION_POLL_PERIOD milliseconds while the mouse is down
+ px = py = j = 0;
+ while((m->r.buttons & GINPUT_MOUSE_BTN_LEFT)) {
+ // Limit sampling period to prevent overflow
+ if (j < CALIBRATION_MAXPRESS_PERIOD/CALIBRATION_POLL_PERIOD) {
+ px += m->r.x;
+ py += m->r.y;
+ j++;
+ }
+ gfxSleepMilliseconds(CALIBRATION_POLL_PERIOD);
+ }
- // We now need display information
- w = gdispGGetWidth(m->display);
- h = gdispGGetHeight(m->display);
+ // Ignore presses less than CALIBRATION_MAXPRESS_PERIOD milliseconds
+ } while(j < CALIBRATION_MINPRESS_PERIOD/CALIBRATION_POLL_PERIOD);
+ points[i].x = px / j;
+ points[i].y = py / j;
- #if GDISP_NEED_CONTROL
- // Do we need to rotate the reading to match the display
- if (!(gmvmt(m)->d.flags & GMOUSE_VFLG_SELFROTATION)) {
- coord_t t;
-
- switch(gdispGGetOrientation(m->display)) {
- 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;
- }
+ // Clear the current calibration point
+ CalibrationCrossClear(m, &cross[i]);
}
- #endif
-
- // Do we need to clip the reading to the display
- if ((m->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;
- }
- }
- }
- {
- const GMouseJitter *pj;
- uint32_t diff;
-
- // Are we in pen or finger mode
- pj = (m->flags & GMOUSE_FLG_FINGERMODE) ? &gmvmt(m)->finger_jitter : &gmvmt(m)->pen_jitter;
+ // Apply 3 point calibration algorithm
+ CalibrationCalculate(m, cross, points);
- // Is this just movement jitter
- if (pj->move > 0) {
- diff = (uint32_t)(r.x - m->r.x) * (uint32_t)(r.x - m->r.x) + (uint32_t)(r.y - m->r.y) * (uint32_t)(r.y - m->r.y);
- if (diff > (uint32_t)pj->move * (uint32_t)pj->move) {
- r.x = m->r.x;
- r.y = m->r.y;
+ // Skip the 4th point tests if we don't want them
+ if (maxpoints < 4)
+ break;
}
- }
- // Check if the click has moved outside the click area and if so cancel the click
- if (pj->click > 0 && (m->flags & GMOUSE_FLG_CLICK_TIMER)) {
- diff = (uint32_t)(r.x - m->clickpos.x) * (uint32_t)(r.x - m->clickpos.x) + (uint32_t)(r.y - m->clickpos.y) * (uint32_t)(r.y - m->clickpos.y);
- if (diff > (uint32_t)pj->click * (uint32_t)pj->click)
- m->flags &= ~GMOUSE_FLG_CLICK_TIMER;
- }
- }
+ /* Verification of correctness of calibration (optional) :
+ * See if the 4th point (Middle of the screen) coincides with the calibrated
+ * result. If point is within +/- Squareroot(ERROR) pixel margin, then successful calibration
+ * Else, start from the beginning.
+ */
+ {
+ const GMouseJitter *pj;
+ uint32_t err;
- {
- GSourceListener *psl;
- GEventMouse *pe;
- unsigned meta;
- uint16_t upbtns, dnbtns;
-
- // Calculate out new event meta value and handle CLICK and CXTCLICK
- dnbtns = r.buttons & ~m->r.buttons;
- upbtns = ~r.buttons & m->r.buttons;
- meta = GMETA_NONE;
+ // Are we in pen or finger mode
+ pj = (m->flags & GMOUSE_FLG_FINGERMODE) ? &gmvmt(m)->finger_jitter : &gmvmt(m)->pen_jitter;
- // Mouse down
- if ((dnbtns & (GINPUT_MOUSE_BTN_LEFT|GINPUT_MOUSE_BTN_RIGHT))) {
- m->clickpos.x = r.x;
- m->clickpos.y = r.y;
- m->clicktime = gfxSystemTicks();
- m->flags |= GMOUSE_FLG_CLICK_TIMER;
- if ((dnbtns & GINPUT_MOUSE_BTN_LEFT))
- meta |= GMETA_MOUSE_DOWN;
- }
+ // Transform the co-ordinates
+ CalibrationTransform((GMouseReading *)&points[3], &m->caldata);
- // Mouse up
- if ((upbtns & (GINPUT_MOUSE_BTN_LEFT|GINPUT_MOUSE_BTN_RIGHT))) {
- if ((upbtns & GINPUT_MOUSE_BTN_LEFT))
- meta |= GMETA_MOUSE_UP;
- if ((m->flags & GMOUSE_FLG_CLICK_TIMER)) {
- if ((upbtns & GINPUT_MOUSE_BTN_LEFT)
- #if GINPUT_TOUCH_CLICK_TIME != TIME_INFINITE
- && gfxSystemTicks() - m->clicktime < gfxMillisecondsToTicks(GINPUT_TOUCH_CLICK_TIME)
- #endif
- )
- meta |= GMETA_MOUSE_CLICK;
- else
- meta |= GMETA_MOUSE_CXTCLICK;
- m->flags &= ~GMOUSE_FLG_CLICK_TIMER;
- }
- }
+ // Do we need to rotate the reading to match the display
+ #if GDISP_NEED_CONTROL
+ if (!(gmvmt(m)->d.flags & GMOUSE_VFLG_SELFROTATION)) {
+ coord_t t;
+
+ switch(gdispGGetOrientation(m->display)) {
+ case GDISP_ROTATE_0:
+ break;
+ case GDISP_ROTATE_90:
+ t = points[3].x;
+ points[3].x = w - 1 - points[3].y;
+ points[3].y = t;
+ break;
+ case GDISP_ROTATE_180:
+ points[3].x = w - 1 - points[3].x;
+ points[3].y = h - 1 - points[3].y;
+ break;
+ case GDISP_ROTATE_270:
+ t = points[3].y;
+ points[3].y = h - 1 - points[3].x;
+ points[3].x = t;
+ break;
+ default:
+ break;
+ }
+ }
+ #endif
- // Send the event to the listeners that are interested.
- psl = 0;
- while ((psl = geventGetSourceListener((GSourceHandle)m, psl))) {
- if (!(pe = (GEventMouse *)geventGetEventBuffer(psl))) {
- // This listener is missing - save the meta events that have happened
- psl->srcflags |= meta;
- continue;
- }
+ // Is this accurate enough?
+ err = (points[3].x - cross[3].x) * (points[3].x - cross[3].x) + (points[3].y - cross[3].y) * (points[3].y - cross[3].y);
+ if (err <= (uint32_t)pj->calibrate * (uint32_t)pj->calibrate)
+ break;
- // 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 == m->r.x && r.y == m->r.y && r.buttons == m->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 = (gmvmt(m)->d.flags & GMOUSE_VFLG_TOUCH) ? GEVENT_TOUCH : GEVENT_MOUSE;
- pe->x = r.x;
- pe->y = r.y;
- pe->z = r.z;
- pe->current_buttons = r.buttons;
- pe->last_buttons = m->r.buttons;
- pe->meta = meta;
- if (psl->srcflags) {
- pe->current_buttons |= GINPUT_MISSED_MOUSE_EVENT;
- pe->meta |= psl->srcflags;
- psl->srcflags = 0;
- }
- pe->display = m->display;
- geventSendEvent(psl);
+ // No - Display error and try again
+ gdispGFillStringBox(m->display,
+ 0, CALIBRATION_ERROR_Y, w, CALIBRATION_ERROR_HEIGHT,
+ CALIBRATION_ERROR_TEXT, font2, CALIBRATION_ERROR_COLOR, CALIBRATION_ERROR_BACKGROUND,
+ justifyCenter);
+ gfxSleepMilliseconds(5000);
}
}
- }
- // Finally save the results
- m->r.x = r.x;
- m->r.y = r.y;
- m->r.z = r.z;
- m->r.buttons = r.buttons;
-}
+ // We are done calibrating
+ gdispCloseFont(font1);
+ gdispCloseFont(font2);
+ m->flags |= GMOUSE_FLG_CALIBRATE|GMOUSE_FLG_CLIP;
+ m->flags &= ~GMOUSE_FLG_IN_CAL;
-static void MousePoll(void *param) {
- GMouse * m;
- (void) param;
+ // Force an initial reading
+ m->r.buttons = 0;
+ GetMouseReading(m);
- for(m = (GMouse *)gdriverGetNext(GDRIVER_TYPE_MOUSE, 0); m; m = (GMouse *)gdriverGetNext(GDRIVER_TYPE_MOUSE, (GDriver *)m)) {
- if (!(gmvmt(m)->d.flags & GMOUSE_VFLG_NOPOLL) || (m->flags & GMOUSE_FLG_NEEDREAD))
- GetMouseReading(m);
+ // Save the calibration data (if possible)
+ #if GINPUT_TOUCH_USER_CALIBRATION_SAVE
+ SaveMouseCalibration(gdriverGetDriverInstanceNumber((GDriver *)m), &m->caldata, sizeof(GMouseCalibration));
+ #endif
+ if (gmvmt(m)->calsave)
+ gmvmt(m)->calsave(m, &m->caldata, sizeof(GMouseCalibration));
+
+ // Clear the screen using the GWIN default background color
+ #if GFX_USE_GWIN
+ gdispGClear(m->display, gwinGetDefaultBgColor());
+ #else
+ gdispGClear(m->display, GDISP_STARTUP_COLOR);
+ #endif
}
-}
+#endif
void _gmouseInit(void) {
// GINPUT_MOUSE_DRIVER_LIST is defined - create each driver instance
@@ -388,298 +615,173 @@ void _gmouseInit(void) {
extern GDriverVMTList GINPUT_MOUSE_DRIVER_LIST;
static const struct GDriverVMT const * dclist[] = {GINPUT_MOUSE_DRIVER_LIST};
- static const unsigned dnlist[] = {GDISP_CONTROLLER_DISPLAYS};
- for(i = 0; i < sizeof(dclist)/sizeof(dclist[0]); i++)
- gdriverRegister(dclist[i]);
+ for(i = 0; i < sizeof(dclist)/sizeof(dclist[0]); i++) {
+ if (!(dclist[i]->flags & GMOUSE_VFLG_DYNAMICONLY))
+ gdriverRegister(dclist[i]);
+ }
}
- // One and only one display
+ // One and only one mouse
#else
{
- extern GDriverVMTList GINPUTMOUSEVMT_OnlyOne;
+ extern GDriverVMTList GMOUSEVMT_OnlyOne;
- gdriverRegister(GINPUTMOUSEVMT_OnlyOne);
+ if (!(GMOUSEVMT_OnlyOne->flags & GMOUSE_VFLG_DYNAMICONLY))
+ gdriverRegister(GMOUSEVMT_OnlyOne);
}
#endif
+
}
void _gmouseDeinit(void) {
+ gtimerDeinit(&MouseTimer);
}
-GSourceHandle ginputGetMouse(uint16_t instance) {
- GMouse *m;
- #if GINPUT_MOUSE_NEED_CALIBRATION
- GCalibration *pc;
+bool_t _gmouseInitDriver(GDriver *g, unsigned driverinstance, unsigned systeminstance) {
+ #define m ((GMouse *)g)
+ (void) systeminstance;
+
+ // Init the mouse
+ if (!gmvmt(m)->init((GMouse *)g, driverinstance))
+ return FALSE;
+
+ #if !GINPUT_TOUCH_NOTOUCH
+ // Should this mouse start in finger mode?
+ if ((gmvmt(m)->d.flags & GMOUSE_VFLG_DEFAULTFINGER))
+ m->flags |= GMOUSE_FLG_FINGERMODE;
#endif
- if (!(m = (GMouse *)gdriverGetInstance(GDRIVER_TYPE_MOUSE, instance)))
- return 0;
+ // Ensure the Poll timer is started
+ if (!gtimerIsActive(&MouseTimer))
+ gtimerStart(&MouseTimer, MousePoll, 0, TRUE, GINPUT_MOUSE_POLL_PERIOD);
+
+ return TRUE;
+
+ #undef m
+}
+
+void _gmousePostInitDriver(GDriver *g) {
+ #define m ((GMouse *)g)
// Make sure we have a valid mouse display
if (!m->display)
m->display = GDISP;
- // Do we need to initialise the mouse subsystem?
- if (!(m->flags & FLG_INIT_DONE)) {
- ginput_lld_mouse_init();
-
- #if GINPUT_MOUSE_NEED_CALIBRATION
- #if GINPUT_MOUSE_LLD_CALIBRATION_LOADSAVE
- if (!m->fnloadcal) {
- m->fnloadcal = ginput_lld_mouse_calibration_load;
- m->flags &= ~FLG_CAL_FREE;
- }
- if (!m->fnsavecal)
- m->fnsavecal = ginput_lld_mouse_calibration_save;
+ #if !GINPUT_TOUCH_NOCALIBRATE && !GINPUT_TOUCH_STARTRAW
+ if ((gmvmt(m)->d.flags & GMOUSE_VFLG_CALIBRATE)) {
+ GMouseCalibration *pc;
+
+ #if GINPUT_TOUCH_USER_CALIBRATION_LOAD
+ if ((pc = (GMouseCalibration *)LoadMouseCalibration(gdriverGetDriverInstanceNumber((GDriver *)m), sizeof(GMouseCalibration)))) {
+ memcpy(&m->caldata, pc, sizeof(GMouseCalibration));
+ #if GINPUT_TOUCH_USER_CALIBRATION_FREE
+ gfxFree(pc);
+ #endif
+ m->flags |= GMOUSE_FLG_CALIBRATE|GMOUSE_FLG_CLIP;
+ } else
+ #endif
+ if (gmvmt(m)->calload && (pc = (GMouseCalibration *)gmvmt(m)->calload(m, sizeof(GMouseCalibration)))) {
+ memcpy(&m->caldata, pc, sizeof(GMouseCalibration));
+ if ((gmvmt(m)->d.flags & GMOUSE_VFLG_CAL_LOADFREE))
+ gfxFree(pc);
+ m->flags |= GMOUSE_FLG_CALIBRATE|GMOUSE_FLG_CLIP;
+ }
+ #if !GINPUT_TOUCH_NOCALIBRATE_GUI
+ else
+ CalibrateMouse(m);
#endif
- if (m->fnloadcal && (pc = (Calibration *)m->fnloadcal(instance))) {
- memcpy(&m->caldata, pc, sizeof(m->caldata));
- m->flags |= (FLG_CAL_OK|FLG_CAL_SAVED);
- if ((m->flags & FLG_CAL_FREE))
- gfxFree((void *)pc);
- } else if (instance == 9999) {
- CalibrationSetIdentity(&m->caldata);
- m->flags |= (FLG_CAL_OK|FLG_CAL_SAVED|FLG_CAL_RAW);
- } else
- ginputCalibrateMouse(instance);
- #endif
+ }
+ #endif
- // Get the first reading
- m->last_buttons = 0;
- get_calibrated_reading(&m->t);
+ // Get the first reading
+ GetMouseReading(m);
- // Mark init as done and start the Poll timer
- m->flags |= FLG_INIT_DONE;
- gtimerStart(&MouseTimer, MousePoll, 0, TRUE, GINPUT_MOUSE_POLL_PERIOD);
- }
+ #undef m
+}
+
+void _gmouseDeInitDriver(GDriver *g) {
+ (void) g;
+}
- // Return our structure as the handle
- return (GSourceHandle)m;
+GSourceHandle ginputGetMouse(unsigned instance) {
+ if (instance == GMOUSE_ALL_INSTANCES)
+ return (GSourceHandle)&MouseTimer;
+ return (GSourceHandle)gdriverGetInstance(GDRIVER_TYPE_MOUSE, instance);
}
-void ginputSetMouseDisplay(uint16_t instance, GDisplay *g) {
- if (instance)
+void ginputSetMouseDisplay(unsigned instance, GDisplay *g) {
+ GMouse *m;
+
+ if (!(m = (GMouse *)gdriverGetInstance(GDRIVER_TYPE_MOUSE, instance)))
return;
m->display = g ? g : GDISP;
}
-GDisplay *ginputGetMouseDisplay(uint16_t instance) {
- if (instance)
+GDisplay *ginputGetMouseDisplay(unsigned instance) {
+ GMouse *m;
+
+ if (!(m = (GMouse *)gdriverGetInstance(GDRIVER_TYPE_MOUSE, instance)))
return 0;
return m->display;
}
-bool_t ginputGetMouseStatus(uint16_t instance, GEventMouse *pe) {
+bool_t ginputGetMouseStatus(unsigned instance, GEventMouse *pe) {
+ GMouse *m;
+
// Win32 threads don't seem to recognise priority and/or pre-emption
// so we add a sleep here to prevent 100% polled applications from locking up.
gfxSleepMilliseconds(1);
- if (instance || (m->flags & (FLG_INIT_DONE|FLG_IN_CAL)) != FLG_INIT_DONE)
+ if (!(m = (GMouse *)gdriverGetInstance(GDRIVER_TYPE_MOUSE, instance)))
return FALSE;
- pe->type = GINPUT_MOUSE_EVENT_TYPE;
- pe->x = m->t.x;
- pe->y = m->t.y;
- pe->z = m->t.z;
- pe->current_buttons = m->t.buttons;
- pe->last_buttons = m->last_buttons;
- if (pe->current_buttons & ~pe->last_buttons & GINPUT_MOUSE_BTN_LEFT)
- pe->meta = GMETA_MOUSE_DOWN;
- else if (~pe->current_buttons & pe->last_buttons & GINPUT_MOUSE_BTN_LEFT)
- pe->meta = GMETA_MOUSE_UP;
- else
- pe->meta = GMETA_NONE;
- return TRUE;
-}
-
-bool_t ginputCalibrateMouse(uint16_t instance) {
- #if GINPUT_TOUCH_NOCALIBRATE
-
- (void) instance;
-
- return FALSE;
- #else
-
- const coord_t height = gdispGGetHeight(MouseConfig.display);
- const coord_t width = gdispGGetWidth(MouseConfig.display);
- #if GINPUT_MOUSE_CALIBRATE_EXTREMES
- const MousePoint cross[] = {{0, 0},
- {(width - 1) , 0},
- {(width - 1) , (height - 1)},
- {(width / 2), (height / 2)}}; /* Check point */
- #else
- const MousePoint cross[] = {{(width / 4), (height / 4)},
- {(width - (width / 4)) , (height / 4)},
- {(width - (width / 4)) , (height - (height / 4))},
- {(width / 2), (height / 2)}}; /* Check point */
- #endif
- MousePoint points[4];
- const MousePoint *pc;
- MousePoint *pt;
- int32_t px, py;
- unsigned i, j;
- font_t font1, font2;
- #if GINPUT_MOUSE_MAX_CALIBRATION_ERROR >= 0
- unsigned err;
- #endif
-
- if (instance || (MouseConfig.flags & FLG_IN_CAL))
+ #if !GINPUT_TOUCH_NOCALIBRATE_GUI
+ if ((m->flags & GMOUSE_FLG_IN_CAL))
return FALSE;
+ #endif
- font1 = gdispOpenFont(GINPUT_MOUSE_CALIBRATION_FONT);
- font2 = gdispOpenFont(GINPUT_MOUSE_CALIBRATION_FONT2);
-
- MouseConfig.flags |= FLG_IN_CAL;
- gtimerStop(&MouseTimer);
- MouseConfig.flags &= ~(FLG_CAL_OK|FLG_CAL_SAVED|FLG_CAL_RAW);
-
- #if GDISP_NEED_CLIP
- gdispGSetClip(MouseConfig.display, 0, 0, width, height);
- #endif
-
- #if GINPUT_MOUSE_MAX_CALIBRATION_ERROR >= 0
- while(1) {
- #endif
- gdispGClear(MouseConfig.display, Blue);
-
- gdispGFillStringBox(MouseConfig.display, 0, 5, width, 30, GINPUT_MOUSE_CALIBRATION_TEXT, font1, White, Blue, justifyCenter);
-
- for(i = 0, pt = points, pc = cross; i < GINPUT_MOUSE_CALIBRATION_POINTS; i++, pt++, pc++) {
- CalibrationCrossDraw(pc);
-
- do {
-
- /* Wait for the mouse to be pressed */
- while(get_raw_reading(&MouseConfig.t), !(MouseConfig.t.buttons & GINPUT_MOUSE_BTN_LEFT))
- gfxSleepMilliseconds(20);
-
- /* Average all the samples while the mouse is down */
- for(px = py = 0, j = 0;
- gfxSleepMilliseconds(20), /* Settling time between readings */
- get_raw_reading(&MouseConfig.t),
- (MouseConfig.t.buttons & GINPUT_MOUSE_BTN_LEFT);
- j++) {
- px += MouseConfig.t.x;
- py += MouseConfig.t.y;
- }
-
- } while(!j);
-
- pt->x = px / j;
- pt->y = py / j;
-
- CalibrationCrossClear(pc);
-
- if (i >= 1 && pt->x == (pt-1)->x && pt->y == (pt-1)->y) {
- gdispGFillStringBox(MouseConfig.display, 0, 35, width, 40, GINPUT_MOUSE_CALIBRATION_SAME_TEXT, font2, Red, Yellow, justifyCenter);
- gfxSleepMilliseconds(5000);
- gdispGFillArea(MouseConfig.display, 0, 35, width, 40, Blue);
- }
-
- }
-
- /* Apply 3 point calibration algorithm */
- CalibrationCalculate(&MouseConfig, cross, points);
-
- /* Verification of correctness of calibration (optional) :
- * See if the 4th point (Middle of the screen) coincides with the calibrated
- * result. If point is within +/- Squareroot(ERROR) pixel margin, then successful calibration
- * Else, start from the beginning.
- */
- #if GINPUT_MOUSE_MAX_CALIBRATION_ERROR >= 0
- /* Transform the co-ordinates */
- MouseConfig.t.x = points[3].x;
- MouseConfig.t.y = points[3].y;
- CalibrationTransform(&MouseConfig.t, &MouseConfig.caldata);
- _tsOrientClip(&MouseConfig.t, MouseConfig.display, FALSE);
-
- /* Calculate the delta */
- err = (MouseConfig.t.x - cross[3].x) * (MouseConfig.t.x - cross[3].x) +
- (MouseConfig.t.y - cross[3].y) * (MouseConfig.t.y - cross[3].y);
-
- if (err <= GINPUT_MOUSE_MAX_CALIBRATION_ERROR * GINPUT_MOUSE_MAX_CALIBRATION_ERROR)
- break;
-
- gdispGFillStringBox(MouseConfig.display, 0, 35, width, 40, GINPUT_MOUSE_CALIBRATION_ERROR_TEXT, font2, Red, Yellow, justifyCenter);
- gfxSleepMilliseconds(5000);
- }
- #endif
-
- // Restart everything
- gdispCloseFont(font1);
- gdispCloseFont(font2);
- MouseConfig.flags |= FLG_CAL_OK;
- MouseConfig.last_buttons = 0;
- get_calibrated_reading(&MouseConfig.t);
- MouseConfig.flags &= ~FLG_IN_CAL;
- if ((MouseConfig.flags & FLG_INIT_DONE))
- gtimerStart(&MouseTimer, MousePoll, 0, TRUE, GINPUT_MOUSE_POLL_PERIOD);
-
- // Save the calibration data (if possible)
- if (MouseConfig.fnsavecal) {
- MouseConfig.fnsavecal(instance, (const uint8_t *)&MouseConfig.caldata, sizeof(MouseConfig.caldata));
- MouseConfig.flags |= FLG_CAL_SAVED;
- }
-
- // Clear the screen using the GWIN default background color
- #if GFX_USE_GWIN
- gdispGClear(MouseConfig.display, gwinGetDefaultBgColor());
- #else
- gdispGClear(MouseConfig.display, Black);
- #endif
-
- return TRUE;
+ #if !GINPUT_TOUCH_NOTOUCH
+ pe->type = (gmvmt(m)->d.flags & GMOUSE_VFLG_TOUCH) ? GEVENT_TOUCH : GEVENT_MOUSE;
+ #else
+ pe->type = GEVENT_MOUSE;
#endif
+ pe->x = m->r.x;
+ pe->y = m->r.y;
+ pe->z = m->r.z;
+ pe->buttons = m->r.buttons;
+ pe->display = m->display;
+ return TRUE;
}
-/* Set the routines to save and fetch calibration data.
- * This function should be called before first calling ginputGetMouse() for a particular instance
- * as the ginputGetMouse() routine may attempt to fetch calibration data and perform a startup calibration if there is no way to get it.
- * If this is called after ginputGetMouse() has been called and the driver requires calibration storage, it will immediately save the data is has already obtained.
- * The 'requireFree' parameter indicates if the fetch buffer must be free()'d to deallocate the buffer provided by the Fetch routine.
- */
-void ginputSetMouseCalibrationRoutines(uint16_t instance, GMouseCalibrationSaveRoutine fnsave, GMouseCalibrationLoadRoutine fnload, bool_t requireFree) {
- #if GINPUT_MOUSE_NEED_CALIBRATION
- if (instance)
+#if !GINPUT_TOUCH_NOTOUCH
+ void ginputSetFingerMode(unsigned instance, bool_t on) {
+ GMouse *m;
+
+ if (!(m = (GMouse *)gdriverGetInstance(GDRIVER_TYPE_MOUSE, instance)))
return;
- MouseConfig.fnloadcal = fnload;
- MouseConfig.fnsavecal = fnsave;
- if (requireFree)
- MouseConfig.flags |= FLG_CAL_FREE;
+ if (on)
+ m->flags |= GMOUSE_FLG_FINGERMODE;
else
- MouseConfig.flags &= ~FLG_CAL_FREE;
- #if GINPUT_MOUSE_LLD_CALIBRATION_LOADSAVE
- if (!MouseConfig.fnloadcal) {
- MouseConfig.fnloadcal = ginput_lld_mouse_calibration_load;
- MouseConfig.flags &= ~FLG_CAL_FREE;
- }
- if (!MouseConfig.fnsavecal)
- MouseConfig.fnsavecal = ginput_lld_mouse_calibration_save;
- #endif
- if (MouseConfig.fnsavecal && (MouseConfig.flags & (FLG_CAL_OK|FLG_CAL_SAVED)) == FLG_CAL_OK) {
- MouseConfig.fnsavecal(instance, (const uint8_t *)&MouseConfig.caldata, sizeof(MouseConfig.caldata));
- MouseConfig.flags |= FLG_CAL_SAVED;
- }
- #else
- (void)instance, (void)fnsave, (void)fnload, (void)requireFree;
- #endif
-}
+ m->flags &= ~GMOUSE_FLG_FINGERMODE;
-/* Test if a particular mouse instance requires routines to save its calibration data. */
-bool_t ginputRequireMouseCalibrationStorage(uint16_t instance) {
- if (instance)
- return FALSE;
+ }
+#endif
+
+#if !GINPUT_TOUCH_NOCALIBRATE_GUI
+ bool_t ginputCalibrateMouse(unsigned instance) {
+ GMouse *m;
- #if GINPUT_MOUSE_NEED_CALIBRATION && !GINPUT_MOUSE_LLD_CALIBRATION_LOADSAVE
+ if (!(m = (GMouse *)gdriverGetInstance(GDRIVER_TYPE_MOUSE, instance)))
+ return FALSE;
+
+ CalibrateMouse(m);
return TRUE;
- #else
- return FALSE;
- #endif
-}
+ }
+#endif
/* Wake up the mouse driver from an interrupt service routine (there may be new readings available) */
void ginputMouseWakeup(GMouse *m) {
diff --git a/src/ginput/ginput_mouse.h b/src/ginput/ginput_mouse.h
index 6cae66d1..1eff64f4 100644
--- a/src/ginput/ginput_mouse.h
+++ b/src/ginput/ginput_mouse.h
@@ -17,7 +17,7 @@
*
* @pre GFX_USE_GINPUT must be set to TRUE in your gfxconf.h
* @pre GINPUT_NEED_MOUSE must be set to TRUE in your gfxconf.h
- *
+ *
* @{
*/
@@ -32,31 +32,29 @@
/* This type definition is also used by touch */
typedef struct GEventMouse_t {
- GEventType type; // The type of this event (GEVENT_MOUSE or GEVENT_TOUCH)
- coord_t x, y, z; // The position of the mouse.
- // - For touch devices, Z is the current pressure if supported (otherwise 0)
- // - For mice, Z is the 3rd dimension if supported (otherwise 0)
- uint16_t current_buttons; // A bit is set if the button is down.
- // - For touch only bit 0 is relevant
- // - For mice the order of the buttons is (from 0 to n) left, right, middle, any other buttons
- // - Bit 15 being set indicates that an important mouse event has been missed.
- #define GINPUT_MOUSE_BTN_LEFT 0x0001
- #define GINPUT_MOUSE_BTN_RIGHT 0x0002
- #define GINPUT_MOUSE_BTN_MIDDLE 0x0004
- #define GINPUT_MOUSE_BTN_4 0x0008
- #define GINPUT_MISSED_MOUSE_EVENT 0x8000
- #define GINPUT_TOUCH_PRESSED GINPUT_MOUSE_BTN_LEFT
- uint16_t last_buttons; // The value of current_buttons on the last event
- enum GMouseMeta_e {
- GMETA_NONE = 0, // There is no meta event currently happening
- GMETA_MOUSE_DOWN = 1, // Button 0 has just gone down
- GMETA_MOUSE_UP = 2, // Button 0 has just gone up
- GMETA_MOUSE_CLICK = 4, // Button 0 has just gone through a short down - up cycle
- GMETA_MOUSE_CXTCLICK = 8 // For mice - The right button has just been depressed
- // For touch - a long press has just occurred
- } meta;
+ GEventType type; // The type of this event (GEVENT_MOUSE or GEVENT_TOUCH)
+ coord_t x, y, z; // The position of the mouse.
+ // - For touch devices, Z is the current pressure if supported (values are device specific)
+ // - For mice, Z is the 3rd dimension if supported (values are device specific)
+ uint16_t buttons; // A bit is set if the button is down or a meta event has occurred.
+ #define GINPUT_MOUSE_BTN_MASK 0x000F // The "button is down" mask
+ #define GINPUT_MOUSE_BTN_LEFT 0x0001 // The left mouse button is currently down
+ #define GINPUT_MOUSE_BTN_RIGHT 0x0002 // The right mouse button is currently down
+ #define GINPUT_MOUSE_BTN_MIDDLE 0x0004 // The middle mouse button is currently down
+ #define GINPUT_MOUSE_BTN_4 0x0008 // The 4th mouse button is currently down
+ #define GINPUT_TOUCH_PRESSED 0x0001 // The touch surface is currently touched
+
+ #define GMETA_MASK 0x00F0 // The "button transition" mask
+ #define GMETA_NONE 0x0000 // No "button transition" events
+ #define GMETA_MOUSE_DOWN 0x0001 // Left mouse/touch has just gone down
+ #define GMETA_MOUSE_UP 0x0002 // Left mouse/touch has just gone up
+ #define GMETA_MOUSE_CLICK 0x0004 // Left mouse/touch has just gone through a click (short down - up cycle)
+ #define GMETA_MOUSE_CXTCLICK 0x0008 // Right mouse has just been depressed or touch has gone through a long click
+
+ #define GINPUT_MISSED_MOUSE_EVENT 0x8000 // Oops - a mouse event has previously been missed
+
GDisplay * display; // The display this mouse is currently associated with.
- } GEventMouse;
+} GEventMouse;
// Mouse/Touch Listen Flags - passed to geventAddSourceToListener()
#define GLISTEN_MOUSEMETA 0x0001 // Create events for meta events such as CLICK and CXTCLICK
@@ -68,12 +66,13 @@ typedef struct GEventMouse_t {
#define GLISTEN_TOUCHUPMOVES GLISTEN_MOUSEUPMOVES
#define GLISTEN_TOUCHNOFILTER GLISTEN_MOUSENOFILTER
-#define GINPUT_MOUSE_NUM_PORTS 1 // The total number of mouse/touch inputs supported
-
// Event types for the mouse ginput source
#define GEVENT_MOUSE (GEVENT_GINPUT_FIRST+0)
#define GEVENT_TOUCH (GEVENT_GINPUT_FIRST+1)
+// All mice
+#define GMOUSE_ALL_INSTANCES ((unsigned)-1)
+
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
@@ -83,16 +82,32 @@ extern "C" {
#endif
/**
- * @brief Creates an instance of a mouse and returns the Source handler
- * @note HACK: if the instance is 9999, it is treated as instance 0 except
- * that no calibration will be performed!
+ * @brief Get the Source handler for a mouse using the instance number
+ *
+ * @param[in] instance The mouse instance number
*
- * @param[in] instance The ID of the mouse input instance (from 0 to 9999)
+ * @return The source handle of the mouse or NULL
+ * @note You can use the special value of GMOUSE_ALL_INSTANCES to
+ * get a source handle that returns events for all mice rather
+ * than a specific mouse. Using GMOUSE_ALL_INSTANCES will always
+ * return a valid spurce handle even if there are currently no mice
+ * in the system.
+ */
+ GSourceHandle ginputGetMouse(unsigned instance);
+
+ /**
+ * @brief Should this device be in Pen mode or Finger mode
+ * @note A touch device (and even theoritically a mouse) can operate
+ * in either pen or finger mode. In finger mode typically a
+ * touch device will be far more tolerant of movement and other
+ * inaccuracies. Each driver specifies its own tolerances for
+ * pen versus finger mode.
*
- * @return The source handle of the created instance
+ * @param[in] instance The ID of the mouse input instance
+ * @param[in] on If true then finger mode is turned on.
*/
- GSourceHandle ginputGetMouse(uint16_t instance);
-
+ void ginputSetFingerMode(unsigned instance, bool_t on);
+
/**
* @brief Assign the display associated with the mouse
* @note This only needs to be called if the mouse is associated with a display
@@ -104,7 +119,7 @@ extern "C" {
* @param[in] instance The ID of the mouse input instance
* @param[in] g The GDisplay to which this mouse belongs
*/
- void ginputSetMouseDisplay(uint16_t instance, GDisplay *g);
+ void ginputSetMouseDisplay(unsigned instance, GDisplay *g);
/**
* @brief Get the display currently associated with the mouse
@@ -112,7 +127,7 @@ extern "C" {
*
* @param[in] instance The ID of the mouse input instance
*/
- GDisplay *ginputGetMouseDisplay(uint16_t instance);
+ GDisplay *ginputGetMouseDisplay(unsigned instance);
/**
* @brief Get the current mouse position and button status
@@ -124,7 +139,7 @@ extern "C" {
*
* @return FALSE on an error (eg. invalid instance)
*/
- bool_t ginputGetMouseStatus(uint16_t instance, GEventMouse *pmouse);
+ bool_t ginputGetMouseStatus(unsigned instance, GEventMouse *pmouse);
/**
* @brief Performs a calibration
@@ -133,42 +148,37 @@ extern "C" {
*
* @return FALSE if the driver dosen't support a calibration of if the handle is invalid
*/
- bool_t ginputCalibrateMouse(uint16_t instance);
-
- /* Set the routines to save and fetch calibration data.
- * This function should be called before first calling ginputGetMouse() for a particular instance
- * as the gdispGetMouse() routine may attempt to fetch calibration data and perform a startup calibration if there is no way to get it.
- * If this is called after gdispGetMouse() has been called and the driver requires calibration storage, it will immediately save the data is has already obtained.
- * The 'requireFree' parameter indicates if the fetch buffer must be free()'d to deallocate the buffer provided by the Fetch routine.
- */
- typedef void (*GMouseCalibrationSaveRoutine)(uint16_t instance, const uint8_t *calbuf, size_t sz); // Save calibration data
- typedef const char * (*GMouseCalibrationLoadRoutine)(uint16_t instance); // Load calibration data (returns NULL if not data saved)
-
- /**
- * @brief Set the routines to store and restore calibration data
+ bool_t ginputCalibrateMouse(unsigned instance);
+
+ /**
+ * @brief Load a set of mouse calibration data
+ * @return A pointer to the data or NULL on failure
+ *
+ * @param[in] instance The mouse input instance number
+ * @param[in] sz The size in bytes of the data to retrieve.
*
- * @details This function should be called before first calling ginputGetMouse() for a particular instance
- * as the gdispGetMouse() routine may attempt to fetch calibration data and perform a startup calibration if there is no way to get it.
- * If this is called after gdispGetMouse() has been called and the driver requires calibration storage, it will immediately save the
- * data is has already obtained.
+ * @note This routine is provided by the user application. It is only
+ * called if GINPUT_TOUCH_USER_CALIBRATION_LOAD has been set to TRUE in the
+ * users gfxconf.h file.
+ * @note If GINPUT_TOUCH_USER_CALIBRATION_FREE has been set to TRUE in the users
+ * gfxconf.h file then the buffer returned will be free'd using gfxFree().
+ */
+ void *LoadMouseCalibration(unsigned instance, size_t sz);
+
+ /**
+ * @brief Save a set of mouse calibration data
+ * @return TRUE if the save operation was successful.
+ *
+ * @param[in] instance The mouse input instance number
+ * @param[in] data The data to save
+ * @param[in] sz The size in bytes of the data to retrieve.
*
- * @param[in] instance The ID of the mouse input instance
- * @param[in] fnsave The routine to save the data
- * @param[in] fnload The routine to restore the data
- * @param[in] requireFree TRUE if the buffer returned by the load function must be freed by the mouse code.
- */
- void ginputSetMouseCalibrationRoutines(uint16_t instance, GMouseCalibrationSaveRoutine fnsave, GMouseCalibrationLoadRoutine fnload, bool_t requireFree);
+ * @note This routine is provided by the user application. It is only
+ * called if GINPUT_TOUCH_USER_CALIBRATION_SAVE has been set to TRUE in the
+ * users gfxconf.h file.
+ */
+ bool_t SaveMouseCalibration(unsigned instance, const void *data, size_t sz);
- /**
- * @brief Test if a particular mouse/touch instance requires routines to save it's alibration data
- * @note Not implemented yet
- *
- * @param[in] instance The ID of the mouse input instance
- *
- * @return TRUE if needed
- */
- bool_t ginputRequireMouseCalibrationStorage(uint16_t instance);
-
#ifdef __cplusplus
}
#endif
diff --git a/src/ginput/sys_options.h b/src/ginput/sys_options.h
index 7ccc7b78..e67a03ce 100644
--- a/src/ginput/sys_options.h
+++ b/src/ginput/sys_options.h
@@ -73,41 +73,97 @@
* @{
*/
/**
- * @brief Turn off touch mouse support.
+ * @brief Start touch devices without loading or running calibration.
* @details Defaults to FALSE
- * @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.
+ * @note This is used if you want to manually control the initial calibration
+ * process. In practice this is only useful for a touch driver test program.
*/
- #ifndef GINPUT_TOUCH_NOTOUCH
- #define GINPUT_TOUCH_NOTOUCH FALSE
+ #ifndef GINPUT_TOUCH_STARTRAW
+ #define GINPUT_TOUCH_STARTRAW FALSE
+ #endif
+ /**
+ * @brief Turn off the touch calibration GUI.
+ * @details Defaults to FALSE
+ * @note Turning off the calibration GUI just turns off the manual calibration
+ * process. Readings may still be calibrated if calibration data
+ * can be loaded.
+ * @note Calibration requires a lot of code. If your device doesn't require it
+ * using this option can save a lot of space.
+ */
+ #ifndef GINPUT_TOUCH_NOCALIBRATE_GUI
+ #define GINPUT_TOUCH_NOCALIBRATE_GUI FALSE
#endif
/**
- * @brief Turn off calibration support.
+ * @brief Turn off all touch calibration support.
* @details Defaults to FALSE
- * @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.
+ * @note With this set to TRUE touch readings will not be calibrated.
+ * @note This automatically turns off the calibration GUI too!
+ * @note Calibration requires a lot of code. If your device doesn't require it
+ * using this option can save a lot of space.
*/
#ifndef GINPUT_TOUCH_NOCALIBRATE
#define GINPUT_TOUCH_NOCALIBRATE FALSE
#endif
/**
+ * @brief Turn off all touch support.
+ * @details Defaults to FALSE
+ * @note This automatically turns off all calibration and the calibration GUI too!
+ * @note Touch device handling requires a lot of code. If your device doesn't require it
+ * using this option can save a lot of space.
+ */
+ #ifndef GINPUT_TOUCH_NOTOUCH
+ #define GINPUT_TOUCH_NOTOUCH FALSE
+ #endif
+ /**
* @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.
+ * but increases CPU usage.
*/
#ifndef GINPUT_MOUSE_POLL_PERIOD
#define GINPUT_MOUSE_POLL_PERIOD 25
#endif
/**
- * @brief Milliseconds separating a CLICK from a CXTCLICK.
+ * @brief Maximum length of CLICK in milliseconds
+ * @details Defaults to 300 millseconds
+ * @note Mouse down to Mouse up times greater than this are not clicks.
+ */
+ #ifndef GINPUT_MOUSE_CLICK_TIME
+ #define GINPUT_MOUSE_CLICK_TIME 300
+ #endif
+ /**
+ * @brief Milliseconds to generate a CXTCLICK on a touch device.
* @details Defaults to 700 millseconds
- * @note How long it takes for a click to turn into a CXTCLICK on a touch device.
+ * @note If you hold the touch down for longer than this a CXTCLICK is generated
+ * but only on a touch device.
*/
- #ifndef GINPUT_TOUCH_CLICK_TIME
- #define GINPUT_TOUCH_CLICK_TIME 700
+ #ifndef GINPUT_TOUCH_CXTCLICK_TIME
+ #define GINPUT_TOUCH_CXTCLICK_TIME 700
+ #endif
+ /**
+ * @brief There is a user supplied routine to load mouse calibration data
+ * @details Defaults to FALSE
+ * @note If TRUE the user must supply the @p LoadMouseCalibration() routine.
+ */
+ #ifndef GINPUT_TOUCH_USER_CALIBRATION_LOAD
+ #define GINPUT_TOUCH_USER_CALIBRATION_LOAD FALSE
+ #endif
+ /**
+ * @brief The buffer returned by the users @p LoadMouseCalibration() routine must be gfxFree()'d
+ * by the mouse code.
+ * @details Defaults to FALSE
+ */
+ #ifndef GINPUT_TOUCH_USER_CALIBRATION_FREE
+ #define GINPUT_TOUCH_USER_CALIBRATION_FREE FALSE
+ #endif
+ /**
+ * @brief There is a user supplied routine to save mouse calibration data
+ * @details Defaults to FALSE
+ * @note If TRUE the user must supply the @p SaveMouseCalibration() routine.
+ */
+ #ifndef GINPUT_TOUCH_USER_CALIBRATION_SAVE
+ #define GINPUT_TOUCH_USER_CALIBRATION_SAVE FALSE
#endif
/** @} */
diff --git a/src/ginput/sys_rules.h b/src/ginput/sys_rules.h
index f98cc469..d9a367ce 100644
--- a/src/ginput/sys_rules.h
+++ b/src/ginput/sys_rules.h
@@ -31,6 +31,21 @@
#undef GFX_USE_GTIMER
#define GFX_USE_GTIMER TRUE
#endif
+ #if GINPUT_NEED_MOUSE
+ #if GINPUT_TOUCH_NOTOUCH
+ // No warning needed for this
+ #undef GINPUT_TOUCH_NOCALIBRATE
+ #define GINPUT_TOUCH_NOCALIBRATE TRUE
+ #endif
+ #if GINPUT_TOUCH_NOCALIBRATE
+ // No warning needed for this
+ #undef GINPUT_TOUCH_NOCALIBRATE_GUI
+ #define GINPUT_TOUCH_NOCALIBRATE_GUI TRUE
+ #endif
+ #if !GINPUT_TOUCH_NOTOUCH && GINPUT_MOUSE_CLICK_TIME > GINPUT_TOUCH_CXTCLICK_TIME
+ #error "GINPUT MOUSE: The GINPUT_MOUSE_CLICK_TIME must be <= GINPUT_TOUCH_CXTCLICK_TIME"
+ #endif
+ #endif
#endif
#endif /* _GINPUT_RULES_H */
diff --git a/src/gwin/gwin_widget.c b/src/gwin/gwin_widget.c
index f85e6f20..cf1f59c7 100644
--- a/src/gwin/gwin_widget.c
+++ b/src/gwin/gwin_widget.c
@@ -114,7 +114,7 @@ static void gwidgetEvent(void *param, GEvent *pe) {
// Is the mouse currently captured by this widget?
if ((h->flags & (GWIN_FLG_WIDGET|GWIN_FLG_MOUSECAPTURE)) == (GWIN_FLG_WIDGET|GWIN_FLG_MOUSECAPTURE)) {
gh = h;
- if ((pme->last_buttons & ~pme->current_buttons & GINPUT_MOUSE_BTN_LEFT)) {
+ if ((pme->buttons & GMETA_MOUSE_UP)) {
gh->flags &= ~GWIN_FLG_MOUSECAPTURE;
if (wvmt->MouseUp)
wvmt->MouseUp(gw, pme->x - gh->x, pme->y - gh->y);
@@ -133,7 +133,7 @@ static void gwidgetEvent(void *param, GEvent *pe) {
// Process any mouse down over the highest order window if it is an enabled widget
if (gh && (gh->flags & (GWIN_FLG_WIDGET|GWIN_FLG_SYSENABLED)) == (GWIN_FLG_WIDGET|GWIN_FLG_SYSENABLED)) {
- if ((~pme->last_buttons & pme->current_buttons & GINPUT_MOUSE_BTN_LEFT)) {
+ if ((pme->buttons & GMETA_MOUSE_DOWN)) {
gh->flags |= GWIN_FLG_MOUSECAPTURE;
if (wvmt->MouseDown)
wvmt->MouseDown(gw, pme->x - gh->x, pme->y - gh->y);
@@ -234,6 +234,7 @@ void _gwidgetInit(void)
{
geventListenerInit(&gl);
geventRegisterCallback(&gl, gwidgetEvent, 0);
+ geventAttachSource(&gl, ginputGetMouse(GMOUSE_ALL_INSTANCES), GLISTEN_MOUSEMETA|GLISTEN_MOUSEDOWNMOVES);
}
void _gwidgetDeinit(void)
@@ -427,13 +428,10 @@ bool_t gwinAttachListener(GListener *pl) {
}
#if GFX_USE_GINPUT && GINPUT_NEED_MOUSE
- bool_t gwinAttachMouse(uint16_t instance) {
- GSourceHandle gsh;
-
- if (!(gsh = ginputGetMouse(instance)))
- return FALSE;
-
- return geventAttachSource(&gl, gsh, GLISTEN_MOUSEMETA|GLISTEN_MOUSEDOWNMOVES);
+ bool_t DEPRECATED("This call can now be removed. Attaching the mouse to GWIN is now automatic.") gwinAttachMouse(uint16_t instance) {
+ // This is now a NULL event because we automatically attach to all mice in the system.
+ (void) instance;
+ return TRUE;
}
#endif
diff --git a/src/gwin/gwin_widget.h b/src/gwin/gwin_widget.h
index 81c76263..2c503116 100644
--- a/src/gwin/gwin_widget.h
+++ b/src/gwin/gwin_widget.h
@@ -199,7 +199,7 @@ void gwinSetDefaultStyle(const GWidgetStyle *pstyle, bool_t updateAll);
* @brief Get the current default style.
*
* @return The current default style.
- *
+ *
* @api
*/
const GWidgetStyle *gwinGetDefaultStyle(void);
@@ -315,7 +315,7 @@ bool_t gwinAttachListener(GListener *pl);
*
* @api
*/
- bool_t gwinAttachMouse(uint16_t instance);
+ bool_t DEPRECATED("This call can now be removed. Attaching the mouse to GWIN is now automatic.") gwinAttachMouse(uint16_t instance);
#endif
#if (GFX_USE_GINPUT && GINPUT_NEED_TOGGLE) || defined(__DOXYGEN__)