Wheel acceleration for e200. A general acceleration interface intended for use on any scroll target and by any code. A general interface to obtain data associated with most recently dequeued button presses and actions. Use #define HAVE_SCROLLWHEEL and set appropriate constants, values in the scroller driver that feel right.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@13959 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
3213d4a0f5
commit
873e0fd1ef
11 changed files with 168 additions and 30 deletions
|
@ -31,6 +31,7 @@
|
|||
|
||||
static int last_button = BUTTON_NONE|BUTTON_REL; /* allow the ipod wheel to
|
||||
work on startup */
|
||||
static intptr_t last_data = 0;
|
||||
static int last_action = ACTION_NONE;
|
||||
static bool repeated = false;
|
||||
|
||||
|
@ -113,6 +114,7 @@ static int get_action_worker(int context, int timeout,
|
|||
else
|
||||
button = button_get_w_tmo(timeout);
|
||||
|
||||
/* Data from sys events can be pulled with button_get_data */
|
||||
if (button == BUTTON_NONE || button&SYS_EVENT)
|
||||
{
|
||||
return button;
|
||||
|
@ -201,6 +203,7 @@ static int get_action_worker(int context, int timeout,
|
|||
|
||||
last_button = button;
|
||||
last_action = ret;
|
||||
last_data = button_get_data();
|
||||
last_action_tick = current_tick;
|
||||
return ret;
|
||||
}
|
||||
|
@ -230,6 +233,11 @@ bool is_keys_locked(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
intptr_t get_action_data(void)
|
||||
{
|
||||
return last_data;
|
||||
}
|
||||
|
||||
int get_action_statuscode(int *button)
|
||||
{
|
||||
int ret = 0;
|
||||
|
|
|
@ -253,6 +253,8 @@ bool is_keys_locked(void);
|
|||
#define ACTION_REPEAT 0x2 /* action was repeated (NOT button) */
|
||||
int get_action_statuscode(int *button);
|
||||
|
||||
/* returns the data value associated with the last action that is not
|
||||
BUTTON_NONE or flagged with SYS_EVENT */
|
||||
intptr_t get_action_data(void);
|
||||
|
||||
|
||||
#endif
|
||||
#endif /* __ACTION_H__ */
|
||||
|
|
|
@ -887,15 +887,22 @@ static void gui_synclist_scroll_left(struct gui_synclist * lists)
|
|||
}
|
||||
#endif /* HAVE_LCD_BITMAP */
|
||||
|
||||
extern intptr_t get_action_data(void);
|
||||
|
||||
unsigned gui_synclist_do_button(struct gui_synclist * lists,
|
||||
unsigned button,enum list_wrap wrap)
|
||||
{
|
||||
#ifdef HAVE_LCD_BITMAP
|
||||
static bool scrolling_left = false;
|
||||
#endif
|
||||
int i;
|
||||
|
||||
#ifdef HAVE_SCROLLWHEEL
|
||||
int next_item_modifier = button_apply_acceleration(get_action_data(),
|
||||
WHEEL_ACCELERATION_FACTOR);
|
||||
#else
|
||||
static int next_item_modifier = 1;
|
||||
static int last_accel_tick = 0;
|
||||
int i;
|
||||
|
||||
if (global_settings.list_accel_start_delay)
|
||||
{
|
||||
|
@ -919,6 +926,7 @@ unsigned gui_synclist_do_button(struct gui_synclist * lists,
|
|||
last_accel_tick = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
switch (wrap)
|
||||
{
|
||||
|
@ -953,8 +961,12 @@ unsigned gui_synclist_do_button(struct gui_synclist * lists,
|
|||
case ACTION_STD_PREVREPEAT:
|
||||
FOR_NB_SCREENS(i)
|
||||
gui_list_select_at_offset(&(lists->gui_list[i]), -next_item_modifier);
|
||||
#ifndef HAVE_SCROLLWHEEL
|
||||
if (queue_count(&button_queue) < FRAMEDROP_TRIGGER)
|
||||
#endif
|
||||
{
|
||||
gui_synclist_draw(lists);
|
||||
}
|
||||
yield();
|
||||
return ACTION_STD_PREV;
|
||||
|
||||
|
@ -962,8 +974,12 @@ unsigned gui_synclist_do_button(struct gui_synclist * lists,
|
|||
case ACTION_STD_NEXTREPEAT:
|
||||
FOR_NB_SCREENS(i)
|
||||
gui_list_select_at_offset(&(lists->gui_list[i]), next_item_modifier);
|
||||
#ifndef HAVE_SCROLLWHEEL
|
||||
if (queue_count(&button_queue) < FRAMEDROP_TRIGGER)
|
||||
#endif
|
||||
{
|
||||
gui_synclist_draw(lists);
|
||||
}
|
||||
yield();
|
||||
return ACTION_STD_NEXT;
|
||||
|
||||
|
|
|
@ -10955,12 +10955,15 @@
|
|||
desc: Delay before list starts accelerating
|
||||
user:
|
||||
<source>
|
||||
e200: ""
|
||||
*: "List Acceleration Start Delay"
|
||||
</source>
|
||||
<dest>
|
||||
e200: ""
|
||||
*: "List Acceleration Start Delay"
|
||||
</dest>
|
||||
<voice>
|
||||
e200: ""
|
||||
*: "List Acceleration Start Delay"
|
||||
</voice>
|
||||
</phrase>
|
||||
|
@ -10969,12 +10972,15 @@
|
|||
desc: list acceleration speed
|
||||
user:
|
||||
<source>
|
||||
e200: ""
|
||||
*: "List Acceleration Speed"
|
||||
</source>
|
||||
<dest>
|
||||
e200: ""
|
||||
*: "List Acceleration Speed"
|
||||
</dest>
|
||||
<voice>
|
||||
e200: ""
|
||||
*: "List Acceleration Speed"
|
||||
</voice>
|
||||
</phrase>
|
||||
|
|
|
@ -313,9 +313,11 @@ MENUITEM_SETTING(jump_scroll, &global_settings.jump_scroll, NULL);
|
|||
MENUITEM_SETTING(jump_scroll_delay, &global_settings.jump_scroll_delay, NULL);
|
||||
#endif
|
||||
/* list acceleration */
|
||||
#ifndef HAVE_SCROLLWHEEL
|
||||
MENUITEM_SETTING(list_accel_start_delay,
|
||||
&global_settings.list_accel_start_delay, NULL);
|
||||
MENUITEM_SETTING(list_accel_wait, &global_settings.list_accel_wait, NULL);
|
||||
#endif /* HAVE_SCROLLWHEEL */
|
||||
#ifdef HAVE_LCD_BITMAP
|
||||
int screenscroll_callback(int action,const struct menu_item_ex *this_item)
|
||||
{
|
||||
|
@ -350,7 +352,9 @@ MAKE_MENU(scroll_settings_menu, ID2P(LANG_SCROLL_MENU), 0, Icon_NOICON,
|
|||
&offset_out_of_view, &screen_scroll_step,
|
||||
#endif
|
||||
&scroll_paginated,
|
||||
#ifndef HAVE_SCROLLWHEEL
|
||||
&list_accel_start_delay, &list_accel_wait
|
||||
#endif
|
||||
);
|
||||
/* SCROLL MENU */
|
||||
/***********************************/
|
||||
|
|
|
@ -731,8 +731,10 @@ struct user_settings
|
|||
#ifdef HAVE_BUTTONLIGHT_BRIGHTNESS
|
||||
int buttonlight_brightness;
|
||||
#endif
|
||||
#ifndef HAVE_SCROLLWHEEL
|
||||
int list_accel_start_delay; /* ms before we start increaseing step size */
|
||||
int list_accel_wait; /* ms between increases */
|
||||
#endif
|
||||
};
|
||||
|
||||
/** global variables **/
|
||||
|
|
|
@ -274,6 +274,7 @@ static void poweroff_idle_timer_formatter(char *buffer, int buffer_size,
|
|||
snprintf(buffer, buffer_size, "%dm", poweroff_idle_timer_times[val]);
|
||||
}
|
||||
|
||||
#ifndef HAVE_SCROLLWHEEL
|
||||
static long listaccel_getlang(int value)
|
||||
{
|
||||
if (value == 0)
|
||||
|
@ -289,6 +290,7 @@ static void listaccel_formatter(char *buffer, int buffer_size,
|
|||
else
|
||||
snprintf(buffer, buffer_size, "%d ms", 5*HZ*val);
|
||||
}
|
||||
#endif /* HAVE_SCROLLWHEEL */
|
||||
|
||||
#if CONFIG_CODEC == SWCODEC
|
||||
static void crossfeed_format(char* buffer, int buffer_size, int value,
|
||||
|
@ -1235,12 +1237,14 @@ const struct settings_list settings[] = {
|
|||
"button light brightness",UNIT_INT, MIN_BRIGHTNESS_SETTING, MAX_BRIGHTNESS_SETTING, 1,
|
||||
NULL, NULL, buttonlight_set_brightness),
|
||||
#endif
|
||||
#ifndef HAVE_SCROLLWHEEL
|
||||
INT_SETTING(0, list_accel_start_delay, LANG_LISTACCEL_START_DELAY,
|
||||
2, "list_accel_start_delay", UNIT_MS, 0, 10, 1,
|
||||
listaccel_formatter, listaccel_getlang, NULL),
|
||||
INT_SETTING(0, list_accel_wait, LANG_LISTACCEL_ACCEL_SPEED,
|
||||
3, "list_accel_wait", UNIT_SEC, 1, 10, 1,
|
||||
scanaccel_formatter, scanaccel_getlang, NULL),
|
||||
#endif /* HAVE_SCROLLWHEEL */
|
||||
};
|
||||
|
||||
const int nb_settings = sizeof(settings)/sizeof(*settings);
|
||||
|
|
|
@ -49,6 +49,7 @@ struct event_queue button_queue;
|
|||
|
||||
static long lastbtn; /* Last valid button status */
|
||||
static long last_read; /* Last button status, for debouncing/filtering */
|
||||
static intptr_t button_data; /* data value from last message dequeued */
|
||||
#ifdef HAVE_LCD_BITMAP
|
||||
static bool flipped; /* buttons can be flipped to match the LCD flip */
|
||||
#endif
|
||||
|
@ -309,7 +310,7 @@ long button_get(bool block)
|
|||
if (current_tick - ev.tick > MAX_EVENT_AGE)
|
||||
return BUTTON_NONE;
|
||||
#endif
|
||||
|
||||
button_data = ev.data;
|
||||
return ev.id;
|
||||
}
|
||||
|
||||
|
@ -329,7 +330,17 @@ long button_get_w_tmo(int ticks)
|
|||
#endif
|
||||
|
||||
queue_wait_w_tmo(&button_queue, &ev, ticks);
|
||||
return (ev.id != SYS_TIMEOUT)? ev.id: BUTTON_NONE;
|
||||
if (ev.id == SYS_TIMEOUT)
|
||||
ev.id = BUTTON_NONE;
|
||||
else
|
||||
button_data = ev.data;
|
||||
|
||||
return ev.id;
|
||||
}
|
||||
|
||||
intptr_t button_get_data(void)
|
||||
{
|
||||
return button_data;
|
||||
}
|
||||
|
||||
void button_init(void)
|
||||
|
@ -470,3 +481,33 @@ void button_clear_queue(void)
|
|||
{
|
||||
queue_clear(&button_queue);
|
||||
}
|
||||
|
||||
#ifdef HAVE_SCROLLWHEEL
|
||||
/**
|
||||
* data:
|
||||
* [31] Use acceleration
|
||||
* [30:24] Message post count (skipped + 1) (1-127)
|
||||
* [23:0] Velocity - clicks/uS - 0.24 fixed point
|
||||
*
|
||||
* factor:
|
||||
* Wheel acceleration scaling factor - x.24 fixed point -
|
||||
* no greater than what will not overflow 64 bits when multiplied
|
||||
* by the driver's maximum velocity in (clicks/usec)^2 in 0.24
|
||||
*/
|
||||
int button_apply_acceleration(unsigned int data, unsigned int factor)
|
||||
{
|
||||
int delta = (data >> 24) & 0x7f;
|
||||
|
||||
if ((data & (1 << 31)) != 0)
|
||||
{
|
||||
unsigned int v = data & 0xffffff;
|
||||
|
||||
v = factor * (unsigned long long)v*v / 0xffffffffffffull;
|
||||
|
||||
if (v > 1)
|
||||
delta *= v;
|
||||
}
|
||||
|
||||
return delta;
|
||||
}
|
||||
#endif /* HAVE_SCROLLWHEEL */
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#define _BUTTON_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <inttypes.h>
|
||||
#include "config.h"
|
||||
#include "button-target.h"
|
||||
|
||||
|
@ -28,6 +29,7 @@ extern struct event_queue button_queue;
|
|||
void button_init (void);
|
||||
long button_get (bool block);
|
||||
long button_get_w_tmo(int ticks);
|
||||
intptr_t button_get_data(void);
|
||||
int button_status(void);
|
||||
void button_clear_queue(void);
|
||||
#ifdef HAVE_LCD_BITMAP
|
||||
|
@ -48,6 +50,10 @@ int wheel_status(void);
|
|||
void wheel_send_events(bool send);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SCROLLWHEEL
|
||||
int button_apply_acceleration(unsigned int data, unsigned int factor);
|
||||
#endif
|
||||
|
||||
#define BUTTON_NONE 0x00000000
|
||||
|
||||
/* Button modifiers */
|
||||
|
|
|
@ -170,4 +170,10 @@
|
|||
|
||||
#define ICODE_ATTR_TREMOR_NOT_MDCT
|
||||
|
||||
#endif
|
||||
/* define this if the unit uses a scrollwheel for navigation */
|
||||
#define HAVE_SCROLLWHEEL
|
||||
/* define wheel acceleration scaling factor */
|
||||
/* Range for this target: 0xffffff*(0.0-16.000000894069724921567733381255) */
|
||||
#define WHEEL_ACCELERATION_FACTOR (0xffffff*7)
|
||||
|
||||
#endif /* SIMULATOR */
|
||||
|
|
|
@ -23,19 +23,21 @@
|
|||
#include "button.h"
|
||||
#include "backlight.h"
|
||||
|
||||
#define WHEEL_REPEAT_INTERVAL 30
|
||||
#define WHEEL_FAST_ON_INTERVAL 2
|
||||
#define WHEEL_FAST_OFF_INTERVAL 6
|
||||
#define WHEEL_REPEAT_INTERVAL 300000
|
||||
#define WHEEL_FAST_ON_INTERVAL 20000
|
||||
#define WHEEL_FAST_OFF_INTERVAL 60000
|
||||
|
||||
/* Clickwheel */
|
||||
#ifndef BOOTLOADER
|
||||
static unsigned int old_wheel_value = 0;
|
||||
static unsigned int wheel_repeat = BUTTON_NONE;
|
||||
static unsigned int wheel_click_count = 0;
|
||||
static unsigned int wheel_delta = 0;
|
||||
static int wheel_fast_mode = 0;
|
||||
static unsigned long last_wheel_tick = 0;
|
||||
static unsigned long last_wheel_post = 0;
|
||||
static unsigned long next_backlight_on = 0;
|
||||
static unsigned long last_wheel_usec = 0;
|
||||
static unsigned long wheel_velocity = 0;
|
||||
static long last_wheel_post = 0;
|
||||
static long next_backlight_on = 0;
|
||||
/* Buttons */
|
||||
static bool hold_button = false;
|
||||
static bool hold_button_old = false;
|
||||
|
@ -64,8 +66,8 @@ void button_init_device(void)
|
|||
GPIOH_INT_EN &= ~0xc0;
|
||||
|
||||
/* Get current tick before enabling button interrupts */
|
||||
last_wheel_tick = current_tick;
|
||||
last_wheel_post = current_tick;
|
||||
last_wheel_usec = USEC_TIMER;
|
||||
last_wheel_post = last_wheel_usec;
|
||||
|
||||
GPIOH_ENABLE |= 0xc0;
|
||||
GPIOH_OUTPUT_EN &= ~0xc0;
|
||||
|
@ -130,38 +132,67 @@ void clickwheel_int(void)
|
|||
|
||||
if (btn != BUTTON_NONE)
|
||||
{
|
||||
int repeat = 1;
|
||||
int repeat = 1; /* assume repeat */
|
||||
unsigned long usec = USEC_TIMER;
|
||||
unsigned v = (usec - last_wheel_usec) & 0x7fffffff;
|
||||
|
||||
/* wheel velocity in 0.24 fixed point - clicks/uS */
|
||||
|
||||
/* velocity cap to 18 bits to allow up to x16 scaling */
|
||||
v = (v < 0x40) ? 0xffffff / 0x40 : 0xffffff / v;
|
||||
|
||||
/* some velocity filtering to smooth things out */
|
||||
wheel_velocity = (7*wheel_velocity + v) / 8;
|
||||
|
||||
if (btn != wheel_repeat)
|
||||
{
|
||||
/* direction reversals nullify all fast mode states */
|
||||
wheel_repeat = btn;
|
||||
repeat =
|
||||
wheel_fast_mode =
|
||||
wheel_velocity =
|
||||
wheel_click_count = 0;
|
||||
}
|
||||
|
||||
if (wheel_fast_mode)
|
||||
if (wheel_fast_mode != 0)
|
||||
{
|
||||
if (TIME_AFTER(current_tick,
|
||||
last_wheel_tick + WHEEL_FAST_OFF_INTERVAL))
|
||||
/* fast OFF happens immediately when velocity drops below
|
||||
threshold */
|
||||
if (TIME_AFTER(usec,
|
||||
last_wheel_usec + WHEEL_FAST_OFF_INTERVAL))
|
||||
{
|
||||
if (++wheel_click_count < 2)
|
||||
btn = BUTTON_NONE;
|
||||
/* moving out of fast mode */
|
||||
wheel_fast_mode = 0;
|
||||
/* reset velocity */
|
||||
wheel_velocity = 0;
|
||||
/* wheel_delta is always 1 in slow mode */
|
||||
wheel_delta = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (repeat && TIME_BEFORE(current_tick,
|
||||
last_wheel_tick + WHEEL_FAST_ON_INTERVAL))
|
||||
wheel_fast_mode = 1;
|
||||
/* fast ON gets filtered to avoid inadvertent jumps to fast mode */
|
||||
if (repeat && wheel_velocity > 0xffffff/WHEEL_FAST_ON_INTERVAL)
|
||||
{
|
||||
/* moving into fast mode */
|
||||
wheel_fast_mode = 1 << 31;
|
||||
wheel_click_count = 0;
|
||||
wheel_velocity = 0xffffff/WHEEL_FAST_OFF_INTERVAL;
|
||||
}
|
||||
else if (++wheel_click_count < 2)
|
||||
{
|
||||
btn = BUTTON_NONE;
|
||||
}
|
||||
|
||||
if (TIME_AFTER(current_tick, next_backlight_on))
|
||||
/* wheel_delta is always 1 in slow mode */
|
||||
wheel_delta = 1;
|
||||
}
|
||||
|
||||
if (TIME_AFTER(usec, next_backlight_on))
|
||||
{
|
||||
next_backlight_on = current_tick + HZ/4;
|
||||
/* poke backlight to turn it on or maintain it no more often
|
||||
than every 1/4 second*/
|
||||
next_backlight_on = usec + 1000000/4;
|
||||
backlight_on();
|
||||
button_backlight_on();
|
||||
}
|
||||
|
@ -170,17 +201,29 @@ void clickwheel_int(void)
|
|||
{
|
||||
wheel_click_count = 0;
|
||||
|
||||
if (repeat && TIME_BEFORE(current_tick,
|
||||
/* generate repeats if quick enough */
|
||||
if (repeat && TIME_BEFORE(usec,
|
||||
last_wheel_post + WHEEL_REPEAT_INTERVAL))
|
||||
btn |= BUTTON_REPEAT;
|
||||
|
||||
last_wheel_post = current_tick;
|
||||
last_wheel_post = usec;
|
||||
|
||||
if (queue_empty(&button_queue))
|
||||
queue_post(&button_queue, btn, 0);
|
||||
{
|
||||
queue_post(&button_queue, btn, wheel_fast_mode |
|
||||
(wheel_delta << 24) | wheel_velocity);
|
||||
/* message posted - reset delta */
|
||||
wheel_delta = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* skipped post - increment delta */
|
||||
if (++wheel_delta > 0x7f)
|
||||
wheel_delta = 0x7f;
|
||||
}
|
||||
}
|
||||
|
||||
last_wheel_tick = current_tick;
|
||||
last_wheel_usec = usec;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue