diff --git a/toonz/sources/include/tools/inputmanager.h b/toonz/sources/include/tools/inputmanager.h
new file mode 100644
index 0000000..63d3560
--- /dev/null
+++ b/toonz/sources/include/tools/inputmanager.h
@@ -0,0 +1,356 @@
+#ifndef INPUTMANAGER_INCLUDED
+#define INPUTMANAGER_INCLUDED
+
+// TnzTools includes
+#include <tools/tooltimer.h>
+#include <tools/inputstate.h>
+#include <tools/track.h>
+
+// TnzCore includes
+#include <tcommon.h>
+#include <tsmartpointer.h>
+
+// Qt includes
+#include <QObject>
+#include <QKeyEvent>
+
+// std includes
+#include <vector>
+#include <algorithm>
+
+
+#undef DVAPI
+#undef DVVAR
+#ifdef TNZTOOLS_EXPORTS
+#define DVAPI DV_EXPORT_API
+#define DVVAR DV_EXPORT_VAR
+#else
+#define DVAPI DV_IMPORT_API
+#define DVVAR DV_IMPORT_VAR
+#endif
+
+
+//====================================================
+
+//  Forward declarations
+
+class TInputModifier;
+class TInputManager;
+
+typedef TSmartPointerT<TInputModifier> TInputModifierP;
+typedef TSmartPointerT<TInputManager> TInputManagerP;
+
+//===================================================================
+
+
+//*****************************************************************************************
+//    TInputSavePoint definition
+//*****************************************************************************************
+
+class TInputSavePoint {
+public:
+  class Holder {
+  private:
+    TInputSavePoint *m_savePoint;
+    bool m_lock = false;
+
+  public:
+    inline explicit Holder(TInputSavePoint *savePoint = NULL, bool lock = true):
+      m_savePoint(), m_lock()
+      { set(savePoint, lock); }
+    inline Holder(const Holder &other):
+      m_savePoint(), m_lock()
+      { *this = other; }
+    inline ~Holder()
+      { reset(); }
+
+    inline Holder& operator= (const Holder &other)
+      { set(other.m_savePoint, other.m_lock); return *this; }
+
+    inline void set(TInputSavePoint *savePoint, bool lock) {
+      if (m_savePoint != savePoint) {
+        if (m_savePoint) {
+          if (m_lock) m_savePoint->unlock();
+          m_savePoint->release();
+        }
+        m_savePoint = savePoint;
+        m_lock = lock;
+        if (m_savePoint) {
+          m_savePoint->hold();
+           if (m_lock) savePoint->lock();
+        }
+      } else
+      if (m_lock != lock) {
+        if (lock) m_savePoint->lock();
+             else m_savePoint->unlock();
+        m_lock = lock;
+      }
+    }
+
+    inline void reset()
+      { set(NULL, false); }
+    inline void lock()
+      { set(m_savePoint, true); }
+    inline void unlock()
+      { set(m_savePoint, false); }
+
+    inline TInputSavePoint* savePoint() const
+      { return m_savePoint; }
+    inline bool locked() const
+      { return m_savePoint && m_lock; }
+    inline bool available() const
+      { return m_savePoint && m_savePoint->available; }
+    inline bool isFree() const
+      { return !m_savePoint || m_savePoint->isFree(); }
+  };
+
+  typedef std::vector<Holder> List;
+
+private:
+  int m_refCount;
+  int m_lockCount;
+
+  inline void hold()
+    { ++m_refCount; }
+  inline void release()
+    { if ((--m_refCount) <= 0) delete this; }
+  inline void lock()
+    { ++m_refCount; }
+  inline void unlock()
+    { if ((--m_refCount) <= 0) delete this; }
+
+public:
+  bool available;
+
+  inline explicit TInputSavePoint(bool available = false):
+    m_refCount(), m_lockCount(), available(available) { }
+  inline bool isFree() const
+    { return m_lockCount <= 0; }
+
+  static inline Holder create(bool available = false)
+    { return Holder(new TInputSavePoint(available)); }
+};
+
+
+//*****************************************************************************************
+//    TInputModifier definition
+//*****************************************************************************************
+
+class TInputModifier: public TSmartObject {
+private:
+  TInputManager *m_manager;
+
+public:
+  typedef std::vector<TInputModifierP> List;
+
+  TInputManager* getManager() const
+    { return m_manager; }
+  void setManager(TInputManager *manager);
+  virtual void onSetManager() { }
+
+  virtual void activate() { }
+
+  virtual void modifyTrack(
+    const TTrackP &track,
+    const TInputSavePoint::Holder &savePoint,
+    TTrackList &outTracks ) { }
+  virtual void modifyTracks(
+    const TTrackList &tracks,
+    const TInputSavePoint::Holder &savePoint,
+    TTrackList &outTracks );
+
+  virtual void modifyHover(
+    const TPointD &hover,
+    THoverList &outHovers ) { }
+  virtual void modifyHovers(
+    const THoverList &hovers,
+    THoverList &outHovers );
+
+  virtual void drawHover(const TPointD &hover) { }
+  virtual void drawTrack(const TTrackP &track) { }
+  virtual void draw(const TTrackList &tracks, const THoverList &hovers);
+
+  virtual void deactivate() { }
+};
+
+
+//*****************************************************************************************
+//    TInputHandler definition
+//*****************************************************************************************
+
+class TInputHandler {
+public:
+  virtual void inputLeftButtonDown(const TTrackPoint&, const TTrack&) { }
+  virtual void inputLeftButtonDrag(const TTrackPoint&, const TTrack&) { }
+  virtual void inputLeftButtonUp(const TTrackPoint&, const TTrack&) { }
+  virtual void inputMouseMove(const TPointD&, const TInputState&) { }
+  virtual void inputRightButtonDown(const TPointD&, const TInputState&) { }
+  virtual bool inputKeyDown(QKeyEvent *) { return false; }
+
+  virtual void inputSetBusy(bool) { }
+  
+  virtual bool inputKeyEvent(
+    bool press,
+    TInputState::Key key,
+    QKeyEvent *event,
+    const TInputManager &manager );
+  
+  virtual void inputButtonEvent(
+    bool press,
+    TInputState::DeviceId device,
+    TInputState::Button button,
+    const TInputManager &manager );
+  
+  virtual void inputHoverEvent(const TInputManager &manager);
+
+  /*! paint single track-point at the top painting level */
+  virtual void inputPaintTrackPoint(const TTrackPoint &point, const TTrack &track, bool firstTrack);
+
+  /*! create new painting level and return true, or do nothing and return false
+      was:            ------O-------O------
+      become:         ------O-------O------O */
+  virtual bool inputPaintPush() { return false; }
+  /*! paint several track-points at the top painting level
+      was:            ------O-------O------
+      become:         ------O-------O------------ */
+  virtual void inputPaintTracks(const TTrackList &tracks);
+  /*! try to merge N top painting levels and return count of levels that actually merged
+      was:            ------O-------O------O------
+      become (N = 2): ------O--------------------- */
+  virtual int inputPaintApply(int count) { return 0; }
+  /*! reset top level to initial state
+      was:            ------O-------O------O------
+      become:         ------O-------O------O */
+  virtual void inputPaintCancel() { }
+  /*! cancel and pop N painting levels
+      was:            ------O-------O------O------
+      become (N = 2): ------O------- */
+  virtual void inputPaintPop(int count) { }
+};
+
+
+//*****************************************************************************************
+//    TInputManager definition
+//*****************************************************************************************
+
+class TInputManager: public TSmartObject {
+public:
+  class TrackHandler: public TTrackHandler {
+  public:
+    std::vector<int> saves;
+    TrackHandler(TTrack &original, int keysCount = 0):
+      TTrackHandler(original), saves(keysCount, 0)
+      { }
+  };
+
+private:
+  TInputHandler *m_handler;
+  TInputModifier::List m_modifiers;
+  std::vector<TTrackList> m_tracks;
+  std::vector<THoverList> m_hovers;
+  TInputSavePoint::List m_savePoints;
+  int m_savePointsSent;
+
+  static TInputState::TouchId m_lastTouchId;
+
+
+public:
+  TInputState state;
+
+
+public:
+  TInputManager();
+
+private:
+  void paintRollbackTo(int saveIndex, TTrackList &subTracks);
+  void paintApply(int count, TTrackList &subTracks);
+  void paintTracks();
+
+  int trackCompare(
+    const TTrack &track,
+    TInputState::DeviceId deviceId,
+    TInputState::TouchId touchId );
+  const TTrackP& createTrack(
+    int index,
+    TInputState::DeviceId deviceId,
+    TInputState::TouchId touchId,
+    TTimerTicks ticks,
+    bool hasPressure,
+    bool hasTilt );
+  const TTrackP& getTrack(
+    TInputState::DeviceId deviceId,
+    TInputState::TouchId touchId,
+    TTimerTicks ticks,
+    bool hasPressure,
+    bool hasTilt );
+  void addTrackPoint(
+    const TTrackP& track,
+    const TPointD &position,
+    double pressure,
+    const TPointD &tilt,
+    double time,
+    bool final );
+  void touchTracks(bool finish = false);
+
+  void modifierActivate(const TInputModifierP &modifier);
+  void modifierDeactivate(const TInputModifierP &modifier);
+
+public:
+  inline const TTrackList& getInputTracks() const
+    { return m_tracks.front(); }
+  inline const TTrackList& getOutputTracks() const
+    { return m_tracks.back(); }
+
+  inline const THoverList& getInputHovers() const
+    { return m_hovers.front(); }
+  inline const THoverList& getOutputHovers() const
+    { return m_hovers.back(); }
+
+  void processTracks();
+  void finishTracks();
+  void reset();
+
+  TInputHandler* getHandler() const
+    { return m_handler; }
+  void setHandler(TInputHandler *handler);
+
+  int getModifiersCount() const
+    { return (int)m_modifiers.size(); }
+  const TInputModifierP& getModifier(int index) const
+    { return m_modifiers[index]; }
+  int findModifier(const TInputModifierP &modifier) const;
+  void insertModifier(int index, const TInputModifierP &modifier);
+  void addModifier(const TInputModifierP &modifier)
+    { insertModifier(getModifiersCount(), modifier); }
+  void removeModifier(int index);
+  void removeModifier(const TInputModifierP &modifier)
+    { removeModifier(findModifier(modifier)); }
+  void clearModifiers();
+
+  void trackEvent(
+    TInputState::DeviceId deviceId,
+    TInputState::TouchId touchId,
+    const TPointD &position,
+    const double *pressure,
+    const TPointD *tilt,
+    bool final,
+    TTimerTicks ticks );
+  bool keyEvent(
+    bool press,
+    TInputState::Key key,
+    TTimerTicks ticks,
+    QKeyEvent *event );
+  void buttonEvent(
+    bool press,
+    TInputState::DeviceId deviceId,
+    TInputState::Button button,
+    TTimerTicks ticks);
+  void hoverEvent(const THoverList &hovers);
+
+  void draw();
+
+  static TInputState::TouchId genTouchId();
+};
+
+
+#endif
diff --git a/toonz/sources/include/tools/inputstate.h b/toonz/sources/include/tools/inputstate.h
index 5fd2109..faab530 100644
--- a/toonz/sources/include/tools/inputstate.h
+++ b/toonz/sources/include/tools/inputstate.h
@@ -10,12 +10,14 @@
 // TnzCore includes
 #include <tcommon.h>
 #include <tsmartpointer.h>
