[dasher: 22/28] TwoPushDynamicFilter: change params; release time opt; guides w/ FrameSpeedMul
- From: Patrick Welche <pwelche src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [dasher: 22/28] TwoPushDynamicFilter: change params; release time opt; guides w/ FrameSpeedMul
- Date: Tue, 22 Nov 2011 17:04:31 +0000 (UTC)
commit 5ca645851aecd001c818bacbd0976367f2f817e7
Author: Alan Lawrence <acl33 inf phy cam ac uk>
Date: Sun Oct 2 11:12:04 2011 +0100
TwoPushDynamicFilter: change params; release time opt; guides w/ FrameSpeedMul
LP_TWO_PUSH_UP and LP_TWO_PUSH_DOWN (inner posns) -> LP_TWO_PUSH_LONG (gap)
and LP_TWO_PUSH_SHORT (%age), as removes interdependencies between params
and matches Android.
Add BP_TWO_PUSH_RELEASE_TIME.
Recompute guide areas according to FrameSpeedMul, caching by effective bitrate.
Move Long-press detection into ButtonMultiPress so TwoPushDynamicFilter doesn't
Src/DasherCore/ButtonMultiPress.cpp | 23 +++-
Src/DasherCore/ButtonMultiPress.h | 16 ++-
Src/DasherCore/DynamicButtons.cpp | 24 +---
Src/DasherCore/DynamicButtons.h | 26 +++--
Src/DasherCore/Parameters.cpp | 5 +-
Src/DasherCore/Parameters.h | 4 +-
Src/DasherCore/TwoPushDynamicFilter.cpp | 206 ++++++++++++++-----------------
Src/DasherCore/TwoPushDynamicFilter.h | 18 +++-
8 files changed, 166 insertions(+), 156 deletions(-)
---
diff --git a/Src/DasherCore/ButtonMultiPress.cpp b/Src/DasherCore/ButtonMultiPress.cpp
index ec68f79..7df57fb 100644
--- a/Src/DasherCore/ButtonMultiPress.cpp
+++ b/Src/DasherCore/ButtonMultiPress.cpp
@@ -27,6 +27,14 @@ CButtonMultiPress::CButtonMultiPress(CSettingsUser *pCreator, CDasherInterfaceBa
: CDynamicButtons(pCreator, pInterface, pFramerate, iID, szName) {
}
+void CButtonMultiPress::Timer(unsigned long iTime, CDasherView *pView, CDasherInput *pInput, CDasherModel *pModel, CExpansionPolicy **pol) {
+ if(m_bKeyDown && !m_bKeyHandled && ((iTime - m_iKeyDownTime) > GetLongParameter(LP_HOLD_TIME))) {
+ ButtonEvent(iTime, m_iHeldId, 1, pModel);
+ m_bKeyHandled = true;
+ }
+ CDynamicButtons::Timer(iTime,pView,pInput,pModel,pol);
+}
+
void CButtonMultiPress::KeyDown(unsigned long iTime, int iId, CDasherView *pView, CDasherInput *pInput, CDasherModel *pModel) {
if (m_bKeyDown) return;
@@ -47,9 +55,7 @@ void CButtonMultiPress::KeyDown(unsigned long iTime, int iId, CDasherView *pView
m_deQueueTimes.push_back(iTime);
return; //we've called Event ourselves, so finished.
}
- }
- else
- {
+ } else {
m_deQueueTimes.clear(); //clear record of previous, different, button
m_iQueueId = iId;
}
@@ -58,10 +64,17 @@ void CButtonMultiPress::KeyDown(unsigned long iTime, int iId, CDasherView *pView
m_deQueueTimes.push_back(iTime);
// ... and process normally; if it changes the state, pause()/reverse()'ll clear the queue
CDynamicButtons::KeyDown(iTime, iId, pView, pInput, pModel);
+
+ // Store the key down time so that long presses can be determined
+ // TODO: This is going to cause problems if multiple buttons are
+ // held down at once
+ m_iKeyDownTime = iTime;
+
+ m_bKeyHandled = false;
}
-void CButtonMultiPress::pause()
-{
+
+void CButtonMultiPress::pause() {
CDynamicButtons::pause();
m_deQueueTimes.clear();
}
diff --git a/Src/DasherCore/ButtonMultiPress.h b/Src/DasherCore/ButtonMultiPress.h
index f1fa348..2f46a3e 100644
--- a/Src/DasherCore/ButtonMultiPress.h
+++ b/Src/DasherCore/ButtonMultiPress.h
@@ -26,16 +26,17 @@
namespace Dasher {
/// \ingroup InputFilter
/// @{
-/// DynamicButtons filter which detects multiple presses of the same button
-/// occurring in a short space of time - up to maxClickCount() consecutive presses,
+/// DynamicButtons filter which detects long and multiple presses - the latter of the
+/// same button, up to maxClickCount() consecutive presses,
/// with a gap of up to LP_MULTIPRESS_TIME ms between the start of _each_pair_ of
-/// presses. Such multi-presses are passed onto the standard ButtonEvent method,
-/// with iType equal to the number of presses, for subclasses to decide how to respond.
+/// presses. Long- and multi-presses are passed onto the standard ButtonEvent method,
+/// with iType 1 or to the number of presses, respectively, for subclasses to decide how to respond.
class CButtonMultiPress : public CDynamicButtons {
public:
CButtonMultiPress(CSettingsUser *pCreator, CDasherInterfaceBase *pInterface, CFrameRate *pFramerate, ModuleID_t iID, const char *szName);
- virtual void KeyDown(unsigned long iTime, int iId, CDasherView *pView, CDasherInput *pInput, CDasherModel *pModel);
+ void Timer(unsigned long iTime, CDasherView *pView, CDasherInput *pInput, CDasherModel *pModel, CExpansionPolicy **pol);
+ void KeyDown(unsigned long iTime, int iId, CDasherView *pView, CDasherInput *pInput, CDasherModel *pModel);
void pause();
protected:
@@ -48,6 +49,11 @@ class CButtonMultiPress : public CDynamicButtons {
int m_iQueueId;
std::deque<unsigned long> m_deQueueTimes;
+
+ ///Whether a long-press has been handled (in Timer) - as the key
+ /// may still be down (and the press becoming ever-longer)!
+ bool m_bKeyHandled;
+ unsigned long m_iKeyDownTime;
};
}
diff --git a/Src/DasherCore/DynamicButtons.cpp b/Src/DasherCore/DynamicButtons.cpp
index 241e834..83c75fd 100644
--- a/Src/DasherCore/DynamicButtons.cpp
+++ b/Src/DasherCore/DynamicButtons.cpp
@@ -30,16 +30,10 @@ CDynamicButtons::CDynamicButtons(CSettingsUser *pCreator, CDasherInterfaceBase *
pause();
}
-void CDynamicButtons::Timer(unsigned long iTime, CDasherView *pDasherView, CDasherInput *pInput, CDasherModel *m_pDasherModel, CExpansionPolicy **pol)
-{
- if(m_bKeyDown && !m_bKeyHandled && ((iTime - m_iKeyDownTime) > GetLongParameter(LP_HOLD_TIME))) {
- ButtonEvent(iTime, m_iHeldId, 1, m_pDasherModel);
- m_bKeyHandled = true;
- //return true; //ACL although that's what old DynamicButtons did, surely we should progress normally?
- }
+void CDynamicButtons::Timer(unsigned long iTime, CDasherView *pDasherView, CDasherInput *pInput, CDasherModel *pModel, CExpansionPolicy **pol) {
if (isPaused()) return;
if (isReversing()) {
- OneStepTowards(m_pDasherModel, 41943,2048, iTime, FrameSpeedMul(m_pDasherModel, iTime));
+ OneStepTowards(pModel, 41943,2048, iTime, FrameSpeedMul(pModel, iTime));
} else {
//moving forwards. Check auto speed control...
if (GetBoolParameter(BP_AUTO_SPEEDCONTROL) && m_uSpeedControlTime < iTime) {
@@ -47,7 +41,7 @@ void CDynamicButtons::Timer(unsigned long iTime, CDasherView *pDasherView, CDash
SetLongParameter(LP_MAX_BITRATE, GetLongParameter(LP_MAX_BITRATE) * (1.0 + GetLongParameter(LP_DYNAMIC_SPEED_INC)/100.0));
m_uSpeedControlTime = iTime + 1000*GetLongParameter(LP_DYNAMIC_SPEED_FREQ);
}
- TimerImpl(iTime, pDasherView, m_pDasherModel, pol);
+ TimerImpl(iTime, pDasherView, pModel, pol);
}
}
@@ -61,15 +55,9 @@ void CDynamicButtons::KeyDown(unsigned long iTime, int iId, CDasherView *pView,
// Pass the basic key down event to the handler
ButtonEvent(iTime, iId, 0, pModel);
-
- // Store the key down time so that long presses can be determined
- // TODO: This is going to cause problems if multiple buttons are
- // held down at once
- m_iKeyDownTime = iTime;
m_iHeldId = iId;
m_bKeyDown = true;
- m_bKeyHandled = false;
}
void CDynamicButtons::KeyUp(unsigned long iTime, int iId, CDasherView *pView, CDasherInput *pInput, CDasherModel *pModel) {
@@ -126,7 +114,7 @@ void CDynamicButtons::pause() {
void CDynamicButtons::reverse(unsigned long iTime) {
m_bForwards=false;
- CDynamicFilter::run(iTime);
+ if (isPaused()) CDynamicFilter::run(iTime);
if (GetBoolParameter(BP_AUTO_SPEEDCONTROL)) {
//treat reversing as a sign of distress --> slow down!
SetLongParameter(LP_MAX_BITRATE, GetLongParameter(LP_MAX_BITRATE) *
@@ -136,9 +124,7 @@ void CDynamicButtons::reverse(unsigned long iTime) {
void CDynamicButtons::run(unsigned long iTime) {
m_bForwards=true;
- if (!isPaused()) return;
- //wasn't running previously
- CDynamicFilter::run(iTime);
+ if (isPaused()) CDynamicFilter::run(iTime); //wasn't running previously
m_uSpeedControlTime = 0; //will be set in Timer()
}
diff --git a/Src/DasherCore/DynamicButtons.h b/Src/DasherCore/DynamicButtons.h
index f308324..f6d0386 100644
--- a/Src/DasherCore/DynamicButtons.h
+++ b/Src/DasherCore/DynamicButtons.h
@@ -26,7 +26,9 @@
/// \ingroup InputFilter
/// @{
namespace Dasher {
-///filter with three states: paused, reversing, running. Hold any button down to reverse.
+///filter with three states: paused, reversing, running. Button 1 is dedicated reverse
+/// button (subclasses may also call reverse()); when reversing, any key pauses,
+/// then any key restarts.
class CDynamicButtons : public CDynamicFilter {
public:
CDynamicButtons(CSettingsUser *pCreator, CDasherInterfaceBase *pInterface, CFrameRate *pFramerate, ModuleID_t iID, const char *szName);
@@ -53,8 +55,17 @@ class CDynamicButtons : public CDynamicFilter {
/// \param iType 0=normal press, 1=long press; see also CButtonMultiPress.
virtual void ActionButton(unsigned long iTime, int iButton, int iType, CDasherModel *pModel) = 0;
+ ///Whether a key (any that we might respond to) is held down.
+ /// If so, m_iHeldId identifies the key in question. We need this
+ /// not just for detecting long-presses etc. (in subclasses), and
+ /// ignoring presses of other keys while the first is down, but also
+ /// simply to filter out key-repeat events (=multiple keydown without a keyup)
bool m_bKeyDown;
- bool m_bKeyHandled;
+
+ ///if m_bKeyDown is true, identifies the key that was first pressed
+ /// that is currently still held down.
+ int m_iHeldId;
+
bool m_bDecorationChanged;
bool isReversing() {return !isPaused() && !m_bForwards;}
bool isRunning() {return !isPaused() && m_bForwards;}
@@ -67,12 +78,11 @@ class CDynamicButtons : public CDynamicFilter {
///Subclasses should all this (rather than pModel->Offset()) to offset the model
/// (it also stores the model, to abort the offset upon pause if necessary)
void ApplyOffset(CDasherModel *pModel, int iOffset);
- private:
- bool m_bForwards;
- int m_iHeldId;
- unsigned long m_iKeyDownTime;
- unsigned long m_uSpeedControlTime;
- CDasherModel *m_pModel;
+
+private:
+ bool m_bForwards;
+ unsigned long m_uSpeedControlTime;
+ CDasherModel *m_pModel;
};
}
#endif
diff --git a/Src/DasherCore/Parameters.cpp b/Src/DasherCore/Parameters.cpp
index 1175dec..e882306 100644
--- a/Src/DasherCore/Parameters.cpp
+++ b/Src/DasherCore/Parameters.cpp
@@ -58,6 +58,7 @@ const bp_table boolparamtable[] = {
{BP_CONTROL_MODE_HAS_COPY, "ControlHasCopy", true, "Provide copy-to-clipboard actions in Control Mode (if platforms supports)"},
{BP_CONTROL_MODE_HAS_SPEECH, "ControlHasSpeech", true, "Provide speech actions in Control Mode (if platform supports)"},
{BP_GAME_HELP_DRAW_PATH, "GameDrawPath", true, "When we give help, show the shortest path to the target sentence"},
+ {BP_TWO_PUSH_RELEASE_TIME, "TwoPushReleaseTime", false, _("Use push and release times of single press rather than push times of two presses")},
};
const lp_table longparamtable[] = {
@@ -122,8 +123,8 @@ const lp_table longparamtable[] = {
{LP_CONVERSION_ORDER, "ConversionOrder", 0, "Conversion ordering"},
{LP_CONVERSION_TYPE, "ConversionType", 0, "Conversion type"},
{LP_TWO_PUSH_OUTER, "TwoPushOuter", 1792, "Offset for one button dynamic mode outer marker"},
- {LP_TWO_PUSH_UP, "TwoPushUp", 1536, "Offset to up marker in one button dynamic"},
- {LP_TWO_PUSH_DOWN, "TwoPushDown", 1280, "Offset to down marker in one button dynamic"},
+ {LP_TWO_PUSH_LONG, "TwoPushLong", 512, _("Distance between down markers (long gap)")},
+ {LP_TWO_PUSH_SHORT, "TwoPushShort", 80, _("Distance between up markers, as %age of long gap")},
{LP_TWO_PUSH_TOLERANCE, "TwoPushTolerance", 100, "Tolerance of two-push-mode pushes, in ms"},
{LP_DYNAMIC_BUTTON_LAG, "DynamicButtonLag", 50, "Lag of pushes in dynamic button mode (ms)"},
{LP_STATIC1B_TIME, "Static1BTime", 2000, "Time for static-1B mode to scan from top to bottom (ms)"},
diff --git a/Src/DasherCore/Parameters.h b/Src/DasherCore/Parameters.h
index 506f3c0..fd4be5b 100644
--- a/Src/DasherCore/Parameters.h
+++ b/Src/DasherCore/Parameters.h
@@ -42,7 +42,7 @@ enum {
BP_TWOBUTTON_REVERSE, BP_2B_INVERT_DOUBLE, BP_SLOW_START,
BP_COPY_ALL_ON_STOP, BP_SPEAK_ALL_ON_STOP, BP_SPEAK_WORDS,
BP_CONTROL_MODE_HAS_HALT, BP_CONTROL_MODE_HAS_EDIT, BP_CONTROL_MODE_HAS_COPY, BP_CONTROL_MODE_HAS_SPEECH,
- BP_GAME_HELP_DRAW_PATH,
+ BP_GAME_HELP_DRAW_PATH, BP_TWO_PUSH_RELEASE_TIME,
END_OF_BPS
};
@@ -60,7 +60,7 @@ enum {
LP_SOCKET_INPUT_Y_MIN, LP_SOCKET_INPUT_Y_MAX, LP_INPUT_FILTER,
LP_CIRCLE_PERCENT, LP_TWO_BUTTON_OFFSET, LP_HOLD_TIME, LP_MULTIPRESS_TIME,
LP_SLOW_START_TIME, LP_CONVERSION_ORDER, LP_CONVERSION_TYPE,
- LP_TWO_PUSH_OUTER, LP_TWO_PUSH_UP, LP_TWO_PUSH_DOWN, LP_TWO_PUSH_TOLERANCE,
+ LP_TWO_PUSH_OUTER, LP_TWO_PUSH_LONG, LP_TWO_PUSH_SHORT, LP_TWO_PUSH_TOLERANCE,
LP_DYNAMIC_BUTTON_LAG, LP_STATIC1B_TIME, LP_STATIC1B_ZOOM,
LP_DEMO_SPRING, LP_DEMO_NOISE_MEM, LP_DEMO_NOISE_MAG, LP_MAXZOOM,
LP_DYNAMIC_SPEED_INC, LP_DYNAMIC_SPEED_FREQ, LP_DYNAMIC_SPEED_DEC,
diff --git a/Src/DasherCore/TwoPushDynamicFilter.cpp b/Src/DasherCore/TwoPushDynamicFilter.cpp
index 413e267..a84dba9 100644
--- a/Src/DasherCore/TwoPushDynamicFilter.cpp
+++ b/Src/DasherCore/TwoPushDynamicFilter.cpp
@@ -28,11 +28,10 @@ using namespace Dasher;
static SModuleSettings sSettings[] = {
{LP_TWO_PUSH_OUTER, T_LONG, 1024, 2048, 2048, 128, _("Offset for outer (second) button")},
- {LP_TWO_PUSH_UP, T_LONG, 257, 2047, 2048/*divisor*/, 128/*step*/, _("Distance for 1st button UP")},
- {LP_TWO_PUSH_DOWN, T_LONG, 256, 2046, 2048, 128, _("Distance for 1st button DOWN")},
+ {LP_TWO_PUSH_LONG, T_LONG, 128, 1024, 2048/*divisor*/, 128/*step*/, _("Distance between down markers (long gap)")},
+ {LP_TWO_PUSH_SHORT, T_LONG, 10, 90, 100, 1, _("Distance between up markers, as %age of long gap")},
{LP_TWO_PUSH_TOLERANCE, T_LONG, 50, 1000, 1, 10, _("Tolerance for inaccurate timing of button pushes (in ms)")},
- /* TRANSLATORS: The time for which a button must be held before it counts as a 'long' (rather than short) press. */
- {LP_HOLD_TIME, T_LONG, 100, 10000, 1000, 100, _("Long press time")},
+ {BP_TWO_PUSH_RELEASE_TIME, T_BOOL, -1, -1, -1, -1, _("Use push and release times of single press rather than push times of two presses")},
/* TRANSLATORS: Backoff = reversing in Dasher to correct mistakes. This allows a single button to be dedicated to activating backoff, rather than using multiple presses of other buttons, and another to be dedicated to starting and stopping. 'Button' in this context is a physical hardware device, not a UI element.*/
{BP_BACKOFF_BUTTON,T_BOOL, -1, -1, -1, -1, _("Enable backoff and start/stop buttons")},
{BP_SLOW_START,T_BOOL, -1, -1, -1, -1, _("Slow startup")},
@@ -62,35 +61,41 @@ void GuideLine(CDasherView *pView, const myint iDasherY, const int iColour)
pView->Dasher2Screen(iDasherX, iDasherY, p[1].x, p[1].y);
pScreen->Polyline(p, 2, 3, iColour);
-}
+}
-bool CTwoPushDynamicFilter::DecorateView(CDasherView *pView, CDasherInput *pInput)
-{
- //outer guides (yellow rects)
- for (int i=0; i<2; i++)
- {
- screenint x1, y1, x2, y2;
- CDasherScreen *pScreen(pView->Screen());
-
- pView->Dasher2Screen(-100, m_aaiGuideAreas[i][0], x1, y1);
- pView->Dasher2Screen(-1000, m_aaiGuideAreas[i][1], x2, y2);
-
- pScreen->DrawRectangle(x1, y1, x2, y2, 62/*pale yellow*/, -1, 0);
+long CTwoPushDynamicFilter::downDist() {
+ return GetLongParameter(LP_TWO_PUSH_OUTER) - GetLongParameter(LP_TWO_PUSH_LONG);
+}
+
+long CTwoPushDynamicFilter::upDist() {
+ return GetLongParameter(LP_TWO_PUSH_OUTER) - (GetLongParameter(LP_TWO_PUSH_LONG) * GetLongParameter(LP_TWO_PUSH_SHORT))/100;
+}
+
+bool CTwoPushDynamicFilter::DecorateView(CDasherView *pView, CDasherInput *pInput) {
+ if (isRunning()) {
+ //outer guides (yellow rects)
+ for (int i=0; i<2; i++) {
+ screenint x1, y1, x2, y2;
+ CDasherScreen *pScreen(pView->Screen());
+
+ pView->Dasher2Screen(-100, m_aaiGuideAreas[i][0], x1, y1);
+ pView->Dasher2Screen(-1000, m_aaiGuideAreas[i][1], x2, y2);
+
+ pScreen->DrawRectangle(x1, y1, x2, y2, 62/*pale yellow*/, -1, 0);
+ }
}
- //inner guides (red lines)
- GuideLine(pView, 2048 - GetLongParameter(LP_TWO_PUSH_UP), 1);
- GuideLine(pView, 2048 + GetLongParameter(LP_TWO_PUSH_DOWN), 1);
+ //inner guides (red lines).
+ GuideLine(pView, 2048 - upDist(), 1);
+ GuideLine(pView, 2048 + downDist(), 1);
//outer guides (at center of rects) - red lines
GuideLine(pView, 2048 - GetLongParameter(LP_TWO_PUSH_OUTER), 1);
GuideLine(pView, 2048 + GetLongParameter(LP_TWO_PUSH_OUTER), 1);
//moving markers - green if active, else yellow
- if (m_bDecorationChanged && isRunning() && m_dNatsSinceFirstPush > -std::numeric_limits<double>::infinity())
- {
- for (int i = 0; i < 2; i++)
- {
+ if (m_bDecorationChanged && isRunning() && m_dNatsSinceFirstPush > -std::numeric_limits<double>::infinity()) {
+ for (int i = 0; i < 2; i++) {
GuideLine(pView, m_aiMarker[i], (i == m_iActiveMarker) ? 240 : 61/*orange*/);
}
}
@@ -100,75 +105,52 @@ bool CTwoPushDynamicFilter::DecorateView(CDasherView *pView, CDasherInput *pInpu
}
void CTwoPushDynamicFilter::HandleEvent(int iParameter) {
- switch (iParameter)
- {
- case LP_TWO_PUSH_OUTER:
- if (GetLongParameter(LP_TWO_PUSH_OUTER)<=GetLongParameter(LP_TWO_PUSH_UP)) {
- //two_push_outer being moved down; force two_push_up down too
- SetLongParameter(LP_TWO_PUSH_UP, GetLongParameter(LP_TWO_PUSH_OUTER)-1);
- return; // as HandleEvent on latter will execute same code (below)
- }
- //deliberate fallthrough
- case LP_TWO_PUSH_UP:
- if (GetLongParameter(LP_TWO_PUSH_UP)>=GetLongParameter(LP_TWO_PUSH_OUTER)) {
- //two_push_up must have changed, or we'd have caught this in previous check for two_push_outer
- SetLongParameter(LP_TWO_PUSH_OUTER, GetLongParameter(LP_TWO_PUSH_UP)+1);
- return;
- }
- if (GetLongParameter(LP_TWO_PUSH_UP)<=GetLongParameter(LP_TWO_PUSH_DOWN)) {
- SetLongParameter(LP_TWO_PUSH_DOWN, GetLongParameter(LP_TWO_PUSH_UP)-1);
- return;
- }
- //deliberate fallthrough
- case LP_TWO_PUSH_DOWN:
- if (GetLongParameter(LP_TWO_PUSH_DOWN)>=GetLongParameter(LP_TWO_PUSH_UP)) {
- SetLongParameter(LP_TWO_PUSH_UP, GetLongParameter(LP_TWO_PUSH_DOWN)+1);
- return;
- }
- {
- //TODO, that means short gap at the top - allow other way around also?
-
-double dOuter = GetLongParameter(LP_TWO_PUSH_OUTER);
-m_dLogUpMul = log(dOuter / (double)GetLongParameter(LP_TWO_PUSH_UP));
-m_dLogDownMul = log(dOuter / (double)GetLongParameter(LP_TWO_PUSH_DOWN));
-//cout << "bitsUp " << m_dLogUpMul << " bitsDown " << m_dLogDownMul << "\n";
- } //and fallthrough
- case LP_TWO_PUSH_TOLERANCE: //deliberate fallthrough
- case LP_MAX_BITRATE:
- {
- //dPressBits just measures the number of bits which would be output in the
- // tolerance time, at full (100%) speed; note it does not take account of
- // the SpeedMul (viscosity) of the node under the cursor (or Slow Start, etc.)
- // - iow, when we are moving slowly for such a reason, we'll be proportionately
- // _more_ tolerant of user inaccuracy in button pushing...
-double dPressBits = GetLongParameter(LP_MAX_BITRATE)/100.0 * (double) GetLongParameter(LP_TWO_PUSH_TOLERANCE) / 1000.0;
-//cout << "Max Bitrate changed - now " << dMaxRate << " user accuracy " << dPressBits;
-m_dMinShortTwoPushTime = m_dLogUpMul - dPressBits;
-//cout << "bits; minShort " << m_dMinShortTwoPushTime;
-m_dMaxShortTwoPushTime = m_dLogUpMul + dPressBits;
-m_dMinLongTwoPushTime = m_dLogDownMul - dPressBits;
-if (m_dMaxShortTwoPushTime > m_dMinLongTwoPushTime)
- m_dMaxShortTwoPushTime = m_dMinLongTwoPushTime = (m_dLogUpMul + m_dLogDownMul)/2.0;
-m_dMaxLongTwoPushTime = m_dLogDownMul + dPressBits;
-//TODO, what requirements do we actually need to make to ensure sanity (specifically, that computed m_aiTarget's are in range)?
-//cout << " maxShort " << m_dMaxShortTwoPushTime << " minLong " << m_dMinLongTwoPushTime << " maxLong " << m_dMaxLongTwoPushTime << "\n";
-m_bDecorationChanged = true;
- } //and fallthrough again
- case LP_DYNAMIC_BUTTON_LAG:
- m_dLagBits = GetLongParameter(LP_MAX_BITRATE)/100.0 * GetLongParameter(LP_DYNAMIC_BUTTON_LAG)/1000.0;
-//cout << " lag (" << m_dLagBits[0] << ", " << m_dLagBits[1] << ", " << m_dLagBits[2] << ", " << m_dLagBits[3] << ")";
- //these areas should really be calculated using short/long push-times modified by the
- // current FrameSpeedMul, which we'd have to do every frame. For now I'm not, so the guide
- // areas will be wrong when the speed multiplier is other than 1.0. TODO reconsider, esp.
- // wrt. possibly memoizing exp() in CDynamicFilter?
- m_aaiGuideAreas[0][0] = 2048 - GetLongParameter(LP_TWO_PUSH_UP)*exp(m_dMaxShortTwoPushTime);
- m_aaiGuideAreas[0][1] = 2048 - GetLongParameter(LP_TWO_PUSH_UP)*exp(m_dMinShortTwoPushTime);
- m_aaiGuideAreas[1][0] = 2048 + GetLongParameter(LP_TWO_PUSH_DOWN)*exp(m_dMinLongTwoPushTime);
- m_aaiGuideAreas[1][1] = 2048 + GetLongParameter(LP_TWO_PUSH_DOWN)*exp(m_dMaxLongTwoPushTime);
- break;
+ switch (iParameter) {
+ case LP_TWO_PUSH_OUTER: //fallthrough
+ case LP_TWO_PUSH_LONG: //fallthrough
+ case LP_TWO_PUSH_SHORT: {
+ //TODO, short gap always at the top - allow other way around also?
+ double dOuter = GetLongParameter(LP_TWO_PUSH_OUTER);
+ m_dLogUpMul = log(dOuter / upDist());
+ m_dLogDownMul = log(dOuter / downDist());
+//cout << "bitsUp " << m_dLogUpMul << " bitsDown " << m_dLogDownMul << std::endl;
+ } //and fallthrough
+ case LP_TWO_PUSH_TOLERANCE: //fallthrough
+ case LP_DYNAMIC_BUTTON_LAG:
+ //recompute rest in Timer
+ m_dLastBitRate=-numeric_limits<double>::infinity();
}
}
+void CTwoPushDynamicFilter::updateBitrate(double dBitrate) {
+ if (dBitrate==m_dLastBitRate) return;
+ m_dLastBitRate = dBitrate;
+
+ double dPressBits = dBitrate * (double) GetLongParameter(LP_TWO_PUSH_TOLERANCE) / 1000.0;
+//cout << "Max Bitrate changed - now " << dBitrate << " user accuracy " << dPressBits;
+ m_dMinShortTwoPushTime = m_dLogUpMul - dPressBits;
+ m_dMaxShortTwoPushTime = m_dLogUpMul + dPressBits;
+ m_dMinLongTwoPushTime = m_dLogDownMul - dPressBits;
+ if (m_dMaxShortTwoPushTime > m_dMinLongTwoPushTime)
+ m_dMaxShortTwoPushTime = m_dMinLongTwoPushTime = (m_dLogUpMul + m_dLogDownMul)/2.0;
+ m_dMaxLongTwoPushTime = m_dLogDownMul + dPressBits;
+ //TODO, what requirements do we actually need to make to ensure sanity (specifically, that computed m_aiTarget's are in range)?
+//cout << "bits; minShort " << m_dMinShortTwoPushTime << " maxShort " << m_dMaxShortTwoPushTime << " minLong " << m_dMinLongTwoPushTime << " maxLong " << m_dMaxLongTwoPushTime << std::endl;
+ m_bDecorationChanged = true;
+
+ m_dLagBits = dBitrate * GetLongParameter(LP_DYNAMIC_BUTTON_LAG)/1000.0;
+
+ const long down(downDist()), up(upDist());
+
+ //the boundaries of the guide areas (around the outer markers) are
+ // then computed from the number of bits _since_ the inner marker:
+ m_aaiGuideAreas[0][0] = 2048 - up*exp(m_dMaxShortTwoPushTime);
+ m_aaiGuideAreas[0][1] = 2048 - up*exp(m_dMinShortTwoPushTime);
+ m_aaiGuideAreas[1][0] = 2048 + down*exp(m_dMinLongTwoPushTime);
+ m_aaiGuideAreas[1][1] = 2048 + down*exp(m_dMaxLongTwoPushTime);
+//cout << "Short " << m_aaiGuideAreas[0][0] << " to " << m_aaiGuideAreas[0][1] << ", Long " << m_aaiGuideAreas[1][0] << " to " << m_aaiGuideAreas[1][1];
+}
+
void CTwoPushDynamicFilter::KeyDown(unsigned long Time, int iId, CDasherView *pView, CDasherInput *pInput, CDasherModel *pModel) {
if (iId == 100 && !GetBoolParameter(BP_BACKOFF_BUTTON))
//mouse click - will be ignored by superclass method.
@@ -182,6 +164,11 @@ void CTwoPushDynamicFilter::KeyUp(unsigned long Time, int iId, CDasherView *pVie
//mouse click - will be ignored by superclass method.
//simulate press of button 2...
iId=2;
+ if (GetBoolParameter(BP_TWO_PUSH_RELEASE_TIME)
+ && isRunning() && iId==m_iHeldId
+ && m_dNatsSinceFirstPush!=-numeric_limits<double>::infinity())
+ ActionButton(Time, iId, 0, pModel);
+ //just records that the key has been released
CDynamicButtons::KeyUp(Time, iId, pView, pInput, pModel);
}
@@ -194,19 +181,16 @@ void CTwoPushDynamicFilter::ActionButton(unsigned long iTime, int iButton, int i
reverse(iTime);
return;
}
- if (m_dNatsSinceFirstPush == -std::numeric_limits<double>::infinity()) //no button pushed (recently)
- {
+ if (m_dNatsSinceFirstPush == -std::numeric_limits<double>::infinity()) {
+ //no button pushed (recently)
m_dNatsSinceFirstPush = pModel->GetNats();
//note, could be negative if overall reversed since last ResetNats (Offset)
//cout << "First push - got " << m_dNatsSinceFirstPush << std::endl;
- }
- else
- {
-//cout << "Second push - event type " << iType << " logGrowth " << pModel->GetNats() << "\n";
+ } else {
+//cout << "Second push - event type " << iType << " logGrowth " << pModel->GetNats() << std::endl;
if (m_iActiveMarker == -1)
reverse(iTime);
- else
- {
+ else {
ApplyOffset(pModel,m_aiTarget[m_iActiveMarker]);
pModel->ResetNats();
//don't really have to reset there, but seems as good a place as any
@@ -215,8 +199,7 @@ void CTwoPushDynamicFilter::ActionButton(unsigned long iTime, int iButton, int i
}
}
-bool doSet(int &var, const int val)
-{
+bool doSet(int &var, const int val) {
if (var == val) return false;
var = val;
return true;
@@ -225,10 +208,11 @@ bool doSet(int &var, const int val)
void CTwoPushDynamicFilter::TimerImpl(unsigned long iTime, CDasherView *m_pDasherView, CDasherModel *m_pDasherModel, CExpansionPolicy **pol) {
DASHER_ASSERT(isRunning());
const double dSpeedMul(FrameSpeedMul(m_pDasherModel, iTime));
- if (m_dNatsSinceFirstPush > -std::numeric_limits<double>::infinity()) // first button has been pushed
- {
+ updateBitrate(GetLongParameter(LP_MAX_BITRATE)*dSpeedMul/100.0);
+ if (m_dNatsSinceFirstPush > -std::numeric_limits<double>::infinity()) {
+ // first button has been pushed
double dLogGrowth(m_pDasherModel->GetNats() - m_dNatsSinceFirstPush), dOuter(GetLongParameter(LP_TWO_PUSH_OUTER)),
- dUp(GetLongParameter(LP_TWO_PUSH_UP)), dDown(GetLongParameter(LP_TWO_PUSH_DOWN));
+ dUp(upDist()), dDown(downDist());
//to move to point currently at outer marker: set m_aiTarget to dOuter==exp( log(dOuter/dUp) ) * dUp
// (note that m_dLogUpMul has already been set to log(dOuter/dUp)...)
@@ -242,17 +226,15 @@ void CTwoPushDynamicFilter::TimerImpl(unsigned long iTime, CDasherView *m_pDashe
double dDownDist = exp( dDownBits ) * dDown;
// (note it's actually slightly more complicated even than that, we have to add in m_dLagBits too!)
- m_aiTarget[0] = dUpDist * exp(m_dLagBits * dSpeedMul);
- m_aiTarget[1] = -dDownDist * exp(m_dLagBits * dSpeedMul);
- m_bDecorationChanged |= doSet(m_aiMarker[0], 2048 - exp(m_dLagBits*dSpeedMul + dLogGrowth) * dUp);
- m_bDecorationChanged |= doSet(m_aiMarker[1], 2048 + exp(m_dLagBits*dSpeedMul + dLogGrowth) * dDown);
- if (dLogGrowth > m_dMaxLongTwoPushTime)
- {
-//cout << " growth " << dLogGrowth << " - reversing\n";
+ m_aiTarget[0] = dUpDist * exp(m_dLagBits);
+ m_aiTarget[1] = -dDownDist * exp(m_dLagBits);
+ m_bDecorationChanged |= doSet(m_aiMarker[0], 2048 - exp(m_dLagBits + dLogGrowth) * dUp);
+ m_bDecorationChanged |= doSet(m_aiMarker[1], 2048 + exp(m_dLagBits + dLogGrowth) * dDown);
+ if (dLogGrowth > m_dMaxLongTwoPushTime) {
+//cout << " growth " << dLogGrowth << " - reversing" << std::endl;
//button pushed, but then waited too long.
reverse(iTime);
- }
- else if (dLogGrowth >= m_dMinShortTwoPushTime && dLogGrowth <= m_dMaxShortTwoPushTime)
+ } else if (dLogGrowth >= m_dMinShortTwoPushTime && dLogGrowth <= m_dMaxShortTwoPushTime)
m_bDecorationChanged |= doSet(m_iActiveMarker, 0 /*up*/);
else if (dLogGrowth >= m_dMinLongTwoPushTime)
m_bDecorationChanged |= doSet(m_iActiveMarker, 1 /*down*/);
diff --git a/Src/DasherCore/TwoPushDynamicFilter.h b/Src/DasherCore/TwoPushDynamicFilter.h
index f893e8f..8b55c59 100644
--- a/Src/DasherCore/TwoPushDynamicFilter.h
+++ b/Src/DasherCore/TwoPushDynamicFilter.h
@@ -25,7 +25,16 @@
namespace Dasher {
/// \ingroup InputFilter
/// @{
-class CTwoPushDynamicFilter : public CDynamicButtons, public CSettingsObserver /*long push, but do our own "multi-push" detection*/ {
+ ///Dynamic filter in which user has two gestures, both performed with a single
+ /// button: one gesture for up and one for down. According to BP_TWO_PUSH_RELEASE_TIME,
+ /// the two gestures are either (a) two pushes with a short gap between, vs
+ /// (b) two pushes with a long gap between; or else, (a) a short vs (b) a long press.
+ ///Note we do not detect long or multiple presses in the usual way (CButtonMultiPress):
+ /// for users capable of making long presses, we suggest turning BP_TWO_PUSH_RELEASE_TIME
+ /// on (and reversing can be achieved by making a press of ambiguous length -
+ /// too short, too long, or inbetween); otherwise, with BP_TWO_PRESS_RELEASE_TIME
+ /// off, reversing can be achieved by making just a single press, and then waiting.
+ class CTwoPushDynamicFilter : public CDynamicButtons, public CSettingsObserver {
public:
CTwoPushDynamicFilter(CSettingsUser *pCreator, CDasherInterfaceBase *pInterface, CFrameRate *pFramerate);
@@ -35,7 +44,7 @@ class CTwoPushDynamicFilter : public CDynamicButtons, public CSettingsObserver /
virtual bool GetMinWidth(int &iMinWidth);
virtual bool GetSettings(SModuleSettings **pSettings, int *iCount);
- //override to get mouse clicks / taps back again...
+ //override to get mouse clicks / taps back again if BACKOFF_BUTTON off...
virtual void KeyDown(unsigned long Time, int iId, CDasherView *pDasherView, CDasherInput *pInput, CDasherModel *pModel);
virtual void KeyUp(unsigned long Time, int iId, CDasherView *pDasherView, CDasherInput *pInput, CDasherModel *pModel);
@@ -48,6 +57,9 @@ class CTwoPushDynamicFilter : public CDynamicButtons, public CSettingsObserver /
virtual void run(unsigned long iTime);
private:
+ void updateBitrate(double dBitrate);
+ long upDist();
+ long downDist();
double m_dLogUpMul, m_dLogDownMul, m_dLagBits;
double m_dMinShortTwoPushTime, m_dMaxShortTwoPushTime,
m_dMinLongTwoPushTime, m_dMaxLongTwoPushTime;
@@ -55,7 +67,7 @@ class CTwoPushDynamicFilter : public CDynamicButtons, public CSettingsObserver /
int m_iActiveMarker;
int m_aiTarget[2];
int m_aaiGuideAreas[2][2];
-
+ double m_dLastBitRate;
double m_dNatsSinceFirstPush;
};
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]