t10 - olikraus/m2tklib GitHub Wiki
Touch screen support is available with v1.10 of M2tklib.
Topics covered by this tutorial:
- How to add touch screen support to M2tklib
- How to setup a touch screen
- How to build data entry screen / dialog boxes with touch screen support
Structure of this tutorial
- The next section (Quick Start) gives a short but complete instruction how to setup touch screen support for m2tklib
- The remaining part of the tutorial provides all information on setup and menu design for touch screen support.
Complete examples (four-wire resistive touch panel) are available for the u8glib variant of m2tklib. See the "TouchMenu"
and "TouchPanel"
examples. Template code is available for GLCD variant ("TouchMenu"
).
In most examples and tutorials, you will find a setup command, more or less similar to the following line:
M2tk m2(&top_el, m2_es_arduino, m2_eh_4bs, m2_gh_u8g_fbs);
Use the following code instead if you want to add touch screen support:
uint8_t m2_es_touch_screen(m2_p ep, uint8_t msg)
{
switch(msg)
{
case M2_ES_MSG_GET_KEY:
if ( check_for_touch_screen_press() )
{
/* (x,y) is a M2 position: (0,0) is lower left */
m2_SetEventSourceArgsM2(ep, get_touch_screen_x_position(), get_touch_screen_y_position() );
return M2_KEY_EVENT(M2_KEY_TOUCH_PRESS);
}
break;
case M2_ES_MSG_INIT:
break;
}
return m2_es_arduino(ep, msg);
}
M2tk m2(&top_el, m2_es_touch_screen, m2_eh_4bsts, m2_gh_u8g_fbs);
-
m2_es_arduino
is replaced by a custom procedurem2_es_touch_screen
-
m2_es_arduino
is called withinm2_es_touch_screen
-
m2_eh_4bs
is replaced bym2_eh_4bsts
-
check_for_touch_screen_press()
must return a none-zero value if the touch screen detects a "press" -
get_touch_screen_x_position()
andget_touch_screen_y_position()
must return the position on the touch screen for M2tklib.
All m2tk elements support the "t" flag. By setting the option "t1" the element will become sensitive to a touch screen press event. In the following example, the three menu buttons are made sensitive for touch screen press events by applying "t1":
M2_ROOT(el_ts_mnu1, "t1w60f8", "menu 1", &top_el_ts_mnu1_sel);
M2_ROOT(el_ts_mnu2, "t1w60f8", "menu 2", &top_el_ts_mnu2_sel);
M2_ROOT(el_ts_mnu3, "t1w60f8", "menu 3", &top_el_ts_mnu3_sel);
M2_LIST(list_ts_mnu) = {
&el_ts_mnu1,
&el_ts_mnu2,
&el_ts_mnu3
};
M2_VLIST(el_ts_mnu_vlist, NULL, list_ts_mnu);
M2_ALIGN(top_el_ts_mnu, "-1|1W64H64", &el_ts_mnu_vlist);
The rest of the tutorial covers the following topics:
- Detailed discussion of the setup for touch screens
- Additional options to setup touch screen support
- Design guidelines for touch screen menus
- Detailed description fo the "t" flag
- Additional design features for menus with the TSK elements
A user interface is different if there is a touch screen (compared vs. push buttons).
- Touch screen: The user enters a specific position on the screen by hitting a specific position on the touch screen (focus change).
- Push buttons: One or more buttons are used to switch between selectable elements of the user interface (cursor, focus). There might be also buttons to increment and decrement data.
Common to both approches is, that there is a cursor which marks the element which has the current focus.
Within M2tklib the element, which has the focus, can receive a SELECT message to perfom an action (increment value, execute a procedure, etc).
- Touch screen: The SELECT message is generated by removing the "touch".
- Push buttons: The SELECT message is generated by releasing the "select" button.
To conclude this, differences are:
- Focus change
- Touch screen: Hit the screen
- Push buttons: Use prev/next buttons
- Sending SELECT message
- Touch screen: Remove preasure from touch screen
- Push buttons: Use select button
- Increase/decrease (numbers, combo element)
- Touch screen: Can be handled by SELECT, decrease not available
- Push buttons: Decrease/Increase buttons
- Home-Key function
- Touch screen: Not available
- Push buttons: Home button
About the "home key" function: Of course such a functionality can be implemented by adding a new selectable element to the dialog, which referes control to the home menu. But in principle, a dialog for a touch screen will be different from a menu for a screen with button control:
M2tklib menus must be designed either for push buttons or for touch screens. Only in some rare and simple cases the menu structure will be identical for both input methods.
The next three sections will introduce the three touch screen design approaches with M2tklib. Each approach can be used for a specific kind of input. It is probably worth to know all design methods:
Properties:
- Simple data entry/menus only
- Can be used with both input methods: Push buttons and touch screen
- Not suitable for U32NUM and TEXT elements.
- Any touch screen event handler can be used (e.g. m2_eh_ts)
Properties:
- Emulates push buttons on the touch screen
- Makes increase and decrease events available
- Can be used with all complex elements (U32NUM, TEXT, etc)
- Uses special touch screen elements (TSK, TSKXBM)
- Combined touch screen event handler must be used (e.g. m2_eh_6bsts, but m2_eh_ts can not be used)
Properties:
- Similar to the "Single Cursor Dialog"
- Values are updated by callback procedures
- Special design for touch screen
M2tklib does not know any touch screen events. Touch screen events must be delivered by a custom made event source.
/* custom event source for touch screen support */
uint8_t m2_es_touch_screen(m2_p ep, uint8_t msg)
{
switch(msg)
{
case M2_ES_MSG_GET_KEY:
/* check, if the touch screen is pressed */
if ( check_for_touch_screen_press() )
{
/* set x and y position of the touch screen */
/* (x,y) is a M2 position: (0,0) is lower left */
m2_SetEventSourceArgsM2(ep, get_touch_screen_x_position(), get_touch_screen_y_position() );
/* no debounce: return M2_KEY_EVENT(M2_KEY_TOUCH_PRESS); */
/* with debounce: return M2_KEY_TOUCH_PRESS; */
return M2_KEY_EVENT(M2_KEY_TOUCH_PRESS);
}
break;
case M2_ES_MSG_INIT:
break;
}
/* return 0 or call other event source */
return m2_es_arduino(ep, msg);
}
If M2tklib asks for an input event (msg == M2_ES_MSG_GET_KEY
), then the custom event source should check for the touch screen state and return an existing position on the touch screen:
- Check if the touch screen is pressed
- Inform M2tklib about the x/y position which has been pressed M2tklib is informed about the current x/y position by calling
void m2_SetEventSourceArgsM2(m2_p m2, uint8_t x, uint8_t y);
It might be required to transform and scale x and y values from the touch screen into the correct position for M2tklib (Position 0,0 is at lower left edge). Example:
x = ((uint16_t)x * (uint16_t)display_width) / (uint16_t)touch_screen_width;
y = ((uint16_t)y * (uint16_t)display_height) / (uint16_t)touch_screen_height;
y = display_height - 1 - y;
In the case, where a touch screen is pressed, the event source must set the position and return M2_KEY_TOUCH_PRESS
or M2_KEY_EVENT(M2_KEY_TOUCH_PRESS)
:
-
M2_KEY_TOUCH_PRESS
: The touch press event will be debounced by the internal M2tklib debounce algorithm. -
M2_KEY_EVENT(M2_KEY_TOUCH_PRESS)
: The touch press event will not be debounced by M2tklib.
After checking for the touch screen state, control can be refered to one of the existing event sources to check for buttons or other input events. Here are some examples:
Event Source | Environment | Remark |
---|---|---|
m2_es_arduino | Arduino | Check for buttons |
m2_es_arduino_serial | Arduino | Check for serial input |
m2_es_arduino_rotary_encoder | Arduino | Check for buttons and rotary encoder |
m2_es_avr_u8g | AVR | Check for buttons |
m2_es_avr_rotary_encoder_u8g | AVR | Check for buttons and rotary encoder |
An event source for the AVR, which checks for buttons and rotary encoder, might look like this:
uint8_t m2_es_touch_screen(m2_p ep, uint8_t msg)
{
switch(msg)
{
case M2_ES_MSG_GET_KEY:
if ( check_for_touch_screen_press() )
{
m2_SetEventSourceArgsM2(ep, get_touch_screen_x_position(), get_touch_screen_y_position() );
return M2_KEY_TOUCH_PRESS;
}
break;
}
return m2_es_avr_rotary_encoder_u8g(ep, msg);
}
A special event handler is required to handle touch screen messages from the event source. Event handler are:
Event handler | Remark |
---|---|
m2_eh_4bsts | Touch screen with 4 button support plus home key |
m2_eh_6bsts | Touch screen with 6 button support plus home key |
m2_eh_ts | Touch screen plus home key |
The pure touch screen handler m2_eh_ts
does not support touch screen key message generation: The TSK elements (such as M2_TSK) can not be used with the m2_eh_ts
handler.
The following tables gives an overview on usecases the prefered event source and handler. The "t" flag (see below) is always supported.
Usecase | Event Source | Handler | TSK-Elements | Remark |
---|---|---|---|---|
Touch screen with TSK elements and buttons | Touch screen and button | m2_eh_4bsts, m2_eh_6bsts | yes | |
Touch screen with TSK elements, no buttons | Touch screen | m2_eh_4bsts, m2_eh_6bsts | yes | |
Touch screen, no TSK elements, no buttons | Touch screen | m2_eh_ts | no | Minimal ROM consumption |
- The 't' flag turns an element (like M2_BUTTON) into a touch screen button.
- The 'r' only applies to the "cursor focus": If the 'r' (read only) flag is set, then the element is read only for any key strokes, but can still receive focus by the touch screen events.
't' flag value | 'r' flag value | Remark |
---|---|---|
t0 |
r0 |
Can receive focus from normal buttons, ignored by touch screen |
t1 |
r0 |
Can receive focus from normal buttons and can be selected by touch screen events |
t0 |
r1 |
The element is can not receive cursor focus and can not be selected by touch screen events |
t1 |
r1 |
The element is can not receive cursor focus, but can be selected with the touch screen |
If the 't' flag is set to 't1', then the corresponding element retrives a select message if selected by the touch screen. In the following example, M2_ROOT
is used as touch screen element:
M2_ROOT(el_ts_mnu1, "t1w60f8", "menu 1", &top_el_ts_mnu1_sel);
M2_ROOT(el_ts_mnu2, "t1w60f8", "menu 2", &top_el_ts_mnu2_sel);
M2_ROOT(el_ts_mnu3, "t1w60f8", "menu 3", &top_el_ts_mnu3_sel);
M2_LIST(list_ts_mnu) = {
&el_ts_mnu1,
&el_ts_mnu2,
&el_ts_mnu3
};
M2_VLIST(el_ts_mnu_vlist, NULL, list_ts_mnu);
M2_ALIGN(top_el_ts_mnu, "-1|1W64H64", &el_ts_mnu_vlist);
Note: In the (usual) case, where there is only a touch foil as input, always use "r1 (on Google Code)" together "t1" to avoid more than one cursor on the screen.
There is a new group of elements: Touch Screen Key (TSK) Elements. These elements behave exactly like external push buttons, but can generate key events. These elements are very useful to emulate push buttons.
In the following example, four TSK elements implement cursor control (left/right arrow) and data input (up/down arrow) for a M2_U32NUM
element.
uint32_t u32val = 0;
M2_LABEL(el_tsk_num_label, NULL, "U32:");
M2_U32NUM(el_tsk_num_u32, "a1c5", &u32val);
M2_TSK(el_tsk_up, "f1", " \xdd ", M2_KEY_DATA_UP); // data up
M2_TSK(el_tsk_down, "f1", " \xdf ", M2_KEY_DATA_DOWN); // data down
M2_TSK(el_tsk_left, "f1", " \xdc ", M2_KEY_PREV); // left
M2_TSK(el_tsk_right, "f1", " \xde ", M2_KEY_NEXT); // right
M2_ROOT(el_tsk_enter, "f1t1r1", " \xbf ", &top_el_tlsm); // enter
M2_LIST(tsk_list) = {
&el_tsk_num_label, &m2_null_element, &el_tsk_up, &m2_null_element,
&el_tsk_num_u32, &el_tsk_left, &el_tsk_enter, &el_tsk_right,
&m2_null_element, &m2_null_element, &el_tsk_down, &m2_null_element,
};
M2_GRIDLIST(el_tsk_num_menu, "c4", tsk_list);
M2_ALIGN(top_el_tsk_num_menu, "-1|1W64H64", &el_tsk_num_menu);
Any TSK element can generate one of the following key events:
Key |
---|
M2_KEY_SELECT |
M2_KEY_EXIT |
M2_KEY_NEXT |
M2_KEY_PREV |
M2_KEY_DATA_UP |
M2_KEY_DATA_DOWN |
M2_KEY_HOME |
Available TSK elements include (see element reference):
Element | Description |
---|---|
M2_TSK |
Text string (RAM area) |
M2_TSKP |
Text string (PROGMEM area) |
M2_XBMTSKP |
XBM picture |
The following code is taken from the GLCD example ("TouchMenu"). Additional code is required to check for the touch panel state.
#include <glcd.h> // inform Arduino IDE that we will use GLCD library
#include "M2tk.h"
#include "m2ghglcd.h"
//================================================================
// touch panel procedures
uint8_t is_touch_panel_pressed() {
// add code here
// return 1 if the touch panel is pressed
return 0;
}
uint8_t get_touch_panel_x() {
// add code here
// return x position between 0 and display width-1
return 0;
}
uint8_t get_touch_panel_y() {
// add code here
// return y position between 0 and display height-1
return 0;
}
//================================================================
// m2tklib forward declarations
extern M2tk m2;
M2_EXTERN_ALIGN(top_el_ts_mnu);
//================================================================
// note: for all selectable elements the read only flag is set, so that the element focus only appears for the
// touch panel focus.
M2_ROOT(el_ts_mnu1_sel, "r1t1", "Menu 1 selected", &top_el_ts_mnu);
M2_ALIGN(top_el_ts_mnu1_sel, "-1|1W64H64", &el_ts_mnu1_sel);
M2_ROOT(el_ts_mnu2_sel, "r1t1", "Menu 2 selected", &top_el_ts_mnu);
M2_ALIGN(top_el_ts_mnu2_sel, "-1|1W64H64", &el_ts_mnu2_sel);
M2_ROOT(el_ts_mnu3_sel, "r1t1", "Menu 3 selected", &top_el_ts_mnu);
M2_ALIGN(top_el_ts_mnu3_sel, "-1|1W64H64", &el_ts_mnu3_sel);
M2_ROOT(el_ts_mnu1, "r1t1w60f8", "menu 1", &top_el_ts_mnu1_sel);
M2_ROOT(el_ts_mnu2, "r1t1w60f8", "menu 2", &top_el_ts_mnu2_sel);
M2_ROOT(el_ts_mnu3, "r1t1w60f8", "menu 3", &top_el_ts_mnu3_sel);
M2_LIST(list_ts_mnu) = {
&el_ts_mnu1,
&el_ts_mnu2,
&el_ts_mnu3
};
M2_VLIST(el_ts_mnu_vlist, NULL, list_ts_mnu);
M2_ALIGN(top_el_ts_mnu, "-1|1W64H64", &el_ts_mnu_vlist);
//================================================================
// new event source and m2tklib constructor
uint8_t m2_es_touch_screen(m2_p ep, uint8_t msg) {
switch(msg) {
case M2_ES_MSG_GET_KEY:
if ( is_touch_panel_pressed() ) {
/* set x and y position of the touch screen */
/* (x,y) is a M2 position: (0,0) is lower left */
m2_SetEventSourceArgsM2(ep, get_touch_panel_x(), get_touch_panel_y() );
/* no debounce: return M2_KEY_EVENT(M2_KEY_TOUCH_PRESS); */
/* with debounce: return M2_KEY_TOUCH_PRESS; */
return M2_KEY_EVENT(M2_KEY_TOUCH_PRESS);
}
break;
case M2_ES_MSG_INIT:
break;
}
/* return 0 or call other event source */
return m2_es_arduino(ep, msg);
}
M2tk m2(&top_el_ts_mnu, m2_es_touch_screen, m2_eh_6bsts, m2_gh_glcd_ffs);
//================================================================
// overall draw procedure for u8glib, includes touch panel calibration
void draw(void) {
m2.draw();
}
//================================================================
// Arduino setup and loop
void setup() {
}
void loop() {
m2.checkKey();
if ( m2.handleKey() ) {
m2.draw();
}
}
- The design of a dialog box or menu differs between touch screen and push buttons.
- Use the "t1" format option to make a M2 element selectable by the touch screen.
- Use the new TSK elements to emulate push buttons.
- Previous Tutorial: Incremental Rotary Encoder
- Wiki Start Page