From 99a9bf45e747f612ce2c2317a913f7d1fdf696f0 Mon Sep 17 00:00:00 2001 From: Andrew Hannam Date: Sun, 2 Dec 2012 16:43:28 +1000 Subject: [PATCH 1/6] Add support for interrupt driven Toggle Inputs --- include/lld/ginput/toggle.h | 42 ++++++++++++++++++++++++------------- src/ginput/toggle.c | 14 +++++++++---- 2 files changed, 38 insertions(+), 18 deletions(-) diff --git a/include/lld/ginput/toggle.h b/include/lld/ginput/toggle.h index 826ace83..72b097f0 100644 --- a/include/lld/ginput/toggle.h +++ b/include/lld/ginput/toggle.h @@ -30,22 +30,28 @@ #ifndef GFX_USE_GINPUT #define GFX_USE_GINPUT FALSE #endif - -#if GFX_USE_GINPUT || defined(__DOXYGEN__) - -#if GINPUT_NEED_TOGGLE - // Describes how the toggle bits are obtained - typedef struct GToggleConfig_t { - void *id; - unsigned mask; - unsigned invert; - iomode_t mode; - } GToggleConfig; +#ifndef GINPUT_NEED_TOGGLE + #define GINPUT_NEED_TOGGLE FALSE #endif +#if (GFX_USE_GINPUT && GINPUT_NEED_TOGGLE) || defined(__DOXYGEN__) + +// Describes how the toggle bits are obtained +typedef struct GToggleConfig_t { + void *id; + unsigned mask; + unsigned invert; + iomode_t mode; +} GToggleConfig; + // This must be included after the above type definition #include "ginput.h" +// n - Millisecs between poll's +#ifndef GINPUT_TOGGLE_POLL_PERIOD + #define GINPUT_TOGGLE_POLL_PERIOD 200 +#endif + /*===========================================================================*/ /* External declarations. */ /*===========================================================================*/ @@ -54,18 +60,26 @@ extern "C" { #endif -#if GINPUT_NEED_TOGGLE extern const GToggleConfig GInputToggleConfigTable[GINPUT_TOGGLE_CONFIG_ENTRIES]; void ginput_lld_toggle_init(const GToggleConfig *ptc); unsigned ginput_lld_toggle_getbits(const GToggleConfig *ptc); -#endif + + /* This routine is provided to low level drivers to wakeup a value read from a thread context. + * Particularly useful if GINPUT_TOGGLE_POLL_PERIOD = TIME_INFINITE + */ + void ginputToggleWakeup(void); + + /* This routine is provided to low level drivers to wakeup a value read from an ISR + * Particularly useful if GINPUT_TOGGLE_POLL_PERIOD = TIME_INFINITE + */ + void ginputToggleWakeupI(void); #ifdef __cplusplus } #endif -#endif /* GFX_USE_GINPUT */ +#endif /* GFX_USE_GINPUT && GINPUT_NEED_TOGGLE */ #endif /* _LLD_GINPUT_TOGGLE_H */ /** @} */ diff --git a/src/ginput/toggle.c b/src/ginput/toggle.c index a49ebfd3..890ac1dc 100644 --- a/src/ginput/toggle.c +++ b/src/ginput/toggle.c @@ -34,10 +34,6 @@ #include "lld/ginput/toggle.h" -#ifndef GINPUT_TOGGLE_POLL_PERIOD - #define GINPUT_TOGGLE_POLL_PERIOD 250 -#endif - #define GINPUT_TOGGLE_ISON 0x01 #define GINPUT_TOGGLE_INVERT 0x02 @@ -157,5 +153,15 @@ bool_t ginputGetToggleStatus(uint16_t instance, GEventToggle *ptoggle) { return TRUE; } +/* Wake up the mouse driver from an interrupt service routine (there may be new readings available) */ +void ginputToggleWakeup(void) { + gtimerJab(&ToggleTimer); +} + +/* Wake up the mouse driver from an interrupt service routine (there may be new readings available) */ +void ginputToggleWakeupI(void) { + gtimerJabI(&ToggleTimer); +} + #endif /* GINPUT_NEED_TOGGLE */ /** @} */ From d24aa689e9f08aab7db73b169db938b5b0e1e88e Mon Sep 17 00:00:00 2001 From: Andrew Hannam Date: Sun, 2 Dec 2012 16:46:13 +1000 Subject: [PATCH 2/6] Win32 Hardware Toggle Emulation Emulates 4 toggle switches and 4 momentary action buttons in the Win32 driver. These are represented as a row of buttons under the GDISP display window. These are implemented as GINPUT Toggle driver (not as GPIO pins). --- drivers/multiple/Win32/gdisp_lld.c | 231 +++++++++++++----- .../multiple/Win32/ginput_lld_toggle_config.h | 51 ++++ 2 files changed, 224 insertions(+), 58 deletions(-) create mode 100644 drivers/multiple/Win32/ginput_lld_toggle_config.h diff --git a/drivers/multiple/Win32/gdisp_lld.c b/drivers/multiple/Win32/gdisp_lld.c index 30cd3389..5a741038 100644 --- a/drivers/multiple/Win32/gdisp_lld.c +++ b/drivers/multiple/Win32/gdisp_lld.c @@ -32,12 +32,6 @@ #if GFX_USE_GDISP /*|| defined(__DOXYGEN__)*/ -/* Include mouse support code */ -#include "lld/ginput/mouse.h" - -/* Include the emulation code for things we don't support */ -#include "lld/gdisp/emulation.c" - #include #include #include @@ -45,11 +39,41 @@ #include #include +#ifndef GINPUT_NEED_TOGGLE + #define GINPUT_NEED_TOGGLE FALSE +#endif +#ifndef GINPUT_NEED_MOUSE + #define GINPUT_NEED_MOUSE FALSE +#endif + +#if GINPUT_NEED_TOGGLE + /* Include toggle support code */ + #include "lld/ginput/toggle.h" + + const GToggleConfig GInputToggleConfigTable[GINPUT_TOGGLE_CONFIG_ENTRIES] = { + {0, 0xFF, 0x00, PAL_MODE_INPUT}, + }; +#endif + +#if GINPUT_NEED_MOUSE + /* Include mouse support code */ + #include "ginput.h" + #include "lld/ginput/mouse.h" +#endif + +/* Include the emulation code for things we don't support */ +#include "lld/gdisp/emulation.c" + /*===========================================================================*/ /* Driver local routines . */ /*===========================================================================*/ #define WIN32_USE_MSG_REDRAW FALSE +#if GINPUT_NEED_TOGGLE + #define WIN32_BUTTON_AREA 16 +#else + #define WIN32_BUTTON_AREA 0 +#endif #define APP_NAME "GDISP" @@ -61,37 +85,104 @@ static HDC dcBuffer = NULL; static HBITMAP dcBitmap = NULL; static HBITMAP dcOldBitmap; static volatile bool_t isReady = FALSE; -static coord_t mousex, mousey; -static uint16_t mousebuttons; +static coord_t wWidth, wHeight; + +#if GINPUT_NEED_MOUSE + static coord_t mousex, mousey; + static uint16_t mousebuttons; +#endif +#if GINPUT_NEED_TOGGLE + static uint8_t toggles = 0; +#endif static LRESULT myWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { - HDC dc; - PAINTSTRUCT ps; + HDC dc; + PAINTSTRUCT ps; + #if GINPUT_NEED_TOGGLE + HBRUSH hbrOn, hbrOff; + HPEN pen; + RECT rect; + HGDIOBJ old; + POINT p; + coord_t pos; + uint8_t bit; + #endif switch (Msg) { case WM_CREATE: break; -#if GINPUT_NEED_MOUSE case WM_LBUTTONDOWN: - mousebuttons = 0x0001; - goto mousemove; + #if GINPUT_NEED_MOUSE + if ((coord_t)HIWORD(lParam) < wHeight) { + mousebuttons |= GINPUT_MOUSE_BTN_LEFT; + goto mousemove; + } + #endif + #if GINPUT_NEED_TOGGLE + bit = 1 << ((coord_t)LOWORD(lParam)*8/wWidth); + toggles ^= bit; + rect.left = 0; + rect.right = wWidth; + rect.top = wHeight; + rect.bottom = wHeight + WIN32_BUTTON_AREA; + InvalidateRect(hWnd, &rect, FALSE); + UpdateWindow(hWnd); + #if GINPUT_TOGGLE_POLL_PERIOD == TIME_INFINITE + ginputToggleWakeup(); + #endif + #endif + break; case WM_LBUTTONUP: - mousebuttons &= ~0x0001; - goto mousemove; + #if GINPUT_NEED_TOGGLE + if ((toggles & 0xF0)) { + toggles &= 0x0F; + rect.left = 0; + rect.right = wWidth; + rect.top = wHeight; + rect.bottom = wHeight + WIN32_BUTTON_AREA; + InvalidateRect(hWnd, &rect, FALSE); + UpdateWindow(hWnd); + #if GINPUT_TOGGLE_POLL_PERIOD == TIME_INFINITE + ginputToggleWakeup(); + #endif + } + #endif + #if GINPUT_NEED_MOUSE + if ((coord_t)HIWORD(lParam) < wHeight) { + mousebuttons &= ~GINPUT_MOUSE_BTN_LEFT; + goto mousemove; + } + #endif + break; +#if GINPUT_NEED_MOUSE case WM_MBUTTONDOWN: - mousebuttons = 0x0004; - goto mousemove; + if ((coord_t)HIWORD(lParam) < wHeight) { + mousebuttons |= GINPUT_MOUSE_BTN_MIDDLE; + goto mousemove; + } + break; case WM_MBUTTONUP: - mousebuttons &= ~0x0004; - goto mousemove; + if ((coord_t)HIWORD(lParam) < wHeight) { + mousebuttons &= ~GINPUT_MOUSE_BTN_MIDDLE; + goto mousemove; + } + break; case WM_RBUTTONDOWN: - mousebuttons = 0x0002; - goto mousemove; + if ((coord_t)HIWORD(lParam) < wHeight) { + mousebuttons |= GINPUT_MOUSE_BTN_RIGHT; + goto mousemove; + } + break; case WM_RBUTTONUP: - mousebuttons &= ~0x0002; - goto mousemove; + if ((coord_t)HIWORD(lParam) < wHeight) { + mousebuttons &= ~GINPUT_MOUSE_BTN_RIGHT; + goto mousemove; + } + break; case WM_MOUSEMOVE: + if ((coord_t)HIWORD(lParam) >= wHeight) + break; mousemove: mousex = (coord_t)LOWORD(lParam); mousey = (coord_t)HIWORD(lParam); @@ -114,8 +205,32 @@ static LRESULT myWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) dc = BeginPaint(hWnd, &ps); BitBlt(dc, ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right - ps.rcPaint.left, - ps.rcPaint.bottom - ps.rcPaint.top, + (ps.rcPaint.bottom > wHeight ? wHeight : ps.rcPaint.bottom) - ps.rcPaint.top, dcBuffer, ps.rcPaint.left, ps.rcPaint.top, SRCCOPY); + #if GINPUT_NEED_TOGGLE + if (ps.rcPaint.bottom >= wHeight) { + pen = CreatePen(PS_SOLID, 1, COLOR2BGR(Black)); + hbrOn = CreateSolidBrush(COLOR2BGR(Blue)); + hbrOff = CreateSolidBrush(COLOR2BGR(Gray)); + old = SelectObject(dc, pen); + MoveToEx(dc, 0, wHeight, &p); + LineTo(dc, wWidth, wHeight); + for(pos = 0, bit=1; pos < wWidth; pos=rect.right, bit <<= 1) { + rect.left = pos; + rect.right = pos + wWidth/8; + rect.top = wHeight; + rect.bottom = wHeight + WIN32_BUTTON_AREA; + FillRect(dc, &rect, (toggles & bit) ? hbrOn : hbrOff); + if (pos > 0) { + MoveToEx(dc, rect.left, rect.top, &p); + LineTo(dc, rect.left, rect.bottom); + } + } + DeleteObject(hbrOn); + DeleteObject(hbrOff); + SelectObject(dc, old); + } + #endif EndPaint(hWnd, &ps); break; case WM_DESTROY: @@ -154,8 +269,8 @@ static DWORD WINAPI WindowThread(LPVOID lpParameter) { wc.lpszClassName = APP_NAME; RegisterClass(&wc); - rect.top = 0; rect.bottom = GDISP.Height; - rect.left = 0; rect.right = GDISP.Width; + rect.top = 0; rect.bottom = wHeight+WIN32_BUTTON_AREA; + rect.left = 0; rect.right = wWidth; AdjustWindowRect(&rect, WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU, 0); winRootWindow = CreateWindow(APP_NAME, "", WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU, 0, 0, rect.right-rect.left, rect.bottom-rect.top, 0, 0, hInstance, NULL); @@ -163,11 +278,11 @@ static DWORD WINAPI WindowThread(LPVOID lpParameter) { GetClientRect(winRootWindow, &rect); - GDISP.Width = rect.right-rect.left; - GDISP.Height = rect.bottom - rect.top; + wWidth = rect.right-rect.left; + wHeight = rect.bottom - rect.top - WIN32_BUTTON_AREA; dc = GetDC(winRootWindow); - dcBitmap = CreateCompatibleBitmap(dc, GDISP.Width, GDISP.Height); + dcBitmap = CreateCompatibleBitmap(dc, wWidth, wHeight); dcBuffer = CreateCompatibleDC(dc); ReleaseDC(winRootWindow, dc); dcOldBitmap = SelectObject(dcBuffer, dcBitmap); @@ -205,12 +320,12 @@ bool_t GDISP_LLD(init)(void) { /* Set the window dimensions */ GetWindowRect(GetDesktopWindow(), &rect); - GDISP.Width = rect.right - rect.left; - GDISP.Height = rect.bottom - rect.top; - if (GDISP.Width > GDISP_SCREEN_WIDTH) - GDISP.Width = GDISP_SCREEN_WIDTH; - if (GDISP.Height > GDISP_SCREEN_HEIGHT) - GDISP.Height = GDISP_SCREEN_HEIGHT; + wWidth = rect.right - rect.left; + wHeight = rect.bottom - rect.top - WIN32_BUTTON_AREA; + if (wWidth > GDISP_SCREEN_WIDTH) + wWidth = GDISP_SCREEN_WIDTH; + if (wHeight > GDISP_SCREEN_HEIGHT) + wHeight = GDISP_SCREEN_HEIGHT; /* Initialise the window */ CreateThread(0, 0, WindowThread, 0, 0, 0); @@ -222,6 +337,8 @@ bool_t GDISP_LLD(init)(void) { GDISP.Powermode = powerOn; GDISP.Backlight = 100; GDISP.Contrast = 50; + GDISP.Width = wWidth; + GDISP.Height = wHeight; #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP GDISP.clipx0 = 0; GDISP.clipy0 = 0; @@ -841,33 +958,26 @@ void GDISP_LLD(drawpixel)(coord_t x, coord_t y, color_t color) { * @notapi */ void GDISP_LLD(control)(unsigned what, void *value) { - RECT rect; - switch(what) { case GDISP_CONTROL_ORIENTATION: if (GDISP.Orientation == (gdisp_orientation_t)value) return; - GetClientRect(winRootWindow, &rect); switch((gdisp_orientation_t)value) { case GDISP_ROTATE_0: - /* Code here */ - GDISP.Width = rect.right-rect.left; - GDISP.Height = rect.bottom - rect.top; + GDISP.Width = wWidth; + GDISP.Height = wHeight; break; case GDISP_ROTATE_90: - /* Code here */ - GDISP.Height = rect.right-rect.left; - GDISP.Width = rect.bottom - rect.top; + GDISP.Height = wWidth; + GDISP.Width = wHeight; break; case GDISP_ROTATE_180: - /* Code here */ - GDISP.Width = rect.right-rect.left; - GDISP.Height = rect.bottom - rect.top; + GDISP.Width = wWidth; + GDISP.Height = wHeight; break; case GDISP_ROTATE_270: - /* Code here */ - GDISP.Height = rect.right-rect.left; - GDISP.Width = rect.bottom - rect.top; + GDISP.Height = wWidth; + GDISP.Width = wHeight; break; default: return; @@ -892,16 +1002,21 @@ void GDISP_LLD(drawpixel)(coord_t x, coord_t y, color_t color) { #if GINPUT_NEED_MOUSE -#include "lld/ginput/mouse.h" + void ginput_lld_mouse_init(void) {} -void ginput_lld_mouse_init(void) {} + void ginput_lld_mouse_get_reading(MouseReading *pt) { + pt->x = mousex; + pt->y = mousey > wHeight ? wHeight : mousey; + pt->z = (mousebuttons & GINPUT_MOUSE_BTN_LEFT) ? 100 : 0; + pt->buttons = mousebuttons; + } -void ginput_lld_mouse_get_reading(MouseReading *pt) { - pt->x = mousex; - pt->y = mousey; - pt->z = (mousebuttons & 0x0001) ? 100 : 0; - pt->buttons = mousebuttons; // We auto-magicaly know that the mousebutton bits match the MouseReading bits. -} +#endif /* GINPUT_NEED_MOUSE */ + +#if GINPUT_NEED_TOGGLE + + void ginput_lld_toggle_init(const GToggleConfig *ptc) { (void) ptc; } + unsigned ginput_lld_toggle_getbits(const GToggleConfig *ptc) { (void) ptc; return toggles; } #endif /* GINPUT_NEED_MOUSE */ diff --git a/drivers/multiple/Win32/ginput_lld_toggle_config.h b/drivers/multiple/Win32/ginput_lld_toggle_config.h new file mode 100644 index 00000000..58e47260 --- /dev/null +++ b/drivers/multiple/Win32/ginput_lld_toggle_config.h @@ -0,0 +1,51 @@ +/* + ChibiOS/GFX - Copyright (C) 2012 + Joel Bodenmann aka Tectu + + This file is part of ChibiOS/GFX. + + ChibiOS/GFX is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS/GFX is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/** + * @file drivers/multiple/Win32/ginput_lld_toggle_config.h + * @brief GINPUT Toggle Driver configuration header. + * + * @addtogroup GINPUT_TOGGLE + * @{ + */ + +#ifndef _GINPUT_LLD_TOGGLE_CONFIG_H +#define _GINPUT_LLD_TOGGLE_CONFIG_H + +#if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE + +#define GINPUT_TOGGLE_POLL_PERIOD TIME_INFINITE // We are interrupt driven (or polled - ether works here) +#define GINPUT_TOGGLE_NUM_PORTS 8 // The total number of toggle inputs +#define GINPUT_TOGGLE_CONFIG_ENTRIES 1 // The total number of GToggleConfig entries + +#define GINPUT_TOGGLE_SW1 0 // Switch 1 - Toggle +#define GINPUT_TOGGLE_SW2 1 // Switch 2 - Toggle +#define GINPUT_TOGGLE_SW3 2 // Switch 3 - Toggle +#define GINPUT_TOGGLE_SW4 3 // Switch 4 - Toggle + +#define GINPUT_TOGGLE_MOMENTARY1 4 // Switch 5 - Momentary +#define GINPUT_TOGGLE_MOMENTARY2 5 // Switch 6 - Momentary +#define GINPUT_TOGGLE_MOMENTARY3 6 // Switch 7 - Momentary +#define GINPUT_TOGGLE_MOMENTARY4 7 // Switch 8 - Momentary + +#endif /* GFX_USE_GDISP && GINPUT_NEED_TOGGLE */ + +#endif /* _GINPUT_LLD_TOGGLE_CONFIG_H */ +/** @} */ From b819359442313689ab12fd6b381657096c143782 Mon Sep 17 00:00:00 2001 From: Andrew Hannam Date: Sun, 2 Dec 2012 16:46:39 +1000 Subject: [PATCH 3/6] Change Mouse Poll period default to a better value --- include/lld/ginput/mouse.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/lld/ginput/mouse.h b/include/lld/ginput/mouse.h index 64c7c5ec..423a6c3e 100644 --- a/include/lld/ginput/mouse.h +++ b/include/lld/ginput/mouse.h @@ -65,7 +65,7 @@ // n - Millisecs between poll's #ifndef GINPUT_MOUSE_POLL_PERIOD - #define GINPUT_MOUSE_POLL_PERIOD 100 + #define GINPUT_MOUSE_POLL_PERIOD 25 #endif // n - Movement allowed without discarding the CLICK or CLICKCXT event (+/- pixels) From 1394b41d48299ebcfbe11f085746dbe09ad20b27 Mon Sep 17 00:00:00 2001 From: Andrew Hannam Date: Sun, 2 Dec 2012 16:47:11 +1000 Subject: [PATCH 4/6] GWIN Button bug fix GWIN Buttons are now tested and working. --- src/gwin/button.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/gwin/button.c b/src/gwin/button.c index fce82a20..43c6d5d4 100644 --- a/src/gwin/button.c +++ b/src/gwin/button.c @@ -305,12 +305,8 @@ bool_t gwinAttachButtonSource(GHandle gh, GSourceHandle gsh, GEventType type) { switch (type) { #if defined(GINPUT_NEED_MOUSE) && GINPUT_NEED_MOUSE case GEVENT_MOUSE: - flags = 0; - break; - #endif - #if defined(GINPUT_NEED_TOUCH) && GINPUT_NEED_TOUCH case GEVENT_TOUCH: - flags = 0; + flags = GLISTEN_MOUSEMETA; break; #endif #if defined(GINPUT_NEED_TOGGLE) && GINPUT_NEED_TOGGLE From a2c192ffd0f28c2d992b18a77cee123924bbad65 Mon Sep 17 00:00:00 2001 From: Andrew Hannam Date: Sun, 2 Dec 2012 16:49:18 +1000 Subject: [PATCH 5/6] Use GWIN Button in Touch Calibrator Demo Added GWIN Buttons to allow Next, Previous capability in the Touch Calibration Demo. Note that until the calibration has occured these buttons do not appear as the touch is not yet accurate enough to drive them. --- demos/modules/ginput_touch_driver_test/main.c | 262 +++++++++++++----- 1 file changed, 191 insertions(+), 71 deletions(-) diff --git a/demos/modules/ginput_touch_driver_test/main.c b/demos/modules/ginput_touch_driver_test/main.c index d93978cf..8a31ec74 100644 --- a/demos/modules/ginput_touch_driver_test/main.c +++ b/demos/modules/ginput_touch_driver_test/main.c @@ -26,18 +26,22 @@ #include "gwin.h" static GConsoleObject gc; +static GButtonObject gNext; +static GButtonObject gPrev; static GListener gl; /*------------------------------------------------------------------------* * GINPUT Touch Driver Calibrator. * *------------------------------------------------------------------------*/ int main(void) { - GSourceHandle gs; + GSourceHandle gs, gsNext, gsPrev; + GEvent *pe; GEventMouse *pem; + GEventGWinButton *peb; coord_t swidth, sheight; - GHandle ghc; + GHandle ghc, ghNext, ghPrev; BaseSequentialStream *gp; - unsigned testnum; + GEventType deviceType; halInit(); // Initialise the Hardware chSysInit(); // Initialize the OS @@ -46,7 +50,7 @@ int main(void) { // Get the display dimensions swidth = gdispGetWidth(); sheight = gdispGetHeight(); - testnum = 0; + ghNext = ghPrev = 0; // Create our title gdispFillStringBox(0, 0, swidth, 20, "Touch Calibration", &fontUI2, Red, White, justifyCenter); @@ -65,52 +69,87 @@ int main(void) { * Test: Device Type */ +StepDeviceType: gwinClear(ghc); gwinSetColor(ghc, Yellow); - chprintf(gp, "\n%u. DEVICE TYPE\n\n", ++testnum); + chprintf(gp, "\n1. DEVICE TYPE\n\n"); pem = (GEventMouse *)&gl.event; ginputGetMouseStatus(0, pem); + deviceType = pem->type; gwinSetColor(ghc, White); chprintf(gp, "This is detected as a %s device\n\n", - pem->type == GEVENT_MOUSE ? "MOUSE" : (pem->type == GEVENT_TOUCH ? "TOUCH" : "UNKNOWN")); + deviceType == GEVENT_MOUSE ? "MOUSE" : (pem->type == GEVENT_TOUCH ? "TOUCH" : "UNKNOWN")); - chprintf(gp, "Press and release your finger (or mouse button) to move on to the next test.\n"); + if (ghNext) + chprintf(gp, "Press Next or Back to continue.\n"); + else if (deviceType == GEVENT_MOUSE) + chprintf(gp, "Click the mouse button to move on to the next test.\n"); + else + chprintf(gp, "Press and release your finger to move on to the next test.\n"); - do { - pem = (GEventMouse *)geventEventWait(&gl, TIME_INFINITE); - if (pem->type != GEVENT_MOUSE && pem->type != GEVENT_TOUCH) // Safety Check - continue; - - } while (!(pem->meta & GMETA_MOUSE_UP)); + while(1) { + pe = geventEventWait(&gl, TIME_INFINITE); + if (pe->type == GEVENT_GWIN_BUTTON) { + peb = (GEventGWinButton *)pe; + if (peb->button == ghPrev) + goto StepClickJitter; + if (peb->button == ghNext) + break; + } + if (pe->type == GEVENT_MOUSE || pe->type == GEVENT_TOUCH) { + pem = (GEventMouse *)pe; + if (!ghNext && (pem->meta & GMETA_MOUSE_UP)) + break; + } + } /* * Test: Mouse raw reading jitter */ +StepRawJitter: gwinClear(ghc); gwinSetColor(ghc, Yellow); - chprintf(gp, "\n%u. GINPUT_MOUSE_READ_CYCLES\n\n", ++testnum); + chprintf(gp, "\n2. GINPUT_MOUSE_READ_CYCLES\n\n"); gwinSetColor(ghc, White); - chprintf(gp, "Press on the surface (or press and hold the mouse button).\n\n"); + if (deviceType == GEVENT_MOUSE) + chprintf(gp, "Press and hold the mouse button.\n\n"); + else + chprintf(gp, "Press and hold on the surface.\n\n"); chprintf(gp, "Numbers will display in this window.\n" "Ensure that values don't jump around very much when your finger is stationary.\n\n" - "Increasing GINPUT_MOUSE_READ_CYCLES helps reduce jitter but increases CPU usage.\n\n" - "Releasing your finger (or mouse button) will move on to the next test.\n\n"); + "Increasing GINPUT_MOUSE_READ_CYCLES helps reduce jitter but increases CPU usage.\n\n"); + + if (ghNext) + chprintf(gp, "Press Next or Back to continue.\n"); + else if (deviceType == GEVENT_MOUSE) + chprintf(gp, "Release the mouse button to move on to the next test.\n"); + else + chprintf(gp, "Release your finger to move on to the next test.\n"); // For this test turn on ALL mouse movement events geventAttachSource(&gl, gs, GLISTEN_MOUSEDOWNMOVES|GLISTEN_MOUSEMETA|GLISTEN_MOUSENOFILTER); - do { - pem = (GEventMouse *)geventEventWait(&gl, TIME_INFINITE); - if (pem->type != GEVENT_MOUSE && pem->type != GEVENT_TOUCH) // Safety Check - continue; - - if ((pem->current_buttons & GINPUT_MOUSE_BTN_LEFT)) - chprintf(gp, "%u:%u\n", pem->x, pem->y); - } while (!(pem->meta & GMETA_MOUSE_UP)); + while(1) { + pe = geventEventWait(&gl, TIME_INFINITE); + if (pe->type == GEVENT_GWIN_BUTTON) { + peb = (GEventGWinButton *)pe; + if (peb->button == ghPrev) + goto StepDeviceType; + if (peb->button == ghNext) + break; + } + if (pe->type == GEVENT_MOUSE || pe->type == GEVENT_TOUCH) { + pem = (GEventMouse *)pe; + if ((pem->current_buttons & GINPUT_MOUSE_BTN_LEFT)) + chprintf(gp, "%u:%u\n", pem->x, pem->y); + if (!ghNext && (pem->meta & GMETA_MOUSE_UP)) + break; + } + } // Reset to just changed movements. geventAttachSource(&gl, gs, GLISTEN_MOUSEDOWNMOVES|GLISTEN_MOUSEMETA); @@ -119,60 +158,124 @@ int main(void) { * Test: Calibration */ +StepCalibrate: gwinClear(ghc); gwinSetColor(ghc, Yellow); - chprintf(gp, "\n%u. GINPUT_MOUSE_CALIBRATION_ERROR\n\n", ++testnum); + chprintf(gp, "\n3. GINPUT_MOUSE_CALIBRATION_ERROR\n\n"); gwinSetColor(ghc, Gray); chprintf(gp, "Ensure GINPUT_MOUSE_NEED_CALIBRATION = TRUE and GINPUT_MOUSE_CALIBRATION_ERROR is >= 0\n\n"); gwinSetColor(ghc, White); - chprintf(gp, "When you press and release the surface, calibration will start.\n"); chprintf(gp, "You will be presented with a number of points to touch.\nPress them in turn.\n\n" - "If the calibration repeatedly fails increase GINPUT_MOUSE_CALIBRATION_ERROR and try again.\n"); + "If the calibration repeatedly fails, increase GINPUT_MOUSE_CALIBRATION_ERROR and try again.\n\n"); - do { - pem = (GEventMouse *)geventEventWait(&gl, TIME_INFINITE); - if (pem->type != GEVENT_MOUSE && pem->type != GEVENT_TOUCH) // Safety Check - continue; + if (ghNext) + chprintf(gp, "Press Next to start the calibration.\n"); + else if (deviceType == GEVENT_MOUSE) + chprintf(gp, "Click the mouse button to start the calibration.\n"); + else + chprintf(gp, "Press and release your finger to start the calibration.\n"); - } while (!(pem->meta & GMETA_MOUSE_UP)); + while(1) { + pe = geventEventWait(&gl, TIME_INFINITE); + if (pe->type == GEVENT_GWIN_BUTTON) { + peb = (GEventGWinButton *)pe; + if (peb->button == ghPrev) + goto StepRawJitter; + if (peb->button == ghNext) + break; + } + if (pe->type == GEVENT_MOUSE || pe->type == GEVENT_TOUCH) { + pem = (GEventMouse *)pe; + if (!ghNext && (pem->meta & GMETA_MOUSE_UP)) + break; + } + } // Calibrate ginputCalibrateMouse(0); - // Calibration uses the whole screen - re-establish our title + /* From now on we can use Next and Previous Buttons */ + if (!ghNext) { + + ghNext = gwinCreateButton(&gNext, swidth-50, 0, 50, 20, &fontUI2, GBTN_NORMAL); + gwinSetButtonText(ghNext, "Next", FALSE); + gsNext = gwinGetButtonSource(ghNext); + geventAttachSource(&gl, gsNext, 0); + gwinAttachButtonSource(ghNext, gs, GEVENT_MOUSE); + + ghPrev = gwinCreateButton(&gPrev, swidth-100, 0, 50, 20, &fontUI2, GBTN_NORMAL); + gwinSetButtonText(ghPrev, "Back", FALSE); + gsPrev = gwinGetButtonSource(ghPrev); + geventAttachSource(&gl, gsPrev, 0); + gwinAttachButtonSource(ghPrev, gs, GEVENT_MOUSE); + +#if 0 + { + GSourceHandle gsButton1, gsButton2; + + // Attach a couple of hardware toggle buttons to our Next and Back buttons as well. + // We can always use the mouse to trigger the buttons if you don't want to use hardware toggles. + // This code depends on your hardware. Turn it on only if you have + // defined a board definition for your toggle driver. Then change + // the next two lines to be correct for your hardware. The values + // below are correct for the Win32 toggle driver. + gsButton1 = ginputGetToggle(GINPUT_TOGGLE_MOMENTARY1); + gsButton2 = ginputGetToggle(GINPUT_TOGGLE_MOMENTARY2); + gwinAttachButtonSource(ghNext, gsButton2, GEVENT_TOGGLE); + gwinAttachButtonSource(ghPrev, gsButton1, GEVENT_TOGGLE); + } +#endif + } + + // Calibration used the whole screen - re-establish our title gdispFillStringBox(0, 0, swidth, 20, "Touch Calibration", &fontUI2, Green, White, justifyCenter); + gwinButtonDraw(ghNext); + gwinButtonDraw(ghPrev); /* * Test: Mouse movement jitter */ +StepJitter: gwinClear(ghc); gwinSetColor(ghc, Yellow); - chprintf(gp, "\n%u. GINPUT_MOUSE_MOVE_JITTER\n\n", ++testnum); + chprintf(gp, "\n4. GINPUT_MOUSE_MOVE_JITTER\n\n"); gwinSetColor(ghc, White); - chprintf(gp, "Press firmly on the surface (or press and hold the mouse button) and move around as if to draw.\n\n"); + if (deviceType == GEVENT_MOUSE) + chprintf(gp, "Press and hold the mouse button and move around as if to draw.\n\n"); + else + chprintf(gp, "Press firmly on the surface and move around as if to draw.\n\n"); + chprintf(gp, "Dots will display in this window. Ensure that when you stop moving your finger that " "new dots stop displaying.\nNew dots should only display when your finger is moving.\n\n" - "Adjust GINPUT_MOUSE_MOVE_JITTER to the smallest value that this reliably works for.\n\n" - "Releasing your finger (or mouse button) will move on to the next test.\n\n"); + "Adjust GINPUT_MOUSE_MOVE_JITTER to the smallest value that this reliably works for.\n\n"); + chprintf(gp, "Press Next or Back to continue.\n\n"); - do { - pem = (GEventMouse *)geventEventWait(&gl, TIME_INFINITE); - if (pem->type != GEVENT_MOUSE && pem->type != GEVENT_TOUCH) // Safety Check - continue; - - if ((pem->current_buttons & GINPUT_MOUSE_BTN_LEFT)) - chprintf(gp, "."); - } while (!(pem->meta & GMETA_MOUSE_UP)); + while(1) { + pe = geventEventWait(&gl, TIME_INFINITE); + if (pe->type == GEVENT_GWIN_BUTTON) { + peb = (GEventGWinButton *)pe; + if (peb->button == ghPrev) + goto StepCalibrate; + if (peb->button == ghNext) + break; + } + if (pe->type == GEVENT_MOUSE || pe->type == GEVENT_TOUCH) { + pem = (GEventMouse *)pe; + if ((pem->current_buttons & GINPUT_MOUSE_BTN_LEFT)) + chprintf(gp, "."); + } + } /* * Test: Polling frequency */ +StepPolling: gwinClear(ghc); gwinSetColor(ghc, Yellow); - chprintf(gp, "\n%u. GINPUT_MOUSE_POLL_PERIOD\n\n", ++testnum); + chprintf(gp, "\n5. GINPUT_MOUSE_POLL_PERIOD\n\n"); gwinSetColor(ghc, White); chprintf(gp, "Press firmly on the surface (or press and hold the mouse button) and move around as if to draw.\n\n"); @@ -180,26 +283,33 @@ int main(void) { "Adjust GINPUT_MOUSE_POLL_PERIOD to the highest value that provides a line without " "gaps that are too big.\nDecreasing the value increases CPU usage.\n" "About 25 (millisecs) normally produces good results." - "This test can be ignored for interrupt driven drivers.\n\n" - "Releasing your finger (or mouse button) will move on to the next test.\n"); - - do { - pem = (GEventMouse *)geventEventWait(&gl, TIME_INFINITE); - if (pem->type != GEVENT_MOUSE && pem->type != GEVENT_TOUCH) // Safety Check - continue; - - if ((pem->current_buttons & GINPUT_MOUSE_BTN_LEFT)) - gdispDrawPixel(pem->x, pem->y, Green); - } while (!(pem->meta & GMETA_MOUSE_UP)); + "This test can be ignored for interrupt driven drivers.\n\n"); + chprintf(gp, "Press Next or Back to continue.\n\n"); + while(1) { + pe = geventEventWait(&gl, TIME_INFINITE); + if (pe->type == GEVENT_GWIN_BUTTON) { + peb = (GEventGWinButton *)pe; + if (peb->button == ghPrev) + goto StepJitter; + if (peb->button == ghNext) + break; + } + if (pe->type == GEVENT_MOUSE || pe->type == GEVENT_TOUCH) { + pem = (GEventMouse *)pe; + if ((pem->current_buttons & GINPUT_MOUSE_BTN_LEFT)) + gdispDrawPixel(pem->x, pem->y, Green); + } + } /* * Test: Click Jitter */ +StepClickJitter: gwinClear(ghc); gwinSetColor(ghc, Yellow); - chprintf(gp, "\n%u. GINPUT_MOUSE_MAX_CLICK_JITTER\n\n", ++testnum); + chprintf(gp, "\n6. GINPUT_MOUSE_MAX_CLICK_JITTER\n\n"); gwinSetColor(ghc, White); chprintf(gp, "Press and release the touch surface to \"click\".\nTry both short and long presses.\n"); @@ -209,21 +319,31 @@ int main(void) { "Adjust GINPUT_MOUSE_CLICK_JITTER to the smallest value that this reliably works for.\n" "Adjust GINPUT_MOUSE_CLICK_TIME to adjust distinguishing short vs long presses.\n" "TIME_INFINITE means there are no long presses (although a right mouse button will still work).\n\n" - "Note: moving your finger (mouse) during a click cancels it." - "This test does not end.\n\n"); + "Note: moving your finger (mouse) during a click cancels it.\n\n"); + chprintf(gp, "This is the last test but you can press Next or Back to continue.\n\n"); while(1) { - pem = (GEventMouse *)geventEventWait(&gl, TIME_INFINITE); - if (pem->type != GEVENT_MOUSE && pem->type != GEVENT_TOUCH) // Safety Check - continue; - - if ((pem->meta & GMETA_MOUSE_CLICK)) { - gwinSetColor(ghc, Yellow); - chprintf(gp, "-"); + pe = geventEventWait(&gl, TIME_INFINITE); + if (pe->type == GEVENT_GWIN_BUTTON) { + peb = (GEventGWinButton *)pe; + if (peb->button == ghPrev) + goto StepPolling; + if (peb->button == ghNext) + break; } - if ((pem->meta & GMETA_MOUSE_CXTCLICK)) { - gwinSetColor(ghc, Red); - chprintf(gp, "x"); + if (pe->type == GEVENT_MOUSE || pe->type == GEVENT_TOUCH) { + pem = (GEventMouse *)pe; + if ((pem->meta & GMETA_MOUSE_CLICK)) { + gwinSetColor(ghc, Yellow); + chprintf(gp, "-"); + } + if ((pem->meta & GMETA_MOUSE_CXTCLICK)) { + gwinSetColor(ghc, Red); + chprintf(gp, "x"); + } } } + + // Can't let this really exit + goto StepDeviceType; } From 74e94d39b9b66adeaf8bcbb8789d79110102bb15 Mon Sep 17 00:00:00 2001 From: Andrew Hannam Date: Sun, 2 Dec 2012 17:10:27 +1000 Subject: [PATCH 6/6] Split Attaching Sources to a GWIN button Split Attaching Sources to a GWIN button to allow for new input types that require a parameter in future eg. Keyboard will require a parameter. --- demos/modules/ginput_touch_driver_test/main.c | 8 ++--- include/gwin/gwin_button.h | 11 ++++-- src/gwin/button.c | 35 ++++++++----------- 3 files changed, 27 insertions(+), 27 deletions(-) diff --git a/demos/modules/ginput_touch_driver_test/main.c b/demos/modules/ginput_touch_driver_test/main.c index 8a31ec74..dc8bb0f9 100644 --- a/demos/modules/ginput_touch_driver_test/main.c +++ b/demos/modules/ginput_touch_driver_test/main.c @@ -201,13 +201,13 @@ StepCalibrate: gwinSetButtonText(ghNext, "Next", FALSE); gsNext = gwinGetButtonSource(ghNext); geventAttachSource(&gl, gsNext, 0); - gwinAttachButtonSource(ghNext, gs, GEVENT_MOUSE); + gwinAttachButtonMouseSource(ghNext, gs); ghPrev = gwinCreateButton(&gPrev, swidth-100, 0, 50, 20, &fontUI2, GBTN_NORMAL); gwinSetButtonText(ghPrev, "Back", FALSE); gsPrev = gwinGetButtonSource(ghPrev); geventAttachSource(&gl, gsPrev, 0); - gwinAttachButtonSource(ghPrev, gs, GEVENT_MOUSE); + gwinAttachButtonMouseSource(ghPrev, gs); #if 0 { @@ -221,8 +221,8 @@ StepCalibrate: // below are correct for the Win32 toggle driver. gsButton1 = ginputGetToggle(GINPUT_TOGGLE_MOMENTARY1); gsButton2 = ginputGetToggle(GINPUT_TOGGLE_MOMENTARY2); - gwinAttachButtonSource(ghNext, gsButton2, GEVENT_TOGGLE); - gwinAttachButtonSource(ghPrev, gsButton1, GEVENT_TOGGLE); + gwinAttachButtonToggleSource(ghNext, gsButton2); + gwinAttachButtonToggleSource(ghPrev, gsButton1); } #endif } diff --git a/include/gwin/gwin_button.h b/include/gwin/gwin_button.h index 69a2474c..e95628e4 100644 --- a/include/gwin/gwin_button.h +++ b/include/gwin/gwin_button.h @@ -129,8 +129,15 @@ extern "C" { // Get the source handle so the application can listen for events #define gwinGetButtonSource(gh) ((GSourceHandle)(gh)) - // Attach a source to this button. Sources recognised: Mouse, Touch and Toggle - others are ignored (returns false). - bool_t gwinAttachButtonSource(GHandle gh, GSourceHandle gsh, GEventType type); + #if defined(GINPUT_NEED_MOUSE) && GINPUT_NEED_MOUSE + // Attach a mouse source to this button. + bool_t gwinAttachButtonMouseSource(GHandle gh, GSourceHandle gsh); + #endif + + #if defined(GINPUT_NEED_TOGGLE) && GINPUT_NEED_TOGGLE + // Attach a toggle source to this button. + bool_t gwinAttachButtonToggleSource(GHandle gh, GSourceHandle gsh); + #endif #ifdef __cplusplus } diff --git a/src/gwin/button.c b/src/gwin/button.c index 43c6d5d4..4e1e45f5 100644 --- a/src/gwin/button.c +++ b/src/gwin/button.c @@ -297,30 +297,23 @@ void gwinButtonDraw(GHandle gh) { #undef gbw } -// Attach a source to this button. Sources recognised: Mouse, Touch and Toggle - others are ignored (returns false). -bool_t gwinAttachButtonSource(GHandle gh, GSourceHandle gsh, GEventType type) { - #define gbw ((GButtonObject *)gh) - unsigned flags; +#if defined(GINPUT_NEED_MOUSE) && GINPUT_NEED_MOUSE + bool_t gwinAttachButtonMouseSource(GHandle gh, GSourceHandle gsh) { + if (gh->type != GW_BUTTON) + return FALSE; - switch (type) { - #if defined(GINPUT_NEED_MOUSE) && GINPUT_NEED_MOUSE - case GEVENT_MOUSE: - case GEVENT_TOUCH: - flags = GLISTEN_MOUSEMETA; - break; - #endif - #if defined(GINPUT_NEED_TOGGLE) && GINPUT_NEED_TOGGLE - case GEVENT_TOGGLE: - flags = GLISTEN_TOGGLE_OFF|GLISTEN_TOGGLE_ON; - break; - #endif - default: - return FALSE; + return geventAttachSource(&((GButtonObject *)gh)->listener, gsh, GLISTEN_MOUSEMETA); } - return geventAttachSource(&gbw->listener, gsh, flags); +#endif - #undef gbw -} +#if defined(GINPUT_NEED_TOGGLE) && GINPUT_NEED_TOGGLE + bool_t gwinAttachButtonToggleSource(GHandle gh, GSourceHandle gsh) { + if (gh->type != GW_BUTTON) + return FALSE; + + return geventAttachSource(&((GButtonObject *)gh)->listener, gsh, GLISTEN_TOGGLE_OFF|GLISTEN_TOGGLE_ON); + } +#endif #endif /* GFX_USE_GWIN && GWIN_NEED_BUTTON */ /** @} */