t10 - olikraus/m2tklib GitHub Wiki

Tutorial 10: Touch Screen Support

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").

Quick Start

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 procedure m2_es_touch_screen
  • m2_es_arduino is called within m2_es_touch_screen
  • m2_eh_4bs is replaced by m2_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() and get_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);

http://wiki.m2tklib.googlecode.com/hg/pic/u8g/u8g_ts_simple_menu.png

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

Theory

Push Buttons and Touch Screen

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:

Single Cursor Dialog

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)

http://wiki.m2tklib.googlecode.com/hg/pic/u8g/u8g_ts_simple_menu.png

Double Cursor Dialog

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)

http://wiki.m2tklib.googlecode.com/hg/pic/u8g/u8g_ts_tsk.png

Direct Update Dialog

Properties:

  • Similar to the "Single Cursor Dialog"
  • Values are updated by callback procedures
  • Special design for touch screen

http://wiki.m2tklib.googlecode.com/hg/pic/u8g/u8g_ts_direct.png

Setup

Event Source

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);
}

Basic Structure of Touch Screen Event Source

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;

Touch Screen Press Event

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.

Additional Check for other Event Sources

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);
}

Event Handler

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.

Setup Options

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

Touch Screen Menu Design

The t flag

  • 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);

http://wiki.m2tklib.googlecode.com/hg/pic/u8g/u8g_ts_simple_menu.png

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.

TSK elements

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);

http://wiki.m2tklib.googlecode.com/hg/pic/u8g/u8g_ts_tsk.png

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

Example

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();
  }
}

Conclusion

  • 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.

Links

⚠️ **GitHub.com Fallback** ⚠️