+#include <tgeometry.h>
 
 // Qt includes
 #include <Qt>
 
 // std includes
 #include <map>
+#include <vector>
 
 
 #undef DVAPI
@@ -29,10 +31,57 @@
 #endif
 
 
+//====================================================
+
+//  Forward declarations
+
+typedef std::vector<TPointD> THoverList;
+
 //===================================================================
 
 
 //*****************************************************************************************
+//    TKey definition
+//*****************************************************************************************
+
+class TKey {
+public:
+  Qt::Key key;
+  bool generic;
+  bool numPad;
+
+  static const TKey shift;
+  static const TKey control;
+  static const TKey alt;
+  static const TKey meta;
+
+  inline explicit TKey(Qt::Key key = Qt::Key(), bool generic = true, bool numPad = false):
+    key(key),
+    generic(generic),
+    numPad(numPad)
+    { }
+
+  inline bool operator== (const TKey &other) const {
+    if (generic || other.generic)
+      return is(other.key);
+    return key == other.key && numPad == other.numPad;
+  }
+
+  inline bool is(Qt::Key key) const
+    { return mapKey(this->key) == mapKey(key); }
+
+  inline bool isModifier() const
+    { return isModifier(key); }
+  inline bool isNumber() const
+    { return isNumber(key); }
+
+  static Qt::Key mapKey(Qt::Key key);
+  static bool isNumber(Qt::Key key);
+  static bool isModifier(Qt::Key key);
+};
+
+
+//*****************************************************************************************
 //    TInputState definition
 //*****************************************************************************************
 
@@ -41,7 +90,7 @@ public:
   typedef qint64 DeviceId;
   typedef long long TouchId;
 
-  typedef Qt::Key Key;
+  typedef TKey Key;
   typedef TKeyHistoryT<Key> KeyHistory;
   typedef KeyHistory::State KeyState;
 
@@ -51,23 +100,25 @@ public:
   typedef std::map<DeviceId, ButtonHistory::Pointer> ButtonHistoryMap;
 
 private:
-  TTimerTicks ticks;
-  KeyHistory::Pointer keyHistory_;
-  mutable ButtonHistoryMap buttonHistories_;
-
-  void touch(TTimerTicks ticks);
+  TTimerTicks m_ticks;
+  KeyHistory::Pointer m_keyHistory;
+  mutable ButtonHistoryMap m_buttonHistories;
 
 public:
   TInputState();
   ~TInputState();
 
-  inline KeyHistory::Pointer keyHistory() const
-    { return keyHistory(); }
+  TTimerTicks ticks() const
+    { return m_ticks; }
+  void touch(TTimerTicks ticks);
+
+  inline const KeyHistory::Pointer& keyHistory() const
+    { return m_keyHistory; }
   inline KeyState::Pointer keyState() const
     { return keyHistory()->current(); }
 
   inline void keyEvent(bool press, Key key, TTimerTicks ticks)
-    { touch(ticks); keyHistory()->change(press, key, this->ticks); }
+    { touch(ticks); keyHistory()->change(press, key, m_ticks); }
   inline void keyPress(Key key, TTimerTicks ticks)
     { keyEvent(true, key, ticks); }
   inline void keyRelease(Key key, TTimerTicks ticks)
@@ -80,21 +131,30 @@ public:
   inline double howLongKeyPressed(Key key, TTimerTicks ticks, double timeOffset = 0.0)
     { return KeyState::Holder::howLongPressed(keyFind(key), ticks, timeOffset); }
   inline double howLongKeyPressed(Key key)
-    { return howLongKeyPressed(key, ticks); }
+    { return howLongKeyPressed(key, m_ticks); }
 
-  ButtonHistory::Pointer buttonHistory(DeviceId device) const;
+  inline KeyState::Holder keyStateHolder(TTimerTicks ticks, double timeOffset = 0.0) const
+    { return KeyState::Holder(keyState(), ticks, timeOffset); }
+  inline KeyState::Holder keyStateHolder() const
+    { return keyStateHolder(m_ticks); }
+  inline KeyHistory::Holder keyHistoryHolder(TTimerTicks ticks, double timeOffset = 0.0) const
+    { return KeyHistory::Holder(keyHistory(), ticks, timeOffset); }
+  inline KeyHistory::Holder keyHistoryHolder() const
+    { return keyHistoryHolder(m_ticks); }
+
+  ButtonHistory::Pointer buttonHistory(DeviceId deviceId) const;
 
   inline const ButtonHistoryMap buttonHistories() const
-    { return buttonHistories_; }
-  inline ButtonState::Pointer buttonState(DeviceId device) const
-    { return buttonHistory(device)->current(); }
-
-  inline void buttonEvent(bool press, DeviceId device, Button button, TTimerTicks ticks)
-    { touch(ticks); buttonHistory(device)->change(press, button, this->ticks); }
-  inline void buttonPress(DeviceId device, Button button, TTimerTicks ticks)
-    { buttonEvent(true, device, button, ticks); }
-  inline void buttonRelease(DeviceId device, Button button, TTimerTicks ticks)
-    { buttonEvent(false, device, button, ticks); }
+    { return m_buttonHistories; }
+  inline ButtonState::Pointer buttonState(DeviceId deviceId) const
+    { return buttonHistory(deviceId)->current(); }
+
+  inline void buttonEvent(bool press, DeviceId deviceId, Button button, TTimerTicks ticks)
+    { touch(ticks); buttonHistory(deviceId)->change(press, button, m_ticks); }
+  inline void buttonPress(DeviceId deviceId, Button button, TTimerTicks ticks)
+    { buttonEvent(true, deviceId, button, ticks); }
+  inline void buttonRelease(DeviceId deviceId, Button button, TTimerTicks ticks)
+    { buttonEvent(false, deviceId, button, ticks); }
   inline void buttonEvent(bool press, Button button, TTimerTicks ticks)
     { buttonEvent(press, 0, button, ticks); }
   inline void buttonPress(Button button, TTimerTicks ticks)
