Callback events for buttons (Click + Long press)

I have noticed that when having both a click and a long-pressed call-back event on the same button the click event fires upon button release, even if the long press was fired before (due to a long press). Is that by design?

I need only one event to fire at a time. Meaning the clicked event fires when clicked and the long press event fires when long pressed. If the current behavior is by design? Is there a way to avoid the click event after a long press?

Hi @Thomas_Houlberg ,

I believe that is the intended behaviour. I am sure @kisvegabor will correct me on this if I am wrong.

For your application can you use the LV_EVENT_PRESSED event for a short press and the LV_EVENT_LONG_PRESSED for a long press and just ignore the LV_CLICKED_EVENT?

Do you think this will work for your requirement?

This is the way I do things in my own applications.

Kind Regards,

Pete

1 Like

Hi Pete.

Thank you for replying.

Just tried your suggestion. However, this causes the pressed event to fire just before the long-pressed event. So, I guess both events are still firing – just in reverse order.

/Thomas

Hi @Thomas_Houlberg ,

What you are describing is the intended behaviour also… :slight_smile:

Can you describe what it is you are trying to achieve and maybe I can suggest a helpful solution.

Kind Regards,

Pete

Hi Pete.

I am trying to control a light bulb using 2 buttons. One button should turn on the light on a click / press and dim up the light upon long press. The other button would turn off the light on a click / press and dim down the light on long press.

The immediate problem, with the current behavior, is that the light will turn off either before dimming down or right after, depending on click or pressed implementation.

/Thomas

Hi @Thomas_Houlberg ,

Okay I understand, let me mull over that for a bit and get back to you. :slight_smile:

Kind Regards,

Pete

1 Like

Hi @Thomas_Houlberg ,

Here is a rough piece of code for you to take and hone to your exact requirements, I am sure it will get you on the right track:

static lv_obj_t	*btn1, *btn2, *dimmer_txt;
static uint8_t	btn1_last_state, btn2_last_state, dimmer_value=0, lamp_state = 0;
static char* on_off[] = {
	"Off",
	"On"
};

static void event_handler(lv_event_t * e)
{
    lv_event_code_t code = lv_event_get_code(e);
    lv_obj_t *btn = lv_event_get_target(e);

    if(code == LV_EVENT_PRESSED) {
    	if(btn == btn1) btn1_last_state = code;
    	if(btn == btn2) btn2_last_state = code;
    }
    if(code == LV_EVENT_LONG_PRESSED ) {
    	if(btn == btn1) btn1_last_state = code;
    	if(btn == btn2) btn2_last_state = code;
    }
    if(code == LV_EVENT_LONG_PRESSED_REPEAT) {
    	if(btn == btn1) if( dimmer_value < 255 ) dimmer_value++;
    	if(btn == btn2) if( dimmer_value > 0 ) dimmer_value--;
        lv_label_set_text_fmt( dimmer_txt, "Dimmer Value: %d Light State: %s", dimmer_value, on_off[lamp_state] );
    }

    if(code == LV_EVENT_CLICKED) {
    	if(btn == btn1) {
    		if( btn1_last_state == LV_EVENT_PRESSED ) lamp_state = 1;
    		if( btn1_last_state == LV_EVENT_LONG_PRESSED || btn1_last_state == LV_EVENT_LONG_PRESSED_REPEAT )
    			if( dimmer_value < 255 ) dimmer_value++;
    	}
    	if(btn == btn2) {
    		if( btn2_last_state == LV_EVENT_PRESSED ) {
    			lamp_state = 0;
    			dimmer_value = 0;
    		}
    		if( btn2_last_state == LV_EVENT_LONG_PRESSED || btn1_last_state == LV_EVENT_LONG_PRESSED_REPEAT )
    				if( dimmer_value > 0 ) dimmer_value--;
    	}
        lv_label_set_text_fmt( dimmer_txt, "Dimmer Value: %d Light State: %s", dimmer_value, on_off[lamp_state] );
    }

}

void dim_control(void)
{
    lv_obj_t * label;

    btn1 = lv_btn_create(lv_scr_act());
    lv_obj_add_event_cb(btn1, event_handler, LV_EVENT_ALL, NULL);
    lv_obj_align(btn1, LV_ALIGN_CENTER, 0, -40);

    label = lv_label_create(btn1);
    lv_label_set_text(label, "On/Up");
    lv_obj_center(label);

    btn2 = lv_btn_create(lv_scr_act());
    lv_obj_add_event_cb(btn2, event_handler, LV_EVENT_ALL, NULL);
    lv_obj_align(btn2, LV_ALIGN_CENTER, 0, 40);
    lv_obj_set_height(btn2, LV_SIZE_CONTENT);

    label = lv_label_create(btn2);
    lv_label_set_text(label, "Off/Down");
    lv_obj_center(label);

    dimmer_txt = lv_label_create(lv_scr_act());
    lv_label_set_text_fmt( dimmer_txt, "Dimmer Value: %d Light State: %s", dimmer_value, on_off[lamp_state] );
    lv_obj_center(dimmer_txt);
 }

I hope that helps!

Kind Regards,

Pete

Hi Pete.

Thank you very much for your effort, which is much appreciated!

I will try your implementation and let you know if it does the trick in my scenario.

/Thomas

You’re looking for LV_EVENT_SHORT_CLICKED. The sequence of events is:

  1. LV_EVENT_PRESSED
  2. LV_EVENT_LONG_PRESSED (if pressed long enough)
  3. LV_EVENT_LONG_PRESSED_REPEAT (if pressed long enough)
  4. LV_EVENT_RELEASED
  5. LV_EVENT_SHORT_CLICKED (if not a long press)
  6. LV_EVENT_CLICKED (both short and long)

From which version lvgl works this events , and works too for indev key?

Looks like 6.0 was the release where clicked was changed to included both short and long presses and a separate short click event was added. It still works this way for all indevs.

Maybe missunderstand, i ask if lvgl have own code for this or callbacks indev need user write all code for determine this events.
I for example for indev encoder send only PR state and mean no your listed events is generated.