From 0f3f8f68f87233bf59c3fa68c3dfe1f492a1a478 Mon Sep 17 00:00:00 2001 From: inmarket Date: Wed, 20 Aug 2014 17:42:53 +1000 Subject: Rename lots of files to help prevent compile time name conflicts. --- src/ginput/dial.c | 153 ---------- src/ginput/dial.h | 111 ------- src/ginput/ginput.c | 36 --- src/ginput/ginput_dial.c | 153 ++++++++++ src/ginput/ginput_dial.h | 111 +++++++ src/ginput/ginput_ginput.c | 36 +++ src/ginput/ginput_keyboard.c | 23 ++ src/ginput/ginput_keyboard.h | 128 ++++++++ src/ginput/ginput_mouse.c | 679 +++++++++++++++++++++++++++++++++++++++++++ src/ginput/ginput_mouse.h | 181 ++++++++++++ src/ginput/ginput_toggle.c | 156 ++++++++++ src/ginput/ginput_toggle.h | 100 +++++++ src/ginput/keyboard.c | 23 -- src/ginput/keyboard.h | 128 -------- src/ginput/mouse.c | 679 ------------------------------------------- src/ginput/mouse.h | 181 ------------ src/ginput/sys_defs.h | 8 +- src/ginput/sys_make.mk | 10 +- src/ginput/toggle.c | 156 ---------- src/ginput/toggle.h | 100 ------- 20 files changed, 1576 insertions(+), 1576 deletions(-) delete mode 100644 src/ginput/dial.c delete mode 100644 src/ginput/dial.h delete mode 100644 src/ginput/ginput.c create mode 100644 src/ginput/ginput_dial.c create mode 100644 src/ginput/ginput_dial.h create mode 100644 src/ginput/ginput_ginput.c create mode 100644 src/ginput/ginput_keyboard.c create mode 100644 src/ginput/ginput_keyboard.h create mode 100644 src/ginput/ginput_mouse.c create mode 100644 src/ginput/ginput_mouse.h create mode 100644 src/ginput/ginput_toggle.c create mode 100644 src/ginput/ginput_toggle.h delete mode 100644 src/ginput/keyboard.c delete mode 100644 src/ginput/keyboard.h delete mode 100644 src/ginput/mouse.c delete mode 100644 src/ginput/mouse.h delete mode 100644 src/ginput/toggle.c delete mode 100644 src/ginput/toggle.h (limited to 'src/ginput') diff --git a/src/ginput/dial.c b/src/ginput/dial.c deleted file mode 100644 index 410efc1a..00000000 --- a/src/ginput/dial.c +++ /dev/null @@ -1,153 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -/** - * @file src/ginput/dial.c - * @brief GINPUT dial code. - * - * @defgroup Dial Dial - * @ingroup GINPUT - * @{ - */ -#include "gfx.h" - -#if GFX_USE_GINPUT && GINPUT_NEED_DIAL - -#include "src/ginput/driver_dial.h" - -static GTIMER_DECL(DialTimer); -static struct DialStatus_t { - uint16_t sensitivity; - uint16_t lastvalue; - uint16_t max; -} DialStatus[GINPUT_DIAL_NUM_PORTS]; - -// The reading callback function -static void DialCallback(uint16_t instance, uint16_t rawvalue) { - struct DialStatus_t *pds; - GSourceListener *psl; - GEventDial *pe; - - /* Get the information we need */ - pds = DialStatus+instance; - - /* Range scale - if needed */ - if (pds->max != GINPUT_DIAL_MAX_VALUE) - rawvalue = (uint16_t)((uint32_t)rawvalue * pds->max / GINPUT_DIAL_MAX_VALUE); - - /* Forget about changes below our sensitivity threshold */ - if (rawvalue >= pds->lastvalue) { - if (rawvalue - pds->lastvalue < pds->sensitivity) return; - } else { - if (pds->lastvalue - rawvalue < pds->sensitivity) return; - } - - /* Save the value */ - pds->lastvalue = rawvalue; - - // Send the event to the listeners that are interested. - psl = 0; - while ((psl = geventGetSourceListener((GSourceHandle)(DialStatus+instance), psl))) { - if (!(pe = (GEventDial *)geventGetEventBuffer(psl))) - continue; - pe->type = GEVENT_DIAL; - pe->instance = instance; - pe->value = pds->lastvalue; - pe->maxvalue = pds->max; - geventSendEvent(psl); - } -} - -GSourceHandle ginputGetDial(uint16_t instance) { - struct DialStatus_t *pds; - - if (instance >= GINPUT_DIAL_NUM_PORTS) - return 0; - - // Do we need to initialise the dial subsystem? - if (!gtimerIsActive(&DialTimer)) { - for(pds = DialStatus; pds < DialStatus+GINPUT_DIAL_NUM_PORTS; pds++) { - pds->max = GINPUT_DIAL_MAX_VALUE; -#if GINPUT_DIAL_MAX_VALUE < 100 - pds->sensitivity = 1; -#else - pds->sensitivity = GINPUT_DIAL_MAX_VALUE/100; -#endif - pds->lastvalue = 0; - } - ginput_lld_dial_init(); - gtimerStart(&DialTimer, (GTimerFunction)ginput_lld_dial_poll, DialCallback, TRUE, GINPUT_DIAL_POLL_PERIOD); - } - - // OK - return this input - return (GSourceHandle)(DialStatus+instance); -} - -void ginputResetDialRange(uint16_t instance) { - if (instance >= GINPUT_DIAL_NUM_PORTS) - return; - - ginputSetDialRange(instance, GINPUT_DIAL_MAX_VALUE); -} - -uint16_t ginputGetDialRange(uint16_t instance) { - if (instance >= GINPUT_DIAL_NUM_PORTS) - return 0; - - return DialStatus[instance].max; -} - -void ginputSetDialRange(uint16_t instance, uint16_t max) { - struct DialStatus_t *pds; - - if (instance >= GINPUT_DIAL_NUM_PORTS) - return; - - pds = DialStatus+instance; - - // Rescale the last value and the sensitivity - if (max != pds->max) { - pds->lastvalue = (uint16_t)((uint32_t)pds->lastvalue * max / pds->max); - pds->sensitivity = (uint16_t)((uint32_t)pds->sensitivity * max / pds->max); - pds->max = max; - } -} - -/** - * @brief Set the level change required before a dial even is generated (threshold) - * @note This is done after range scaling - * - * @param[in] instance The ID of the dial input instance - * @param[in] diff The amount of level changes - */ -void ginputSetDialSensitivity(uint16_t instance, uint16_t diff) { - if (instance >= GINPUT_DIAL_NUM_PORTS) - return; - - DialStatus[instance].sensitivity = diff; -} - -/** - * @brief Get the current dial status - * - * @param[in] instance The ID of the dial input instance - * @param[in] pdial The dial event struct - * - * @return Returns FALSE on an error (eg invalid instance) - */ -bool_t ginputGetDialStatus(uint16_t instance, GEventDial *pdial) { - if (instance >= GINPUT_DIAL_NUM_PORTS) - return FALSE; - pdial->type = GEVENT_DIAL; - pdial->instance = instance; - pdial->value = DialStatus[instance].lastvalue; - pdial->maxvalue = DialStatus[instance].max; - return TRUE; -} - -#endif /* GFX_USE_GINPUT && GINPUT_NEED_DIAL */ -/** @} */ diff --git a/src/ginput/dial.h b/src/ginput/dial.h deleted file mode 100644 index f2d3fb58..00000000 --- a/src/ginput/dial.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -/** - * @file src/ginput/dial.h - * @brief GINPUT GFX User Input subsystem header file. - * - * @defgroup Dial Dial - * @ingroup GINPUT - * - * @details A dial provides a powerful way to navigate through menus - * on a display. - * - * @pre GFX_USE_GINPUT must be set to TRUE in your gfxconf.h - * @pre GINPUT_NEED_DIAL must be set to TRUE in your gfxconf.h - * - * @{ - */ -#ifndef _GINPUT_DIAL_H -#define _GINPUT_DIAL_H - -#if GINPUT_NEED_DIAL || defined(__DOXYGEN__) - -/*===========================================================================*/ -/* Type definitions */ -/*===========================================================================*/ - -// Event types for various ginput sources -#define GEVENT_DIAL (GEVENT_GINPUT_FIRST+4) - -typedef struct GEventDial_t { - GEventType type; // The type of this event (GEVENT_DIAL) - uint16_t instance; // The dial instance - uint16_t value; // The dial value - uint16_t maxvalue; // The maximum dial value - } GEventDial; - -/*===========================================================================*/ -/* External declarations. */ -/*===========================================================================*/ - -#ifdef __cplusplus -extern "C" { -#endif - - /** - * @brief Create a dial input instance - * - * @param[in] instance The ID of the dial input instance (from 0 to 9999) - * - * @return The soure handle of the created dial instance - */ - GSourceHandle ginputGetDial(uint16_t instance); - - /** - * @brief Reset the value back to the hardware default - * - * @param[in] instance The ID of the dial input instance - */ - void ginputResetDialRange(uint16_t instance); - - /** - * @brief Get the maximum value - * @details The readings are scaled to be 0 ... max. - * - * @param[in] instance The ID of the dial input instance - * - * @return The maximum value - */ - uint16_t ginputGetDialRange(uint16_t instance); - - /** - * @brief Set the maximum value - * @details The readings are scaled to be 0 ... max. - * - * @param[in] instance The ID of the dial input instance - * @param[in] max The maximum value to be set - */ - void ginputSetDialRange(uint16_t instance, uint16_t max); - - /** - * @brief Set the level change required before a dial even is generated (threshold) - * @note This is done after range scaling - * - * @param[in] instance The ID of the dial input instance - * @param[in] diff The amount of level changes - */ - void ginputSetDialSensitivity(uint16_t instance, uint16_t diff); - - /** - * @brief Get the current dial status - * - * @param[in] instance The ID of the dial input instance - * @param[in] pdial The dial event struct - * - * @return Returns FALSE on an error (eg invalid instance) - */ - bool_t ginputGetDialStatus(uint16_t instance, GEventDial *pdial); - -#ifdef __cplusplus -} -#endif - -#endif /* GINPUT_NEED_DIAL */ - -#endif /* _GINPUT_DIAL_H */ -/** @} */ diff --git a/src/ginput/ginput.c b/src/ginput/ginput.c deleted file mode 100644 index abd16cd8..00000000 --- a/src/ginput/ginput.c +++ /dev/null @@ -1,36 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -/** - * @file src/ginput/ginput.c - * @brief GINPUT subsystem common code. - * - * @addtogroup GINPUT - * @{ - */ -#include "gfx.h" - -#if GFX_USE_GINPUT - -void _ginputInit(void) -{ - /* ToDo */ - - /** - * This should really call an init routine for each ginput sub-system. - * Maybe we'll do this later. - */ -} - -void _ginputDeinit(void) -{ - -} - -#endif /* GFX_USE_GINPUT */ -/** @} */ - diff --git a/src/ginput/ginput_dial.c b/src/ginput/ginput_dial.c new file mode 100644 index 00000000..6af89b31 --- /dev/null +++ b/src/ginput/ginput_dial.c @@ -0,0 +1,153 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @file src/ginput/ginput_dial.c + * @brief GINPUT dial code. + * + * @defgroup Dial Dial + * @ingroup GINPUT + * @{ + */ +#include "gfx.h" + +#if GFX_USE_GINPUT && GINPUT_NEED_DIAL + +#include "driver_dial.h" + +static GTIMER_DECL(DialTimer); +static struct DialStatus_t { + uint16_t sensitivity; + uint16_t lastvalue; + uint16_t max; +} DialStatus[GINPUT_DIAL_NUM_PORTS]; + +// The reading callback function +static void DialCallback(uint16_t instance, uint16_t rawvalue) { + struct DialStatus_t *pds; + GSourceListener *psl; + GEventDial *pe; + + /* Get the information we need */ + pds = DialStatus+instance; + + /* Range scale - if needed */ + if (pds->max != GINPUT_DIAL_MAX_VALUE) + rawvalue = (uint16_t)((uint32_t)rawvalue * pds->max / GINPUT_DIAL_MAX_VALUE); + + /* Forget about changes below our sensitivity threshold */ + if (rawvalue >= pds->lastvalue) { + if (rawvalue - pds->lastvalue < pds->sensitivity) return; + } else { + if (pds->lastvalue - rawvalue < pds->sensitivity) return; + } + + /* Save the value */ + pds->lastvalue = rawvalue; + + // Send the event to the listeners that are interested. + psl = 0; + while ((psl = geventGetSourceListener((GSourceHandle)(DialStatus+instance), psl))) { + if (!(pe = (GEventDial *)geventGetEventBuffer(psl))) + continue; + pe->type = GEVENT_DIAL; + pe->instance = instance; + pe->value = pds->lastvalue; + pe->maxvalue = pds->max; + geventSendEvent(psl); + } +} + +GSourceHandle ginputGetDial(uint16_t instance) { + struct DialStatus_t *pds; + + if (instance >= GINPUT_DIAL_NUM_PORTS) + return 0; + + // Do we need to initialise the dial subsystem? + if (!gtimerIsActive(&DialTimer)) { + for(pds = DialStatus; pds < DialStatus+GINPUT_DIAL_NUM_PORTS; pds++) { + pds->max = GINPUT_DIAL_MAX_VALUE; +#if GINPUT_DIAL_MAX_VALUE < 100 + pds->sensitivity = 1; +#else + pds->sensitivity = GINPUT_DIAL_MAX_VALUE/100; +#endif + pds->lastvalue = 0; + } + ginput_lld_dial_init(); + gtimerStart(&DialTimer, (GTimerFunction)ginput_lld_dial_poll, DialCallback, TRUE, GINPUT_DIAL_POLL_PERIOD); + } + + // OK - return this input + return (GSourceHandle)(DialStatus+instance); +} + +void ginputResetDialRange(uint16_t instance) { + if (instance >= GINPUT_DIAL_NUM_PORTS) + return; + + ginputSetDialRange(instance, GINPUT_DIAL_MAX_VALUE); +} + +uint16_t ginputGetDialRange(uint16_t instance) { + if (instance >= GINPUT_DIAL_NUM_PORTS) + return 0; + + return DialStatus[instance].max; +} + +void ginputSetDialRange(uint16_t instance, uint16_t max) { + struct DialStatus_t *pds; + + if (instance >= GINPUT_DIAL_NUM_PORTS) + return; + + pds = DialStatus+instance; + + // Rescale the last value and the sensitivity + if (max != pds->max) { + pds->lastvalue = (uint16_t)((uint32_t)pds->lastvalue * max / pds->max); + pds->sensitivity = (uint16_t)((uint32_t)pds->sensitivity * max / pds->max); + pds->max = max; + } +} + +/** + * @brief Set the level change required before a dial even is generated (threshold) + * @note This is done after range scaling + * + * @param[in] instance The ID of the dial input instance + * @param[in] diff The amount of level changes + */ +void ginputSetDialSensitivity(uint16_t instance, uint16_t diff) { + if (instance >= GINPUT_DIAL_NUM_PORTS) + return; + + DialStatus[instance].sensitivity = diff; +} + +/** + * @brief Get the current dial status + * + * @param[in] instance The ID of the dial input instance + * @param[in] pdial The dial event struct + * + * @return Returns FALSE on an error (eg invalid instance) + */ +bool_t ginputGetDialStatus(uint16_t instance, GEventDial *pdial) { + if (instance >= GINPUT_DIAL_NUM_PORTS) + return FALSE; + pdial->type = GEVENT_DIAL; + pdial->instance = instance; + pdial->value = DialStatus[instance].lastvalue; + pdial->maxvalue = DialStatus[instance].max; + return TRUE; +} + +#endif /* GFX_USE_GINPUT && GINPUT_NEED_DIAL */ +/** @} */ diff --git a/src/ginput/ginput_dial.h b/src/ginput/ginput_dial.h new file mode 100644 index 00000000..88a2e165 --- /dev/null +++ b/src/ginput/ginput_dial.h @@ -0,0 +1,111 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @file src/ginput/ginput_dial.h + * @brief GINPUT GFX User Input subsystem header file. + * + * @defgroup Dial Dial + * @ingroup GINPUT + * + * @details A dial provides a powerful way to navigate through menus + * on a display. + * + * @pre GFX_USE_GINPUT must be set to TRUE in your gfxconf.h + * @pre GINPUT_NEED_DIAL must be set to TRUE in your gfxconf.h + * + * @{ + */ +#ifndef _GINPUT_DIAL_H +#define _GINPUT_DIAL_H + +#if GINPUT_NEED_DIAL || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Type definitions */ +/*===========================================================================*/ + +// Event types for various ginput sources +#define GEVENT_DIAL (GEVENT_GINPUT_FIRST+4) + +typedef struct GEventDial_t { + GEventType type; // The type of this event (GEVENT_DIAL) + uint16_t instance; // The dial instance + uint16_t value; // The dial value + uint16_t maxvalue; // The maximum dial value + } GEventDial; + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + + /** + * @brief Create a dial input instance + * + * @param[in] instance The ID of the dial input instance (from 0 to 9999) + * + * @return The soure handle of the created dial instance + */ + GSourceHandle ginputGetDial(uint16_t instance); + + /** + * @brief Reset the value back to the hardware default + * + * @param[in] instance The ID of the dial input instance + */ + void ginputResetDialRange(uint16_t instance); + + /** + * @brief Get the maximum value + * @details The readings are scaled to be 0 ... max. + * + * @param[in] instance The ID of the dial input instance + * + * @return The maximum value + */ + uint16_t ginputGetDialRange(uint16_t instance); + + /** + * @brief Set the maximum value + * @details The readings are scaled to be 0 ... max. + * + * @param[in] instance The ID of the dial input instance + * @param[in] max The maximum value to be set + */ + void ginputSetDialRange(uint16_t instance, uint16_t max); + + /** + * @brief Set the level change required before a dial even is generated (threshold) + * @note This is done after range scaling + * + * @param[in] instance The ID of the dial input instance + * @param[in] diff The amount of level changes + */ + void ginputSetDialSensitivity(uint16_t instance, uint16_t diff); + + /** + * @brief Get the current dial status + * + * @param[in] instance The ID of the dial input instance + * @param[in] pdial The dial event struct + * + * @return Returns FALSE on an error (eg invalid instance) + */ + bool_t ginputGetDialStatus(uint16_t instance, GEventDial *pdial); + +#ifdef __cplusplus +} +#endif + +#endif /* GINPUT_NEED_DIAL */ + +#endif /* _GINPUT_DIAL_H */ +/** @} */ diff --git a/src/ginput/ginput_ginput.c b/src/ginput/ginput_ginput.c new file mode 100644 index 00000000..4197fa25 --- /dev/null +++ b/src/ginput/ginput_ginput.c @@ -0,0 +1,36 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @file src/ginput/ginput_ginput.c + * @brief GINPUT subsystem common code. + * + * @addtogroup GINPUT + * @{ + */ +#include "gfx.h" + +#if GFX_USE_GINPUT + +void _ginputInit(void) +{ + /* ToDo */ + + /** + * This should really call an init routine for each ginput sub-system. + * Maybe we'll do this later. + */ +} + +void _ginputDeinit(void) +{ + +} + +#endif /* GFX_USE_GINPUT */ +/** @} */ + diff --git a/src/ginput/ginput_keyboard.c b/src/ginput/ginput_keyboard.c new file mode 100644 index 00000000..5443572b --- /dev/null +++ b/src/ginput/ginput_keyboard.c @@ -0,0 +1,23 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @file src/ginput/ginput_keyboard.c + * @brief GINPUT keyboard code. + * + * @defgroup Keyboard Keyboard + * @ingroup GINPUT + * + * @{ + */ + +#include "gfx.h" + +#if (GFX_USE_GINPUT && GINPUT_NEED_KEYBOARD) || defined(__DOXYGEN__) + #error "GINPUT: GINPUT_NEED_KEYBOARD - Not Implemented Yet" +#endif /* GFX_USE_GINPUT && GINPUT_NEED_KEYBOARD */ +/** @} */ diff --git a/src/ginput/ginput_keyboard.h b/src/ginput/ginput_keyboard.h new file mode 100644 index 00000000..f5737255 --- /dev/null +++ b/src/ginput/ginput_keyboard.h @@ -0,0 +1,128 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @file src/ginput/ginput_keyboard.h + * @brief GINPUT GFX User Input subsystem header file. + * + * @defgroup Keyboard Keyboard + * @ingroup GINPUT + * @{ + */ + +#ifndef _GINPUT_KEYBOARD_H +#define _GINPUT_KEYBOARD_H + +#if GINPUT_NEED_KEYBOARD || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Type definitions */ +/*===========================================================================*/ + +#define GINPUT_KEYBOARD_NUM_PORTS 1 // The total number of keyboard inputs + +// Event types for various ginput sources +#define GEVENT_KEYBOARD (GEVENT_GINPUT_FIRST+2) + +typedef struct GEventKeyboard_t { + GEventType type; // The type of this event (GEVENT_KEYBOARD) + uint16_t instance; // The keyboard instance + char c; // The Ascii code for the current key press. + // The only possible values are 0(NUL), 8(BS), 9(TAB), 13(CR), 27(ESC), 32(SPACE) to 126(~), 127(DEL) + // 0 indicates an extended only key. + uint16_t code; // An extended keyboard code. Codes less than 128 match their ascii equivelent. + #define GKEY_NULL 0 + #define GKEY_BACKSPACE 8 + #define GKEY_TAB 9 + #define GKEY_CR 13 + #define GKEY_ESC 27 + #define GKEY_SPACE 32 + #define GKEY_DEL 127 + #define GKEY_UP 0x0101 + #define GKEY_DOWN 0x0102 + #define GKEY_LEFT 0x0103 + #define GKEY_RIGHT 0x0104 + #define GKEY_HOME 0x0105 + #define GKEY_END 0x0106 + #define GKEY_PAGEUP 0x0107 + #define GKEY_PAGEDOWN 0x0108 + #define GKEY_INSERT 0x0109 + #define GKEY_DELETE 0x010A + #define GKEY_SHIFT 0x0201 + #define GKEY_CNTRL 0x0202 + #define GKEY_ALT 0x0203 + #define GKEY_WINKEY 0x0204 + #define GKEY_RCLKEY 0x0205 + #define GKEY_FNKEY 0x0206 + #define GKEY_FN1 0x0301 + #define GKEY_FN2 0x0302 + #define GKEY_FN3 0x0303 + #define GKEY_FN4 0x0304 + #define GKEY_FN5 0x0305 + #define GKEY_FN6 0x0306 + #define GKEY_FN7 0x0307 + #define GKEY_FN8 0x0308 + #define GKEY_FN9 0x0309 + #define GKEY_FN10 0x030A + #define GKEY_FN11 0x030B + #define GKEY_FN12 0x030C + uint16_t current_buttons; // A bit is set to indicate various meta status. + #define GMETA_KEY_DOWN 0x0001 + #define GMETA_KEY_SHIFT 0x0002 + #define GMETA_KEY_CNTRL 0x0004 + #define GMETA_KEY_ALT 0x0008 + #define GMETA_KEY_WINKEY 0x0010 + #define GMETA_KEY_RCLKKEY 0x0020 + #define GMETA_KEY_FN 0x0040 + #define GMETA_KEY_MISSED_EVENT 0x8000 + uint16_t last_buttons; // The value of current_buttons on the last event +} GEventKeyboard; + +// Keyboard Listen Flags - passed to geventAddSourceToListener() +#define GLISTEN_KEYREPEATS 0x0001 // Return key repeats (where the key is held down to get a repeat character) +#define GLISTEN_KEYCODES 0x0002 // Return all key presses including extended code key presses (not just ascii codes) +#define GLISTEN_KEYALL 0x0004 // Return keyup's, keydown's and everything in between (but not repeats unless GLISTEN_KEYREPEATS is set). +#define GLISTEN_KEYSINGLE 0x8000 // Return only when one particular extended code key is pressed or released. The particular extended code is OR'd into this value + // eg. (GLISTEN_KEYSINGLE | GKEY_CR) + // No other flags may be set with this flag. + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + + /** + * @brief Create a keyboard input instance + * + * @param[in] instance The ID of the keyboard input instance (from 0 to 9999) + * + * @return The source handle of the created input instance + */ + GSourceHandle ginputGetKeyboard(uint16_t instance); + + /** + * @brief Get the current keyboard status + * + * @param[in] instance The ID of the keyboard input instance + * @param[in] pkeyboard The keyboard event struct + * + * @return Returns FALSE on an error (eg invalid instance) + */ + bool_t ginputGetKeyboardStatus(uint16_t instance, GEventKeyboard *pkeyboard); + +#ifdef __cplusplus +} +#endif + +#endif /* GINPUT_NEED_KEYBOARD */ + +#endif /* _GINPUT_KEYBOARD_H */ +/** @} */ + diff --git a/src/ginput/ginput_mouse.c b/src/ginput/ginput_mouse.c new file mode 100644 index 00000000..a0daba98 --- /dev/null +++ b/src/ginput/ginput_mouse.c @@ -0,0 +1,679 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @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__) + +#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" + #endif + + #include // Required for memcpy + + #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!" + + #if GINPUT_MOUSE_MAX_CALIBRATION_ERROR < 0 + #define GINPUT_MOUSE_CALIBRATION_POINTS 3 + #else + #define GINPUT_MOUSE_CALIBRATION_POINTS 4 + #endif + + typedef struct Calibration_t { + float ax; + float bx; + float cx; + float ay; + float by; + float cy; + } Calibration; +#endif + +typedef struct MousePoint_t { + coord_t x, y; +} MousePoint; + +static GTIMER_DECL(MouseTimer); + +static struct MouseConfig_t { + MouseReading t; + MousePoint movepos; + MousePoint clickpos; + systemticks_t clicktime; + uint16_t last_buttons; + uint16_t flags; + #define FLG_INIT_DONE 0x8000 + #define FLG_CLICK_TIMER 0x0001 + #define FLG_IN_CAL 0x0010 + #define FLG_CAL_OK 0x0020 + #define FLG_CAL_SAVED 0x0040 + #define FLG_CAL_FREE 0x0080 + #define FLG_CAL_RAW 0x0100 + #if GINPUT_MOUSE_NEED_CALIBRATION + GMouseCalibrationSaveRoutine fnsavecal; + GMouseCalibrationLoadRoutine fnloadcal; + Calibration caldata; + #endif + GDisplay * display; +} MouseConfig; + +void _tsOrientClip(MouseReading *pt, GDisplay *g, bool_t doClip) { + coord_t w, h; + + w = gdispGGetWidth(g); + h = gdispGGetHeight(g); + + #if GDISP_NEED_CONTROL && !GINPUT_MOUSE_NO_ROTATION + switch(gdispGGetOrientation(g)) { + case GDISP_ROTATE_0: + break; + case GDISP_ROTATE_90: + { + coord_t t = pt->x; + pt->x = w - 1 - pt->y; + pt->y = t; + } + break; + case GDISP_ROTATE_180: + pt->x = w - 1 - pt->x; + pt->y = h - 1 - pt->y; + break; + case GDISP_ROTATE_270: + { + coord_t t = pt->y; + pt->y = h - 1 - pt->x; + pt->x = t; + } + break; + default: + break; + } + #endif + + if (doClip) { + if (pt->x < 0) pt->x = 0; + else if (pt->x >= w) pt->x = w-1; + if (pt->y < 0) pt->y = 0; + else if (pt->y >= h) pt->y = h-1; + } +} + +#if GINPUT_MOUSE_NEED_CALIBRATION + static inline void _tsSetIdentity(Calibration *c) { + c->ax = 1; + c->bx = 0; + c->cx = 0; + c->ay = 0; + c->by = 1; + c->cy = 0; + } + + 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); + + 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)); + + 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)); + + 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)); + + 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)); + } + + static inline void _tsClearCross(const MousePoint *pp) { + gdispGFillArea(MouseConfig.display, pp->x - 15, pp->y - 15, 42, 42, Blue); + } + + 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 _tsDo3PointCalibration(const MousePoint *cross, const MousePoint *points, GDisplay *g, Calibration *c) { + float dx; + coord_t c0, c1, c2; + + #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; + } + #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; + + #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; + } + #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; + } +#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; + } + + /* 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 + +static void get_calibrated_reading(MouseReading *pt) { + get_raw_reading(pt); + + #if GINPUT_MOUSE_NEED_CALIBRATION + _tsTransform(pt, &MouseConfig.caldata); + #endif + + _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; + } + + // 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; + } + + // 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; + } + + // 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; + } + } + + // Send the event to the listeners that are interested. + psl = 0; + while ((psl = geventGetSourceListener((GSourceHandle)(&MouseConfig), psl))) { + if (!(pe = (GEventMouse *)geventGetEventBuffer(psl))) { + // This listener is missing - save the meta events that have happened + psl->srcflags |= meta; + continue; + } + + // If we haven't really moved (and there are no meta events) don't bother sending the event + if (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; + } + 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; + + // Do we need to initialise the mouse subsystem? + if (!(MouseConfig.flags & FLG_INIT_DONE)) { + ginput_lld_mouse_init(); + + #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); + #endif + + // 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); + } + + // Return our structure as the handle + return (GSourceHandle)&MouseConfig; +} + +void ginputSetMouseDisplay(uint16_t instance, GDisplay *g) { + if (instance) + return; + + MouseConfig.display = g ? g : GDISP; +} + +GDisplay *ginputGetMouseDisplay(uint16_t instance) { + if (instance) + return 0; + + 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); + + if (instance || (MouseConfig.flags & (FLG_INIT_DONE|FLG_IN_CAL)) != FLG_INIT_DONE) + return FALSE; + + 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; +} + +bool_t ginputCalibrateMouse(uint16_t instance) { + #if !GINPUT_MOUSE_NEED_CALIBRATION + (void) instance; + + return FALSE; + #else + + const coord_t height = gdispGGetHeight(MouseConfig.display); + const coord_t width = gdispGGetWidth(MouseConfig.display); + #if GINPUT_MOUSE_CALIBRATE_EXTREMES + const MousePoint cross[] = {{0, 0}, + {(width - 1) , 0}, + {(width - 1) , (height - 1)}, + {(width / 2), (height / 2)}}; /* Check point */ + #else + const MousePoint cross[] = {{(width / 4), (height / 4)}, + {(width - (width / 4)) , (height / 4)}, + {(width - (width / 4)) , (height - (height / 4))}, + {(width / 2), (height / 2)}}; /* Check point */ + #endif + MousePoint points[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 + + if (instance || (MouseConfig.flags & FLG_IN_CAL)) + return FALSE; + + font1 = gdispOpenFont(GINPUT_MOUSE_CALIBRATION_FONT); + font2 = gdispOpenFont(GINPUT_MOUSE_CALIBRATION_FONT2); + + MouseConfig.flags |= FLG_IN_CAL; + gtimerStop(&MouseTimer); + MouseConfig.flags &= ~(FLG_CAL_OK|FLG_CAL_SAVED|FLG_CAL_RAW); + + #if GDISP_NEED_CLIP + gdispGSetClip(MouseConfig.display, 0, 0, width, height); + #endif + + #if GINPUT_MOUSE_MAX_CALIBRATION_ERROR >= 0 + while(1) { + #endif + gdispGClear(MouseConfig.display, Blue); + + gdispGFillStringBox(MouseConfig.display, 0, 5, width, 30, GINPUT_MOUSE_CALIBRATION_TEXT, font1, White, Blue, justifyCenter); + + for(i = 0, pt = points, pc = cross; i < GINPUT_MOUSE_CALIBRATION_POINTS; i++, pt++, pc++) { + _tsDrawCross(pc); + + do { + + /* Wait for the mouse to be pressed */ + while(get_raw_reading(&MouseConfig.t), !(MouseConfig.t.buttons & GINPUT_MOUSE_BTN_LEFT)) + gfxSleepMilliseconds(20); + + /* Average all the samples while the mouse is down */ + for(px = py = 0, j = 0; + gfxSleepMilliseconds(20), /* Settling time between readings */ + get_raw_reading(&MouseConfig.t), + (MouseConfig.t.buttons & GINPUT_MOUSE_BTN_LEFT); + j++) { + px += MouseConfig.t.x; + py += MouseConfig.t.y; + } + + } while(!j); + + pt->x = px / j; + pt->y = py / j; + + _tsClearCross(pc); + + if (i >= 1 && pt->x == (pt-1)->x && pt->y == (pt-1)->y) { + gdispGFillStringBox(MouseConfig.display, 0, 35, width, 40, GINPUT_MOUSE_CALIBRATION_SAME_TEXT, font2, Red, Yellow, justifyCenter); + gfxSleepMilliseconds(5000); + gdispGFillArea(MouseConfig.display, 0, 35, width, 40, Blue); + } + + } + + /* Apply 3 point calibration algorithm */ + _tsDo3PointCalibration(cross, points, MouseConfig.display, &MouseConfig.caldata); + + /* 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; + + gdispGFillStringBox(MouseConfig.display, 0, 35, width, 40, GINPUT_MOUSE_CALIBRATION_ERROR_TEXT, font2, Red, Yellow, justifyCenter); + gfxSleepMilliseconds(5000); + } + #endif + + // Restart everything + gdispCloseFont(font1); + gdispCloseFont(font2); + MouseConfig.flags |= FLG_CAL_OK; + MouseConfig.last_buttons = 0; + get_calibrated_reading(&MouseConfig.t); + MouseConfig.flags &= ~FLG_IN_CAL; + if ((MouseConfig.flags & FLG_INIT_DONE)) + gtimerStart(&MouseTimer, MousePoll, 0, TRUE, GINPUT_MOUSE_POLL_PERIOD); + + // Save the calibration data (if possible) + if (MouseConfig.fnsavecal) { + MouseConfig.fnsavecal(instance, (const uint8_t *)&MouseConfig.caldata, sizeof(MouseConfig.caldata)); + MouseConfig.flags |= FLG_CAL_SAVED; + } + + // Clear the screen using the GWIN default background color + #if GFX_USE_GWIN + gdispGClear(MouseConfig.display, gwinGetDefaultBgColor()); + #else + gdispGClear(MouseConfig.display, Black); + #endif + + return TRUE; + #endif +} + +/* 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) + return; + + MouseConfig.fnloadcal = fnload; + MouseConfig.fnsavecal = fnsave; + if (requireFree) + MouseConfig.flags |= FLG_CAL_FREE; + 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 +} + +/* Test if a particular mouse instance requires routines to save its calibration data. */ +bool_t ginputRequireMouseCalibrationStorage(uint16_t instance) { + if (instance) + return FALSE; + + #if GINPUT_MOUSE_NEED_CALIBRATION && !GINPUT_MOUSE_LLD_CALIBRATION_LOADSAVE + return TRUE; + #else + return FALSE; + #endif +} + +/* Wake up the mouse driver from an interrupt service routine (there may be new readings available) */ +void ginputMouseWakeup(void) { + gtimerJab(&MouseTimer); +} + +/* Wake up the mouse driver from an interrupt service routine (there may be new readings available) */ +void ginputMouseWakeupI(void) { + gtimerJabI(&MouseTimer); +} + +#endif /* GFX_USE_GINPUT && GINPUT_NEED_MOUSE */ +/** @} */ diff --git a/src/ginput/ginput_mouse.h b/src/ginput/ginput_mouse.h new file mode 100644 index 00000000..61ad35e0 --- /dev/null +++ b/src/ginput/ginput_mouse.h @@ -0,0 +1,181 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @file src/ginput/ginput_mouse.h + * @brief GINPUT GFX User Input subsystem header file for mouse and touch. + * + * @defgroup Mouse Mouse + * @ingroup GINPUT + * + * @details GINPUT allows it to easily interface touchscreens and mices to + * your application. + * + * @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 + * + * @{ + */ + +#ifndef _GINPUT_MOUSE_H +#define _GINPUT_MOUSE_H + +#if GINPUT_NEED_MOUSE || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Type definitions */ +/*===========================================================================*/ + +/* 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; + GDisplay * display; // The display this mouse is currently associated with. + } GEventMouse; + +// Mouse/Touch Listen Flags - passed to geventAddSourceToListener() +#define GLISTEN_MOUSEMETA 0x0001 // Create events for meta events such as CLICK and CXTCLICK +#define GLISTEN_MOUSEDOWNMOVES 0x0002 // Creates mouse move events when the primary mouse button is down (touch is on the surface) +#define GLISTEN_MOUSEUPMOVES 0x0004 // Creates mouse move events when the primary mouse button is up (touch is off the surface - if the hardware allows). +#define GLISTEN_MOUSENOFILTER 0x0008 // Don't filter out mouse moves where the position hasn't changed. +#define GLISTEN_TOUCHMETA GLISTEN_MOUSEMETA +#define GLISTEN_TOUCHDOWNMOVES GLISTEN_MOUSEDOWNMOVES +#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) + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +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! + * + * @param[in] instance The ID of the mouse input instance (from 0 to 9999) + * + * @return The source handle of the created instance + */ + GSourceHandle ginputGetMouse(uint16_t instance); + + /** + * @brief Assign the display associated with the mouse + * @note This only needs to be called if the mouse is associated with a display + * other than the current default display. It must be called before + * @p ginputGetMouse() if the new display is to be used during the calibration + * process. Other than calibration the display is used for range checking, + * and may also be used to display a mouse pointer. + * + * @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); + + /** + * @brief Get the display currently associated with the mouse + * @return A pointer to the display + * + * @param[in] instance The ID of the mouse input instance + */ + GDisplay *ginputGetMouseDisplay(uint16_t instance); + + /** + * @brief Get the current mouse position and button status + * @note Unlinke a listener event, this status cannot record meta events such as + * "CLICK". + * + * @param[in] instance The ID of the mouse input instance + * @param[in] pmouse The mouse event + * + * @return FALSE on an error (eg. invalid instance) + */ + bool_t ginputGetMouseStatus(uint16_t instance, GEventMouse *pmouse); + + /** + * @brief Performs a calibration + * + * @param[in] instance The ID of the mouse input instance + * + * @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 + * + * @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. + * + * @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); + + /** + * @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 + +#endif /* GINPUT_NEED_MOUSE */ + +#endif /* _GINPUT_MOUSE_H */ +/** @} */ + diff --git a/src/ginput/ginput_toggle.c b/src/ginput/ginput_toggle.c new file mode 100644 index 00000000..4c6dc9ae --- /dev/null +++ b/src/ginput/ginput_toggle.c @@ -0,0 +1,156 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @file src/ginput/ginput_toggle.c + * @brief GINPUT toggle code. + * + * @defgroup Toggle Toggle + * @ingroup GINPUT + * @{ + */ +#include "gfx.h" + +#if (GFX_USE_GINPUT && GINPUT_NEED_TOGGLE) || defined(__DOXYGEN__) + +#include "driver_toggle.h" + +#define GINPUT_TOGGLE_ISON 0x01 +#define GINPUT_TOGGLE_INVERT 0x02 + +static GTIMER_DECL(ToggleTimer); +static struct GEventToggleStatus_t { + uint8_t status; +} ToggleStatus[GINPUT_TOGGLE_NUM_PORTS]; + +// Our polling function +static void TogglePoll(void *param) { + (void) param; + + const GToggleConfig *ptc; + GSourceListener *psl; + GEventToggle *pe; + unsigned i, bits, mask; + uint8_t state; + + // Loop while there are bits to get + for(ptc = GInputToggleConfigTable, i=0; i < GINPUT_TOGGLE_NUM_PORTS; ptc++) { + + // Get the next block of bits + bits = ginput_lld_toggle_getbits(ptc) ^ ptc->invert; + + // Extract the bits of use + for(mask = ptc->mask; i < GINPUT_TOGGLE_NUM_PORTS && mask; mask >>= 1, bits >>= 1) { + // Ignore bits not in our mask + if (!(mask & 1)) + continue; + + // Calculate our new state + state = ToggleStatus[i].status & ~GINPUT_TOGGLE_ISON; + if (state & GINPUT_TOGGLE_INVERT) + bits ^= 1; + if (bits & 1) + state |= GINPUT_TOGGLE_ISON; + + // Has it changed? + if ((state ^ ToggleStatus[i].status) & GINPUT_TOGGLE_ISON) { + + // Save the new state + ToggleStatus[i].status = state; + + // Send the event to the listeners that are interested. + psl = 0; + while ((psl = geventGetSourceListener((GSourceHandle)(ToggleStatus+i), psl))) { + if (!(pe = (GEventToggle *)geventGetEventBuffer(psl))) + continue; + if ((state & GINPUT_TOGGLE_ISON)) { + if ((psl->listenflags & GLISTEN_TOGGLE_ON)) { + pe->type = GEVENT_TOGGLE; + pe->instance = i; + pe->on = TRUE; + geventSendEvent(psl); + } + } else { + if ((psl->listenflags & GLISTEN_TOGGLE_OFF)) { + pe->type = GEVENT_TOGGLE; + pe->instance = i; + pe->on = FALSE; + geventSendEvent(psl); + } + } + } + } + + // Next toggle switch + i++; + } + } +} + +/* Hardware Toggle/Switch/Button Functions */ +GSourceHandle ginputGetToggle(uint16_t instance) { + const GToggleConfig *ptc; + + if (instance >= GINPUT_TOGGLE_NUM_PORTS) + return 0; + + // Do we need to initialise the toggle subsystem? + if (!gtimerIsActive(&ToggleTimer)) { + for(ptc = GInputToggleConfigTable; ptc < GInputToggleConfigTable+sizeof(GInputToggleConfigTable)/sizeof(GInputToggleConfigTable[0]); ptc++) + ginput_lld_toggle_init(ptc); + gtimerStart(&ToggleTimer, TogglePoll, 0, TRUE, GINPUT_TOGGLE_POLL_PERIOD); + } + + // OK - return this input + return (GSourceHandle)(ToggleStatus+instance); +} + +// If invert is true, invert the on/off sense for the toggle +void ginputInvertToggle(uint16_t instance, bool_t invert) { + if (instance >= GINPUT_TOGGLE_NUM_PORTS) + return; + if (invert) { + if (!(ToggleStatus[instance].status & GINPUT_TOGGLE_INVERT)) { + ToggleStatus[instance].status |= GINPUT_TOGGLE_INVERT; + ToggleStatus[instance].status ^= GINPUT_TOGGLE_ISON; + } + } else { + if ((ToggleStatus[instance].status & GINPUT_TOGGLE_INVERT)) { + ToggleStatus[instance].status &= ~GINPUT_TOGGLE_INVERT; + ToggleStatus[instance].status ^= GINPUT_TOGGLE_ISON; + } + } +} + +/* Get the current toggle status. + * Returns FALSE on error (eg invalid instance) + */ +bool_t ginputGetToggleStatus(uint16_t instance, GEventToggle *ptoggle) { + // Win32 threads don't seem to recognise priority and/or pre-emption + // so we add a sleep here to prevent 100% polled applications from locking up. + gfxSleepMilliseconds(1); + + if (instance >= GINPUT_TOGGLE_NUM_PORTS) + return FALSE; + ptoggle->type = GEVENT_TOGGLE; + ptoggle->instance = instance; + ptoggle->on = (ToggleStatus[instance].status & GINPUT_TOGGLE_ISON) ? TRUE : FALSE; + 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 /* GFX_USE_GINPUT && GINPUT_NEED_TOGGLE */ +/** @} */ diff --git a/src/ginput/ginput_toggle.h b/src/ginput/ginput_toggle.h new file mode 100644 index 00000000..7fc075d6 --- /dev/null +++ b/src/ginput/ginput_toggle.h @@ -0,0 +1,100 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @file src/ginput/ginput_toggle.h + * @brief GINPUT GFX User Input subsystem header file. + * + * @defgroup Toggle Toggle + * @ingroup GINPUT + * + * @details GINPUT allows it to interface toggle buttons easily to your + * application. + * + * @pre GFX_USE_GINPUT must be set to TRUE in your gfxconf.h + * @pre GINPUT_NEED_TOGGLE must be set to TRUE in your gfxconf.h + * + * @{ + */ + +#ifndef _GINPUT_TOGGLE_H +#define _GINPUT_TOGGLE_H + +#if GINPUT_NEED_TOGGLE || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Low Level Driver details and error checks. */ +/*===========================================================================*/ + +// Get the hardware definitions - Number of instances etc. +#include "ginput_lld_toggle_config.h" + +#ifndef GINPUT_TOGGLE_POLL_PERIOD + #define GINPUT_TOGGLE_POLL_PERIOD 200 +#endif + +/*===========================================================================*/ +/* Type definitions */ +/*===========================================================================*/ + +// Event types for various ginput sources +#define GEVENT_TOGGLE (GEVENT_GINPUT_FIRST+3) + +typedef struct GEventToggle_t { + GEventType type; // The type of this event (GEVENT_TOGGLE) + uint16_t instance; // The toggle instance + bool_t on; // True if the toggle/button is on + } GEventToggle; + +// Toggle Listen Flags - passed to geventAddSourceToListener() +#define GLISTEN_TOGGLE_ON 0x0001 // Return an event when the toggle turns on +#define GLISTEN_TOGGLE_OFF 0x0002 // Return an event when the toggle turns off + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + + /** + * @brief Create a toggle input instance + * + * @param[in] instance The ID of the toggle input instance (from 0 to 9999) + * + * @return The source handle of the created instance + */ + GSourceHandle ginputGetToggle(uint16_t instance); + + /** + * @brief Can be used to invert the sense of a toggle + * + * @param[in] instance The ID of the toggle input instance + * @param[in] invert If TRUE, will be inverted + */ + void ginputInvertToggle(uint16_t instance, bool_t invert); + + /** + * @brief Get the current toggle status + * + * @param[in] instance The ID of the toggle input instance + * @param[in] ptoggle The toggle event struct + * + * @return Returns FALSE on an error (eg invalid instance) + */ + bool_t ginputGetToggleStatus(uint16_t instance, GEventToggle *ptoggle); + +#ifdef __cplusplus +} +#endif + +#endif /* GINPUT_NEED_TOGGLE */ + +#endif /* _GINPUT_TOGGLE_H */ +/** @} */ + diff --git a/src/ginput/keyboard.c b/src/ginput/keyboard.c deleted file mode 100644 index 98fad414..00000000 --- a/src/ginput/keyboard.c +++ /dev/null @@ -1,23 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -/** - * @file src/ginput/keyboard.c - * @brief GINPUT keyboard code. - * - * @defgroup Keyboard Keyboard - * @ingroup GINPUT - * - * @{ - */ - -#include "gfx.h" - -#if (GFX_USE_GINPUT && GINPUT_NEED_KEYBOARD) || defined(__DOXYGEN__) - #error "GINPUT: GINPUT_NEED_KEYBOARD - Not Implemented Yet" -#endif /* GFX_USE_GINPUT && GINPUT_NEED_KEYBOARD */ -/** @} */ diff --git a/src/ginput/keyboard.h b/src/ginput/keyboard.h deleted file mode 100644 index eff5cc6f..00000000 --- a/src/ginput/keyboard.h +++ /dev/null @@ -1,128 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -/** - * @file src/ginput/keyboard.h - * @brief GINPUT GFX User Input subsystem header file. - * - * @defgroup Keyboard Keyboard - * @ingroup GINPUT - * @{ - */ - -#ifndef _GINPUT_KEYBOARD_H -#define _GINPUT_KEYBOARD_H - -#if GINPUT_NEED_KEYBOARD || defined(__DOXYGEN__) - -/*===========================================================================*/ -/* Type definitions */ -/*===========================================================================*/ - -#define GINPUT_KEYBOARD_NUM_PORTS 1 // The total number of keyboard inputs - -// Event types for various ginput sources -#define GEVENT_KEYBOARD (GEVENT_GINPUT_FIRST+2) - -typedef struct GEventKeyboard_t { - GEventType type; // The type of this event (GEVENT_KEYBOARD) - uint16_t instance; // The keyboard instance - char c; // The Ascii code for the current key press. - // The only possible values are 0(NUL), 8(BS), 9(TAB), 13(CR), 27(ESC), 32(SPACE) to 126(~), 127(DEL) - // 0 indicates an extended only key. - uint16_t code; // An extended keyboard code. Codes less than 128 match their ascii equivelent. - #define GKEY_NULL 0 - #define GKEY_BACKSPACE 8 - #define GKEY_TAB 9 - #define GKEY_CR 13 - #define GKEY_ESC 27 - #define GKEY_SPACE 32 - #define GKEY_DEL 127 - #define GKEY_UP 0x0101 - #define GKEY_DOWN 0x0102 - #define GKEY_LEFT 0x0103 - #define GKEY_RIGHT 0x0104 - #define GKEY_HOME 0x0105 - #define GKEY_END 0x0106 - #define GKEY_PAGEUP 0x0107 - #define GKEY_PAGEDOWN 0x0108 - #define GKEY_INSERT 0x0109 - #define GKEY_DELETE 0x010A - #define GKEY_SHIFT 0x0201 - #define GKEY_CNTRL 0x0202 - #define GKEY_ALT 0x0203 - #define GKEY_WINKEY 0x0204 - #define GKEY_RCLKEY 0x0205 - #define GKEY_FNKEY 0x0206 - #define GKEY_FN1 0x0301 - #define GKEY_FN2 0x0302 - #define GKEY_FN3 0x0303 - #define GKEY_FN4 0x0304 - #define GKEY_FN5 0x0305 - #define GKEY_FN6 0x0306 - #define GKEY_FN7 0x0307 - #define GKEY_FN8 0x0308 - #define GKEY_FN9 0x0309 - #define GKEY_FN10 0x030A - #define GKEY_FN11 0x030B - #define GKEY_FN12 0x030C - uint16_t current_buttons; // A bit is set to indicate various meta status. - #define GMETA_KEY_DOWN 0x0001 - #define GMETA_KEY_SHIFT 0x0002 - #define GMETA_KEY_CNTRL 0x0004 - #define GMETA_KEY_ALT 0x0008 - #define GMETA_KEY_WINKEY 0x0010 - #define GMETA_KEY_RCLKKEY 0x0020 - #define GMETA_KEY_FN 0x0040 - #define GMETA_KEY_MISSED_EVENT 0x8000 - uint16_t last_buttons; // The value of current_buttons on the last event -} GEventKeyboard; - -// Keyboard Listen Flags - passed to geventAddSourceToListener() -#define GLISTEN_KEYREPEATS 0x0001 // Return key repeats (where the key is held down to get a repeat character) -#define GLISTEN_KEYCODES 0x0002 // Return all key presses including extended code key presses (not just ascii codes) -#define GLISTEN_KEYALL 0x0004 // Return keyup's, keydown's and everything in between (but not repeats unless GLISTEN_KEYREPEATS is set). -#define GLISTEN_KEYSINGLE 0x8000 // Return only when one particular extended code key is pressed or released. The particular extended code is OR'd into this value - // eg. (GLISTEN_KEYSINGLE | GKEY_CR) - // No other flags may be set with this flag. - -/*===========================================================================*/ -/* External declarations. */ -/*===========================================================================*/ - -#ifdef __cplusplus -extern "C" { -#endif - - /** - * @brief Create a keyboard input instance - * - * @param[in] instance The ID of the keyboard input instance (from 0 to 9999) - * - * @return The source handle of the created input instance - */ - GSourceHandle ginputGetKeyboard(uint16_t instance); - - /** - * @brief Get the current keyboard status - * - * @param[in] instance The ID of the keyboard input instance - * @param[in] pkeyboard The keyboard event struct - * - * @return Returns FALSE on an error (eg invalid instance) - */ - bool_t ginputGetKeyboardStatus(uint16_t instance, GEventKeyboard *pkeyboard); - -#ifdef __cplusplus -} -#endif - -#endif /* GINPUT_NEED_KEYBOARD */ - -#endif /* _GINPUT_KEYBOARD_H */ -/** @} */ - diff --git a/src/ginput/mouse.c b/src/ginput/mouse.c deleted file mode 100644 index f7842e33..00000000 --- a/src/ginput/mouse.c +++ /dev/null @@ -1,679 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -/** - * @file src/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__) - -#include "src/ginput/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" - #endif - - #include // Required for memcpy - - #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!" - - #if GINPUT_MOUSE_MAX_CALIBRATION_ERROR < 0 - #define GINPUT_MOUSE_CALIBRATION_POINTS 3 - #else - #define GINPUT_MOUSE_CALIBRATION_POINTS 4 - #endif - - typedef struct Calibration_t { - float ax; - float bx; - float cx; - float ay; - float by; - float cy; - } Calibration; -#endif - -typedef struct MousePoint_t { - coord_t x, y; -} MousePoint; - -static GTIMER_DECL(MouseTimer); - -static struct MouseConfig_t { - MouseReading t; - MousePoint movepos; - MousePoint clickpos; - systemticks_t clicktime; - uint16_t last_buttons; - uint16_t flags; - #define FLG_INIT_DONE 0x8000 - #define FLG_CLICK_TIMER 0x0001 - #define FLG_IN_CAL 0x0010 - #define FLG_CAL_OK 0x0020 - #define FLG_CAL_SAVED 0x0040 - #define FLG_CAL_FREE 0x0080 - #define FLG_CAL_RAW 0x0100 - #if GINPUT_MOUSE_NEED_CALIBRATION - GMouseCalibrationSaveRoutine fnsavecal; - GMouseCalibrationLoadRoutine fnloadcal; - Calibration caldata; - #endif - GDisplay * display; -} MouseConfig; - -void _tsOrientClip(MouseReading *pt, GDisplay *g, bool_t doClip) { - coord_t w, h; - - w = gdispGGetWidth(g); - h = gdispGGetHeight(g); - - #if GDISP_NEED_CONTROL && !GINPUT_MOUSE_NO_ROTATION - switch(gdispGGetOrientation(g)) { - case GDISP_ROTATE_0: - break; - case GDISP_ROTATE_90: - { - coord_t t = pt->x; - pt->x = w - 1 - pt->y; - pt->y = t; - } - break; - case GDISP_ROTATE_180: - pt->x = w - 1 - pt->x; - pt->y = h - 1 - pt->y; - break; - case GDISP_ROTATE_270: - { - coord_t t = pt->y; - pt->y = h - 1 - pt->x; - pt->x = t; - } - break; - default: - break; - } - #endif - - if (doClip) { - if (pt->x < 0) pt->x = 0; - else if (pt->x >= w) pt->x = w-1; - if (pt->y < 0) pt->y = 0; - else if (pt->y >= h) pt->y = h-1; - } -} - -#if GINPUT_MOUSE_NEED_CALIBRATION - static inline void _tsSetIdentity(Calibration *c) { - c->ax = 1; - c->bx = 0; - c->cx = 0; - c->ay = 0; - c->by = 1; - c->cy = 0; - } - - 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); - - 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)); - - 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)); - - 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)); - - 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)); - } - - static inline void _tsClearCross(const MousePoint *pp) { - gdispGFillArea(MouseConfig.display, pp->x - 15, pp->y - 15, 42, 42, Blue); - } - - 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 _tsDo3PointCalibration(const MousePoint *cross, const MousePoint *points, GDisplay *g, Calibration *c) { - float dx; - coord_t c0, c1, c2; - - #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; - } - #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; - - #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; - } - #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; - } -#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; - } - - /* 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 - -static void get_calibrated_reading(MouseReading *pt) { - get_raw_reading(pt); - - #if GINPUT_MOUSE_NEED_CALIBRATION - _tsTransform(pt, &MouseConfig.caldata); - #endif - - _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; - } - - // 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; - } - - // 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; - } - - // 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; - } - } - - // Send the event to the listeners that are interested. - psl = 0; - while ((psl = geventGetSourceListener((GSourceHandle)(&MouseConfig), psl))) { - if (!(pe = (GEventMouse *)geventGetEventBuffer(psl))) { - // This listener is missing - save the meta events that have happened - psl->srcflags |= meta; - continue; - } - - // If we haven't really moved (and there are no meta events) don't bother sending the event - if (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; - } - 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; - - // Do we need to initialise the mouse subsystem? - if (!(MouseConfig.flags & FLG_INIT_DONE)) { - ginput_lld_mouse_init(); - - #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); - #endif - - // 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); - } - - // Return our structure as the handle - return (GSourceHandle)&MouseConfig; -} - -void ginputSetMouseDisplay(uint16_t instance, GDisplay *g) { - if (instance) - return; - - MouseConfig.display = g ? g : GDISP; -} - -GDisplay *ginputGetMouseDisplay(uint16_t instance) { - if (instance) - return 0; - - 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); - - if (instance || (MouseConfig.flags & (FLG_INIT_DONE|FLG_IN_CAL)) != FLG_INIT_DONE) - return FALSE; - - 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; -} - -bool_t ginputCalibrateMouse(uint16_t instance) { - #if !GINPUT_MOUSE_NEED_CALIBRATION - (void) instance; - - return FALSE; - #else - - const coord_t height = gdispGGetHeight(MouseConfig.display); - const coord_t width = gdispGGetWidth(MouseConfig.display); - #if GINPUT_MOUSE_CALIBRATE_EXTREMES - const MousePoint cross[] = {{0, 0}, - {(width - 1) , 0}, - {(width - 1) , (height - 1)}, - {(width / 2), (height / 2)}}; /* Check point */ - #else - const MousePoint cross[] = {{(width / 4), (height / 4)}, - {(width - (width / 4)) , (height / 4)}, - {(width - (width / 4)) , (height - (height / 4))}, - {(width / 2), (height / 2)}}; /* Check point */ - #endif - MousePoint points[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 - - if (instance || (MouseConfig.flags & FLG_IN_CAL)) - return FALSE; - - font1 = gdispOpenFont(GINPUT_MOUSE_CALIBRATION_FONT); - font2 = gdispOpenFont(GINPUT_MOUSE_CALIBRATION_FONT2); - - MouseConfig.flags |= FLG_IN_CAL; - gtimerStop(&MouseTimer); - MouseConfig.flags &= ~(FLG_CAL_OK|FLG_CAL_SAVED|FLG_CAL_RAW); - - #if GDISP_NEED_CLIP - gdispGSetClip(MouseConfig.display, 0, 0, width, height); - #endif - - #if GINPUT_MOUSE_MAX_CALIBRATION_ERROR >= 0 - while(1) { - #endif - gdispGClear(MouseConfig.display, Blue); - - gdispGFillStringBox(MouseConfig.display, 0, 5, width, 30, GINPUT_MOUSE_CALIBRATION_TEXT, font1, White, Blue, justifyCenter); - - for(i = 0, pt = points, pc = cross; i < GINPUT_MOUSE_CALIBRATION_POINTS; i++, pt++, pc++) { - _tsDrawCross(pc); - - do { - - /* Wait for the mouse to be pressed */ - while(get_raw_reading(&MouseConfig.t), !(MouseConfig.t.buttons & GINPUT_MOUSE_BTN_LEFT)) - gfxSleepMilliseconds(20); - - /* Average all the samples while the mouse is down */ - for(px = py = 0, j = 0; - gfxSleepMilliseconds(20), /* Settling time between readings */ - get_raw_reading(&MouseConfig.t), - (MouseConfig.t.buttons & GINPUT_MOUSE_BTN_LEFT); - j++) { - px += MouseConfig.t.x; - py += MouseConfig.t.y; - } - - } while(!j); - - pt->x = px / j; - pt->y = py / j; - - _tsClearCross(pc); - - if (i >= 1 && pt->x == (pt-1)->x && pt->y == (pt-1)->y) { - gdispGFillStringBox(MouseConfig.display, 0, 35, width, 40, GINPUT_MOUSE_CALIBRATION_SAME_TEXT, font2, Red, Yellow, justifyCenter); - gfxSleepMilliseconds(5000); - gdispGFillArea(MouseConfig.display, 0, 35, width, 40, Blue); - } - - } - - /* Apply 3 point calibration algorithm */ - _tsDo3PointCalibration(cross, points, MouseConfig.display, &MouseConfig.caldata); - - /* 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; - - gdispGFillStringBox(MouseConfig.display, 0, 35, width, 40, GINPUT_MOUSE_CALIBRATION_ERROR_TEXT, font2, Red, Yellow, justifyCenter); - gfxSleepMilliseconds(5000); - } - #endif - - // Restart everything - gdispCloseFont(font1); - gdispCloseFont(font2); - MouseConfig.flags |= FLG_CAL_OK; - MouseConfig.last_buttons = 0; - get_calibrated_reading(&MouseConfig.t); - MouseConfig.flags &= ~FLG_IN_CAL; - if ((MouseConfig.flags & FLG_INIT_DONE)) - gtimerStart(&MouseTimer, MousePoll, 0, TRUE, GINPUT_MOUSE_POLL_PERIOD); - - // Save the calibration data (if possible) - if (MouseConfig.fnsavecal) { - MouseConfig.fnsavecal(instance, (const uint8_t *)&MouseConfig.caldata, sizeof(MouseConfig.caldata)); - MouseConfig.flags |= FLG_CAL_SAVED; - } - - // Clear the screen using the GWIN default background color - #if GFX_USE_GWIN - gdispGClear(MouseConfig.display, gwinGetDefaultBgColor()); - #else - gdispGClear(MouseConfig.display, Black); - #endif - - return TRUE; - #endif -} - -/* 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) - return; - - MouseConfig.fnloadcal = fnload; - MouseConfig.fnsavecal = fnsave; - if (requireFree) - MouseConfig.flags |= FLG_CAL_FREE; - 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 -} - -/* Test if a particular mouse instance requires routines to save its calibration data. */ -bool_t ginputRequireMouseCalibrationStorage(uint16_t instance) { - if (instance) - return FALSE; - - #if GINPUT_MOUSE_NEED_CALIBRATION && !GINPUT_MOUSE_LLD_CALIBRATION_LOADSAVE - return TRUE; - #else - return FALSE; - #endif -} - -/* Wake up the mouse driver from an interrupt service routine (there may be new readings available) */ -void ginputMouseWakeup(void) { - gtimerJab(&MouseTimer); -} - -/* Wake up the mouse driver from an interrupt service routine (there may be new readings available) */ -void ginputMouseWakeupI(void) { - gtimerJabI(&MouseTimer); -} - -#endif /* GFX_USE_GINPUT && GINPUT_NEED_MOUSE */ -/** @} */ diff --git a/src/ginput/mouse.h b/src/ginput/mouse.h deleted file mode 100644 index 79ad1f08..00000000 --- a/src/ginput/mouse.h +++ /dev/null @@ -1,181 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -/** - * @file src/ginput/mouse.h - * @brief GINPUT GFX User Input subsystem header file for mouse and touch. - * - * @defgroup Mouse Mouse - * @ingroup GINPUT - * - * @details GINPUT allows it to easily interface touchscreens and mices to - * your application. - * - * @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 - * - * @{ - */ - -#ifndef _GINPUT_MOUSE_H -#define _GINPUT_MOUSE_H - -#if GINPUT_NEED_MOUSE || defined(__DOXYGEN__) - -/*===========================================================================*/ -/* Type definitions */ -/*===========================================================================*/ - -/* 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; - GDisplay * display; // The display this mouse is currently associated with. - } GEventMouse; - -// Mouse/Touch Listen Flags - passed to geventAddSourceToListener() -#define GLISTEN_MOUSEMETA 0x0001 // Create events for meta events such as CLICK and CXTCLICK -#define GLISTEN_MOUSEDOWNMOVES 0x0002 // Creates mouse move events when the primary mouse button is down (touch is on the surface) -#define GLISTEN_MOUSEUPMOVES 0x0004 // Creates mouse move events when the primary mouse button is up (touch is off the surface - if the hardware allows). -#define GLISTEN_MOUSENOFILTER 0x0008 // Don't filter out mouse moves where the position hasn't changed. -#define GLISTEN_TOUCHMETA GLISTEN_MOUSEMETA -#define GLISTEN_TOUCHDOWNMOVES GLISTEN_MOUSEDOWNMOVES -#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) - -/*===========================================================================*/ -/* External declarations. */ -/*===========================================================================*/ - -#ifdef __cplusplus -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! - * - * @param[in] instance The ID of the mouse input instance (from 0 to 9999) - * - * @return The source handle of the created instance - */ - GSourceHandle ginputGetMouse(uint16_t instance); - - /** - * @brief Assign the display associated with the mouse - * @note This only needs to be called if the mouse is associated with a display - * other than the current default display. It must be called before - * @p ginputGetMouse() if the new display is to be used during the calibration - * process. Other than calibration the display is used for range checking, - * and may also be used to display a mouse pointer. - * - * @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); - - /** - * @brief Get the display currently associated with the mouse - * @return A pointer to the display - * - * @param[in] instance The ID of the mouse input instance - */ - GDisplay *ginputGetMouseDisplay(uint16_t instance); - - /** - * @brief Get the current mouse position and button status - * @note Unlinke a listener event, this status cannot record meta events such as - * "CLICK". - * - * @param[in] instance The ID of the mouse input instance - * @param[in] pmouse The mouse event - * - * @return FALSE on an error (eg. invalid instance) - */ - bool_t ginputGetMouseStatus(uint16_t instance, GEventMouse *pmouse); - - /** - * @brief Performs a calibration - * - * @param[in] instance The ID of the mouse input instance - * - * @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 - * - * @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. - * - * @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); - - /** - * @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 - -#endif /* GINPUT_NEED_MOUSE */ - -#endif /* _GINPUT_MOUSE_H */ -/** @} */ - diff --git a/src/ginput/sys_defs.h b/src/ginput/sys_defs.h index 33259da4..cab1e15d 100644 --- a/src/ginput/sys_defs.h +++ b/src/ginput/sys_defs.h @@ -39,10 +39,10 @@ */ // Include various ginput types -#include "src/ginput/mouse.h" -#include "src/ginput/keyboard.h" -#include "src/ginput/toggle.h" -#include "src/ginput/dial.h" +#include "ginput_mouse.h" +#include "ginput_keyboard.h" +#include "ginput_toggle.h" +#include "ginput_dial.h" #endif /* GFX_USE_GINPUT */ diff --git a/src/ginput/sys_make.mk b/src/ginput/sys_make.mk index 34ac4a55..9abe1645 100644 --- a/src/ginput/sys_make.mk +++ b/src/ginput/sys_make.mk @@ -1,5 +1,5 @@ -GFXSRC += $(GFXLIB)/src/ginput/ginput.c \ - $(GFXLIB)/src/ginput/mouse.c \ - $(GFXLIB)/src/ginput/keyboard.c \ - $(GFXLIB)/src/ginput/toggle.c \ - $(GFXLIB)/src/ginput/dial.c +GFXSRC += $(GFXLIB)/src/ginput/ginput_ginput.c \ + $(GFXLIB)/src/ginput/ginput_mouse.c \ + $(GFXLIB)/src/ginput/ginput_keyboard.c \ + $(GFXLIB)/src/ginput/ginput_toggle.c \ + $(GFXLIB)/src/ginput/ginput_dial.c diff --git a/src/ginput/toggle.c b/src/ginput/toggle.c deleted file mode 100644 index aad9c862..00000000 --- a/src/ginput/toggle.c +++ /dev/null @@ -1,156 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -/** - * @file src/ginput/toggle.c - * @brief GINPUT toggle code. - * - * @defgroup Toggle Toggle - * @ingroup GINPUT - * @{ - */ -#include "gfx.h" - -#if (GFX_USE_GINPUT && GINPUT_NEED_TOGGLE) || defined(__DOXYGEN__) - -#include "src/ginput/driver_toggle.h" - -#define GINPUT_TOGGLE_ISON 0x01 -#define GINPUT_TOGGLE_INVERT 0x02 - -static GTIMER_DECL(ToggleTimer); -static struct GEventToggleStatus_t { - uint8_t status; -} ToggleStatus[GINPUT_TOGGLE_NUM_PORTS]; - -// Our polling function -static void TogglePoll(void *param) { - (void) param; - - const GToggleConfig *ptc; - GSourceListener *psl; - GEventToggle *pe; - unsigned i, bits, mask; - uint8_t state; - - // Loop while there are bits to get - for(ptc = GInputToggleConfigTable, i=0; i < GINPUT_TOGGLE_NUM_PORTS; ptc++) { - - // Get the next block of bits - bits = ginput_lld_toggle_getbits(ptc) ^ ptc->invert; - - // Extract the bits of use - for(mask = ptc->mask; i < GINPUT_TOGGLE_NUM_PORTS && mask; mask >>= 1, bits >>= 1) { - // Ignore bits not in our mask - if (!(mask & 1)) - continue; - - // Calculate our new state - state = ToggleStatus[i].status & ~GINPUT_TOGGLE_ISON; - if (state & GINPUT_TOGGLE_INVERT) - bits ^= 1; - if (bits & 1) - state |= GINPUT_TOGGLE_ISON; - - // Has it changed? - if ((state ^ ToggleStatus[i].status) & GINPUT_TOGGLE_ISON) { - - // Save the new state - ToggleStatus[i].status = state; - - // Send the event to the listeners that are interested. - psl = 0; - while ((psl = geventGetSourceListener((GSourceHandle)(ToggleStatus+i), psl))) { - if (!(pe = (GEventToggle *)geventGetEventBuffer(psl))) - continue; - if ((state & GINPUT_TOGGLE_ISON)) { - if ((psl->listenflags & GLISTEN_TOGGLE_ON)) { - pe->type = GEVENT_TOGGLE; - pe->instance = i; - pe->on = TRUE; - geventSendEvent(psl); - } - } else { - if ((psl->listenflags & GLISTEN_TOGGLE_OFF)) { - pe->type = GEVENT_TOGGLE; - pe->instance = i; - pe->on = FALSE; - geventSendEvent(psl); - } - } - } - } - - // Next toggle switch - i++; - } - } -} - -/* Hardware Toggle/Switch/Button Functions */ -GSourceHandle ginputGetToggle(uint16_t instance) { - const GToggleConfig *ptc; - - if (instance >= GINPUT_TOGGLE_NUM_PORTS) - return 0; - - // Do we need to initialise the toggle subsystem? - if (!gtimerIsActive(&ToggleTimer)) { - for(ptc = GInputToggleConfigTable; ptc < GInputToggleConfigTable+sizeof(GInputToggleConfigTable)/sizeof(GInputToggleConfigTable[0]); ptc++) - ginput_lld_toggle_init(ptc); - gtimerStart(&ToggleTimer, TogglePoll, 0, TRUE, GINPUT_TOGGLE_POLL_PERIOD); - } - - // OK - return this input - return (GSourceHandle)(ToggleStatus+instance); -} - -// If invert is true, invert the on/off sense for the toggle -void ginputInvertToggle(uint16_t instance, bool_t invert) { - if (instance >= GINPUT_TOGGLE_NUM_PORTS) - return; - if (invert) { - if (!(ToggleStatus[instance].status & GINPUT_TOGGLE_INVERT)) { - ToggleStatus[instance].status |= GINPUT_TOGGLE_INVERT; - ToggleStatus[instance].status ^= GINPUT_TOGGLE_ISON; - } - } else { - if ((ToggleStatus[instance].status & GINPUT_TOGGLE_INVERT)) { - ToggleStatus[instance].status &= ~GINPUT_TOGGLE_INVERT; - ToggleStatus[instance].status ^= GINPUT_TOGGLE_ISON; - } - } -} - -/* Get the current toggle status. - * Returns FALSE on error (eg invalid instance) - */ -bool_t ginputGetToggleStatus(uint16_t instance, GEventToggle *ptoggle) { - // Win32 threads don't seem to recognise priority and/or pre-emption - // so we add a sleep here to prevent 100% polled applications from locking up. - gfxSleepMilliseconds(1); - - if (instance >= GINPUT_TOGGLE_NUM_PORTS) - return FALSE; - ptoggle->type = GEVENT_TOGGLE; - ptoggle->instance = instance; - ptoggle->on = (ToggleStatus[instance].status & GINPUT_TOGGLE_ISON) ? TRUE : FALSE; - 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 /* GFX_USE_GINPUT && GINPUT_NEED_TOGGLE */ -/** @} */ diff --git a/src/ginput/toggle.h b/src/ginput/toggle.h deleted file mode 100644 index 40149754..00000000 --- a/src/ginput/toggle.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -/** - * @file src/ginput/toggle.h - * @brief GINPUT GFX User Input subsystem header file. - * - * @defgroup Toggle Toggle - * @ingroup GINPUT - * - * @details GINPUT allows it to interface toggle buttons easily to your - * application. - * - * @pre GFX_USE_GINPUT must be set to TRUE in your gfxconf.h - * @pre GINPUT_NEED_TOGGLE must be set to TRUE in your gfxconf.h - * - * @{ - */ - -#ifndef _GINPUT_TOGGLE_H -#define _GINPUT_TOGGLE_H - -#if GINPUT_NEED_TOGGLE || defined(__DOXYGEN__) - -/*===========================================================================*/ -/* Low Level Driver details and error checks. */ -/*===========================================================================*/ - -// Get the hardware definitions - Number of instances etc. -#include "ginput_lld_toggle_config.h" - -#ifndef GINPUT_TOGGLE_POLL_PERIOD - #define GINPUT_TOGGLE_POLL_PERIOD 200 -#endif - -/*===========================================================================*/ -/* Type definitions */ -/*===========================================================================*/ - -// Event types for various ginput sources -#define GEVENT_TOGGLE (GEVENT_GINPUT_FIRST+3) - -typedef struct GEventToggle_t { - GEventType type; // The type of this event (GEVENT_TOGGLE) - uint16_t instance; // The toggle instance - bool_t on; // True if the toggle/button is on - } GEventToggle; - -// Toggle Listen Flags - passed to geventAddSourceToListener() -#define GLISTEN_TOGGLE_ON 0x0001 // Return an event when the toggle turns on -#define GLISTEN_TOGGLE_OFF 0x0002 // Return an event when the toggle turns off - -/*===========================================================================*/ -/* External declarations. */ -/*===========================================================================*/ - -#ifdef __cplusplus -extern "C" { -#endif - - /** - * @brief Create a toggle input instance - * - * @param[in] instance The ID of the toggle input instance (from 0 to 9999) - * - * @return The source handle of the created instance - */ - GSourceHandle ginputGetToggle(uint16_t instance); - - /** - * @brief Can be used to invert the sense of a toggle - * - * @param[in] instance The ID of the toggle input instance - * @param[in] invert If TRUE, will be inverted - */ - void ginputInvertToggle(uint16_t instance, bool_t invert); - - /** - * @brief Get the current toggle status - * - * @param[in] instance The ID of the toggle input instance - * @param[in] ptoggle The toggle event struct - * - * @return Returns FALSE on an error (eg invalid instance) - */ - bool_t ginputGetToggleStatus(uint16_t instance, GEventToggle *ptoggle); - -#ifdef __cplusplus -} -#endif - -#endif /* GINPUT_NEED_TOGGLE */ - -#endif /* _GINPUT_TOGGLE_H */ -/** @} */ - -- cgit v1.2.3