@@ -102,14 +162,14 @@ public:
   inline void buttonRelease(Button button, TTimerTicks ticks)
     { buttonEvent(false, button, ticks); }
 
-  inline ButtonState::Pointer buttonFind(DeviceId device, Button button)
-    { return buttonState(device)->find(button); }
-  inline bool isButtonPressed(DeviceId device, Button button)
-    { return buttonFind(device, button); }
-  inline double howLongButtonPressed(DeviceId device, Button button, TTimerTicks ticks, double timeOffset = 0.0)
-    { return ButtonState::Holder::howLongPressed(buttonFind(device, button), ticks, timeOffset); }
-  inline double howLongButtonPressed(DeviceId device, Button button)
-    { return howLongButtonPressed(device, button, ticks); }
+  inline ButtonState::Pointer buttonFind(DeviceId deviceId, Button button)
+    { return buttonState(deviceId)->find(button); }
+  inline bool isButtonPressed(DeviceId deviceId, Button button)
+    { return buttonFind(deviceId, button); }
+  inline double howLongButtonPressed(DeviceId deviceId, Button button, TTimerTicks ticks, double timeOffset = 0.0)
+    { return ButtonState::Holder::howLongPressed(buttonFind(deviceId, button), ticks, timeOffset); }
+  inline double howLongButtonPressed(DeviceId deviceId, Button button)
+    { return howLongButtonPressed(deviceId, button, m_ticks); }
 
   inline ButtonState::Pointer buttonFindDefault(Button button)
     { return buttonFind(DeviceId(), button); }
@@ -118,36 +178,27 @@ public:
   inline double howLongButtonPressedDefault(Button button, TTimerTicks ticks, double timeOffset = 0.0)
     { return howLongButtonPressed(DeviceId(), button, ticks, timeOffset); }
   inline double howLongButtonPressedDefault(Button button)
-    { return howLongButtonPressedDefault(button, ticks); }
+    { return howLongButtonPressedDefault(button, m_ticks); }
 
   ButtonState::Pointer buttonFindAny(Button button, DeviceId &outDevice);
 
   inline ButtonState::Pointer buttonFindAny(Button button)
-    { DeviceId device; return buttonFindAny(button, device); }
+    { DeviceId deviceId; return buttonFindAny(button, deviceId); }
   inline bool isButtonPressedAny(Button button)
     { return buttonFindAny(button); }
   inline double howLongButtonPressedAny(Button button, TTimerTicks ticks, double timeOffset = 0.0)
     { return ButtonState::Holder::howLongPressed(buttonFindAny(button), ticks, timeOffset); }
   inline double howLongButtonPressedAny(Button button)
-    { return howLongButtonPressedAny(button, ticks); }
-
-  inline KeyState::Holder keyStateHolder(TTimerTicks ticks, double timeOffset = 0.0) const
-    { return KeyState::Holder(keyState(), ticks, timeOffset); }
-  inline KeyState::Holder keyStateHolder()
-    { return keyStateHolder(ticks); }
-  inline KeyHistory::Holder keyHistoryHolder(TTimerTicks ticks, double timeOffset = 0.0)
-    { return KeyHistory::Holder(keyHistory(), ticks, timeOffset); }
-  inline KeyHistory::Holder keyHistoryHolder()
-    { return keyHistoryHolder(ticks); }
-
-  inline ButtonState::Holder buttonStateHolder(DeviceId device, TTimerTicks ticks, double timeOffset = 0.0)
-    { return ButtonState::Holder(buttonState(device), ticks, timeOffset); }
-  inline ButtonState::Holder buttonStateHolder(DeviceId device)
-    { return buttonStateHolder(device, ticks); }
-  inline ButtonHistory::Holder buttonHistoryHolder(DeviceId device, long ticks, double timeOffset = 0.0)
-    { return ButtonHistory::Holder(buttonHistory(device), ticks, timeOffset); }
-  inline ButtonHistory::Holder buttonHistoryHolder(DeviceId device)
-    { return buttonHistoryHolder(device, ticks); }
+    { return howLongButtonPressedAny(button, m_ticks); }
+
+  inline ButtonState::Holder buttonStateHolder(DeviceId deviceId, TTimerTicks ticks, double timeOffset = 0.0)
+    { return ButtonState::Holder(buttonState(deviceId), ticks, timeOffset); }
+  inline ButtonState::Holder buttonStateHolder(DeviceId deviceId)
+    { return buttonStateHolder(deviceId, m_ticks); }
+  inline ButtonHistory::Holder buttonHistoryHolder(DeviceId deviceId, long ticks, double timeOffset = 0.0)
+    { return ButtonHistory::Holder(buttonHistory(deviceId), ticks, timeOffset); }
+  inline ButtonHistory::Holder buttonHistoryHolder(DeviceId deviceId)
+    { return buttonHistoryHolder(deviceId, m_ticks); }
 };
 
 
diff --git a/toonz/sources/include/tools/keyhistory.h b/toonz/sources/include/tools/keyhistory.h
index 79537fb..6bf4d27 100644
--- a/toonz/sources/include/tools/keyhistory.h
+++ b/toonz/sources/include/tools/keyhistory.h
@@ -30,26 +30,12 @@
 
 //===================================================================
 
-//    Base Classee Declarations
-
-
-class DVAPI TKeyStateBase : public TSmartObject {
-  DECLARE_CLASS_CODE
-};
-
-class DVAPI TKeyHistoryBase : public TSmartObject {
-  DECLARE_CLASS_CODE
-};
-
-//===================================================================
-
-
 //*****************************************************************************************
 //    TKeyState definition
 //*****************************************************************************************
 
 template<typename T>
