void button_init(void) { /* Init used objects first */ queue_init(&button_queue, true); #ifdef HAVE_BUTTON_DATA int temp; #endif /* hardware inits */ button_init_device(); #ifdef HAVE_BUTTON_DATA button_read(&temp); lastbtn = button_read(&temp); #else button_read(); lastbtn = button_read(); #endif reset_poweroff_timer(); #ifdef HAVE_LCD_BITMAP flipped = false; #endif #ifdef HAVE_BACKLIGHT filter_first_keypress = false; #ifdef HAVE_REMOTE_LCD remote_filter_first_keypress = false; #endif #endif #ifdef HAVE_TOUCHSCREEN last_touchscreen_touch = 0xffff; #endif /* Start polling last */ tick_add_task(button_tick); }
static void button_tick(void) { static int count = 0; static int repeat_speed = REPEAT_INTERVAL_START; static int repeat_count = 0; static bool repeat = false; static bool post = false; #ifdef HAVE_BACKLIGHT static bool skip_release = false; #ifdef HAVE_REMOTE_LCD static bool skip_remote_release = false; #endif #endif int diff; int btn; #ifdef HAVE_BUTTON_DATA int data = 0; #else const int data = 0; #endif #if defined(HAS_SERIAL_REMOTE) && !defined(SIMULATOR) /* Post events for the remote control */ btn = remote_control_rx(); if(btn) button_try_post(btn, 0); #endif #ifdef HAVE_BUTTON_DATA btn = button_read(&data); #else btn = button_read(); #endif #if defined(HAVE_HEADPHONE_DETECTION) if (headphones_inserted() != phones_present) { /* Use the autoresetting oneshot to debounce the detection signal */ phones_present = !phones_present; timeout_register(&hp_detect_timeout, btn_detect_callback, HZ/2, phones_present); } #endif /* Find out if a key has been released */ diff = btn ^ lastbtn; if(diff && (btn & diff) == 0) { #ifdef HAVE_BACKLIGHT #ifdef HAVE_REMOTE_LCD if(diff & BUTTON_REMOTE) if(!skip_remote_release) button_try_post(BUTTON_REL | diff, data); else skip_remote_release = false; else #endif if(!skip_release) button_try_post(BUTTON_REL | diff, data); else skip_release = false; #else button_try_post(BUTTON_REL | diff, data); #endif } else { if ( btn ) { /* normal keypress */ if ( btn != lastbtn ) { post = true; repeat = false; repeat_speed = REPEAT_INTERVAL_START; } else /* repeat? */ { if ( repeat ) { if (!post) count--; if (count == 0) { post = true; /* yes we have repeat */ if (repeat_speed > REPEAT_INTERVAL_FINISH) repeat_speed--; count = repeat_speed; repeat_count++; /* Send a SYS_POWEROFF event if we have a device which doesn't shut down easily with the OFF key */ #ifdef HAVE_SW_POWEROFF if ((btn & POWEROFF_BUTTON #ifdef RC_POWEROFF_BUTTON || btn == RC_POWEROFF_BUTTON #endif ) && #if CONFIG_CHARGING && !defined(HAVE_POWEROFF_WHILE_CHARGING) !charger_inserted() && #endif repeat_count > POWEROFF_COUNT) { /* Tell the main thread that it's time to power off */ sys_poweroff(); /* Safety net for players without hardware poweroff */ #if (CONFIG_PLATFORM & PLATFORM_NATIVE) if(repeat_count > POWEROFF_COUNT * 10) power_off(); #endif } #endif } } else { if (count++ > REPEAT_START) { post = true; repeat = true; repeat_count = 0; /* initial repeat */ count = REPEAT_INTERVAL_START; } #ifdef HAVE_TOUCHSCREEN else if (lastdata != data && btn == lastbtn) { /* only coordinates changed, post anyway */ if (touchscreen_get_mode() == TOUCHSCREEN_POINT) post = true; } #endif } } if ( post ) { if (repeat) { /* Only post repeat events if the queue is empty, * to avoid afterscroll effects. */ if (button_try_post(BUTTON_REPEAT | btn, data)) { #ifdef HAVE_BACKLIGHT #ifdef HAVE_REMOTE_LCD skip_remote_release = false; #endif skip_release = false; #endif post = false; } } else { #ifdef HAVE_BACKLIGHT #ifdef HAVE_REMOTE_LCD if (btn & BUTTON_REMOTE) { if (!remote_filter_first_keypress || is_remote_backlight_on(false) #if defined(IRIVER_H100_SERIES) || defined(IRIVER_H300_SERIES) || (remote_type()==REMOTETYPE_H300_NONLCD) #endif ) button_try_post(btn, data); else skip_remote_release = true; } else #endif if (!filter_first_keypress || is_backlight_on(false) #if BUTTON_REMOTE || (btn & BUTTON_REMOTE) #endif ) button_try_post(btn, data); else skip_release = true; #else /* no backlight, nothing to skip */ button_try_post(btn, data); #endif post = false; } #ifdef HAVE_REMOTE_LCD if(btn & BUTTON_REMOTE) remote_backlight_on(); else #endif { backlight_on(); #ifdef HAVE_BUTTON_LIGHT buttonlight_on(); #endif } reset_poweroff_timer(); } } else { repeat = false; count = 0; } } lastbtn = btn & ~(BUTTON_REL | BUTTON_REPEAT); #ifdef HAVE_BUTTON_DATA lastdata = data; #endif }
static void handle_scroll_wheel(int new_scroll) { static const signed char scroll_state[4][4] = { {0, 1, -1, 0}, {-1, 0, 0, 1}, {1, 0, 0, -1}, {0, -1, 1, 0} }; static int prev_scroll = -1; static int direction = 0; static int count = 0; static long next_backlight_on = 0; int wheel_keycode = BUTTON_NONE; int scroll; static unsigned long wheel_delta = 1ul << 24; static unsigned long wheel_velocity = 0; static unsigned long last_wheel_usec = 0; static int prev_keypost = BUTTON_NONE; unsigned long usec; unsigned long v; if ( prev_scroll == -1 ) { prev_scroll = new_scroll; return; } scroll = scroll_state[prev_scroll][new_scroll]; prev_scroll = new_scroll; if (direction != scroll) { /* direction reversal or was hold - reset all */ direction = scroll; count = 0; prev_keypost = BUTTON_NONE; wheel_velocity = 0; wheel_delta = 1ul << 24; return; } /* poke backlight every 1/4s of activity */ if (TIME_AFTER(current_tick, next_backlight_on)) { backlight_on(); reset_poweroff_timer(); next_backlight_on = current_tick + HZ/4; } if (++count < WHEEL_BASE_SENSITIVITY) return; count = 0; /* Mini 1st Gen wheel has inverse direction mapping * compared to 1st..3rd Gen wheel. */ switch (direction) { case 1: wheel_keycode = BUTTON_SCROLL_FWD; break; case -1: wheel_keycode = BUTTON_SCROLL_BACK; break; default: /* only happens if we get out of sync */ break; } /* have a keycode */ usec = USEC_TIMER; v = usec - last_wheel_usec; /* calculate deg/s based upon sensitivity-adjusted interrupt period */ if ((long)v <= 0) { /* timer wrapped (no activity for awhile), skip acceleration */ v = 0; wheel_delta = 1ul << 24; } else { if (v > 0xfffffffful/WHEELCLICKS_PER_ROTATION) { v = 0xfffffffful/WHEELCLICKS_PER_ROTATION; /* check overflow below */ } v = 360000000ul*WHEEL_BASE_SENSITIVITY / (v*WHEELCLICKS_PER_ROTATION); if (v > 0xfffffful) v = 0xfffffful; /* limit to 24 bits */ } if (v < WHEEL_SMOOTHING_VELOCITY) { /* very slow - no smoothing */ wheel_velocity = v; /* ensure backlight never gets stuck for an extended period if tick * wrapped such that next poke is very far ahead */ next_backlight_on = current_tick - 1; } else { /* some velocity filtering to smooth things out */ wheel_velocity = (7*wheel_velocity + v) / 8; } if (queue_empty(&button_queue)) { int key = wheel_keycode; if (v >= WHEEL_REPEAT_VELOCITY && prev_keypost == key) { /* quick enough and same key is being posted more than once in a * row - generate repeats - use unsmoothed v to guage */ key |= BUTTON_REPEAT; } prev_keypost = wheel_keycode; /* post wheel keycode with wheel data */ queue_post(&button_queue, key, (wheel_velocity >= WHEEL_ACCEL_START ? (1ul << 31) : 0) | wheel_delta | wheel_velocity); /* message posted - reset delta */ wheel_delta = 1ul << 24; } else { /* skipped post - increment delta and limit to 7 bits */ wheel_delta += 1ul << 24; if (wheel_delta > (0x7ful << 24)) wheel_delta = 0x7ful << 24; } last_wheel_usec = usec; }