Index: apps/action.h
===================================================================
--- apps/action.h (revision 15077)
+++ apps/action.h (working copy)
@@ -111,6 +111,9 @@
ACTION_WPS_ID3SCREEN,/* optional */
ACTION_WPS_CONTEXT,
ACTION_WPS_QUICKSCREEN,/* optional */
+#ifdef ACCEPT_DOUBLE_CLICK
+ ACTION_WPS_SCRUBSEEK,/* optional */
+#endif
ACTION_WPS_MENU, /*this should be the same as ACTION_STD_MENU */
ACTION_WPS_REC,
#if 0
Index: apps/abrepeat.h
===================================================================
--- apps/abrepeat.h (revision 15077)
+++ apps/abrepeat.h (working copy)
@@ -49,7 +49,7 @@
#ifdef HAVE_LCD_BITMAP
#include "screen_access.h"
void ab_draw_markers(struct screen * screen, int capacity,
- int x0, int x1, int y, int h);
+ int x0, int x1, int y, int h);
#endif
/* These functions really need to be inlined for speed */
Index: apps/lang/english.lang
===================================================================
--- apps/lang/english.lang (revision 15077)
+++ apps/lang/english.lang (working copy)
@@ -11028,6 +11028,20 @@
+ id: LANG_DOUBLE_CLICK_DELAY
+ desc: set delay in ms between clicks to detect double click
+ user:
+
+ *: "Set Double-Click Delay"
+
+
+ *: "Set Double-Click Delay"
+
+
+ *: "Set Double-Click Delay"
+
+
+
id: LANG_EXT_ONLY_VIEW_ALL
desc: in settings_menu
user:
@@ -11342,6 +11356,20 @@
+ id: LANG_SCRUB_MODE_TIMEOUT
+ desc: Menu item to select timeout for Scrub mode (scrollwheel devices)
+ user:
+
+ *: "Scrub Mode Timeout"
+
+
+ *: "Scrub Mode Timeout"
+
+
+ *: ""
+
+
+
id: LANG_THEME_MENU
desc: in the settings menu
user:
Index: apps/gui/gwps-common.c
===================================================================
--- apps/gui/gwps-common.c (revision 15077)
+++ apps/gui/gwps-common.c (working copy)
@@ -142,6 +142,225 @@
return false;
}
+bool scrub_ffwd_rew(int button)
+{
+ static const uint16_t ff_rew_steps[] = {
+ 1000, 2000, 3000, 4000,
+ 5000, 6000, 8000, 10000,
+ 15000, 20000, 25000, 30000,
+ 45000, 60000
+ };
+
+ unsigned int step = 0; /* current ff/rewind step */
+ unsigned int max_step = 0; /* maximum ff/rewind step */
+ int ff_rewind_count = 0; /* current ff/rewind count (in ticks) */
+ int direction = -1; /* forward=1 or backward=-1 */
+ long accel_tick = 0; /* next time at which to bump the step size */
+ bool exit = false;
+ bool usb = false;
+ bool update=false; /* update audio */
+ bool timeout=false; /* time out scrub mode after preset seconds */
+ long cur_pos=0; /* used to get round unsigned/signed comparison */
+ long old_pos=0; /* used to calculate timeout */
+ int wait_time=0; /* wait time before updating audio - makes for smooth scrubbing */
+ int i = 0;
+
+ if (button == ACTION_WPS_BROWSE) /* exit - should never happen */
+ {
+ status_set_ffmode(0);
+ return usb;
+ }
+
+if ( (audio_status() & AUDIO_STATUS_PLAY) &&
+ wps_state.id3 && wps_state.id3->length )
+ {
+ if ((!wps_state.paused) && (global_settings.scrub_mode_timeout==0)) /* pause audio if timeout is 0 */
+#if (CONFIG_CODEC == SWCODEC)
+ audio_pre_ff_rewind();
+#else
+ audio_pause();
+#endif
+#if CONFIG_KEYPAD == PLAYER_PAD
+if (global_settings.scrub_mode_timeout==0)
+ FOR_NB_SCREENS(i)
+ gui_wps[i].display->stop_scroll();
+#endif
+
+ wps_state.ff_rewind = true; /* set scrub mode for progress bar */
+
+ step = ff_rew_steps[global_settings.ff_rewind_min_step];
+
+ accel_tick = current_tick +
+ global_settings.ff_rewind_accel*HZ;
+ }
+ old_pos=wps_state.id3->elapsed; /* get old position for time out (should be redundant actually) */
+
+ while (!exit) /* main loop - read button, take action*/
+ {
+ switch ( button )
+ {
+ case ACTION_WPS_VOLUP:
+ direction = 1;
+ case ACTION_WPS_VOLDOWN:
+ if (wps_state.ff_rewind) /* enabled earlier */
+ {
+ if (direction == 1)
+ {
+ /* fast forwarding, calc max step relative to end */
+ max_step = (wps_state.id3->length -
+ (wps_state.id3->elapsed +
+ ff_rewind_count)) *
+ FF_REWIND_MAX_PERCENT / 100;
+ status_set_ffmode(STATUS_FASTFORWARD);
+ }
+ else
+ {
+ /* rewinding, calc max step relative to start */
+ max_step = (wps_state.id3->elapsed + ff_rewind_count) *
+ FF_REWIND_MAX_PERCENT / 100;
+ status_set_ffmode(STATUS_FASTBACKWARD);
+ }
+
+ max_step = MAX(max_step, MIN_FF_REWIND_STEP);
+
+ if (step > max_step)
+ step = max_step;
+
+ ff_rewind_count += step * direction;
+
+ if (global_settings.ff_rewind_accel != 0 &&
+ current_tick >= accel_tick)
+ {
+ step *= 2;
+ accel_tick = current_tick +
+ global_settings.ff_rewind_accel*HZ;
+ }
+ }
+ if (direction > 0) {
+ if ((wps_state.id3->elapsed + ff_rewind_count) >
+ wps_state.id3->length)
+ ff_rewind_count = wps_state.id3->length -
+ wps_state.id3->elapsed;
+ }
+ else {
+ if ((int)(wps_state.id3->elapsed + ff_rewind_count) < 0)
+ ff_rewind_count = -wps_state.id3->elapsed;
+
+ }
+ FOR_NB_SCREENS(i)
+ gui_wps_refresh(&gui_wps[i],
+ (wps_state.wps_time_countup == false)?
+ ff_rewind_count:-ff_rewind_count,
+ WPS_REFRESH_PLAYER_PROGRESS |
+ WPS_REFRESH_DYNAMIC);
+
+ direction = -1;
+ update = true;
+ wait_time=0;
+ if ((wps_state.id3->length - wps_state.id3->elapsed) < 2000) /* few seconds to go before we run out of current song */
+#if (CONFIG_CODEC == SWCODEC)
+ audio_pre_ff_rewind(); /* so pause playback while we are still scrubbing*/
+#else
+ audio_pause();
+#endif
+ break;
+
+ case ACTION_WPS_BROWSE: /* Exit on Select */
+ case ACTION_WPS_PLAY: /* Exit on Play */
+ if ((global_settings.scrub_mode_timeout==0) || (update))
+ /* update playback if we are scrubbing while paused, or update required */
+ {
+ wps_state.id3->elapsed = wps_state.id3->elapsed+ff_rewind_count;
+ audio_ff_rewind(wps_state.id3->elapsed);
+ }
+ ff_rewind_count = 0;
+ wps_state.ff_rewind = false;
+ status_set_ffmode(0);
+#if (CONFIG_CODEC != SWCODEC)
+ if (!wps_state.paused)
+ audio_resume();
+#endif
+#ifdef HAVE_LCD_CHARCELLS
+ //gui_wps_display();
+#endif
+ exit = true;
+ break;
+
+ case ACTION_NONE: /* No Button Pressed */
+ if (global_settings.scrub_mode_timeout==0)
+ {
+ status_set_ffmode(STATUS_PAUSE); /* display paused when not ff or rew */
+ FOR_NB_SCREENS(i)
+ gui_wps_refresh(&gui_wps[i], (wps_state.wps_time_countup == false)?
+ ff_rewind_count:-ff_rewind_count,
+ WPS_REFRESH_PLAYER_PROGRESS | WPS_REFRESH_DYNAMIC);
+ }
+ else
+ {
+ if ((update) && (wait_time > 3)) /* wait time of 3 works OK, should this be a variable? */
+ {
+ wait_time =0;
+#if (CONFIG_CODEC == SWCODEC)
+ audio_pre_ff_rewind(); /* pause audio so that we can update cleanly */
+#else
+ audio_pause();
+#endif
+ if (wps_state.id3->elapsed+ff_rewind_count < wps_state.id3->length)
+ wps_state.id3->elapsed = wps_state.id3->elapsed+ff_rewind_count; /* update position if not beyond end of file */
+ else
+ {
+ wps_state.id3->elapsed = wps_state.id3->length;
+ timeout=true; /* scrubbed to end of song */
+ }
+ audio_ff_rewind(wps_state.id3->elapsed); /* update file with new position */
+ old_pos=wps_state.id3->elapsed; /*update old_pos for time out calculation */
+ ff_rewind_count = 0; /*reset scrub position now that we have updated */
+#if (CONFIG_CODEC != SWCODEC)
+ if (!wps_state.paused)
+ audio_resume();
+#endif
+ update=false; /* only update once */
+ }
+ else
+ {
+ if (!update) /* we havent scrubbed yet, so just show progress as normal */
+ {
+ FOR_NB_SCREENS(i)
+ gui_wps_refresh(&gui_wps[i],
+ 0,
+ WPS_REFRESH_PLAYER_PROGRESS |
+ WPS_REFRESH_DYNAMIC);
+ }
+ else /* we have scrubbed so increment wait_time */
+ {
+ wait_time++;
+ DEBUGF("wait time is %d\n", wait_time);
+ old_pos=wps_state.id3->elapsed; /*update old_pos for time out calculation */
+ }
+ if ((wps_state.id3->length - wps_state.id3->elapsed) < 2250) /* .25 seconds to go before we run out of current song */
+ timeout=true;
+ cur_pos=wps_state.id3->elapsed;
+ if ((short)(cur_pos - old_pos)/1000 > global_settings.scrub_mode_timeout) /* time out calculation */
+ timeout=true;
+ }
+ }
+ break;
+
+ default: /* loop unless USB is connected */
+ if(default_event_handler(button) == SYS_USB_CONNECTED) {
+ status_set_ffmode(0);
+ usb = true;
+ exit = true;
+ }
+ }
+ if ((!exit) && (timeout==false)) /* if we are not exiting and timeout has not elapsed, read button */
+ button = get_action(CONTEXT_WPS|ALLOW_SOFTLOCK,HZ/5);
+ else
+ button = ACTION_WPS_PLAY; /* otherwise we are exiting, so go back to play as normal */
+ }
+ return usb;
+}
+
bool ffwd_rew(int button)
{
static const uint16_t ff_rew_steps[] = {
@@ -448,6 +667,35 @@
}
#ifdef HAVE_LCD_BITMAP
+static inline void scrub_draw_marker(struct screen * screen, int mark, int capacity,
+ int offset, int size, int y, int h)
+{
+ int pos;
+ int pos2;
+
+ int w = size - offset;
+ pos = offset + ( (w * mark) / capacity );
+ pos2=pos;
+
+ /* draw lines in decreasing size until a height of zero is reached */
+ screen->set_drawmode(DRMODE_SOLID);
+ //screen->vline(pos, y, y+h-1); /* draw centre line */
+ while( h > 0 )
+ {
+ screen->set_drawmode(DRMODE_COMPLEMENT);
+ screen->vline(pos, y, y+h-1); /* draw diamond right */
+ screen->vline(pos2, y, y+h-1);/* draw diamond left */
+ h -= 2;
+ y++;
+ pos++;
+ if (pos >= size-1)
+ pos=size-1;
+ pos2--;
+ if (pos2 <= offset)
+ pos2=offset;
+ }
+
+}
static void draw_progressbar(struct gui_wps *gwps, int line)
{
@@ -455,6 +703,7 @@
struct screen *display = gwps->display;
struct wps_state *state = gwps->state;
int h = font_get(FONT_UI)->height;
+ int ff_rewind_count;
int sb_y;
if (data->progress_top < 0)
@@ -466,17 +715,21 @@
if (!data->progress_end)
data->progress_end=display->width;
-
- if (gwps->data->progressbar.have_bitmap_pb)
+
+ ff_rewind_count=state->ff_rewind_count;
+ if ((wps_state.ff_rewind) && (global_settings.scrub_mode_timeout!=0)) /* for scrubbing */
+ state->ff_rewind_count=0;
+
+ if (gwps->data->progressbar.have_bitmap_pb)
gui_bitmap_scrollbar_draw(display, data->progressbar.bm,
- data->progress_start, sb_y,
- data->progress_end-data->progress_start,
- data->progressbar.bm.height,
- state->id3->length ? state->id3->length : 1, 0,
- state->id3->length ? state->id3->elapsed
- + state->ff_rewind_count : 0,
- HORIZONTAL);
- else
+ data->progress_start, sb_y,
+ data->progress_end-data->progress_start,
+ data->progressbar.bm.height,
+ state->id3->length ? state->id3->length : 1, 0,
+ state->id3->length ? state->id3->elapsed
+ + state->ff_rewind_count : 0,
+ HORIZONTAL);
+ else
gui_scrollbar_draw(display, data->progress_start, sb_y,
data->progress_end-data->progress_start,
data->progress_height,
@@ -485,6 +738,14 @@
+ state->ff_rewind_count : 0,
HORIZONTAL);
+if ((wps_state.ff_rewind) && (global_settings.scrub_mode_timeout!=0)) /* if scrubbing draw marker */
+ scrub_draw_marker(display,
+ state->id3->elapsed+ff_rewind_count,
+ state->id3->length, data->progress_start,
+ data->progress_end , sb_y,
+ data->progress_height);
+
+
#ifdef AB_REPEAT_ENABLE
if ( ab_repeat_mode_enabled() && state->id3->length != 0 )
ab_draw_markers(display, state->id3->length,
@@ -1073,6 +1334,8 @@
mode = 4;
if (status_get_ffmode() == STATUS_FASTBACKWARD)
mode = 5;
+ if (status_get_ffmode() == STATUS_PAUSE)
+ mode = 3;
if (intval) {
*intval = mode;
Index: apps/gui/gwps-common.h
===================================================================
--- apps/gui/gwps-common.h (revision 15077)
+++ apps/gui/gwps-common.h (working copy)
@@ -27,6 +27,7 @@
bool gui_wps_display(void);
bool update_onvol_change(struct gui_wps * gwps);
bool update(struct gui_wps *gwps);
+bool scrub_ffwd_rew(int button);
bool ffwd_rew(int button);
void display_keylock_text(bool locked);
Index: apps/gui/gwps.c
===================================================================
--- apps/gui/gwps.c (revision 15077)
+++ apps/gui/gwps.c (working copy)
@@ -502,7 +502,15 @@
return GO_TO_ROOT;
break;
+#ifdef ACCEPT_DOUBLE_CLICK
+ case ACTION_WPS_SCRUBSEEK:
+ if (global_settings.party_mode) /* don't do anything in party mode */
+ break;
+ scrub_ffwd_rew(ACTION_NONE); /* go into scrub mode, but don't seek unless vol up or down */
+ break;
+#endif
+
#ifdef HAVE_QUICKSCREEN
case ACTION_WPS_QUICKSCREEN:
#if LCD_DEPTH > 1
Index: apps/settings.h
===================================================================
--- apps/settings.h (revision 15077)
+++ apps/settings.h (working copy)
@@ -749,6 +749,15 @@
int list_accel_start_delay; /* ms before we start increaseing step size */
int list_accel_wait; /* ms between increases */
#endif
+
+ int scrub_mode_timeout; /* time to wait before exiting scrub mode
+ 0 = never
+ number = time to wait in seconds */
+
+#ifdef ACCEPT_DOUBLE_CLICK
+ int btn_double_click_delay;
+#endif
+
#ifdef HAVE_USBSTACK
int usb_stack_mode; /* device or host */
unsigned char usb_stack_device_driver[32]; /* usb device driver to load */
Index: apps/menus/settings_menu.c
===================================================================
--- apps/menus/settings_menu.c (revision 15077)
+++ apps/menus/settings_menu.c (working copy)
@@ -344,6 +344,10 @@
MENUITEM_SETTING(buttonlight_brightness, &global_settings.buttonlight_brightness, NULL);
#endif
+#ifdef ACCEPT_DOUBLE_CLICK
+MENUITEM_SETTING(btn_double_click_delay, &global_settings.btn_double_click_delay, NULL);
+#endif
+
MAKE_MENU(system_menu, ID2P(LANG_SYSTEM),
0, Icon_System_menu,
&start_screen,
@@ -374,8 +378,11 @@
&buttonlight_timeout,
#endif
#ifdef HAVE_BUTTONLIGHT_BRIGHTNESS
- &buttonlight_brightness
+ &buttonlight_brightness,
#endif
+#ifdef ACCEPT_DOUBLE_CLICK
+ &btn_double_click_delay
+#endif
);
/* SYSTEM MENU */
Index: apps/menus/playback_menu.c
===================================================================
--- apps/menus/playback_menu.c (revision 15077)
+++ apps/menus/playback_menu.c (working copy)
@@ -60,8 +60,9 @@
MENUITEM_SETTING(ff_rewind_accel, &global_settings.ff_rewind_accel, NULL);
MENUITEM_SETTING(ff_rewind_min_step, &global_settings.ff_rewind_min_step, NULL);
+MENUITEM_SETTING(scrub_mode_timeout, &global_settings.scrub_mode_timeout, NULL);
MAKE_MENU(ff_rewind_settings_menu, ID2P(LANG_WIND_MENU), 0, Icon_NOICON,
- &ff_rewind_min_step, &ff_rewind_accel);
+ &ff_rewind_min_step, &ff_rewind_accel, &scrub_mode_timeout);
#ifndef HAVE_FLASH_STORAGE
#if CONFIG_CODEC == SWCODEC
int buffermargin_callback(int action,const struct menu_item_ex *this_item)
Index: apps/settings_list.c
===================================================================
--- apps/settings_list.c (revision 15077)
+++ apps/settings_list.c (working copy)
@@ -258,6 +258,24 @@
snprintf(buffer, buffer_size, "2x/%ds", val);
}
+static const int scrub_mode_timeout_vals[] = {0,4,5,6,7,8,9,10,15,20,30};
+static long scrub_mode_timeout_getlang(int value)
+{
+ if (value == 0)
+ return LANG_OFF;
+ return TALK_ID(scrub_mode_timeout_vals[value], UNIT_SEC);
+}
+static void scrub_mode_timeout_formatter(char *buffer, size_t buffer_size,
+ int val, const char *unit)
+{
+ (void)unit;
+ if (val == 0)
+ strcpy(buffer, str(LANG_OFF));
+ else
+ snprintf(buffer, buffer_size, "%ds", scrub_mode_timeout_vals[val]);
+}
+
+
static const unsigned char poweroff_idle_timer_times[] = {0,1,2,3,4,5,6,7,8,9,10,15,30,45,60};
static long poweroff_idle_timer_getlang(int value)
{
@@ -650,6 +668,10 @@
ff_rewind_min_step_getlang, NULL),
INT_SETTING(0, ff_rewind_accel, LANG_FFRW_ACCEL, 3, "scan accel",
UNIT_SEC, 16, 0, -1, scanaccel_formatter, scanaccel_getlang, NULL),
+ INT_SETTING(0, scrub_mode_timeout, LANG_SCRUB_MODE_TIMEOUT,
+ 0, "scrub mode timeout", UNIT_SEC, 0, 10, 1,
+ scrub_mode_timeout_formatter, scrub_mode_timeout_getlang, NULL),
+
#if (CONFIG_CODEC == SWCODEC) && !defined(HAVE_FLASH_STORAGE)
STRINGCHOICE_SETTING(0, buffer_margin, LANG_MP3BUFFER_MARGIN, 0,"antiskip",
"5s,15s,30s,1min,2min,3min,5min,10min",NULL, 8,
@@ -1273,6 +1295,13 @@
3, "list_accel_wait", UNIT_SEC, 1, 10, 1,
scanaccel_formatter, scanaccel_getlang, NULL),
#endif /* HAVE_SCROLLWHEEL */
+
+#ifdef ACCEPT_DOUBLE_CLICK
+ INT_SETTING(0, btn_double_click_delay, LANG_DOUBLE_CLICK_DELAY, DC_DELAY_DEF,
+ "dbl click delay", UNIT_MS, DC_DELAY_MIN, DC_DELAY_MAX, 20,
+ NULL, NULL, btn_set_double_click_delay),
+#endif
+
#ifdef HAVE_USBSTACK
CHOICE_SETTING(0, usb_stack_mode, LANG_USBSTACK_MODE, 0, "usb mode",
"device,host",
Index: apps/keymaps/keymap-ipod.c
===================================================================
--- apps/keymaps/keymap-ipod.c (revision 15077)
+++ apps/keymaps/keymap-ipod.c (working copy)
@@ -75,6 +75,9 @@
};
static const struct button_mapping button_context_wps[] = {
+#ifdef ACCEPT_DOUBLE_CLICK
+ { ACTION_WPS_SCRUBSEEK, BUTTON_SELECT|BUTTON_REL, BUTTON_SELECT|BUTTON_DBL },
+#endif
{ ACTION_WPS_PLAY, BUTTON_PLAY|BUTTON_REL, BUTTON_PLAY },
{ ACTION_WPS_STOP, BUTTON_PLAY|BUTTON_REPEAT, BUTTON_PLAY },
{ ACTION_WPS_SKIPPREV, BUTTON_LEFT|BUTTON_REL, BUTTON_LEFT },
Index: firmware/export/button.h
===================================================================
--- firmware/export/button.h (revision 15077)
+++ firmware/export/button.h (working copy)
@@ -61,5 +61,17 @@
#define BUTTON_REL 0x02000000
#define BUTTON_REPEAT 0x04000000
#define BUTTON_TOUCHPAD 0x08000000
+#ifdef ACCEPT_DOUBLE_CLICK
+#define BUTTON_DBL 0x08000000
+#endif
+#ifdef ACCEPT_DOUBLE_CLICK
+#define DC_DELAY_MIN 100
+#define DC_DELAY_MAX 500
+#define DC_DELAY_DEF 300
+#define DC_DELAY_START 30
+
+void btn_set_double_click_delay(int delay);
+#endif
+
#endif /* _BUTTON_H_ */
Index: firmware/export/config-ipodvideo.h
===================================================================
--- firmware/export/config-ipodvideo.h (revision 15077)
+++ firmware/export/config-ipodvideo.h (working copy)
@@ -159,4 +159,7 @@
#define ICODE_ATTR_TREMOR_NOT_MDCT
+/* define this to turn on double click captures */
+#define ACCEPT_DOUBLE_CLICK
+
#endif
Index: firmware/export/config-ipod3g.h
===================================================================
--- firmware/export/config-ipod3g.h (revision 15077)
+++ firmware/export/config-ipod3g.h (working copy)
@@ -133,4 +133,7 @@
#define ICODE_ATTR_TREMOR_NOT_MDCT
+/* define this to turn on double click captures */
+#define ACCEPT_DOUBLE_CLICK
+
#endif /* SIMULATOR */
Index: firmware/export/config-ipodcolor.h
===================================================================
--- firmware/export/config-ipodcolor.h (revision 15077)
+++ firmware/export/config-ipodcolor.h (working copy)
@@ -141,4 +141,7 @@
#define ICODE_ATTR_TREMOR_NOT_MDCT
+/* define this to turn on double click captures */
+#define ACCEPT_DOUBLE_CLICK
+
#endif
Index: firmware/export/config-ipodmini.h
===================================================================
--- firmware/export/config-ipodmini.h (revision 15077)
+++ firmware/export/config-ipodmini.h (working copy)
@@ -146,4 +146,7 @@
#define ICODE_ATTR_TREMOR_NOT_MDCT
+/* define this to turn on double click captures */
+#define ACCEPT_DOUBLE_CLICK
+
#endif
Index: firmware/export/config-ipod1g2g.h
===================================================================
--- firmware/export/config-ipod1g2g.h (revision 15077)
+++ firmware/export/config-ipod1g2g.h (working copy)
@@ -130,4 +130,7 @@
#define ICODE_ATTR_TREMOR_NOT_MDCT
+/* define this to turn on double click captures */
+#define ACCEPT_DOUBLE_CLICK
+
#endif /* SIMULATOR */
Index: firmware/export/config-ipodmini2g.h
===================================================================
--- firmware/export/config-ipodmini2g.h (revision 15077)
+++ firmware/export/config-ipodmini2g.h (working copy)
@@ -149,4 +149,7 @@
#define ICODE_ATTR_TREMOR_NOT_MDCT
+/* define this to turn on double click captures */
+#define ACCEPT_DOUBLE_CLICK
+
#endif
Index: firmware/export/config-ipodnano.h
===================================================================
--- firmware/export/config-ipodnano.h (revision 15077)
+++ firmware/export/config-ipodnano.h (working copy)
@@ -147,4 +147,7 @@
#define ICODE_ATTR_TREMOR_NOT_MDCT
+/* define this to turn on double click captures */
+#define ACCEPT_DOUBLE_CLICK
+
#endif
Index: firmware/export/config-ipod4g.h
===================================================================
--- firmware/export/config-ipod4g.h (revision 15077)
+++ firmware/export/config-ipod4g.h (working copy)
@@ -152,4 +152,7 @@
#define ICODE_ATTR_TREMOR_NOT_MDCT
+/* define this to turn on double click captures */
+#define ACCEPT_DOUBLE_CLICK
+
#endif
Index: firmware/drivers/button.c
===================================================================
--- firmware/drivers/button.c (revision 15077)
+++ firmware/drivers/button.c (working copy)
@@ -64,6 +64,12 @@
bool phones_present = false;
#endif
+#ifdef ACCEPT_DOUBLE_CLICK
+static int double_click_interval;
+static int double_click_start;
+static int double_click_count;
+#endif
+
/* how long until repeat kicks in, in ticks */
#define REPEAT_START 30
@@ -82,6 +88,9 @@
static int repeat_count = 0;
static bool repeat = false;
static bool post = false;
+#ifdef ACCEPT_DOUBLE_CLICK
+ static int lastbtn_pushed = 0;
+#endif
#ifdef HAVE_BACKLIGHT
static bool skip_release = false;
#ifdef HAVE_REMOTE_LCD
@@ -90,7 +99,7 @@
#endif
int diff;
int btn;
-
+
#ifdef HAS_SERIAL_REMOTE
/* Post events for the remote control */
btn = remote_control_rx();
@@ -133,23 +142,66 @@
else
#endif
if(!skip_release)
+#ifdef ACCEPT_DOUBLE_CLICK
+ {
+ /* if double_click is < start then a double click was
+ * detected and queued, now we must queue the release, and dbl
+ */
+ if (lastbtn_pushed > 0 && double_click_count < double_click_start)
+ {
+ queue_post(&button_queue, BUTTON_DBL | lastbtn_pushed, 0);
+ queue_post(&button_queue, BUTTON_REL | lastbtn_pushed, 0);
+ double_click_count = double_click_interval;
+ lastbtn_pushed = 0;
+ }
+ }
+#else /* !ACCEPT_DOUBLE_CLICK */
queue_post(&button_queue, BUTTON_REL | diff, 0);
+#endif
else
skip_release = false;
-#else
+#else /* !HAVE_REMOTE_LCD */
+#ifdef ACCEPT_DOUBLE_CLICK
+ /* see above section comment */
+ if (lastbtn_pushed > 0 && double_click_count < double_click_start)
+ {
+ queue_post(&button_queue, BUTTON_DBL | lastbtn_pushed, 0);
+ queue_post(&button_queue, BUTTON_REL | lastbtn_pushed, 0);
+ double_click_count = double_click_interval;
+ lastbtn_pushed = 0;
+ }
+#else /* !ACCEPT_DOUBLE_CLICK */
queue_post(&button_queue, BUTTON_REL | diff, 0);
#endif
+#endif
}
else
{
if ( btn )
{
+#ifdef ACCEPT_DOUBLE_CLICK
+ /* check for double click */
+ /* double clicked if lastbtn == 0, and we've waited long enough */
+ if (lastbtn == 0 && btn == lastbtn_pushed && double_click_count < double_click_start)
+ {
+ /* double clicked now wait for button to be released
+ * cannot post yet, as the second click could be a hold */
+ post = false;
+ double_click_count = 0;
+ }
+ else
+#endif
/* normal keypress */
if ( btn != lastbtn )
{
post = true;
repeat = false;
repeat_speed = REPEAT_INTERVAL_START;
+#ifdef ACCEPT_DOUBLE_CLICK
+ /* diff btn - reset double click, no post */
+ post = false;
+ double_click_count = double_click_interval;
+#endif
}
else /* repeat? */
{
@@ -201,6 +253,18 @@
repeat_count = 0;
/* initial repeat */
count = REPEAT_INTERVAL_START;
+#ifdef ACCEPT_DOUBLE_CLICK
+ /* post original button press and release */
+ if (double_click_count == 0)
+ {
+ queue_post(&button_queue, btn, 0);
+ queue_post(&button_queue, BUTTON_REL | btn, 0);
+ }
+ /* post current button press */
+ queue_post(&button_queue, btn, 0);
+ /* reset double click detection */
+ double_click_count = double_click_interval;
+#endif
}
}
}
@@ -243,7 +307,9 @@
|| (btn&BUTTON_REMOTE)
#endif
)
+ {
queue_post(&button_queue, btn, 0);
+ }
else
skip_release = true;
#else /* no backlight, nothing to skip */
@@ -268,11 +334,35 @@
}
else
{
+#ifdef ACCEPT_DOUBLE_CLICK
+ /* if we've waited longer than double_click_interval
+ * then it isn't a double click, so queue the button
+ * we also know it isn't a double click if repeat is true
+ */
+ if (repeat || (lastbtn_pushed && --double_click_count <= 0))
+ {
+ /* queue both the original press if not repeating,
+ * and the release
+ */
+ if (!repeat)
+ queue_post(&button_queue, lastbtn_pushed, 0);
+ queue_post(&button_queue, BUTTON_REL | lastbtn_pushed, 0);
+ double_click_count = double_click_interval;
+ lastbtn_pushed = 0;
+ }
+#endif
repeat = false;
count = 0;
}
}
+
+#ifdef ACCEPT_DOUBLE_CLICK
+ lastbtn = btn & ~(BUTTON_REL | BUTTON_REPEAT | BUTTON_DBL);
+ if (lastbtn)
+ lastbtn_pushed = lastbtn;
+#else
lastbtn = btn & ~(BUTTON_REL | BUTTON_REPEAT);
+#endif
}
#ifdef HAVE_ADJUSTABLE_CPU_FREQ
@@ -375,6 +465,10 @@
remote_filter_first_keypress = false;
#endif
#endif
+
+#ifdef ACCEPT_DOUBLE_CLICK
+ btn_set_double_click_delay(DC_DELAY_DEF);
+#endif
}
#ifdef HAVE_LCD_BITMAP /* only bitmap displays can be flipped */
@@ -520,3 +614,17 @@
return delta;
}
#endif /* HAVE_SCROLLWHEEL */
+
+#ifdef ACCEPT_DOUBLE_CLICK
+void btn_set_double_click_delay(int delay)
+{
+ if (delay < DC_DELAY_MIN ||
+ delay > DC_DELAY_MAX)
+ delay = DC_DELAY_DEF;
+
+ double_click_interval = delay / 10; // convert to ticks
+ double_click_start = (delay - DC_DELAY_START) / 10; // conver to ticks
+ double_click_count = double_click_interval;
+}
+#endif
+