-class TKeyStateT : public TKeyStateBase {
+class TKeyStateT : public TSmartObject {
 public:
   typedef T Type;
   typedef TSmartPointerT<TKeyStateT> Pointer;
@@ -59,7 +45,7 @@ public:
     TTimerTicks ticks;
     double timeOffset;
 
-    explicit Holder(const Pointer &state, TTimerTicks ticks = 0, double timeOffset = 0.0):
+    explicit Holder(const Pointer &state = Pointer(), TTimerTicks ticks = 0, double timeOffset = 0.0):
       state(state), ticks(ticks), timeOffset(timeOffset) { }
 
     Pointer find(const Type &value) const
@@ -145,7 +131,7 @@ const typename TKeyStateT<T>::Pointer TKeyStateT<T>::empty = new TKeyStateT<T>()
 //*****************************************************************************************
 
 template<typename T>
-class TKeyHistoryT : public TKeyHistoryBase {
+class TKeyHistoryT : public TSmartObject {
 public:
   typedef T Type;
   typedef TSmartPointerT<TKeyHistoryT> Pointer;
@@ -155,19 +141,19 @@ public:
 
   class Holder {
   private:
-    Pointer history_;
-    TTimerTicks ticks_;
-    double timeOffset_;
-    TTimerTicks heldTicks;
+    Pointer m_history;
+    TTimerTicks m_ticks;
+    double m_timeOffset;
+    TTimerTicks m_heldTicks;
 
   public:
     Holder():
-      ticks_(), timeOffset_(), heldTicks() { }
+      m_ticks(), m_timeOffset(), m_heldTicks() { }
     Holder(const Pointer &history, TTimerTicks ticks, double timeOffset = 0.0):
-      ticks_(), timeOffset_(), heldTicks()
+      m_ticks(), m_timeOffset(), m_heldTicks()
       { set(history, ticks, timeOffset); }
     Holder(const Holder &other):
-      ticks_(), timeOffset_(), heldTicks()
+      m_ticks(), m_timeOffset(), m_heldTicks()
       { set(other); }
     ~Holder()
       { reset(); }
@@ -176,11 +162,11 @@ public:
       { set(other); return *this; }
 
     void set(const Pointer &history, TTimerTicks ticks, double timeOffset = 0.0) {
-      if (history_) history_->releaseTicks(heldTicks);
-      history_ = history;
-      ticks_ = ticks;
-      timeOffset_ = timeOffset;
-      heldTicks = (history_ ? history_->holdTicks(ticks_) : 0);
+      if (m_history) m_history->releaseTicks(m_heldTicks);
+      m_history = history;
+      m_ticks = ticks;
+      m_timeOffset = timeOffset;
+      m_heldTicks = (m_history ? m_history->holdTicks(m_ticks) : 0);
     }
     void set(const Holder &other)
       { set(other.history(), other.ticks(), other.timeOffset()); }
@@ -188,11 +174,11 @@ public:
       { set(Pointer(), 0); }
 
     Pointer history() const
-      { return history_; }
+      { return m_history; }
     TTimerTicks ticks() const
-      { return ticks_; }
+      { return m_ticks; }
     double timeOffset() const
-      { return timeOffset_; }
+      { return m_timeOffset; }
 
     Holder offset(double timeOffset) const {
       return fabs(timeOffset) < TToolTimer::epsilon ? *this
@@ -200,49 +186,49 @@ public:
     }
 
     StateHolder get(double time) const {
-      TTimerTicks dticks = (TTimerTicks)ceil(TToolTimer::frequency*(time + timeOffset));
-      StatePointer state = history_->get(ticks + dticks);
-      return StateHolder(state, ticks, timeOffset + time);
+      TTimerTicks dticks = (TTimerTicks)ceil(TToolTimer::frequency*(time + m_timeOffset));
+      StatePointer state = m_history->get(m_ticks + dticks);
+      return StateHolder(state, m_ticks, m_timeOffset + time);
     }
   };
 
 private:
-  std::map<TTimerTicks, StatePointer> states;
-  std::multiset<TTimerTicks> locks;
+  std::map<TTimerTicks, StatePointer> m_states;
+  std::multiset<TTimerTicks> m_locks;
 
   void autoRemove() {
-    TTimerTicks ticks = locks.empty()
-                      ? states.rbegin()->first
-                      : *locks.begin();
+    TTimerTicks ticks = m_locks.empty()
+                      ? m_states.rbegin()->first
+                      : *m_locks.begin();
     while(true) {
-      typename std::map<TTimerTicks, StatePointer>::iterator i = states.begin();
+      typename std::map<TTimerTicks, StatePointer>::iterator i = m_states.begin();
       ++i;
-      if (i == states.end() || (!i->second->isEmpty() && i->first >= ticks)) break;
-      states.erase(i);
+      if (i == m_states.end() || (!i->second->isEmpty() && i->first >= ticks)) break;
+      m_states.erase(i);
     }
   }
 
   TTimerTicks holdTicks(TTimerTicks ticks)
-    { return *locks.insert(std::max(ticks, states.begin()->first)); }
+    { return *m_locks.insert(std::max(ticks, m_states.begin()->first)); }
   void releaseTicks(TTimerTicks heldTicks)
-    { locks.erase(heldTicks); autoRemove(); }
+    { m_locks.erase(heldTicks); autoRemove(); }
 
   StatePointer get(TTimerTicks ticks) {
-    typename std::map<TTimerTicks, StatePointer>::iterator i = states.upper_bound(ticks);
-    return i == states.begin() ? i->second : (--i)->second;
+    typename std::map<TTimerTicks, StatePointer>::iterator i = m_states.upper_bound(ticks);
+    return i == m_states.begin() ? i->second : (--i)->second;
   }
 
 public:
   TKeyHistoryT()
-    { states[TTimerTicks()] = StatePointer(new State()); }
+    { m_states[TTimerTicks()] = StatePointer(new State()); }
 
   StatePointer current() const
-    { return states.rbegin()->second; }
+    { return m_states.rbegin()->second; }
 
   StatePointer change(bool press, Type value, TTimerTicks ticks)  {
     StatePointer state = current()->change(press, value, ticks);
-    if (state != current() && state->ticks > states.rbegin()->first)
-      states[state->ticks] = state;
+    if (state != current() && state->ticks > m_states.rbegin()->first)
+      m_states[state->ticks] = state;
     autoRemove();
     return current();
   }
diff --git a/toonz/sources/include/tools/tool.h b/toonz/sources/include/tools/tool.h
index ab30f5a..4aed87a 100644
--- a/toonz/sources/include/tools/tool.h
+++ b/toonz/sources/include/tools/tool.h
@@ -391,7 +391,7 @@ return true if the method execution can have changed the current tool
   virtual void rightButtonDown(const TPointD &, const TMouseEvent &) {}
   virtual bool keyDown(QKeyEvent *) { return false; }
 
-  virtual void onInputText(std::wstring, std::wstring, int, int){};
+  virtual void onInputText(const std::wstring&, const std::wstring&, int, int){};
 
   virtual void onSetViewer() {}
 
diff --git a/toonz/sources/include/tools/tooltimer.h b/toonz/sources/include/tools/tooltimer.h
index ec73471..60f6df5 100644
--- a/toonz/sources/include/tools/tooltimer.h
+++ b/toonz/sources/include/tools/tooltimer.h
@@ -30,8 +30,8 @@ typedef qint64 TTimerTicks;
 
 class DVAPI TToolTimer {
 private:
-  static TToolTimer instance;
-  QElapsedTimer timer;
+  static TToolTimer m_instance;
+  QElapsedTimer m_timer;
   TToolTimer();
 
 public:
@@ -40,7 +40,7 @@ public:
   static const double epsilon;
 
   static inline TTimerTicks ticks()
-    { return instance.timer.nsecsElapsed(); }
+    { return m_instance.m_timer.nsecsElapsed(); }
 };
 
 
diff --git a/toonz/sources/include/tools/track.h b/toonz/sources/include/tools/track.h
index 84fa7a4..2883a19 100644
--- a/toonz/sources/include/tools/track.h
+++ b/toonz/sources/include/tools/track.h
@@ -34,11 +34,15 @@
 //    Forward Declarations
 
 class TTrack;
+class TTrackPoint;
 class TTrackHandler;
 class TTrackModifier;
+
 typedef TSmartPointerT<TTrack> TTrackP;
 typedef TSmartPointerT<TTrackHandler> TTrackHandlerP;
 typedef TSmartPointerT<TTrackModifier> TTrackModifierP;
+
+typedef std::vector<TTrackPoint> TTrackPointList;
 typedef std::vector<TTrackP> TTrackList;
 
 //===================================================================
@@ -48,7 +52,7 @@ typedef std::vector<TTrackP> TTrackList;
 //    TTrackPoint definition
 //*****************************************************************************************
 
-struct TTrackPoint {
+class TTrackPoint {
 public:
   TPointD position;
   double pressure;
@@ -85,7 +89,6 @@ public:
 //*****************************************************************************************
 
 class DVAPI TTrackHandler : public TSmartObject {
-  DECLARE_CLASS_CODE
 public:
   TTrack &original;
   std::vector<TTrackP> tracks;
@@ -99,7 +102,6 @@ public:
 //*****************************************************************************************
 
 class DVAPI TTrackModifier : public TSmartObject {
-  DECLARE_CLASS_CODE
 public:
     TTrackHandler &handler;
     TTrack &original;
@@ -116,15 +118,13 @@ public:
 //*****************************************************************************************
 
 class DVAPI TTrack : public TSmartObject {
-  DECLARE_CLASS_CODE
-
 public:
   typedef long long Id;
 
   static const double epsilon;
 
 private:
-  static Id lastId;
+  static Id m_lastId;
 
 public:
   const Id id;
@@ -132,15 +132,17 @@ public:
   const TInputState::TouchId touchId;
   const TInputState::KeyHistory::Holder keyHistory;
   const TInputState::ButtonHistory::Holder buttonHistory;
+  const bool hasPressure;
+  const bool hasTilt;
   const TTrackModifierP modifier;
 
   TTrackHandlerP handler;
-  int wayPointsRemoved;
-  int wayPointsAdded;
+  int pointsRemoved;
+  int pointsAdded;
 
 private:
-  std::vector<TTrackPoint> points_;
-  const TTrackPoint none;
+  TTrackPointList m_points;
+  const TTrackPoint m_none;
 
 public:
 
@@ -148,7 +150,9 @@ public:
     TInputState::DeviceId deviceId = TInputState::DeviceId(),
     TInputState::TouchId touchId = TInputState::TouchId(),
     const TInputState::KeyHistory::Holder &keyHistory = TInputState::KeyHistory::Holder(),
-    const TInputState::ButtonHistory::Holder &buttonHistory = TInputState::ButtonHistory::Holder()
+    const TInputState::ButtonHistory::Holder &buttonHistory = TInputState::ButtonHistory::Holder(),
+    bool hasPressure = false,
+    bool hasTilt = false
   );
 
   explicit TTrack(const TTrackModifierP &modifier);
@@ -160,7 +164,7 @@ public:
   inline TTimerTicks ticks() const
     { return keyHistory.ticks(); }
   inline bool changed() const
-    { return wayPointsAdded != 0 || wayPointsRemoved != 0; }
+    { return pointsAdded != 0 || pointsRemoved != 0; }
 
   const TTrack* root() const;
   TTrack* root();
@@ -187,22 +191,22 @@ public:
     { return point(ceilIndex(index)); }
 
   inline const TTrackPoint& point(int index) const
-    { return empty() ? none : points_[clampIndex(index)]; }
+    { return empty() ? m_none : m_points[clampIndex(index)]; }
 
   inline int size() const
-    { return (int)points_.size(); }
+    { return (int)m_points.size(); }
   inline bool empty() const
-    { return points_.empty(); }
+    { return m_points.empty(); }
   inline const TTrackPoint& front() const
     { return point(0); }
   inline const TTrackPoint& back() const
     { return point(size() - 1); }
   inline bool finished() const
-    { return !points_.empty() && back().final; }
+    { return !m_points.empty() && back().final; }
   inline const TTrackPoint& operator[] (int index) const
     { return point(index); }
-  inline const std::vector<TTrackPoint>& points() const
-    { return points_; }
+  inline const TTrackPointList& points() const
+    { return m_points; }
 
   void push_back(const TTrackPoint &point);
   void pop_back(int count = 1);
@@ -210,22 +214,32 @@ public:
   inline void truncate(int count)
     { pop_back(size() - count); }
 
+  inline const TTrackPoint& current() const
+    { return point(size() - pointsAdded); }
+  inline TInputState::KeyState::Holder getKeyState(double time) const
+    { return keyHistory.get(time); }
+  inline TInputState::KeyState::Holder getCurrentKeyState() const
+    { return getKeyState(current().time); }
+  inline TInputState::ButtonState::Holder getButtonState(double time) const
+    { return buttonHistory.get(time); }
+  inline TInputState::ButtonState::Holder getCurrentButtonState() const
+    { return getButtonState(current().time); }
 
 private:
   template<double TTrackPoint::*Field>
   double binarySearch(double value) const {
     // points_[a].value <= value < points_[b].value
-    if (points_.empty()) return 0.0;
+    if (m_points.empty()) return 0.0;
     int a = 0;
-    double aa = points_[a].*Field;
+    double aa = m_points[a].*Field;
     if (value - aa <= 0.5*epsilon) return (double)a;
-    int b = (int)points_.size() - 1;
-    double bb = points_[b].*Field;
+    int b = (int)m_points.size() - 1;
+    double bb = m_points[b].*Field;
     if (bb - value <= 0.5*epsilon) return (double)b;
     while(true) {
       int c = (a + b)/2;
       if (a == c) break;
-      double cc = points_[c].*Field;
+      double cc = m_points[c].*Field;
       if (cc - value > 0.5*epsilon)
         { b = c; bb = cc; } else { a = c; aa = cc; }
     }
@@ -261,6 +275,8 @@ public:
 
   TTrackPoint calcPoint(double index) const;
   TPointD calcTangent(double index, double distance = 0.1) const;
+  double rootIndexByIndex(double index) const;
+  TTrackPoint calcRootPoint(double index) const;
 
   inline TTrackPoint interpolateLinear(double index) const {
     double frac;
diff --git a/toonz/sources/tnztools/CMakeLists.txt b/toonz/sources/tnztools/CMakeLists.txt
index cfaa257..113061e 100644
--- a/toonz/sources/tnztools/CMakeLists.txt
+++ b/toonz/sources/tnztools/CMakeLists.txt
@@ -47,6 +47,7 @@ set(HEADERS
     ../include/tools/keyhistory.h
     ../include/tools/inputstate.h
     ../include/tools/track.h
+    ../include/tools/inputmanager.h
 )
 
 set(SOURCES
@@ -111,9 +112,9 @@ set(SOURCES
     toonzrasterbrushtool.cpp
     toonzvectorbrushtool.cpp
     tooltimer.cpp
-    keyhistory.cpp
     inputstate.cpp
     track.cpp
+    inputmanager.cpp
 )
 
 set(RESOURCES tnztools.qrc)
diff --git a/toonz/sources/tnztools/inputmanager.cpp b/toonz/sources/tnztools/inputmanager.cpp
new file mode 100644
index 0000000..13069a7
--- /dev/null
+++ b/toonz/sources/tnztools/inputmanager.cpp
@@ -0,0 +1,592 @@
+
+
+#include <tools/inputmanager.h>
+
+
+//*****************************************************************************************
+//    static members
+//*****************************************************************************************
+
+TInputState::TouchId TInputManager::m_lastTouchId = 0;
+
+
+//*****************************************************************************************
+//    TInputModifier implementation
+//*****************************************************************************************
+
+
+void
+TInputModifier::setManager(TInputManager *manager) {
+  if (m_manager != manager)
+    { m_manager = manager; onSetManager(); }
+}
+
+
+void
+TInputModifier::modifyTracks(
+    const TTrackList &tracks,
+    const TInputSavePoint::Holder &savePoint,
+    TTrackList &outTracks )
+{
+  for(TTrackList::const_iterator i = tracks.begin(); i != tracks.end(); ++i)
+    modifyTrack(*i, savePoint, outTracks);
+}
+
+
+void
+TInputModifier::modifyHovers(
+  const THoverList &hovers,
+  THoverList &outHovers )
+{
+  for(THoverList::const_iterator i = hovers.begin(); i != hovers.end(); ++i)
+    modifyHover(*i, outHovers);
+}
+
+
+void
+TInputModifier::draw(const TTrackList &tracks, const THoverList &hovers) {
+  for(TTrackList::const_iterator i = tracks.begin(); i != tracks.end(); ++i)
+    drawTrack(*i);
+  for(THoverList::const_iterator i = hovers.begin(); i != hovers.end(); ++i)
+    drawHover(*i);
+}
+
+
+//*****************************************************************************************
+//    TInputHandler implementation
+//*****************************************************************************************
+
+
+bool
+TInputHandler::inputKeyEvent(
+  bool press,
+  TInputState::Key key,
+  QKeyEvent *event,
+  const TInputManager &manager )
+{
+  return press && inputKeyDown(event);
+}
+
+
+void
+TInputHandler::inputButtonEvent(
+  bool press,
+  TInputState::DeviceId device,
+  TInputState::Button button,
+  const TInputManager &manager )
+{
+  if (press && button == Qt::RightButton && !manager.getOutputHovers().empty())
+    inputRightButtonDown(manager.getOutputHovers().front(), manager.state);
+}
+
+
+void
+TInputHandler::inputHoverEvent(const TInputManager &manager) {
+  if (!manager.getOutputHovers().empty())
+    inputMouseMove(manager.getOutputHovers().front(), manager.state);
+}
+
+
+void
+TInputHandler::inputPaintTrackPoint(const TTrackPoint &point, const TTrack &track, bool firstTrack) {
+  if (firstTrack) {
+    if (track.pointsAdded == track.size())
+      inputLeftButtonDown(point, track);
+    else
+    if (point.final)
+      inputLeftButtonUp(point, track);
+    else
+      inputLeftButtonDrag(point, track);
+   }
+}
+
+
+void
+TInputHandler::inputPaintTracks(const TTrackList &tracks) {
+  // paint track points in chronological order
+  while(true) {
+    TTrackP track;
+    TTimerTicks minTicks = 0;
+    double minTimeOffset = 0.0;
+    for(TTrackList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
+      const TTrack &t = **i;
+      if (t.pointsAdded > 0) {
+        TTimerTicks ticks = t.ticks();
+        double timeOffset = t.timeOffset() + t.current().time;
+        if (!track || (ticks - minTicks)*TToolTimer::frequency + timeOffset - minTimeOffset < 0.0) {
+          track = *i;
+          minTicks = ticks;
+          minTimeOffset = timeOffset;
+        }
+      }
+    }
+    if (!track) break;
+    inputPaintTrackPoint(track->current(), *track, track == tracks.front());
+    --track->pointsAdded;
+  }
+}
+
+
+//*****************************************************************************************
+//    TInputManager implementation
+//*****************************************************************************************
+
+
+TInputManager::TInputManager():
+  m_handler(),
+  m_tracks(1),
+  m_hovers(1),
+  m_savePointsSent()
+{ }
+
+
+void
+TInputManager::paintRollbackTo(int saveIndex, TTrackList &subTracks) {
+  if (saveIndex >= (int)m_savePoints.size())
+    return;
+
+  int level = saveIndex + 1;
+  if (level <= m_savePointsSent) {
+    if (m_handler) {
+      if (level < m_savePointsSent)
+        m_handler->inputPaintPop(m_savePointsSent - level);
+      m_handler->inputPaintCancel();
+    }
+    m_savePointsSent = level;
+  }
+
+  for(TTrackList::const_iterator i = subTracks.begin(); i != subTracks.end(); ++i) {
+    TTrack &track = **i;
+    if (TrackHandler *handler = dynamic_cast<TrackHandler*>(track.handler.getPointer())) {
+      handler->saves.erase(handler->saves.begin() + level, handler->saves.end());
+      int cnt = handler->saves[saveIndex];
+      track.pointsRemoved = 0;
+      track.pointsAdded = track.size() - cnt;
+    }
+  }
+  for(int i = level; i < (int)m_savePoints.size(); ++i)
+    m_savePoints[i].savePoint()->available = false;
+  m_savePoints.erase(m_savePoints.begin() + level, m_savePoints.end());
+}
+
+
+void
+TInputManager::paintApply(int count, TTrackList &subTracks) {
+  if (count <= 0)
+    return;
+
+  int level = (int)m_savePoints.size() - count;
+  bool resend = true;
+
+  if (level < m_savePointsSent) {
+    // apply
+    int applied = m_handler ? m_handler->inputPaintApply(m_savePointsSent - level) : false;
+    applied = std::max(0, std::min(m_savePointsSent - level, applied));
+    m_savePointsSent -= applied;
+    if (m_savePointsSent == level) resend = false;
+  }
+
+  if (level < m_savePointsSent) {
+    // rollback
+    if (m_handler) m_handler->inputPaintPop(m_savePointsSent - level);
+    m_savePointsSent = level;
+  }
+
+  // remove keypoints
+  for(TTrackList::const_iterator i = subTracks.begin(); i != subTracks.end(); ++i) {
+    TTrack &track = **i;
+    if (TrackHandler *handler = dynamic_cast<TrackHandler*>(track.handler.getPointer())) {
+      if (resend) {
+        track.pointsRemoved = 0;
+        track.pointsAdded = track.size() - handler->saves[m_savePointsSent];
+      }
+      handler->saves.erase(handler->saves.begin() + level, handler->saves.end());
+    }
+  }
+  for(int i = level; i < (int)m_savePoints.size(); ++i)
+    m_savePoints[i].savePoint()->available = false;
+  m_savePoints.erase(m_savePoints.begin() + level, m_savePoints.end());
+}
+
+
+void
+TInputManager::paintTracks() {
+  bool allFinished = true;
+  for(TTrackList::const_iterator i = m_tracks.front().begin(); i != m_tracks.front().end(); ++i)
+    if (!(*i)->finished())
+      { allFinished = false; break; }
+
+  while(true) {
+    // run modifiers
+    TInputSavePoint::Holder newSavePoint = TInputSavePoint::create(true);
+    for(int i = 0; i < (int)m_modifiers.size(); ++i) {
+      m_tracks[i+1].clear();
+      m_modifiers[i]->modifyTracks(m_tracks[i], newSavePoint, m_tracks[i+1]);
+    }
+    TTrackList &subTracks = m_tracks.back();
+
+    // create handlers
+    for(TTrackList::const_iterator i = subTracks.begin(); i != subTracks.end(); ++i)
+      if (!(*i)->handler)
+        (*i)->handler = new TrackHandler(**i, (int)m_savePoints.size());
+
+    if (!m_savePoints.empty()) {
+      // rollback
+      int rollbackIndex = (int)m_savePoints.size();
+      for(TTrackList::const_iterator i = subTracks.begin(); i != subTracks.end(); ++i) {
+        TTrack &track = **i;
+        if (track.pointsRemoved > 0) {
+          int count = track.size() - track.pointsAdded;
+          if (TrackHandler *handler = dynamic_cast<TrackHandler*>(track.handler.getPointer()))
+            while(rollbackIndex > 0 && (rollbackIndex >= (int)m_savePoints.size() || handler->saves[rollbackIndex] > count))
+              --rollbackIndex;
+        }
+      }
+      paintRollbackTo(rollbackIndex, subTracks);
+
+      // apply
+      int applyCount = 0;
+      while(applyCount < (int)m_savePoints.size() && m_savePoints[(int)m_savePoints.size() - applyCount - 1].isFree())
+        ++applyCount;
+      paintApply(applyCount, subTracks);
+    }
+
+    // send to handler
+    if (m_savePointsSent == (int)m_savePoints.size() && !subTracks.empty() && m_handler)
+      m_handler->inputPaintTracks(subTracks);
+    for(TTrackList::const_iterator i = subTracks.begin(); i != subTracks.end(); ++i) {
+      TTrack &track = **i;
+      track.pointsRemoved = 0;
+      track.pointsAdded = 0;
+    }
+
+    // is paint finished?
+    if (newSavePoint.isFree()) {
+      newSavePoint.savePoint()->available = false;
+      if (allFinished) {
+        paintApply((int)m_savePoints.size(), subTracks);
+        for(std::vector<TTrackList>::iterator i = m_tracks.begin(); i != m_tracks.end(); ++i)
+          i->clear();
+        if (m_handler) m_handler->inputSetBusy(false);
+      }
+      break;
+    }
+
+    // create save point
+    if (m_handler && m_handler->inputPaintPush()) ++m_savePointsSent;
+    m_savePoints.push_back(newSavePoint);
+    for(TTrackList::const_iterator i = subTracks.begin(); i != subTracks.end(); ++i)
+      if (TrackHandler *handler = dynamic_cast<TrackHandler*>((*i)->handler.getPointer()))
+        handler->saves.push_back((*i)->size());
+  }
+}
+
+
+int
+TInputManager::trackCompare(
+  const TTrack &track,
+  TInputState::DeviceId deviceId,
+  TInputState::TouchId touchId )
+{
+  if (track.deviceId < deviceId) return -1;
+  if (deviceId < track.deviceId) return  1;
+  if (track.touchId < touchId) return -1;
+  if (touchId < track.touchId) return 1;
+  return 0;
+}
+
+
+const TTrackP&
+TInputManager::createTrack(
+  int index,
+  TInputState::DeviceId deviceId,
+  TInputState::TouchId touchId,
+  TTimerTicks ticks,
+  bool hasPressure,
+  bool hasTilt )
+{
+  TTrackP track = new TTrack(
+    deviceId,
+    touchId,
+    state.keyHistoryHolder(ticks),
+    state.buttonHistoryHolder(deviceId, ticks),
+    hasPressure,
+    hasTilt );
+  return *m_tracks.front().insert(m_tracks[0].begin() + index, track);
+}
+
+
+const TTrackP&
+TInputManager::getTrack(
+  TInputState::DeviceId deviceId,
+  TInputState::TouchId touchId,
+  TTimerTicks ticks,
+  bool hasPressure,
+  bool hasTilt )
+{
+  TTrackList &origTracks = m_tracks.front();
+  if (origTracks.empty())
+    return createTrack(0, deviceId, touchId, ticks, hasPressure, hasTilt);
+  int cmp;
+
+  int a = 0;
+  cmp = trackCompare(*origTracks[a], deviceId, touchId);
+  if (cmp == 0) return origTracks[a];
+  if (cmp < 0) return createTrack(a, deviceId, touchId, ticks, hasPressure, hasTilt);
+
+  int b = (int)origTracks.size() - 1;
+  cmp = trackCompare(*origTracks[b], deviceId, touchId);
+  if (cmp == 0) return origTracks[b];
+  if (cmp > 0) return createTrack(b+1, deviceId, touchId, ticks, hasPressure, hasTilt);
+
+  // binary search: tracks[a] < tracks[c] < tracks[b]
+  while(true) {
+    int c = (a + b)/2;
+    if (a == c) break;
+    cmp = trackCompare(*origTracks[c], deviceId, touchId);
+    if (cmp < 0) b = c; else
+      if (cmp > 0) a = c; else
+        return origTracks[c];
+  }
+  return createTrack(b, deviceId, touchId, ticks, hasPressure, hasTilt);
+}
+
+
+void
+TInputManager::addTrackPoint(
+  const TTrackP& track,
+  const TPointD &position,
+  double pressure,
+  const TPointD &tilt,
+  double time,
+  bool final )
+{
+  track->push_back( TTrackPoint(
+    position,
+    pressure,
+    tilt,
+    (double)track->size(),
+    time,
+    0.0, // length will calculated inside of TTrack::push_back
+    final ));
+  ++track->pointsAdded;
+}
+
+
+void
+TInputManager::touchTracks(bool finish) {
+  for(TTrackList::const_iterator i = m_tracks.front().begin(); i != m_tracks.front().end(); ++i) {
+    if (!(*i)->finished() && (*i)->size() > 0) {
+      const TTrackPoint &p = (*i)->back();
+      addTrackPoint(*i, p.position, p.pressure, p.tilt, p.time, finish);
+    }
+  }
+}
+
+
+void
+TInputManager::modifierActivate(const TInputModifierP &modifier) {
+  modifier->setManager(this);
+  modifier->activate();
+}
+
+
+void
+TInputManager::modifierDeactivate(const TInputModifierP &modifier) {
+  modifier->deactivate();
+  modifier->setManager(NULL);
+}
+
+
+void
+TInputManager::processTracks()
+  { paintTracks(); }
+
+
+void
+TInputManager::finishTracks() {
+  touchTracks(true);
+  processTracks();
+}
+
+
+void
+TInputManager::reset() {
+  // forget about handler paint stack
+  // assuime it was already reset by outside
+  m_savePointsSent = 0;
+
+  // reset save point
+  for(int i = 0; i < (int)m_savePoints.size(); ++i)
+    m_savePoints[i].savePoint()->available = false;
+  m_savePoints.clear();
+
+  // reset tracks
+  for(int i = 0; i < (int)m_tracks.size(); ++i)
+    m_tracks[i].clear();
+}
+
+
+void
+TInputManager::setHandler(TInputHandler *handler) {
+  if (m_handler == handler)
+    return;
+  reset();
+  m_handler = handler;
+}
+
+
+int
+TInputManager::findModifier(const TInputModifierP &modifier) const {
+  for(int i = 0; i < getModifiersCount(); ++i)
+    if (getModifier(i) == modifier)
+      return i;
+  return -1;
+}
+
+
+void
+TInputManager::insertModifier(int index, const TInputModifierP &modifier) {
+  if (findModifier(modifier) >= 0) return;
+  finishTracks();
+  m_modifiers.insert(m_modifiers.begin() + index, modifier);
+  m_tracks.insert(m_tracks.begin() + index + 1, TTrackList());
+  m_hovers.insert(m_hovers.begin() + index + 1, THoverList());
+  modifierActivate(modifier);
+}
+
+
+void
+TInputManager::removeModifier(int index) {
+  if (index >= 0 && index < getModifiersCount()) {
+    finishTracks();
+    modifierDeactivate(m_modifiers[index]);
+    m_modifiers.erase(m_modifiers.begin() + index);
+    m_tracks.erase(m_tracks.begin() + index + 1);
+    m_hovers.erase(m_hovers.begin() + index + 1);
+  }
+}
+
+
+void
+TInputManager::clearModifiers() {
+  while(getModifiersCount() > 0)
+    removeModifier(getModifiersCount() - 1);
+}
+
+
+void
+TInputManager::trackEvent(
+  TInputState::DeviceId deviceId,
+  TInputState::TouchId touchId,
+  const TPointD &position,
+  const double *pressure,
+  const TPointD *tilt,
+  bool final,
+  TTimerTicks ticks )
+{
+  if (getInputTracks().empty() && m_handler)
+    m_handler->inputSetBusy(true);
+
+  TTrackP track = getTrack(deviceId, touchId, ticks, (bool)pressure, (bool)tilt);
+  if (!track->finished()) {
+    double time = (double)(ticks - track->ticks())*TToolTimer::step - track->timeOffset();
+    addTrackPoint(
+      track,
+      position,
+      pressure ? *pressure : 0.5,
+      tilt ? *tilt : TPointD(),
+      time,
+      final );
+  }
+}
+
+
+bool
+TInputManager::keyEvent(
+  bool press,
+  TInputState::Key key,
+  TTimerTicks ticks,
+  QKeyEvent *event )
+{
+  state.keyEvent(press, key, ticks);
+  processTracks();
+  bool result = m_handler && m_handler->inputKeyEvent(press, key, event, *this);
+  touchTracks();
+  processTracks();
+  //hoverEvent(getInputHovers());
+  return result;
+}
+
+
+void
+TInputManager::buttonEvent(
+  bool press,
+  TInputState::DeviceId deviceId,
+  TInputState::Button button,
+  TTimerTicks ticks )
+{
+  state.buttonEvent(press, deviceId, button, ticks);
+  processTracks();
+  if (m_handler) m_handler->inputButtonEvent(press, deviceId, button, *this);
+  touchTracks();
+  processTracks();
+}
+
+
+void
+TInputManager::hoverEvent(const THoverList &hovers) {
+  if (&m_hovers[0] != &hovers)
+    m_hovers[0] = hovers;
+  for(int i = 0; i < (int)m_modifiers.size(); ++i) {
+    m_hovers[i+1].clear();
+    m_modifiers[i]->modifyHovers(m_hovers[i], m_hovers[i+1]);
+  }
+  if (m_handler) m_handler->inputHoverEvent(*this);
+}
+
+
+void
+TInputManager::draw() {
+  // TODO: paint
+
+  // paint not sent sub-tracks
+  if (m_savePointsSent < (int)m_savePoints.size()) {
+    //context.Save();
+    //penPreview.apply(context);
+    for(TTrackList::const_iterator i = getOutputTracks().begin(); i != getOutputTracks().end(); ++i) {
+      TTrack &track = **i;
+      if (TrackHandler *handler = dynamic_cast<TrackHandler*>(track.handler.getPointer())) {
+        int start = handler->saves[m_savePointsSent] - 1;
+        if (start < 0) start = 0;
+        if (start < track.size()) {
+          //Drawing.Color color = penPreview.color;
+          int level = m_savePointsSent;
+
+          //color.apply(context);
+          //context.MoveTo(track[start].position.x, track.points[start].position.y);
+          for(int i = start + 1; i < track.size(); ++i) {
+            while(level < (int)handler->saves.size() && handler->saves[level] <= i) {
+              //context.Stroke();
+              //context.MoveTo(track[i-1].position.x, track[i-1].position.y);
+              //color.a *= levelAlpha;
+              //color.apply(context);
+              ++level;
+            }
+            //context.LineTo(track[i].position.x, track[i].position.y);
+          }
+        }
+      }
+    }
+    //context.Stroke();
+    //context.Restore();
+  }
+
+  // paint modifiers
+  for(int i = 0; i < (int)m_modifiers.size(); ++i)
+    m_modifiers[i]->draw(m_tracks[i], m_hovers[i]);
+}
+
+TInputState::TouchId
+TInputManager::genTouchId()
+  { return ++m_lastTouchId; }
diff --git a/toonz/sources/tnztools/inputstate.cpp b/toonz/sources/tnztools/inputstate.cpp
index db414e0..5251d1e 100644
--- a/toonz/sources/tnztools/inputstate.cpp
+++ b/toonz/sources/tnztools/inputstate.cpp
@@ -4,12 +4,50 @@
 
 
 //*****************************************************************************************
-//    TInputState static members
+//    TKey static members
+//*****************************************************************************************
+
+const TKey TKey::shift   ( Qt::Key_Shift   , true );
+const TKey TKey::control ( Qt::Key_Control , true );
+const TKey TKey::alt     ( Qt::Key_Alt     , true );
+const TKey TKey::meta    ( Qt::Key_Meta    , true );
+
+
+Qt::Key
+TKey::mapKey(Qt::Key key) {
+  switch(key) {
+  case Qt::Key_AltGr: return Qt::Key_Alt;
+  default: break;
+  }
+  return key;
+}
+
+
+bool
+TKey::isModifier(Qt::Key key) {
+  key = mapKey(key);
+  return key == Qt::Key_Shift
+      || key == Qt::Key_Control
+      || key == Qt::Key_Alt
+      || key == Qt::Key_AltGr
+      || key == Qt::Key_Meta;
+}
+
+
+bool
+TKey::isNumber(Qt::Key key) {
+  key = mapKey(key);
+  return key >= Qt::Key_0 && key <= Qt::Key_9;
+}
+
+
+//*****************************************************************************************
+//    TInputState implementation
 //*****************************************************************************************
 
 TInputState::TInputState():
-  ticks(),
-  keyHistory_(new KeyHistory())
+  m_ticks(),
+  m_keyHistory(new KeyHistory())
   { }
 
 TInputState::~TInputState()
@@ -17,22 +55,22 @@ TInputState::~TInputState()
 
 void
 TInputState::touch(TTimerTicks ticks) {
-  if (this->ticks < ticks)
-    this->ticks = ticks;
+  if (m_ticks < ticks)
+    m_ticks = ticks;
   else
-    ++this->ticks;
+    ++m_ticks;
 }
 
 TInputState::ButtonHistory::Pointer
 TInputState::buttonHistory(DeviceId device) const {
-  ButtonHistory::Pointer &history = buttonHistories_[device];
+  ButtonHistory::Pointer &history = m_buttonHistories[device];
   if (!history) history = new ButtonHistory();
   return history;
 }
 
 TInputState::ButtonState::Pointer
 TInputState::buttonFindAny(Button button, DeviceId &outDevice) {
-  for(ButtonHistoryMap::const_iterator i = buttonHistories_.begin(); i != buttonHistories_.end(); ++i) {
+  for(ButtonHistoryMap::const_iterator i = m_buttonHistories.begin(); i != m_buttonHistories.end(); ++i) {
     ButtonState::Pointer state = i->second->current()->find(button);
     if (state) {
       outDevice = i->first;
diff --git a/toonz/sources/tnztools/keyhistory.cpp b/toonz/sources/tnztools/keyhistory.cpp
deleted file mode 100644
index 121ac56..0000000
--- a/toonz/sources/tnztools/keyhistory.cpp
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-#include <tools/keyhistory.h>
-
-
-//*****************************************************************************************
-//    TKeyStateBase static members
-//*****************************************************************************************
-
-DEFINE_CLASS_CODE(TKeyStateBase, 125)
-DEFINE_CLASS_CODE(TKeyHistoryBase, 126)
-
diff --git a/toonz/sources/tnztools/tooltimer.cpp b/toonz/sources/tnztools/tooltimer.cpp
index 45bd778..5dfdc15 100644
--- a/toonz/sources/tnztools/tooltimer.cpp
+++ b/toonz/sources/tnztools/tooltimer.cpp
@@ -10,7 +10,7 @@
 const TTimerTicks TToolTimer::frequency = 1000000000;
 const double TToolTimer::step = 1e-9;
 const double TToolTimer::epsilon = 1e-10;
-TToolTimer TToolTimer::instance;
+TToolTimer TToolTimer::m_instance;
 
 
 //*****************************************************************************************
@@ -18,4 +18,4 @@ TToolTimer TToolTimer::instance;
 //*****************************************************************************************
 
 TToolTimer::TToolTimer()
-  { timer.start(); }
+  { m_timer.start(); }
diff --git a/toonz/sources/tnztools/track.cpp b/toonz/sources/tnztools/track.cpp
index b603517..27d8b1e 100644
--- a/toonz/sources/tnztools/track.cpp
+++ b/toonz/sources/tnztools/track.cpp
@@ -4,15 +4,11 @@
 
 
 //*****************************************************************************************
-//    Class definitions
+//    Static fields
 //*****************************************************************************************
 
 const double TTrack::epsilon = 1e-9;
-TTrack::Id TTrack::lastId = 0;
-
-DEFINE_CLASS_CODE(TTrackHandler, 130)
-DEFINE_CLASS_CODE(TTrackModifier, 131)
-DEFINE_CLASS_CODE(TTrack, 132)
+TTrack::Id TTrack::m_lastId = 0;
 
 
 //*****************************************************************************************
@@ -35,25 +31,31 @@ TTrack::TTrack(
   TInputState::DeviceId deviceId,
   TInputState::TouchId touchId,
   const TInputState::KeyHistory::Holder &keyHistory,
-  const TInputState::ButtonHistory::Holder &buttonHistory
+  const TInputState::ButtonHistory::Holder &buttonHistory,
+  bool hasPressure,
+  bool hasTilt
 ):
-  id(++lastId),
+  id(++m_lastId),
   deviceId(deviceId),
   touchId(touchId),
   keyHistory(keyHistory),
   buttonHistory(buttonHistory),
-  wayPointsRemoved(),
-  wayPointsAdded()
+  hasPressure(hasPressure),
+  hasTilt(hasTilt),
+  pointsRemoved(),
+  pointsAdded()
   { }
 
 TTrack::TTrack(const TTrackModifierP &modifier):
-  id(++lastId),
+  id(++m_lastId),
   deviceId(modifier->original.deviceId),
   touchId(modifier->original.touchId),
   keyHistory(modifier->original.keyHistory),
   buttonHistory(modifier->original.buttonHistory),
-  wayPointsRemoved(),
-  wayPointsAdded()
+  hasPressure(modifier->original.hasPressure),
+  hasTilt(modifier->original.hasTilt),
+  pointsRemoved(),
+  pointsAdded()
   { }
 
 const TTrack*
@@ -81,11 +83,11 @@ TTrack::floorIndex(double index, double &outFrac) const {
 
 void
 TTrack::push_back(const TTrackPoint &point) {
-  points_.push_back(point);
+  m_points.push_back(point);
   if (size() == 1) return;
 
-  const TTrackPoint &prev = *(points_.rbegin() + 1);
-  TTrackPoint &p = points_.back();
+  const TTrackPoint &prev = *(m_points.rbegin() + 1);
+  TTrackPoint &p = m_points.back();
 
   // fix originalIndex
   if (p.originalIndex < prev.originalIndex)
@@ -103,7 +105,7 @@ void
 TTrack::pop_back(int count) {
   if (count > (int)size()) count = size();
   if (count <= 0) return;
-  points_.erase(points_.end() - count, points_.end());
+  m_points.erase(m_points.end() - count, m_points.end());
 }
 
 
@@ -124,3 +126,17 @@ TTrack::calcTangent(double index, double distance) const {
   double lenSqr = dp.x*dp.x + dp.y*dp.y;
   return lenSqr > epsilon*epsilon ? dp*sqrt(1.0/lenSqr) : TPointD();
 }
+
+double
+TTrack::rootIndexByIndex(double index) const {
+  return modifier
+       ? modifier->original.rootIndexByIndex( originalIndexByIndex(index) )
+       : index;
+}
+
+TTrackPoint
+TTrack::calcRootPoint(double index) const {
+  return modifier
+       ? modifier->original.calcRootPoint( originalIndexByIndex(index) )
+       : calcPoint(index);
+}
diff --git a/toonz/sources/tnztools/typetool.cpp b/toonz/sources/tnztools/typetool.cpp
index 1c3ca6d..a2a3b72 100644
--- a/toonz/sources/tnztools/typetool.cpp
+++ b/toonz/sources/tnztools/typetool.cpp
@@ -363,7 +363,7 @@ public:
   void rightButtonDown(const TPointD &pos, const TMouseEvent &) override;
   bool keyDown(QKeyEvent *event) override;
 
-  void onInputText(std::wstring preedit, std::wstring commit,
+  void onInputText(const std::wstring &preedit, const std::wstring &commit,
                    int replacementStart, int replacementLen) override;
 
   // cancella gli StrokeChar fra from e to-1 e inserisce nuovi StrokeChar
@@ -1665,7 +1665,7 @@ bool TypeTool::keyDown(QKeyEvent *event) {
 
 //-----------------------------------------------------------------------------
 
-void TypeTool::onInputText(std::wstring preedit, std::wstring commit,
+void TypeTool::onInputText(const std::wstring &preedit, const std::wstring &commit,
                            int replacementStart, int replacementLen) {
   // butto la vecchia preedit string
   m_preeditRange.first  = std::max(0, m_preeditRange.first);