//--- // gint:keyboard - Keyboard input //--- #ifndef GINT_KEYBOARD #define GINT_KEYBOARD /* Keyboard, key events and getkey() gint's keyboard driver regularly scans the keyboard matrix and produces *key events*, the most primitive type of event exposed to the user. A key event basically says that a key has been pressed, held, or released at some point in time. They are suited for real-time applications like games. - pollevent() fetches the next queued keyboard event, and returns an event of type KEYEV_NONE if none is available. - waitevent() fetches the next queued keyboard event and waits if none is available. The timeout can be configured. GUI programs like the system applications will prefer using a GetKey()-like functions that return a single key press at a time, heeds for releases, for SHIFT and ALPHA modifiers, handles backlight and return-to-menu. - getkey_opt() is gint's enhanced GetKey()-like function, with support for custom repetition and many fine-tunable options. - getkey() is a specific call to getkey_opt(), that imitates GetKey(). */ #include #include /* key_event_t - any keyboard event This structure represents an event that occurs on the keyboard. This is a low-level structure that is produced by the keyboard scanner. It reports key presses, key releases, and key repeats. These events are detected and reported each time the keyboard is scanned, which is 128 Hz by default, so you'll get 128 repeat events by second if a key is kept pressed. We could filter the events to emit one only every second, for example, but it's difficult to do it for all keys at the same time. Thus the control of repeat delays is left to getkey(). When [mod = 1], attributes [shift] and [alpha] indicate whether the key has been modified. Only key press events returned by getkey() have [mod = 1]. Note that you can't have, e.g. [key=KEY_SHIFT] and [mod=1] at the same time. The [time] attribute indicates when the event occurred. It is a snapshot of a time counter that increases at each keyboard scan and *wraps around every 8 minutes* (at 128 Hz). I expect this attribute to be useful to analyze combo sequences in games. Make sure you are aware of the two nitpicks: * Don't keep the time values for too long because of the wrap-around effect. * 0xffff is "just before" 0x0000, not "long after". */ typedef struct { uint time :16; /* Time of event, unique over short periods */ uint :3; /* Reserved for future use */ uint mod :1; /* Whether modifiers are used */ uint shift :1; /* If mod=1, whether SHIFT was pressed */ uint alpha :1; /* If mod=1, whether ALPHA was pressed */ uint type :2; /* Type of key event */ uint key :8; /* Hit key */ } GPACKED(4) key_event_t; /* Keyboard event types, as in the type field of key_event_t */ enum { KEYEV_NONE = 0, /* No event available (poll() only) */ KEYEV_DOWN = 1, /* Key was pressed */ KEYEV_UP = 2, /* Key was released */ KEYEV_HOLD = 3, /* A key that was pressed has been held down */ }; /* Size of the buffer event queue, can be customized using gint's configure script before compiling the library. Better be a power of 2. */ #ifndef KEYBOARD_QUEUE_SIZE #define KEYBOARD_QUEUE_SIZE 64 #endif /* Keyboard frequency analysis, must be at least 64 for the keyboard to work, and at most 32768 for the extra timer to support it. Better if a power of 2. TODO: Add a configure or runtime setting for KEYBOARD_SCAN_FREQUENCY */ #ifndef KEYBOARD_SCAN_FREQUENCY #define KEYBOARD_SCAN_FREQUENCY 128 #endif //--- // Keyboard functions //--- /* pollevent() - poll the next keyboard event This function returns the next yet-unpolled event from the keyboard buffer. If no event is available, it returns a dummy event with type = KEYEV_NONE. This event has always mod = 0, shift = 0, alpha = 0. */ key_event_t pollevent(void); /* waitevent() - wait for the next keyboard event This function works as pollevent() but waits if no event is available. When timeout = NULL, it waits indefinitely. Otherwise, it waits until *timeout becomes non-zero. It is particularly suitable to set *timeout to 1 using a timer with [timer_timeout] as callback. See . */ key_event_t waitevent(volatile int *timeout); /* getkey() - wait for a pressed key This function mimics the behavior of the fxlib GetKey(). It returns a key_event_t object where [mod=1], and where [shift] and [alpha] indicate whether SHIFT or ALPHA was pressed before the key was hit. [event] is KEYEV_DOWN when a new key is pressed and KEYEV_HOLD in case of repeats. Similarities with GetKey() include: - Wait for a key to be pressed *after* the call (held keys don't count) - Supports SHIFT and ALPHA modifiers - Repeats arrows keys - Allows return to main menu if the MENU key is pressed - Controls backlight on models that have a back-lit screen getkey() is equivalent to getkey_opt(GETKEY_DEFAULT, NULL). */ key_event_t getkey(void); /* The following are the option bits for getkey_opt(). */ enum { /* Enable modifiers keys */ GETKEY_MOD_SHIFT = 0x01, GETKEY_MOD_ALPHA = 0x02, /* SHIFT + OPTN toggles backlight (requires GETKEY_MOD_SHIFT) */ GETKEY_BACKLIGHT = 0x04, /* MENU triggers a task switch and displays the main menu */ GETKEY_MENU = 0x08, /* Repeat arrow keys, or even all keys */ GETKEY_REP_ARROWS = 0x10, GETKEY_REP_ALL = 0x20, /* Default settings of getkey() */ GETKEY_DEFAULT = 0x1f, }; /* getkey_opt() - enhanced getkey() This function enhances getkey() with more general features. An or-combination of option flags (see above) must be supplied as first argument; 0 stands for no option. getkey_opt() returns the same kind of values as getkey(). getkey_opt() supports a generic timeout function in the form of a volatile pointer [timeout]. If it's NULL, getkey_opt() waits indefinitely. Otherwise, it waits until *timeout becomes non-zero. It's up to you to change the value whenever you want to interrupt the call; using a timer with [timer_timeout] as callback is suitable. @options An or-combination of values from the GETKEY_* enumeration @timeout Optional pointer to a timeout value Returns a key event of type KEYEV_DOWN or KEYEV_HOLD with [mod=1]. */ key_event_t getkey_opt(int options, volatile int *timeout); /* getkey_repeat() - set repeat delays for getkey() This function updates the repeat delays of getkey() and getkey_opt(). The unit of the argument is in milliseconds, but the granularity of the delay is dependent on the keyboard scan frequency. In the default setting (128 Hz scans), the possible repeat delays are approximately 8 ms, 16 ms, 23 ms, 31 ms... the provided arguments will be rounded to the closest feasible delays to ensure that repetitions are perfectly regular, rather than approximating the requested frequency. The system default is (625 ms, 25 ms). With the 128 Hz setting, this default will be approximated at (625 ms, 23.4375 ms). @first Delay between key press and first repeat (no more than one hour) @next Delay between subsequent repeats (no more than one hour) */ void getkey_repeat(int first, int next); #endif /* GINT_KEYBOARD */