diff options
-rw-r--r-- | demos/modules/gwin/button/main.c | 5 | ||||
-rw-r--r-- | demos/modules/gwin/checkbox/main.c | 7 | ||||
-rw-r--r-- | demos/modules/gwin/container/main.c | 5 | ||||
-rw-r--r-- | demos/modules/gwin/container_nested/main.c | 11 | ||||
-rw-r--r-- | demos/modules/gwin/frame/main.c | 7 | ||||
-rw-r--r-- | demos/modules/gwin/label/main.c | 3 | ||||
-rw-r--r-- | demos/modules/gwin/list/main.c | 3 | ||||
-rw-r--r-- | demos/modules/gwin/radio/main.c | 3 | ||||
-rw-r--r-- | demos/modules/gwin/slider/main.c | 3 | ||||
-rw-r--r-- | demos/modules/gwin/widgets/main.c | 5 | ||||
-rw-r--r-- | docs/releases.txt | 7 | ||||
-rw-r--r-- | drivers/multiple/Win32/gdisp_lld_Win32.c | 133 | ||||
-rw-r--r-- | drivers/multiple/X/gdisp_lld_X.c | 132 | ||||
-rw-r--r-- | gfxconf.example.h | 10 | ||||
-rw-r--r-- | src/ginput/driver_mouse.h | 205 | ||||
-rw-r--r-- | src/ginput/ginput_ginput.c | 14 | ||||
-rw-r--r-- | src/ginput/ginput_mouse.c | 1226 | ||||
-rw-r--r-- | src/ginput/ginput_mouse.h | 151 | ||||
-rw-r--r-- | src/ginput/sys_options.h | 99 | ||||
-rw-r--r-- | src/ginput/sys_rules.h | 15 | ||||
-rw-r--r-- | src/gwin/gwin_widget.c | 16 | ||||
-rw-r--r-- | src/gwin/gwin_widget.h | 4 |
22 files changed, 1166 insertions, 898 deletions
diff --git a/demos/modules/gwin/button/main.c b/demos/modules/gwin/button/main.c index 15e8e5a7..1d8aa2e6 100644 --- a/demos/modules/gwin/button/main.c +++ b/demos/modules/gwin/button/main.c @@ -39,7 +39,7 @@ static void createWidgets(void) { gwinWidgetClearInit(&wi); wi.g.show = TRUE; - // Apply the button parameters + // Apply the button parameters wi.g.width = 100; wi.g.height = 30; wi.g.y = 10; @@ -67,9 +67,6 @@ int main(void) { gwinSetDefaultStyle(&WhiteWidgetStyle, FALSE); gdispClear(White); - // Attach the mouse input - gwinAttachMouse(0); - // create the widget createWidgets(); diff --git a/demos/modules/gwin/checkbox/main.c b/demos/modules/gwin/checkbox/main.c index 28122bee..22963e40 100644 --- a/demos/modules/gwin/checkbox/main.c +++ b/demos/modules/gwin/checkbox/main.c @@ -39,14 +39,14 @@ static void createWidgets(void) { gwinWidgetClearInit(&wi); wi.g.show = TRUE; - // Apply the checkbox parameters + // Apply the checkbox parameters wi.g.width = 100; // includes text wi.g.height = 20; wi.g.y = 10; wi.g.x = 10; wi.text = "Checkbox"; - // Create the actual checkbox + // Create the actual checkbox ghCheckbox1 = gwinCheckboxCreate(0, &wi); } @@ -61,9 +61,6 @@ int main(void) { gwinSetDefaultStyle(&WhiteWidgetStyle, FALSE); gdispClear(White); - // Attach the mouse input - gwinAttachMouse(0); - // create the widget createWidgets(); diff --git a/demos/modules/gwin/container/main.c b/demos/modules/gwin/container/main.c index 4e73b0c4..75e3f78b 100644 --- a/demos/modules/gwin/container/main.c +++ b/demos/modules/gwin/container/main.c @@ -19,7 +19,7 @@ static void createWidgets(void) { ghContainer = gwinContainerCreate(0, &wi, GWIN_CONTAINER_BORDER); wi.g.show = TRUE; - // Apply the button parameters + // Apply the button parameters wi.g.width = 120; wi.g.height = 30; wi.g.y = 10; @@ -37,9 +37,6 @@ int main(void) { // Initialize the display gfxInit(); - // Attach the mouse input - gwinAttachMouse(0); - // Set the widget defaults gwinSetDefaultFont(gdispOpenFont("*")); gwinSetDefaultStyle(&WhiteWidgetStyle, FALSE); diff --git a/demos/modules/gwin/container_nested/main.c b/demos/modules/gwin/container_nested/main.c index 2d90f76b..5cd5e793 100644 --- a/demos/modules/gwin/container_nested/main.c +++ b/demos/modules/gwin/container_nested/main.c @@ -40,7 +40,7 @@ static void createWidgets(void) { wi.text = "Container 3"; ghContainer3 = gwinContainerCreate(0, &wi, GWIN_CONTAINER_BORDER); - // Button 1 + // Button 1 wi.g.width = 80; wi.g.height = 20; wi.g.y = 10; @@ -49,7 +49,7 @@ static void createWidgets(void) { wi.g.parent = ghContainer2; ghButton1 = gwinButtonCreate(0, &wi); - // Button 2 + // Button 2 wi.g.width = 80; wi.g.height = 20; wi.g.y = 40; @@ -58,7 +58,7 @@ static void createWidgets(void) { wi.g.parent = ghContainer2; ghButton2 = gwinButtonCreate(0, &wi); - // Button 3 + // Button 3 wi.g.width = 80; wi.g.height = 20; wi.g.y = 10; @@ -67,7 +67,7 @@ static void createWidgets(void) { wi.g.parent = ghContainer3; ghButton3 = gwinButtonCreate(0, &wi); - // Button 4 + // Button 4 wi.g.width = 80; wi.g.height = 20; wi.g.y = 40; @@ -115,9 +115,6 @@ int main(void) { // Initialize the display gfxInit(); - // Attach the mouse input - gwinAttachMouse(0); - // Set the widget defaults gwinSetDefaultFont(gdispOpenFont("*")); gwinSetDefaultStyle(&WhiteWidgetStyle, FALSE); diff --git a/demos/modules/gwin/frame/main.c b/demos/modules/gwin/frame/main.c index fe956925..a97525ab 100644 --- a/demos/modules/gwin/frame/main.c +++ b/demos/modules/gwin/frame/main.c @@ -33,7 +33,7 @@ static void _createWidgets(void) { wi.text = "Surprise!"; gwinLabelCreate(0, &wi); - // Apply the frame parameters + // Apply the frame parameters wi.g.width = 300; wi.g.height = 200; wi.g.y = 10; @@ -107,7 +107,7 @@ static void _createWidgets(void) { wi.g.x = 10; wi.g.y = 90; ghWindow1 = gwinWindowCreate(0, &wi.g); - + _updateColor(); } @@ -117,9 +117,6 @@ int main(void) { // Initialize the display gfxInit(); - // Attach the mouse input - gwinAttachMouse(0); - // Set the widget defaults gwinSetDefaultFont(gdispOpenFont("*")); gwinSetDefaultStyle(&WhiteWidgetStyle, FALSE); diff --git a/demos/modules/gwin/label/main.c b/demos/modules/gwin/label/main.c index aab9cd76..425436ea 100644 --- a/demos/modules/gwin/label/main.c +++ b/demos/modules/gwin/label/main.c @@ -63,9 +63,6 @@ int main(void) { gwinSetDefaultStyle(&WhiteWidgetStyle, FALSE); gdispClear(White); - // Attach the mouse input - gwinAttachMouse(0); - // create the widget createWidgets(); diff --git a/demos/modules/gwin/list/main.c b/demos/modules/gwin/list/main.c index ed5b6905..0102f276 100644 --- a/demos/modules/gwin/list/main.c +++ b/demos/modules/gwin/list/main.c @@ -79,9 +79,6 @@ int main(void) { gwinSetDefaultStyle(&WhiteWidgetStyle, FALSE); gdispClear(White); - // Attach the mouse input - gwinAttachMouse(0); - // create the widget createWidgets(); diff --git a/demos/modules/gwin/radio/main.c b/demos/modules/gwin/radio/main.c index 7455c770..59b86983 100644 --- a/demos/modules/gwin/radio/main.c +++ b/demos/modules/gwin/radio/main.c @@ -83,9 +83,6 @@ int main(void) { gwinSetDefaultStyle(&WhiteWidgetStyle, FALSE); gdispClear(White); - // Attach the mouse input - gwinAttachMouse(0); - // create the widget createWidgets(); diff --git a/demos/modules/gwin/slider/main.c b/demos/modules/gwin/slider/main.c index ddcd90df..bf0aacfc 100644 --- a/demos/modules/gwin/slider/main.c +++ b/demos/modules/gwin/slider/main.c @@ -59,9 +59,6 @@ int main(void) { gwinSetDefaultStyle(&WhiteWidgetStyle, FALSE); gdispClear(White); - // Attach the mouse input - gwinAttachMouse(0); - // create the widget createWidgets(); diff --git a/demos/modules/gwin/widgets/main.c b/demos/modules/gwin/widgets/main.c index 3239ab4c..d2f6882b 100644 --- a/demos/modules/gwin/widgets/main.c +++ b/demos/modules/gwin/widgets/main.c @@ -418,11 +418,6 @@ int main(void) { // Initialize the display gfxInit(); - // Connect the mouse - #if GINPUT_NEED_MOUSE - gwinAttachMouse(0); - #endif - // Set the widget defaults font = gdispOpenFont("*"); // Get the first defined font. gwinSetDefaultFont(font); diff --git a/docs/releases.txt b/docs/releases.txt index adf7ca12..aa01972b 100644 --- a/docs/releases.txt +++ b/docs/releases.txt @@ -31,11 +31,14 @@ FIX: Improve memory usage for the GWIN Frame widget. FEATURE: Added transparent custom draws for GWIN containers and frame widgets FEATURE: Added image custom draws for GWIN containers and frame widgets FEATURE: Added GDRIVER infrastructure. Ported GDISP to use it. +FEATURE: Ported GINPUT MOUSE to GDRIVER infrastructure. +FEATURE: Mouse/Touch now support both pen and finger mode. +DEPRECATE: gwinAttachMouse() is now handled automaticly. *** Release 2.1 *** FIX: Significant improvements to the way the MCU touch driver works. -FEATURE: Add support for edge to edge touch calibration. +FEATURE: Add support for edge to edge touch calibration. FEATURE: Added progressbar widget FEATURE: Added gdispGDrawThickLine() by user jpa- DEPRECATE: TDISP module removed @@ -78,7 +81,7 @@ FEATURE: GDISP Streaming API and demos. DEPRECATE: GDISP_NEED_ASYNC is now deprecated. DEPRECATE: 3rd party boing demo is now deprecated (replaced by GDISP Streaming demo) FIX: Remove GOS definitions from demo conf files so that it can be supplied by a makefile. -FEATURE: Repair GDISP low level driver interfaces so they can now be included in the doxygen documentation. +FEATURE: Repair GDISP low level driver interfaces so they can now be included in the doxygen documentation. FEATURE: New driver interface for GDISP FEATURE: Multiple display support FEATURE: Multiple controller support diff --git a/drivers/multiple/Win32/gdisp_lld_Win32.c b/drivers/multiple/Win32/gdisp_lld_Win32.c index 3643d727..875c7ad1 100644 --- a/drivers/multiple/Win32/gdisp_lld_Win32.c +++ b/drivers/multiple/Win32/gdisp_lld_Win32.c @@ -10,7 +10,7 @@ #if GFX_USE_GDISP #define GDISP_DRIVER_VMT GDISPVMT_Win32 -#include "drivers/multiple/Win32/gdisp_lld_config.h" +#include "gdisp_lld_config.h" #include "src/gdisp/driver.h" #ifndef GDISP_SCREEN_WIDTH @@ -52,7 +52,6 @@ #define GDISP_FLG_READY (GDISP_FLG_DRIVER<<0) #define GDISP_FLG_HASTOGGLE (GDISP_FLG_DRIVER<<1) -#define GDISP_FLG_HASMOUSE (GDISP_FLG_DRIVER<<2) #if GDISP_HARDWARE_STREAM_WRITE || GDISP_HARDWARE_STREAM_READ #define GDISP_FLG_WSTREAM (GDISP_FLG_DRIVER<<3) #define GDISP_FLG_WRAPPED (GDISP_FLG_DRIVER<<4) @@ -64,16 +63,50 @@ #endif #if GINPUT_NEED_MOUSE - /* Include mouse support code */ + // Include mouse support code + #define GMOUSE_DRIVER_VMT GMOUSEVMT_Win32 #include "src/ginput/driver_mouse.h" + + // Forward definitions + static bool_t Win32MouseInit(GMouse *m, unsigned driverinstance); + static void Win32MouseRead(GMouse *m, GMouseReading *prd); + + const GMouseVMT const GMOUSE_DRIVER_VMT[1] = {{ + { + GDRIVER_TYPE_MOUSE, + GMOUSE_VFLG_NOPOLL|GMOUSE_VFLG_DYNAMICONLY, + // Extra flags for testing only + //GMOUSE_VFLG_TOUCH|GMOUSE_VFLG_SELFROTATION|GMOUSE_VFLG_DEFAULTFINGER + //GMOUSE_VFLG_CALIBRATE|GMOUSE_VFLG_CAL_EXTREMES|GMOUSE_VFLG_CAL_TEST|GMOUSE_VFLG_CAL_LOADFREE + //GMOUSE_VFLG_ONLY_DOWN|GMOUSE_VFLG_POORUPDOWN + sizeof(GMouse), + _gmouseInitDriver, _gmousePostInitDriver, _gmouseDeInitDriver + }, + 1, // z_max + 0, // z_min + 1, // z_touchon + 0, // z_touchoff + { // pen_jitter + 0, // calibrate + 0, // click + 0 // move + }, + { // finger_jitter + 0, // calibrate + 2, // click + 2 // move + }, + Win32MouseInit, // init + 0, // deinit + Win32MouseRead, // get + 0, // calsave + 0 // calload + }}; #endif static DWORD winThreadId; static volatile bool_t QReady; static HANDLE drawMutex; -#if GINPUT_NEED_MOUSE - static GDisplay * mouseDisplay; -#endif /*===========================================================================*/ /* Driver local routines . */ @@ -95,6 +128,7 @@ typedef struct winPriv { #if GINPUT_NEED_MOUSE coord_t mousex, mousey; uint16_t mousebuttons; + GMouse *mouse; #endif #if GINPUT_NEED_TOGGLE uint8_t toggles; @@ -149,7 +183,7 @@ static LRESULT myWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) // Handle mouse down on the window #if GINPUT_NEED_MOUSE - if ((coord_t)HIWORD(lParam) < GDISP_SCREEN_HEIGHT && (g->flags & GDISP_FLG_HASMOUSE)) { + if ((coord_t)HIWORD(lParam) < GDISP_SCREEN_HEIGHT) { priv->mousebuttons |= GINPUT_MOUSE_BTN_LEFT; goto mousemove; } @@ -198,7 +232,7 @@ static LRESULT myWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) // Handle mouse up on the window #if GINPUT_NEED_MOUSE - if ((coord_t)HIWORD(lParam) < GDISP_SCREEN_HEIGHT && (g->flags & GDISP_FLG_HASMOUSE)) { + if ((coord_t)HIWORD(lParam) < GDISP_SCREEN_HEIGHT) { priv->mousebuttons &= ~GINPUT_MOUSE_BTN_LEFT; goto mousemove; } @@ -210,7 +244,7 @@ static LRESULT myWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) case WM_MBUTTONDOWN: g = (GDisplay *)GetWindowLongPtr(hWnd, GWLP_USERDATA); priv = (winPriv *)g->priv; - if ((coord_t)HIWORD(lParam) < GDISP_SCREEN_HEIGHT && (g->flags & GDISP_FLG_HASMOUSE)) { + if ((coord_t)HIWORD(lParam) < GDISP_SCREEN_HEIGHT) { priv->mousebuttons |= GINPUT_MOUSE_BTN_MIDDLE; goto mousemove; } @@ -218,7 +252,7 @@ static LRESULT myWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) case WM_MBUTTONUP: g = (GDisplay *)GetWindowLongPtr(hWnd, GWLP_USERDATA); priv = (winPriv *)g->priv; - if ((coord_t)HIWORD(lParam) < GDISP_SCREEN_HEIGHT && (g->flags & GDISP_FLG_HASMOUSE)) { + if ((coord_t)HIWORD(lParam) < GDISP_SCREEN_HEIGHT) { priv->mousebuttons &= ~GINPUT_MOUSE_BTN_MIDDLE; goto mousemove; } @@ -226,7 +260,7 @@ static LRESULT myWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) case WM_RBUTTONDOWN: g = (GDisplay *)GetWindowLongPtr(hWnd, GWLP_USERDATA); priv = (winPriv *)g->priv; - if ((coord_t)HIWORD(lParam) < GDISP_SCREEN_HEIGHT && (g->flags & GDISP_FLG_HASMOUSE)) { + if ((coord_t)HIWORD(lParam) < GDISP_SCREEN_HEIGHT) { priv->mousebuttons |= GINPUT_MOUSE_BTN_RIGHT; goto mousemove; } @@ -234,7 +268,7 @@ static LRESULT myWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) case WM_RBUTTONUP: g = (GDisplay *)GetWindowLongPtr(hWnd, GWLP_USERDATA); priv = (winPriv *)g->priv; - if ((coord_t)HIWORD(lParam) < GDISP_SCREEN_HEIGHT && (g->flags & GDISP_FLG_HASMOUSE)) { + if ((coord_t)HIWORD(lParam) < GDISP_SCREEN_HEIGHT) { priv->mousebuttons &= ~GINPUT_MOUSE_BTN_RIGHT; goto mousemove; } @@ -242,14 +276,13 @@ static LRESULT myWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) case WM_MOUSEMOVE: g = (GDisplay *)GetWindowLongPtr(hWnd, GWLP_USERDATA); priv = (winPriv *)g->priv; - if ((coord_t)HIWORD(lParam) >= GDISP_SCREEN_HEIGHT || !(g->flags & GDISP_FLG_HASMOUSE)) + if ((coord_t)HIWORD(lParam) >= GDISP_SCREEN_HEIGHT) break; mousemove: priv->mousex = (coord_t)LOWORD(lParam); priv->mousey = (coord_t)HIWORD(lParam); - #if GINPUT_MOUSE_POLL_PERIOD == TIME_INFINITE - ginputMouseWakeup(); - #endif + if ((gmvmt(priv->mouse)->d.flags & GMOUSE_VFLG_NOPOLL)) // For normal setup this is always TRUE + _gmouseWakeup(priv->mouse); break; #endif @@ -445,14 +478,6 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { g->flags |= GDISP_FLG_HASTOGGLE; #endif - // Only turn on mouse on the first window for now - #if GINPUT_NEED_MOUSE - if (!g->controllerdisplay) { - mouseDisplay = g; - g->flags |= GDISP_FLG_HASMOUSE; - } - #endif - // Create a private area for this window priv = gfxAlloc(sizeof(winPriv)); assert(priv != 0); @@ -476,6 +501,11 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { ShowWindow(priv->hwnd, SW_SHOW); UpdateWindow(priv->hwnd); + // Create the associated mouse + #if GINPUT_NEED_MOUSE + priv->mouse = (GMouse *)gdriverRegister((const GDriverVMT const *)GMOUSE_DRIVER_VMT, g); + #endif + return TRUE; } @@ -686,10 +716,10 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { winPriv * priv; int x, y; COLORREF color; - + priv = g->priv; color = gdispColor2Native(g->p.color); - + #if GDISP_NEED_CONTROL switch(g->g.Orientation) { case GDISP_ROTATE_0: @@ -818,7 +848,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { sz = (size_t)g->p.cx * (size_t)g->p.cy; if (!(dstbuf = (pixel_t *)malloc(sz * sizeof(pixel_t)))) return 0; - + // Copy the bits we need switch(g->g.Orientation) { case GDISP_ROTATE_0: @@ -847,7 +877,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { return dstbuf; } #endif - + #if GDISP_HARDWARE_BITFILLS #if COLOR_SYSTEM != GDISP_COLORSYSTEM_TRUECOLOR || COLOR_TYPE_BITS <= 8 #error "GDISP Win32: This driver's bitblit currently only supports true-color with bit depths > 8 bits." @@ -863,7 +893,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { priv = g->priv; buffer = g->p.ptr; buffer += g->p.x2*g->p.y1; - + memset(&bmpInfo, 0, sizeof(bmpInfo)); bmpInfo.bV4Size = sizeof(bmpInfo); bmpInfo.bV4Planes = 1; @@ -982,7 +1012,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { color = GetPixel(priv->dcBuffer, g->p.x, g->p.y); #endif ReleaseMutex(drawMutex); - + return gdispNative2Color(color); } #endif @@ -992,7 +1022,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { winPriv * priv; RECT rect; coord_t lines; - + priv = g->priv; #if GDISP_NEED_CONTROL @@ -1134,18 +1164,49 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { #endif #if GINPUT_NEED_MOUSE - void ginput_lld_mouse_init(void) {} - void ginput_lld_mouse_get_reading(MouseReading *pt) { + static bool_t Win32MouseInit(GMouse *m, unsigned driverinstance) { + (void) m; + (void) driverinstance; + return TRUE; + } + static void Win32MouseRead(GMouse *m, GMouseReading *pt) { GDisplay * g; winPriv * priv; - g = mouseDisplay; + g = m->display; priv = g->priv; pt->x = priv->mousex; - pt->y = priv->mousey > g->g.Height ? g->g.Height : priv->mousey; - pt->z = (priv->mousebuttons & GINPUT_MOUSE_BTN_LEFT) ? 100 : 0; + pt->y = priv->mousey; + pt->z = (priv->mousebuttons & GINPUT_MOUSE_BTN_LEFT) ? 1 : 0; pt->buttons = priv->mousebuttons; + + #if GDISP_NEED_CONTROL + // If the self-rotation has been set in the VMT then do that here (TESTING ONLY) + if ((gmvmt(m)->d.flags & GMOUSE_VFLG_SELFROTATION)) { // For normal setup this is always False + coord_t t; + + switch(gdispGGetOrientation(m->display)) { + case GDISP_ROTATE_0: + default: + break; + case GDISP_ROTATE_90: + t = pt->x; + pt->x = g->g.Width - 1 - pt->y; + pt->y = t; + break; + case GDISP_ROTATE_180: + pt->x = g->g.Width - 1 - pt->x; + pt->y = g->g.Height - 1 - pt->y; + break; + case GDISP_ROTATE_270: + t = pt->y; + pt->y = g->g.Height - 1 - pt->x; + pt->x = t; + break; + } + } + #endif } #endif /* GINPUT_NEED_MOUSE */ diff --git a/drivers/multiple/X/gdisp_lld_X.c b/drivers/multiple/X/gdisp_lld_X.c index 00b2748b..0462d0d6 100644 --- a/drivers/multiple/X/gdisp_lld_X.c +++ b/drivers/multiple/X/gdisp_lld_X.c @@ -10,10 +10,10 @@ #if GFX_USE_GDISP #define GDISP_DRIVER_VMT GDISPVMT_X11 -#include "drivers/multiple/X/gdisp_lld_config.h" +#include "gdisp_lld_config.h" #include "src/gdisp/driver.h" -#ifndef GDISP_FORCE_24BIT +#ifndef GDISP_FORCE_24BIT #define GDISP_FORCE_24BIT FALSE #endif @@ -27,8 +27,45 @@ #define GDISP_FLG_READY (GDISP_FLG_DRIVER<<0) #if GINPUT_NEED_MOUSE - /* Include mouse support code */ + // Include mouse support code + #define GMOUSE_DRIVER_VMT GMOUSEVMT_X11 #include "src/ginput/driver_mouse.h" + + // Forward definitions + static bool_t XMouseInit(GMouse *m, unsigned driverinstance); + static void XMouseRead(GMouse *m, GMouseReading *prd); + + const GMouseVMT const GMOUSE_DRIVER_VMT[1] = {{ + { + GDRIVER_TYPE_MOUSE, + GMOUSE_VFLG_NOPOLL|GMOUSE_VFLG_DYNAMICONLY, + // Extra flags for testing only + //GMOUSE_VFLG_TOUCH|GMOUSE_VFLG_SELFROTATION|GMOUSE_VFLG_DEFAULTFINGER + //GMOUSE_VFLG_CALIBRATE|GMOUSE_VFLG_CAL_EXTREMES|GMOUSE_VFLG_CAL_TEST|GMOUSE_VFLG_CAL_LOADFREE + //GMOUSE_VFLG_ONLY_DOWN|GMOUSE_VFLG_POORUPDOWN + sizeof(GMouse), + _gmouseInitDriver, _gmousePostInitDriver, _gmouseDeInitDriver + }, + 1, // z_max + 0, // z_min + 1, // z_touchon + 0, // z_touchoff + { // pen_jitter + 0, // calibrate + 0, // click + 0 // move + }, + { // finger_jitter + 0, // calibrate + 2, // click + 2 // move + }, + XMouseInit, // init + 0, // deinit + XMouseRead, // get + 0, // calsave + 0 // calload + }}; #endif #include <X11/Xlib.h> @@ -44,15 +81,16 @@ static XEvent evt; static Colormap cmap; static XVisualInfo vis; static XContext cxt; -#if GINPUT_NEED_MOUSE - static coord_t mousex, mousey; - static uint16_t mousebuttons; -#endif typedef struct xPriv { Pixmap pix; GC gc; Window win; + #if GINPUT_NEED_MOUSE + coord_t mousex, mousey; + uint16_t buttons; + GMouse * mouse; + #endif } xPriv; static void ProcessEvent(GDisplay *g, xPriv *priv) { @@ -68,42 +106,36 @@ static void ProcessEvent(GDisplay *g, xPriv *priv) { case Expose: XCopyArea(dis, priv->pix, evt.xexpose.window, priv->gc, evt.xexpose.x, evt.xexpose.y, - evt.xexpose.width, evt.xexpose.height, + evt.xexpose.width, evt.xexpose.height, evt.xexpose.x, evt.xexpose.y); break; #if GINPUT_NEED_MOUSE case ButtonPress: - mousex = evt.xbutton.x; - mousey = evt.xbutton.y; + priv->mousex = evt.xbutton.x; + priv->mousey = evt.xbutton.y; switch(evt.xbutton.button){ - case 1: mousebuttons |= GINPUT_MOUSE_BTN_LEFT; break; - case 2: mousebuttons |= GINPUT_MOUSE_BTN_MIDDLE; break; - case 3: mousebuttons |= GINPUT_MOUSE_BTN_RIGHT; break; - case 4: mousebuttons |= GINPUT_MOUSE_BTN_4; break; + case 1: priv->buttons |= GINPUT_MOUSE_BTN_LEFT; break; + case 2: priv->buttons |= GINPUT_MOUSE_BTN_MIDDLE; break; + case 3: priv->buttons |= GINPUT_MOUSE_BTN_RIGHT; break; + case 4: priv->buttons |= GINPUT_MOUSE_BTN_4; break; } - #if GINPUT_MOUSE_POLL_PERIOD == TIME_INFINITE - ginputMouseWakeup(); - #endif + _gmouseWakeup(priv->mouse); break; case ButtonRelease: - mousex = evt.xbutton.x; - mousey = evt.xbutton.y; + priv->mousex = evt.xbutton.x; + priv->mousey = evt.xbutton.y; switch(evt.xbutton.button){ - case 1: mousebuttons &= ~GINPUT_MOUSE_BTN_LEFT; break; - case 2: mousebuttons &= ~GINPUT_MOUSE_BTN_MIDDLE; break; - case 3: mousebuttons &= ~GINPUT_MOUSE_BTN_RIGHT; break; - case 4: mousebuttons &= ~GINPUT_MOUSE_BTN_4; break; + case 1: priv->buttons &= ~GINPUT_MOUSE_BTN_LEFT; break; + case 2: priv->buttons &= ~GINPUT_MOUSE_BTN_MIDDLE; break; + case 3: priv->buttons &= ~GINPUT_MOUSE_BTN_RIGHT; break; + case 4: priv->buttons &= ~GINPUT_MOUSE_BTN_4; break; } - #if GINPUT_MOUSE_POLL_PERIOD == TIME_INFINITE - ginputMouseWakeup(); - #endif + _gmouseWakeup(priv->mouse); break; case MotionNotify: - mousex = evt.xmotion.x; - mousey = evt.xmotion.y; - #if GINPUT_MOUSE_POLL_PERIOD == TIME_INFINITE - ginputMouseWakeup(); - #endif + priv->mousex = evt.xmotion.x; + priv->mousey = evt.xmotion.y; + _gmouseWakeup(priv->mouse); break; #endif } @@ -125,7 +157,7 @@ static DECLARE_THREAD_FUNCTION(ThreadX, arg) { } return 0; } - + static int FatalXIOError(Display *d) { (void) d; @@ -187,13 +219,13 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { xa.colormap = cmap; xa.border_pixel = 0xFFFFFF; xa.background_pixel = 0x000000; - + priv->win = XCreateWindow(dis, RootWindow(dis, scr), 16, 16, GDISP_SCREEN_WIDTH, GDISP_SCREEN_HEIGHT, 0, vis.depth, InputOutput, vis.visual, CWBackPixel|CWColormap|CWBorderPixel, &xa); XSync(dis, TRUE); - + XSaveContext(dis, priv->win, cxt, (XPointer)g); { @@ -205,7 +237,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { XSetWMIconName(dis, priv->win, &WindowTitle); XSync(dis, TRUE); } - + pSH = XAllocSizeHints(); pSH->flags = PSize | PMinSize | PMaxSize; pSH->min_width = pSH->max_width = pSH->base_width = GDISP_SCREEN_WIDTH; @@ -213,7 +245,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { XSetWMNormalHints(dis, priv->win, pSH); XFree(pSH); XSync(dis, TRUE); - + priv->pix = XCreatePixmap(dis, priv->win, GDISP_SCREEN_WIDTH, GDISP_SCREEN_HEIGHT, vis.depth); XSync(dis, TRUE); @@ -236,6 +268,12 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { g->g.Contrast = 50; g->g.Width = GDISP_SCREEN_WIDTH; g->g.Height = GDISP_SCREEN_HEIGHT; + + // Create the associated mouse + #if GINPUT_NEED_MOUSE + priv->mouse = (GMouse *)gdriverRegister((const GDriverVMT const *)GMOUSE_DRIVER_VMT, g); + #endif + return TRUE; } @@ -312,16 +350,20 @@ LLDSPEC void gdisp_lld_draw_pixel(GDisplay *g) #endif #if GINPUT_NEED_MOUSE - - void ginput_lld_mouse_init(void) {} - - void ginput_lld_mouse_get_reading(MouseReading *pt) { - pt->x = mousex; - pt->y = mousey; - pt->z = (mousebuttons & GINPUT_MOUSE_BTN_LEFT) ? 100 : 0; - pt->buttons = mousebuttons; + static bool_t XMouseInit(GMouse *m, unsigned driverinstance) { + (void) m; + (void) driverinstance; + return TRUE; + } + static void XMouseRead(GMouse *m, GMouseReading *pt) { + xPriv * priv; + + priv = m->display->priv; + pt->x = priv->mousex; + pt->y = priv->mousey; + pt->z = (priv->buttons & GINPUT_MOUSE_BTN_LEFT) ? 1 : 0; + pt->buttons = priv->buttons; } - #endif /* GINPUT_NEED_MOUSE */ #endif /* GFX_USE_GDISP */ diff --git a/gfxconf.example.h b/gfxconf.example.h index 7ac48591..0ff436ca 100644 --- a/gfxconf.example.h +++ b/gfxconf.example.h @@ -210,6 +210,16 @@ //#define GFX_USE_GINPUT FALSE //#define GINPUT_NEED_MOUSE FALSE +// #define GINPUT_TOUCH_STARTRAW FALSE +// #define GINPUT_TOUCH_NOTOUCH FALSE +// #define GINPUT_TOUCH_NOCALIBRATE FALSE +// #define GINPUT_TOUCH_NOCALIBRATE_GUI FALSE +// #define GINPUT_MOUSE_POLL_PERIOD 25 +// #define GINPUT_MOUSE_CLICK_TIME 300 +// #define GINPUT_TOUCH_CXTCLICK_TIME 700 +// #define GINPUT_TOUCH_USER_CALIBRATION_LOAD FALSE +// #define GINPUT_TOUCH_USER_CALIBRATION_FREE FALSE +// #define GINPUT_TOUCH_USER_CALIBRATION_SAVE FALSE //#define GINPUT_NEED_KEYBOARD FALSE //#define GINPUT_NEED_TOGGLE FALSE //#define GINPUT_NEED_DIAL FALSE diff --git a/src/ginput/driver_mouse.h b/src/ginput/driver_mouse.h index 21d87dac..76367ba2 100644 --- a/src/ginput/driver_mouse.h +++ b/src/ginput/driver_mouse.h @@ -19,160 +19,131 @@ #if GINPUT_NEED_MOUSE || defined(__DOXYGEN__) -#include "ginput_lld_mouse_config.h" +// Include the GDRIVER infrastructure +#include "src/gdriver/sys_defs.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 - -// ms - Millisecs seperating a CLICK from a CXTCLICK -#ifndef GINPUT_MOUSE_CLICK_TIME - #define GINPUT_MOUSE_CLICK_TIME 700 -#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 MouseReading_t { +typedef struct GMouseReading { coord_t x, y, z; uint16_t buttons; - } MouseReading; + } GMouseReading; + +#if !GINPUT_TOUCH_NOCALIBRATE + typedef struct GMouseCalibration { + float ax; + float bx; + float cx; + float ay; + float by; + float cy; + } GMouseCalibration; +#endif + +typedef struct GMouse { + GDriver d; // The driver overheads and vmt + GMouseReading r; // The current position and state + uint16_t flags; // Flags + #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 + GMouseCalibration caldata; // The calibration data + #endif + // Other driver specific fields may follow. +} GMouse; + +typedef struct GMouseJitter { + 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 +} GMouseJitter; + +typedef struct GMouseVMT { + GDriverVMT d; // Device flags are part of the general vmt + #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_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 + coord_t z_touchoff; // TOUCH: z values between z_min and this are a solid touch off + + GMouseJitter pen_jitter; // PEN MODE: Jitter settings + GMouseJitter finger_jitter; // FINGER MODE: Jitter settings + + 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, size_t sz); // Optional: Can return NULL if no data is saved. +} GMouseVMT; + +#define gmvmt(m) ((const GMouseVMT const *)((m)->d.vmt)) /*===========================================================================*/ /* 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 Initialise the mouse/touch. + * @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 + * @{ */ - void ginput_lld_mouse_init(void); - - /** - * @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. - * - * @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 + bool_t _gmouseInitDriver(GDriver *g, void *display, 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 - * @note Particularly useful if GINPUT_MOUSE_POLL_PERIOD = TIME_INFINITE * * @notapi */ - void ginputMouseWakeup(void); + void _gmouseWakeup(GMouse *m); /** * @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 */ - void ginputMouseWakeupI(void); + void _gmouseWakeupI(GMouse *m); #ifdef __cplusplus } #endif -#endif /* GINPUT_NEED_MOUSE || GINPUT_NEED_TOUCH */ +#endif /* GINPUT_NEED_MOUSE */ #endif /* _LLD_GINPUT_MOUSE_H */ /** @} */ diff --git a/src/ginput/ginput_ginput.c b/src/ginput/ginput_ginput.c index 4197fa25..191ae025 100644 --- a/src/ginput/ginput_ginput.c +++ b/src/ginput/ginput_ginput.c @@ -16,10 +16,16 @@ #if GFX_USE_GINPUT +#if GINPUT_NEED_MOUSE + extern void _gmouseInit(void); + extern void _gmouseDeinit(void); +#endif + void _ginputInit(void) { - /* ToDo */ - + #if GINPUT_NEED_MOUSE + _gmouseInit(); + #endif /** * This should really call an init routine for each ginput sub-system. * Maybe we'll do this later. @@ -28,7 +34,9 @@ void _ginputInit(void) void _ginputDeinit(void) { - + #if GINPUT_NEED_MOUSE + _gmouseDeinit(); + #endif } #endif /* GFX_USE_GINPUT */ diff --git a/src/ginput/ginput_mouse.c b/src/ginput/ginput_mouse.c index a0daba98..ee6555b2 100644 --- a/src/ginput/ginput_mouse.c +++ b/src/ginput/ginput_mouse.c @@ -8,670 +8,796 @@ /** * @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 + +// Just to make code easier +#if !GFX_USE_GDISP + #define GDISP 0 +#endif +// 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" -#if GINPUT_MOUSE_NEED_CALIBRATION - #if !defined(GFX_USE_GDISP) || !GFX_USE_GDISP - #error "GINPUT: GFX_USE_GDISP must be defined when mouse or touch calibration is required" +// The mouse poll timer +static GTIMER_DECL(MouseTimer); + +// Calibration application +#if !GINPUT_TOUCH_NOCALIBRATE + #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 + +static void SendMouseEvent(GSourceListener *psl, GMouse *m, GMouseReading *r) { + GEventMouse *pe; + + // 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; + } + + // 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; - #define GINPUT_MOUSE_CALIBRATION_FONT "* Double" - #define GINPUT_MOUSE_CALIBRATION_FONT2 "* Narrow" - #define GINPUT_MOUSE_CALIBRATION_TEXT "Calibration" - #define GINPUT_MOUSE_CALIBRATION_ERROR_TEXT "Failed - Please try again!" - #define GINPUT_MOUSE_CALIBRATION_SAME_TEXT "Error: Same Reading - Check Driver!" + // 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_MOUSE_MAX_CALIBRATION_ERROR < 0 - #define GINPUT_MOUSE_CALIBRATION_POINTS 3 + #if !GINPUT_TOUCH_NOTOUCH + pe->type = (gmvmt(m)->d.flags & GMOUSE_VFLG_TOUCH) ? GEVENT_TOUCH : GEVENT_MOUSE; #else - #define GINPUT_MOUSE_CALIBRATION_POINTS 4 + 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); +} - typedef struct Calibration_t { - float ax; - float bx; - float cx; - float ay; - float by; - float cy; - } Calibration; -#endif +static void GetMouseReading(GMouse *m) { + GMouseReading r; + + // Step 1 - Get the Raw Reading + { + m->flags &= ~GMOUSE_FLG_NEEDREAD; + gmvmt(m)->get(m, &r); + } -typedef struct MousePoint_t { - coord_t x, y; -} MousePoint; + // 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 + } + } -static GTIMER_DECL(MouseTimer); + // 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; -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; + // Should we start a transition test + } else if (((r.buttons ^ m->r.buttons) & GINPUT_MOUSE_BTN_LEFT)) { + m->flags |= GMOUSE_FLG_INDELTA; + return; } - 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; + } + #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 + } + + // 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; } - 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; + // 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; -#if GINPUT_MOUSE_NEED_CALIBRATION - static inline void _tsSetIdentity(Calibration *c) { - c->ax = 1; - c->bx = 0; - c->cx = 0; - c->ay = 0; - c->by = 1; - c->cy = 0; + // 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 + } } - static inline void _tsDrawCross(const MousePoint *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); - gdispGDrawLine(MouseConfig.display, pp->x, pp->y+2, pp->x, pp->y+15, White); + // 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); - gdispGDrawLine(MouseConfig.display, pp->x-15, pp->y+15, pp->x-7, pp->y+15, RGB2COLOR(184,158,131)); - gdispGDrawLine(MouseConfig.display, pp->x-15, pp->y+7, pp->x-15, pp->y+15, RGB2COLOR(184,158,131)); + // Send to the mouse specific source listeners + psl = 0; + while ((psl = geventGetSourceListener((GSourceHandle)m, psl))) + SendMouseEvent(psl, m, &r); + } - gdispGDrawLine(MouseConfig.display, pp->x-15, pp->y-15, pp->x-7, pp->y-15, RGB2COLOR(184,158,131)); - gdispGDrawLine(MouseConfig.display, pp->x-15, pp->y-7, pp->x-15, pp->y-15, RGB2COLOR(184,158,131)); + // 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; +} - gdispGDrawLine(MouseConfig.display, pp->x+7, pp->y+15, pp->x+15, pp->y+15, RGB2COLOR(184,158,131)); - gdispGDrawLine(MouseConfig.display, pp->x+15, pp->y+7, pp->x+15, pp->y+15, RGB2COLOR(184,158,131)); +static void MousePoll(void *param) { + GMouse * m; + (void) param; - gdispGDrawLine(MouseConfig.display, pp->x+7, pp->y-15, pp->x+15, pp->y-15, RGB2COLOR(184,158,131)); - gdispGDrawLine(MouseConfig.display, pp->x+15, pp->y-15, pp->x+15, pp->y-7, RGB2COLOR(184,158,131)); + 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 _tsClearCross(const MousePoint *pp) { - gdispGFillArea(MouseConfig.display, pp->x - 15, pp->y - 15, 42, 42, Blue); + 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 _tsTransform(MouseReading *pt, const Calibration *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); + 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 _tsDo3PointCalibration(const MousePoint *cross, const MousePoint *points, GDisplay *g, Calibration *c) { + static inline void CalibrationCalculate(GMouse *m, const point *cross, const point *points) { float dx; coord_t c0, c1, c2; + (void) m; + + // Work on x values + c0 = cross[0].x; + c1 = cross[1].x; + c2 = cross[2].x; #if GDISP_NEED_CONTROL - /* Convert all cross points back to GDISP_ROTATE_0 convention - * before calculating the calibration matrix. - */ - switch(gdispGGetOrientation(g)) { - case GDISP_ROTATE_90: - c0 = cross[0].y; - c1 = cross[1].y; - c2 = cross[2].y; - break; - case GDISP_ROTATE_180: - c0 = c1 = c2 = gdispGGetWidth(g) - 1; - c0 -= cross[0].x; - c1 -= cross[1].x; - c2 -= cross[2].x; - break; - case GDISP_ROTATE_270: - c0 = c1 = c2 = gdispGGetHeight(g) - 1; - c0 -= cross[0].y; - c1 -= cross[1].y; - c2 -= cross[2].y; - break; - case GDISP_ROTATE_0: - default: - c0 = cross[0].x; - c1 = cross[1].x; - c2 = cross[2].x; - break; + if (!(gmvmt(m)->d.flags & GMOUSE_VFLG_SELFROTATION)) { + /* Convert all cross points back to GDISP_ROTATE_0 convention + * before calculating the calibration matrix. + */ + switch(gdispGGetOrientation(m->display)) { + case GDISP_ROTATE_90: + c0 = cross[0].y; + c1 = cross[1].y; + c2 = cross[2].y; + break; + case GDISP_ROTATE_180: + c0 = c1 = c2 = gdispGGetWidth(m->display) - 1; + c0 -= cross[0].x; + c1 -= cross[1].x; + c2 -= cross[2].x; + break; + case GDISP_ROTATE_270: + c0 = c1 = c2 = gdispGGetHeight(m->display) - 1; + c0 -= cross[0].y; + c1 -= cross[1].y; + c2 -= cross[2].y; + break; + default: + break; + } } - #else - (void) g; - - c0 = cross[0].x; - c1 = cross[1].x; - c2 = cross[2].x; #endif /* Compute all the required determinants */ dx = (float)(points[0].x - points[2].x) * (float)(points[1].y - points[2].y) - (float)(points[1].x - points[2].x) * (float)(points[0].y - points[2].y); - c->ax = ((float)(c0 - c2) * (float)(points[1].y - points[2].y) - - (float)(c1 - c2) * (float)(points[0].y - points[2].y)) / dx; - c->bx = ((float)(c1 - c2) * (float)(points[0].x - points[2].x) - - (float)(c0 - c2) * (float)(points[1].x - points[2].x)) / dx; - c->cx = (c0 * ((float)points[1].x * (float)points[2].y - (float)points[2].x * (float)points[1].y) - - 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; + m->caldata.ax = ((float)(c0 - c2) * (float)(points[1].y - points[2].y) + - (float)(c1 - c2) * (float)(points[0].y - points[2].y)) / dx; + m->caldata.bx = ((float)(c1 - c2) * (float)(points[0].x - points[2].x) + - (float)(c0 - c2) * (float)(points[1].x - points[2].x)) / dx; + m->caldata.cx = (c0 * ((float)points[1].x * (float)points[2].y - (float)points[2].x * (float)points[1].y) + - 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; + + // Work on y values + c0 = cross[0].y; + c1 = cross[1].y; + c2 = cross[2].y; #if GDISP_NEED_CONTROL - switch(gdispGGetOrientation(g)) { - case GDISP_ROTATE_90: - c0 = c1 = c2 = gdispGGetWidth(g) - 1; - c0 -= cross[0].x; - c1 -= cross[1].x; - c2 -= cross[2].x; - break; - case GDISP_ROTATE_180: - c0 = c1 = c2 = gdispGGetHeight(g) - 1; - c0 -= cross[0].y; - c1 -= cross[1].y; - c2 -= cross[2].y; - break; - case GDISP_ROTATE_270: - c0 = cross[0].x; - c1 = cross[1].x; - c2 = cross[2].x; - break; - case GDISP_ROTATE_0: - default: - c0 = cross[0].y; - c1 = cross[1].y; - c2 = cross[2].y; - break; + if (!(gmvmt(m)->d.flags & GMOUSE_VFLG_SELFROTATION)) { + switch(gdispGGetOrientation(m->display)) { + case GDISP_ROTATE_90: + c0 = c1 = c2 = gdispGGetWidth(m->display) - 1; + c0 -= cross[0].x; + c1 -= cross[1].x; + c2 -= cross[2].x; + break; + case GDISP_ROTATE_180: + c0 = c1 = c2 = gdispGGetHeight(m->display) - 1; + c0 -= cross[0].y; + c1 -= cross[1].y; + c2 -= cross[2].y; + break; + case GDISP_ROTATE_270: + c0 = cross[0].x; + c1 = cross[1].x; + c2 = cross[2].x; + break; + default: + break; + } } - #else - c0 = cross[0].y; - c1 = cross[1].y; - c2 = cross[2].y; #endif - c->ay = ((float)(c0 - c2) * (float)(points[1].y - points[2].y) - - (float)(c1 - c2) * (float)(points[0].y - points[2].y)) / dx; - c->by = ((float)(c1 - c2) * (float)(points[0].x - points[2].x) - - (float)(c0 - c2) * (float)(points[1].x - points[2].x)) / dx; - c->cy = (c0 * ((float)points[1].x * (float)points[2].y - (float)points[2].x * (float)points[1].y) - - 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; + m->caldata.ay = ((float)(c0 - c2) * (float)(points[1].y - points[2].y) + - (float)(c1 - c2) * (float)(points[0].y - points[2].y)) / dx; + m->caldata.by = ((float)(c1 - c2) * (float)(points[0].x - points[2].x) + - (float)(c0 - c2) * (float)(points[1].x - points[2].x)) / dx; + m->caldata.cy = (c0 * ((float)points[1].x * (float)points[2].y - (float)points[2].x * (float)points[1].y) + - 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 -#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 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; - /* 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; - } -#else - #define get_raw_reading(pt) ginput_lld_mouse_get_reading(pt) -#endif + 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 -static void get_calibrated_reading(MouseReading *pt) { - get_raw_reading(pt); + // 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); + } - #if GINPUT_MOUSE_NEED_CALIBRATION - _tsTransform(pt, &MouseConfig.caldata); - #endif + // 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; - _tsOrientClip(pt, MouseConfig.display, !(MouseConfig.flags & FLG_CAL_RAW)); -} - -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; - } + // Clear the current calibration point + CalibrationCrossClear(m, &cross[i]); + } - // 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; - } + // Apply 3 point calibration algorithm + CalibrationCalculate(m, cross, points); - // 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; - } + // Skip the 4th point tests if we don't want them + if (maxpoints < 4) + break; + } - // 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; - } - } + /* 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; + + // Are we in pen or finger mode + pj = (m->flags & GMOUSE_FLG_FINGERMODE) ? &gmvmt(m)->finger_jitter : &gmvmt(m)->pen_jitter; + + // Transform the co-ordinates + CalibrationTransform((GMouseReading *)&points[3], &m->caldata); + + // 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)(&MouseConfig), 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 (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; + // 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); } - pe->display = MouseConfig.display; - geventSendEvent(psl); } - } -} - -GSourceHandle ginputGetMouse(uint16_t instance) { - #if GINPUT_MOUSE_NEED_CALIBRATION - Calibration *pc; - #endif - // We only support a single mouse instance currently - // Instance 9999 is the same as instance 0 except that it installs - // a special "raw" calibration if there isn't one we can load. - if (instance && instance != 9999) - return 0; - - // Make sure we have a valid mouse display - if (!MouseConfig.display) - MouseConfig.display = GDISP; + // We are done calibrating + gdispCloseFont(font1); + gdispCloseFont(font2); + m->flags |= GMOUSE_FLG_CALIBRATE|GMOUSE_FLG_CLIP; + m->flags &= ~GMOUSE_FLG_IN_CAL; - // Do we need to initialise the mouse subsystem? - if (!(MouseConfig.flags & FLG_INIT_DONE)) { - ginput_lld_mouse_init(); + // Force an initial reading + m->r.buttons = 0; + GetMouseReading(m); - #if GINPUT_MOUSE_NEED_CALIBRATION - #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.fnloadcal && (pc = (Calibration *)MouseConfig.fnloadcal(instance))) { - memcpy(&MouseConfig.caldata, pc, sizeof(MouseConfig.caldata)); - MouseConfig.flags |= (FLG_CAL_OK|FLG_CAL_SAVED); - if ((MouseConfig.flags & FLG_CAL_FREE)) - gfxFree((void *)pc); - } else if (instance == 9999) { - _tsSetIdentity(&MouseConfig.caldata); - MouseConfig.flags |= (FLG_CAL_OK|FLG_CAL_SAVED|FLG_CAL_RAW); - } else - ginputCalibrateMouse(instance); + // 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)); - // Get the first reading - MouseConfig.last_buttons = 0; - get_calibrated_reading(&MouseConfig.t); - - // Mark init as done and start the Poll timer - MouseConfig.flags |= FLG_INIT_DONE; - gtimerStart(&MouseTimer, MousePoll, 0, TRUE, GINPUT_MOUSE_POLL_PERIOD); + // 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 - // Return our structure as the handle - return (GSourceHandle)&MouseConfig; -} +void _gmouseInit(void) { + // GINPUT_MOUSE_DRIVER_LIST is defined - create each driver instance + #if defined(GINPUT_MOUSE_DRIVER_LIST) + { + int i; -void ginputSetMouseDisplay(uint16_t instance, GDisplay *g) { - if (instance) - return; + extern GDriverVMTList GINPUT_MOUSE_DRIVER_LIST; + static const struct GDriverVMT const * dclist[] = {GINPUT_MOUSE_DRIVER_LIST}; - MouseConfig.display = g ? g : GDISP; -} + for(i = 0; i < sizeof(dclist)/sizeof(dclist[0]); i++) { + if (!(dclist[i]->flags & GMOUSE_VFLG_DYNAMICONLY)) + gdriverRegister(dclist[i], GDISP); + } + } -GDisplay *ginputGetMouseDisplay(uint16_t instance) { - if (instance) - return 0; + // One and only one mouse + #else + { + extern GDriverVMTList GMOUSEVMT_OnlyOne; + + if (!(GMOUSEVMT_OnlyOne->flags & GMOUSE_VFLG_DYNAMICONLY)) + gdriverRegister(GMOUSEVMT_OnlyOne, GDISP); + } + #endif - return MouseConfig.display; } -bool_t ginputGetMouseStatus(uint16_t instance, GEventMouse *pe) { - // 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); +void _gmouseDeinit(void) { + gtimerDeinit(&MouseTimer); +} - if (instance || (MouseConfig.flags & (FLG_INIT_DONE|FLG_IN_CAL)) != FLG_INIT_DONE) - return FALSE; +bool_t _gmouseInitDriver(GDriver *g, void *display, unsigned driverinstance, unsigned systeminstance) { + #define m ((GMouse *)g) + (void) systeminstance; - pe->type = GINPUT_MOUSE_EVENT_TYPE; - pe->instance = instance; - 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; - 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; -} + // The initial display is passed in the parameter for mice + m->display = display; -bool_t ginputCalibrateMouse(uint16_t instance) { - #if !GINPUT_MOUSE_NEED_CALIBRATION - (void) instance; - - return FALSE; - #else + #if !GINPUT_TOUCH_NOTOUCH + // Should this mouse start in finger mode? (according to the VMT) + if ((gmvmt(m)->d.flags & GMOUSE_VFLG_DEFAULTFINGER)) + m->flags |= GMOUSE_FLG_FINGERMODE; + #endif - 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[GINPUT_MOUSE_CALIBRATION_POINTS]; - 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 + // Init the mouse + if (!gmvmt(m)->init((GMouse *)g, driverinstance)) + return FALSE; - if (instance || (MouseConfig.flags & FLG_IN_CAL)) - return FALSE; + // Ensure the Poll timer is started + if (!gtimerIsActive(&MouseTimer)) + gtimerStart(&MouseTimer, MousePoll, 0, TRUE, GINPUT_MOUSE_POLL_PERIOD); - font1 = gdispOpenFont(GINPUT_MOUSE_CALIBRATION_FONT); - font2 = gdispOpenFont(GINPUT_MOUSE_CALIBRATION_FONT2); + return TRUE; - MouseConfig.flags |= FLG_IN_CAL; - gtimerStop(&MouseTimer); - MouseConfig.flags &= ~(FLG_CAL_OK|FLG_CAL_SAVED|FLG_CAL_RAW); + #undef m +} - #if GDISP_NEED_CLIP - gdispGSetClip(MouseConfig.display, 0, 0, width, height); - #endif +void _gmousePostInitDriver(GDriver *g) { + #define m ((GMouse *)g) + + #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 + } + #endif - #if GINPUT_MOUSE_MAX_CALIBRATION_ERROR >= 0 - while(1) { - #endif - gdispGClear(MouseConfig.display, Blue); + // Get the first reading + GetMouseReading(m); - gdispGFillStringBox(MouseConfig.display, 0, 5, width, 30, GINPUT_MOUSE_CALIBRATION_TEXT, font1, White, Blue, justifyCenter); + #undef m +} - for(i = 0, pt = points, pc = cross; i < GINPUT_MOUSE_CALIBRATION_POINTS; i++, pt++, pc++) { - _tsDrawCross(pc); +void _gmouseDeInitDriver(GDriver *g) { + (void) g; +} - do { +GSourceHandle ginputGetMouse(unsigned instance) { + if (instance == GMOUSE_ALL_INSTANCES) + return (GSourceHandle)&MouseTimer; + return (GSourceHandle)gdriverGetInstance(GDRIVER_TYPE_MOUSE, instance); +} - /* 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; - } +void ginputSetMouseDisplay(unsigned instance, GDisplay *g) { + GMouse *m; - } while(!j); + if (!(m = (GMouse *)gdriverGetInstance(GDRIVER_TYPE_MOUSE, instance))) + return; - pt->x = px / j; - pt->y = py / j; + m->display = g ? g : GDISP; +} - _tsClearCross(pc); +GDisplay *ginputGetMouseDisplay(unsigned instance) { + GMouse *m; - 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); - } + if (!(m = (GMouse *)gdriverGetInstance(GDRIVER_TYPE_MOUSE, instance))) + return 0; - } + return m->display; +} - /* Apply 3 point calibration algorithm */ - _tsDo3PointCalibration(cross, points, MouseConfig.display, &MouseConfig.caldata); +bool_t ginputGetMouseStatus(unsigned instance, GEventMouse *pe) { + GMouse *m; - /* 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; - _tsTransform(&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; + // 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); - gdispGFillStringBox(MouseConfig.display, 0, 35, width, 40, GINPUT_MOUSE_CALIBRATION_ERROR_TEXT, font2, Red, Yellow, justifyCenter); - gfxSleepMilliseconds(5000); - } - #endif + if (!(m = (GMouse *)gdriverGetInstance(GDRIVER_TYPE_MOUSE, instance))) + return FALSE; - // 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; - } + #if !GINPUT_TOUCH_NOCALIBRATE_GUI + if ((m->flags & GMOUSE_FLG_IN_CAL)) + return FALSE; + #endif - // 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 (!(m = (GMouse *)gdriverGetInstance(GDRIVER_TYPE_MOUSE, instance))) + return FALSE; - #if GINPUT_MOUSE_NEED_CALIBRATION && !GINPUT_MOUSE_LLD_CALIBRATION_LOADSAVE + 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(void) { +void _gmouseWakeup(GMouse *m) { + if (m) + m->flags |= GMOUSE_FLG_NEEDREAD; gtimerJab(&MouseTimer); } /* Wake up the mouse driver from an interrupt service routine (there may be new readings available) */ -void ginputMouseWakeupI(void) { +void _gmouseWakeupI(GMouse *m) { + if (m) + m->flags |= GMOUSE_FLG_NEEDREAD; gtimerJabI(&MouseTimer); } diff --git a/src/ginput/ginput_mouse.h b/src/ginput/ginput_mouse.h index 61ad35e0..3e9c017b 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,32 +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) - uint16_t instance; // The mouse/touch instance - 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 0x0010 // Left mouse/touch has just gone down + #define GMETA_MOUSE_UP 0x0020 // Left mouse/touch has just gone up + #define GMETA_MOUSE_CLICK 0x0040 // Left mouse/touch has just gone through a click (short down - up cycle) + #define GMETA_MOUSE_CXTCLICK 0x0080 // 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 @@ -69,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. */ /*===========================================================================*/ @@ -84,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 @@ -105,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 @@ -113,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 @@ -125,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 @@ -134,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 c606262b..e67a03ce 100644 --- a/src/ginput/sys_options.h +++ b/src/ginput/sys_options.h @@ -73,40 +73,97 @@ * @{ */ /** - * @brief Use a custom board definition for the mouse/touch driver even if a board definition exists. + * @brief Start touch devices without loading or running calibration. * @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 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_MOUSE_USE_CUSTOM_BOARD - #define GINPUT_MOUSE_USE_CUSTOM_BOARD FALSE + #ifndef GINPUT_TOUCH_STARTRAW + #define GINPUT_TOUCH_STARTRAW FALSE #endif - /** - * @brief Use a custom board definition for the keyboard driver even if a board definition exists. + /** + * @brief Turn off the touch calibration GUI. * @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 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_KEYBOARD_USE_CUSTOM_BOARD - #define GINPUT_KEYBOARD_USE_CUSTOM_BOARD FALSE + #ifndef GINPUT_TOUCH_NOCALIBRATE_GUI + #define GINPUT_TOUCH_NOCALIBRATE_GUI FALSE #endif /** - * @brief Use a custom board definition for the toggle driver even if a board definition exists. + * @brief Turn off all touch calibration support. * @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. + * @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_TOGGLE_USE_CUSTOM_BOARD - #define GINPUT_TOGGLE_USE_CUSTOM_BOARD FALSE + #ifndef GINPUT_TOUCH_NOCALIBRATE + #define GINPUT_TOUCH_NOCALIBRATE FALSE #endif /** - * @brief Use a custom board definition for the dial driver even if a board definition exists. + * @brief Turn off all touch support. * @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. + * @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_DIAL_USE_CUSTOM_BOARD - #define GINPUT_DIAL_USE_CUSTOM_BOARD FALSE + #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. + */ + #ifndef GINPUT_MOUSE_POLL_PERIOD + #define GINPUT_MOUSE_POLL_PERIOD 25 + #endif + + /** + * @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 If you hold the touch down for longer than this a CXTCLICK is generated + * but only on a touch device. + */ + #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__) |