|
|
2b429e |
#pragma once
|
|
|
2b429e |
|
|
|
2b429e |
#ifndef KEYSTATE_INCLUDED
|
|
|
2b429e |
#define KEYSTATE_INCLUDED
|
|
|
2b429e |
|
|
|
2b429e |
// TnzTools includes
|
|
|
2b429e |
#include <tools tooltimer.h=""></tools>
|
|
|
2b429e |
|
|
|
2b429e |
// TnzCore includes
|
|
|
2b429e |
#include <tcommon.h></tcommon.h>
|
|
|
2b429e |
#include <tsmartpointer.h></tsmartpointer.h>
|
|
|
2b429e |
|
|
|
2b429e |
// std includes
|
|
|
2b429e |
#include <map></map>
|
|
|
2b429e |
#include <set></set>
|
|
|
2b429e |
#include <algorithm></algorithm>
|
|
|
2b429e |
#include <cmath></cmath>
|
|
|
2b429e |
|
|
|
2b429e |
|
|
|
2b429e |
#undef DVAPI
|
|
|
2b429e |
#undef DVVAR
|
|
|
2b429e |
#ifdef TNZTOOLS_EXPORTS
|
|
|
2b429e |
#define DVAPI DV_EXPORT_API
|
|
|
2b429e |
#define DVVAR DV_EXPORT_VAR
|
|
|
2b429e |
#else
|
|
|
2b429e |
#define DVAPI DV_IMPORT_API
|
|
|
2b429e |
#define DVVAR DV_IMPORT_VAR
|
|
|
2b429e |
#endif
|
|
|
2b429e |
|
|
|
2b429e |
|
|
|
2b429e |
//===================================================================
|
|
|
2b429e |
|
|
|
2b429e |
//*****************************************************************************************
|
|
|
2b429e |
// TKeyState definition
|
|
|
2b429e |
//*****************************************************************************************
|
|
|
2b429e |
|
|
|
2b429e |
template<typename t=""></typename>
|
|
|
49945e |
class TKeyStateT : public TSmartObject {
|
|
|
2b429e |
public:
|
|
|
2b429e |
typedef T Type;
|
|
|
2b429e |
typedef TSmartPointerT<tkeystatet> Pointer;</tkeystatet>
|
|
|
2b429e |
|
|
|
2b429e |
struct Holder {
|
|
|
2b429e |
Pointer state;
|
|
|
2b429e |
TTimerTicks ticks;
|
|
|
2b429e |
double timeOffset;
|
|
|
2b429e |
|
|
|
49945e |
explicit Holder(const Pointer &state = Pointer(), TTimerTicks ticks = 0, double timeOffset = 0.0):
|
|
|
2b429e |
state(state), ticks(ticks), timeOffset(timeOffset) { }
|
|
|
2b429e |
|
|
|
2b429e |
Pointer find(const Type &value) const
|
|
|
2b429e |
{ return state ? state->find(value) : Pointer(); }
|
|
|
2b429e |
bool isEmpty() const
|
|
|
2b429e |
{ return !state || state->isEmpty(); }
|
|
|
2b429e |
bool isPressed(const Type &value) const
|
|
|
2b429e |
{ return find(value); }
|
|
|
2b429e |
double howLongPressed(const Type &value)
|
|
|
2b429e |
{ return howLongPressed(find(value), ticks, timeOffset); }
|
|
|
2b429e |
|
|
|
2b429e |
static double howLongPressed(const Pointer &state, long ticks, double timeOffset) {
|
|
|
efa14d |
return state
|
|
|
efa14d |
? std::max(TToolTimer::step, (ticks - state->ticks)*TToolTimer::step + timeOffset)
|
|
|
efa14d |
: 0.0;
|
|
|
2b429e |
}
|
|
|
2b429e |
};
|
|
|
2b429e |
|
|
|
16421e |
static const Type& none() {
|
|
|
16421e |
static Type none;
|
|
|
16421e |
return none;
|
|
|
16421e |
}
|
|
|
16421e |
|
|
|
16421e |
static const Pointer& empty() {
|
|
|
16421e |
static Pointer empty = new TKeyStateT();
|
|
|
16421e |
return empty;
|
|
|
16421e |
}
|
|
|
2b429e |
|
|
|
2b429e |
const Pointer previous;
|
|
|
2b429e |
const TTimerTicks ticks;
|
|
|
2b429e |
const Type value;
|
|
|
2b429e |
|
|
|
2b429e |
private:
|
|
|
2b429e |
TKeyStateT(const Pointer &previous, TTimerTicks ticks, const Type &value):
|
|
|
2b429e |
previous(previous), ticks(ticks), value(value) { }
|
|
|
2b429e |
|
|
|
2b429e |
Pointer makeChainWithout(const Pointer &state) {
|
|
|
d8eddc |
return state == this ? previous
|
|
|
d8eddc |
: previous ? Pointer(new TKeyStateT(previous->makeChainWithout(state), ticks, value))
|
|
|
d8eddc |
: this;
|
|
|
2b429e |
}
|
|
|
2b429e |
|
|
|
2b429e |
public:
|
|
|
16421e |
TKeyStateT(): ticks(0), value(none()) { }
|
|
|
2b429e |
|
|
|
2b429e |
Pointer find(const Type &value) {
|
|
|
16421e |
return value == none() ? Pointer()
|
|
|
2b429e |
: value == this->value ? this
|
|
|
2b429e |
: previous ? previous->find(value)
|
|
|
2b429e |
: Pointer();
|
|
|
2b429e |
}
|
|
|
2b429e |
|
|
|
2b429e |
Pointer change(bool press, const Type &value, TTimerTicks ticks) {
|
|
|
16421e |
if (value == none())
|
|
|
2b429e |
return Pointer(this);
|
|
|
d8eddc |
|
|
|
d8eddc |
Pointer p = find(value);
|
|
|
d8eddc |
if (press == bool(p))
|
|
|
d8eddc |
return Pointer(this);
|
|
|
d8eddc |
|
|
|
2b429e |
if (ticks <= this->ticks)
|
|
|
2b429e |
ticks = this->ticks + 1;
|
|
|
2b429e |
|
|
|
d8eddc |
if (press)
|
|
|
2b429e |
return Pointer(new TKeyStateT((isEmpty() ? Pointer() : Pointer(this)), ticks, value));
|
|
|
2b429e |
Pointer chain = makeChainWithout(p);
|
|
|
16421e |
return chain ? chain : Pointer(new TKeyStateT(Pointer(), ticks, none()));
|
|
|
2b429e |
}
|
|
|
2b429e |
|
|
|
2b429e |
bool isEmpty()
|
|
|
16421e |
{ return value == none() && (!previous || previous->isEmpty()); }
|
|
|
2b429e |
bool isPressed(const Type &value)
|
|
|
2b429e |
{ return find(value); }
|
|
|
2b429e |
|
|
|
2b429e |
Pointer pressed(const Type &value, long ticks)
|
|
|
2b429e |
{ return change(true, value, ticks); }
|
|
|
2b429e |
Pointer released(const Type &value, long ticks)
|
|
|
2b429e |
{ return change(false, value, ticks); }
|
|
|
2b429e |
};
|
|
|
2b429e |
|
|
|
2b429e |
|
|
|
2b429e |
//*****************************************************************************************
|
|
|
2b429e |
// TKeyHistory definition
|
|
|
2b429e |
//*****************************************************************************************
|
|
|
2b429e |
|
|
|
2b429e |
template<typename t=""></typename>
|
|
|
49945e |
class TKeyHistoryT : public TSmartObject {
|
|
|
2b429e |
public:
|
|
|
2b429e |
typedef T Type;
|
|
|
2b429e |
typedef TSmartPointerT<tkeyhistoryt> Pointer;</tkeyhistoryt>
|
|
|
2b429e |
typedef TKeyStateT<type> State;</type>
|
|
|
2b429e |
typedef typename TKeyStateT<type>::Pointer StatePointer;</type>
|
|
|
2b429e |
typedef typename TKeyStateT<type>::Holder StateHolder;</type>
|
|
|
d8eddc |
typedef std::map<ttimerticks, statepointer=""> StateMap;</ttimerticks,>
|
|
|
d8eddc |
typedef std::multiset<ttimerticks> LockSet;</ttimerticks>
|
|
|
2b429e |
|
|
|
2b429e |
class Holder {
|
|
|
2b429e |
private:
|
|
|
49945e |
Pointer m_history;
|
|
|
49945e |
TTimerTicks m_ticks;
|
|
|
49945e |
double m_timeOffset;
|
|
|
49945e |
TTimerTicks m_heldTicks;
|
|
|
2b429e |
|
|
|
2b429e |
public:
|
|
|
2b429e |
Holder():
|
|
|
49945e |
m_ticks(), m_timeOffset(), m_heldTicks() { }
|
|
|
2b429e |
Holder(const Pointer &history, TTimerTicks ticks, double timeOffset = 0.0):
|
|
|
49945e |
m_ticks(), m_timeOffset(), m_heldTicks()
|
|
|
2b429e |
{ set(history, ticks, timeOffset); }
|
|
|
2b429e |
Holder(const Holder &other):
|
|
|
49945e |
m_ticks(), m_timeOffset(), m_heldTicks()
|
|
|
2b429e |
{ set(other); }
|
|
|
2b429e |
~Holder()
|
|
|
2b429e |
{ reset(); }
|
|
|
2b429e |
|
|
|
2b429e |
Holder& operator= (const Holder &other)
|
|
|
2b429e |
{ set(other); return *this; }
|
|
|
2b429e |
|
|
|
2b429e |
void set(const Pointer &history, TTimerTicks ticks, double timeOffset = 0.0) {
|
|
|
d8eddc |
TTimerTicks prevHeldTicks = m_heldTicks;
|
|
|
d8eddc |
Pointer prevHistory = m_history;
|
|
|
49945e |
m_history = history;
|
|
|
49945e |
m_ticks = ticks;
|
|
|
49945e |
m_timeOffset = timeOffset;
|
|
|
49945e |
m_heldTicks = (m_history ? m_history->holdTicks(m_ticks) : 0);
|
|
|
d8eddc |
if (prevHistory) prevHistory->releaseTicks(prevHeldTicks);
|
|
|
2b429e |
}
|
|
|
2b429e |
void set(const Holder &other)
|
|
|
2b429e |
{ set(other.history(), other.ticks(), other.timeOffset()); }
|
|
|
2b429e |
void reset()
|
|
|
2b429e |
{ set(Pointer(), 0); }
|
|
|
2b429e |
|
|
|
2b429e |
Pointer history() const
|
|
|
49945e |
{ return m_history; }
|
|
|
2b429e |
TTimerTicks ticks() const
|
|
|
49945e |
{ return m_ticks; }
|
|
|
2b429e |
double timeOffset() const
|
|
|
49945e |
{ return m_timeOffset; }
|
|
|
2b429e |
|
|
|
2b429e |
Holder offset(double timeOffset) const {
|
|
|
2b429e |
return fabs(timeOffset) < TToolTimer::epsilon ? *this
|
|
|
16421e |
: Holder(m_history, m_ticks, m_timeOffset + timeOffset);
|
|
|
2b429e |
}
|
|
|
2b429e |
|
|
|
2b429e |
StateHolder get(double time) const {
|
|
|
49945e |
TTimerTicks dticks = (TTimerTicks)ceil(TToolTimer::frequency*(time + m_timeOffset));
|
|
|
49945e |
StatePointer state = m_history->get(m_ticks + dticks);
|
|
|
49945e |
return StateHolder(state, m_ticks, m_timeOffset + time);
|
|
|
2b429e |
}
|
|
|
2b429e |
};
|
|
|
2b429e |
|
|
|
2b429e |
private:
|
|
|
d8eddc |
StateMap m_states;
|
|
|
d8eddc |
LockSet m_locks;
|
|
|
2b429e |
|
|
|
2b429e |
void autoRemove() {
|
|
|
d8eddc |
TTimerTicks ticks = m_states.rbegin()->first;
|
|
|
d8eddc |
if (!m_locks.empty())
|
|
|
d8eddc |
ticks = std::min(ticks, *m_locks.begin());
|
|
|
2b429e |
while(true) {
|
|
|
d8eddc |
typename StateMap::iterator i = m_states.begin();
|
|
|
2b429e |
++i;
|
|
|
49945e |
if (i == m_states.end() || (!i->second->isEmpty() && i->first >= ticks)) break;
|
|
|
49945e |
m_states.erase(i);
|
|
|
2b429e |
}
|
|
|
2b429e |
}
|
|
|
2b429e |
|
|
|
2b429e |
TTimerTicks holdTicks(TTimerTicks ticks)
|
|
|
49945e |
{ return *m_locks.insert(std::max(ticks, m_states.begin()->first)); }
|
|
|
d8eddc |
void releaseTicks(TTimerTicks heldTicks) {
|
|
|
d8eddc |
typename LockSet::iterator i = m_locks.find(heldTicks);
|
|
|
d8eddc |
if (i == m_locks.end()) return;
|
|
|
d8eddc |
m_locks.erase(i);
|
|
|
d8eddc |
autoRemove();
|
|
|
d8eddc |
}
|
|
|
2b429e |
|
|
|
2b429e |
StatePointer get(TTimerTicks ticks) {
|
|
|
d8eddc |
typename StateMap::iterator i = m_states.upper_bound(ticks);
|
|
|
49945e |
return i == m_states.begin() ? i->second : (--i)->second;
|
|
|
2b429e |
}
|
|
|
2b429e |
|
|
|
2b429e |
public:
|
|
|
2b429e |
TKeyHistoryT()
|
|
|
49945e |
{ m_states[TTimerTicks()] = StatePointer(new State()); }
|
|
|
2b429e |
|
|
|
2b429e |
StatePointer current() const
|
|
|
49945e |
{ return m_states.rbegin()->second; }
|
|
|
2b429e |
|
|
|
2b429e |
StatePointer change(bool press, Type value, TTimerTicks ticks) {
|
|
|
2b429e |
StatePointer state = current()->change(press, value, ticks);
|
|
|
9e42bc |
if (state != current() && ticks > m_states.rbegin()->first)
|
|
|
49945e |
m_states[state->ticks] = state;
|
|
|
2b429e |
autoRemove();
|
|
|
2b429e |
return current();
|
|
|
2b429e |
}
|
|
|
2b429e |
|
|
|
2b429e |
StatePointer pressed(Type value, TTimerTicks ticks)
|
|
|
2b429e |
{ return change(true, value, ticks); }
|
|
|
2b429e |
|
|
|
2b429e |
StatePointer released(Type value, TTimerTicks ticks)
|
|
|
2b429e |
{ return change(false, value, ticks); }
|
|
|
d8eddc |
|
|
|
d8eddc |
inline const StateMap& getStates() const
|
|
|
d8eddc |
{ return m_states; }
|
|
|
d8eddc |
inline const LockSet& getLocks() const
|
|
|
d8eddc |
{ return m_locks; }
|
|
|
2b429e |
};
|
|
|
2b429e |
|
|
|
2b429e |
|
|
|
2b429e |
#endif
|