diff --git a/toonz/sources/include/tools/inputmanager.h b/toonz/sources/include/tools/inputmanager.h
index 5cbe005..dad6a50 100644
--- a/toonz/sources/include/tools/inputmanager.h
+++ b/toonz/sources/include/tools/inputmanager.h
@@ -40,7 +40,6 @@ class TInputModifier;
 class TInputManager;
 
 typedef TSmartPointerT<TInputModifier> TInputModifierP;
-typedef TSmartPointerT<TInputManager> TInputManagerP;
 
 //===================================================================
 
@@ -69,6 +68,9 @@ public:
     inline Holder& operator= (const Holder &other)
       { set(other.m_savePoint, other.m_lock); return *this; }
 
+    inline operator bool () const
+      { return assigned(); }
+
     inline void set(TInputSavePoint *savePoint, bool lock) {
       if (m_savePoint != savePoint) {
         if (m_savePoint) {
@@ -83,8 +85,10 @@ public:
         }
       } else
       if (m_lock != lock) {
-        if (lock) m_savePoint->lock();
-             else m_savePoint->unlock();
+        if (m_savePoint) {
+          if (lock) m_savePoint->lock();
+               else m_savePoint->unlock();
+        }
         m_lock = lock;
       }
     }
@@ -98,6 +102,8 @@ public:
 
     inline TInputSavePoint* savePoint() const
       { return m_savePoint; }
+    inline bool assigned() const
+      { return savePoint(); }
     inline bool locked() const
       { return m_savePoint && m_lock; }
     inline bool available() const
@@ -235,7 +241,7 @@ public:
 //    TInputManager definition
 //*****************************************************************************************
 
-class TInputManager: public TSmartObject {
+class TInputManager {
 public:
   class TrackHandler: public TTrackHandler {
   public:
@@ -246,6 +252,7 @@ public:
   };
 
 private:
+  TTimerTicks m_lastTicks;
   TInputHandler *m_handler;
   TInputModifier::List m_modifiers;
   std::vector<TTrackList> m_tracks;
@@ -264,6 +271,11 @@ public:
   TInputManager();
 
 private:
+  inline TTimerTicks fixTicks(TTimerTicks ticks) {
+    if (ticks <= m_lastTicks) ticks = m_lastTicks + 1;
+    return m_lastTicks = ticks;
+  }
+  
   void paintRollbackTo(int saveIndex, TTrackList &subTracks);
   void paintApply(int count, TTrackList &subTracks);
   void paintTracks();
@@ -271,7 +283,7 @@ private:
   int trackCompare(
     const TTrack &track,
     TInputState::DeviceId deviceId,
-    TInputState::TouchId touchId );
+    TInputState::TouchId touchId ) const;
   const TTrackP& createTrack(
     int index,
     TInputState::DeviceId deviceId,
diff --git a/toonz/sources/include/tools/inputstate.h b/toonz/sources/include/tools/inputstate.h
index faab530..628f906 100644
--- a/toonz/sources/include/tools/inputstate.h
+++ b/toonz/sources/include/tools/inputstate.h
@@ -18,6 +18,7 @@
 // std includes
 #include <map>
 #include <vector>
+#include <iostream>
 
 
 #undef DVAPI
@@ -199,6 +200,10 @@ public:
     { return ButtonHistory::Holder(buttonHistory(deviceId), ticks, timeOffset); }
   inline ButtonHistory::Holder buttonHistoryHolder(DeviceId deviceId)
     { return buttonHistoryHolder(deviceId, m_ticks); }
+    
+  void print(std::ostream &stream, const std::string &tab = std::string()) const;
+  inline void print(const std::string &tab = std::string()) const
+    { print(std::cout, tab); }
 };
 
 
diff --git a/toonz/sources/include/tools/keyhistory.h b/toonz/sources/include/tools/keyhistory.h
index 6bf4d27..0c0e5fe 100644
--- a/toonz/sources/include/tools/keyhistory.h
+++ b/toonz/sources/include/tools/keyhistory.h
@@ -76,8 +76,9 @@ private:
     previous(previous), ticks(ticks), value(value) { }
 
   Pointer makeChainWithout(const Pointer &state) {
-    return state == this || !previous ? previous
-         : Pointer(new TKeyStateT(previous->makeChainWithout(state), ticks, value));
+    return state == this ? previous
+         : previous ? Pointer(new TKeyStateT(previous->makeChainWithout(state), ticks, value))
+         : this;
   }
 
 public:
@@ -93,18 +94,18 @@ public:
   Pointer change(bool press, const Type &value, TTimerTicks ticks) {
     if (value == none)
       return Pointer(this);
+    
+    Pointer p = find(value);
+    if (press == bool(p))
+      return Pointer(this);
+    
     if (ticks <= this->ticks)
       ticks = this->ticks + 1;
 
-    Pointer p = find(value);
-    if (press) {
-      if (p) return Pointer(this);
+    if (press)
       return Pointer(new TKeyStateT((isEmpty() ? Pointer() : Pointer(this)), ticks, value));
-    }
-
-    if (!p) return Pointer(this);
     Pointer chain = makeChainWithout(p);
-    return chain ? chain : Pointer(new TKeyStateT());
+    return chain ? chain : Pointer(new TKeyStateT(Pointer(), ticks, none));
   }
 
   bool isEmpty()
@@ -138,6 +139,8 @@ public:
   typedef TKeyStateT<Type> State;
   typedef typename TKeyStateT<Type>::Pointer StatePointer;
   typedef typename TKeyStateT<Type>::Holder StateHolder;
+  typedef std::map<TTimerTicks, StatePointer> StateMap;
+  typedef std::multiset<TTimerTicks> LockSet;
 
   class Holder {
   private:
@@ -162,11 +165,13 @@ public:
       { set(other); return *this; }
 
     void set(const Pointer &history, TTimerTicks ticks, double timeOffset = 0.0) {
-      if (m_history) m_history->releaseTicks(m_heldTicks);
+      TTimerTicks prevHeldTicks = m_heldTicks;
+      Pointer prevHistory = m_history;
       m_history = history;
       m_ticks = ticks;
       m_timeOffset = timeOffset;
       m_heldTicks = (m_history ? m_history->holdTicks(m_ticks) : 0);
+      if (prevHistory) prevHistory->releaseTicks(prevHeldTicks);
     }
     void set(const Holder &other)
       { set(other.history(), other.ticks(), other.timeOffset()); }
@@ -193,15 +198,15 @@ public:
   };
 
 private:
-  std::map<TTimerTicks, StatePointer> m_states;
-  std::multiset<TTimerTicks> m_locks;
+  StateMap m_states;
+  LockSet m_locks;
 
   void autoRemove() {
-    TTimerTicks ticks = m_locks.empty()
-                      ? m_states.rbegin()->first
-                      : *m_locks.begin();
+    TTimerTicks ticks = m_states.rbegin()->first;
+    if (!m_locks.empty())
+      ticks = std::min(ticks, *m_locks.begin());
     while(true) {
-      typename std::map<TTimerTicks, StatePointer>::iterator i = m_states.begin();
+      typename StateMap::iterator i = m_states.begin();
       ++i;
       if (i == m_states.end() || (!i->second->isEmpty() && i->first >= ticks)) break;
       m_states.erase(i);
@@ -210,11 +215,15 @@ private:
 
   TTimerTicks holdTicks(TTimerTicks ticks)
     { return *m_locks.insert(std::max(ticks, m_states.begin()->first)); }
-  void releaseTicks(TTimerTicks heldTicks)
-    { m_locks.erase(heldTicks); autoRemove(); }
+  void releaseTicks(TTimerTicks heldTicks) {
+    typename LockSet::iterator i = m_locks.find(heldTicks);
+    if (i == m_locks.end()) return;
+    m_locks.erase(i);
+    autoRemove();
+  }
 
   StatePointer get(TTimerTicks ticks) {
-    typename std::map<TTimerTicks, StatePointer>::iterator i = m_states.upper_bound(ticks);
+    typename StateMap::iterator i = m_states.upper_bound(ticks);
     return i == m_states.begin() ? i->second : (--i)->second;
   }
 
@@ -238,6 +247,11 @@ public:
 
   StatePointer released(Type value, TTimerTicks ticks)
     { return change(false, value, ticks); }
+  
+  inline const StateMap& getStates() const
+    { return m_states; }
+  inline const LockSet& getLocks() const
+    { return m_locks; }
 };
 
 
diff --git a/toonz/sources/include/tools/modifiers/modifiersegmentation.h b/toonz/sources/include/tools/modifiers/modifiersegmentation.h
new file mode 100644
index 0000000..b6466d0
--- /dev/null
+++ b/toonz/sources/include/tools/modifiers/modifiersegmentation.h
@@ -0,0 +1,45 @@
+#pragma once
+
+#ifndef MODIFIERSEGMENTATION_INCLUDED
+#define MODIFIERSEGMENTATION_INCLUDED
+
+// TnzTools includes
+#include <tools/inputmanager.h>
+
+
+#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
+
+
+//===================================================================
+
+//*****************************************************************************************
+//    TModifierSegmentation definition
+//*****************************************************************************************
+
+class TModifierSegmentation: public TInputModifier {
+public:
+  const double precision;
+  const double precisionSqr;
+
+private:
+  void addSegments(TTrack &track, const TTrackPoint &p0, const TTrackPoint &p1, int level = 0);
+
+public:
+  TModifierSegmentation(double precision = 1.0);
+
+  void modifyTrack(
+    const TTrackP &track,
+    const TInputSavePoint::Holder &savePoint,
+    TTrackList &outTracks ) override;
+};
+
+
+#endif
diff --git a/toonz/sources/include/tools/modifiers/modifiertangents.h b/toonz/sources/include/tools/modifiers/modifiertangents.h
new file mode 100644
index 0000000..12e4059
--- /dev/null
+++ b/toonz/sources/include/tools/modifiers/modifiertangents.h
@@ -0,0 +1,46 @@
+#pragma once
+
+#ifndef MODIFIERTANGENTS_INCLUDED
+#define MODIFIERTANGENTS_INCLUDED
+
+// TnzTools includes
+#include <tools/inputmanager.h>
+
+
+#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
+
+
+//===================================================================
+
+//*****************************************************************************************
+//    TModifierTangents definition
+//*****************************************************************************************
+
+class TModifierTangents: public TInputModifier {
+public:
+  class Modifier: public TTrackModifier {
+  public:
+    explicit Modifier(TTrackHandler &handler):
+      TTrackModifier(handler) { }
+
+    TInputSavePoint::Holder savePoint;
+    TTrackTangentList tangents;
+
+    TTrackPoint calcPoint(double originalIndex) override;
+  };
+
+  void modifyTrack(
+    const TTrackP &track,
+    const TInputSavePoint::Holder &savePoint,
+    TTrackList &outTracks ) override;
+};
+
+#endif
diff --git a/toonz/sources/include/tools/modifiers/modifiertest.h b/toonz/sources/include/tools/modifiers/modifiertest.h
new file mode 100644
index 0000000..d21c813
--- /dev/null
+++ b/toonz/sources/include/tools/modifiers/modifiertest.h
@@ -0,0 +1,58 @@
+#pragma once
+
+#ifndef MODIFIERTEST_INCLUDED
+#define MODIFIERTEST_INCLUDED
+
+// TnzTools includes
+#include <tools/inputmanager.h>
+
+
+#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
+
+
+//===================================================================
+
+//*****************************************************************************************
+//    TModifierTest definition
+//*****************************************************************************************
+
+class TModifierTest: public TInputModifier {
+public:
+  class Handler: public TTrackHandler {
+  public:
+    std::vector<double> angles;
+    Handler(TTrack &original): TTrackHandler(original) { }
+  };
+
+  class Modifier: public TTrackModifier {
+  public:
+    double angle;
+    double radius;
+    double speed;
+
+    Modifier(TTrackHandler &handler, double angle, double radius, double speed = 0.25);
+    TTrackPoint calcPoint(double originalIndex) override;
+  };
+
+public:
+  const int count;
+  const double radius;
+
+  TModifierTest();
+
+  void modifyTrack(
+    const TTrackP &track,
+    const TInputSavePoint::Holder &savePoint,
+    TTrackList &outTracks ) override;
+};
+
+
+#endif
diff --git a/toonz/sources/include/tools/modifiertest.h b/toonz/sources/include/tools/modifiertest.h
deleted file mode 100644
index b328e0f..0000000
--- a/toonz/sources/include/tools/modifiertest.h
+++ /dev/null
@@ -1,61 +0,0 @@
-#pragma once
-
-#ifndef MODIFIERTEST_INCLUDED
-#define MODIFIERTEST_INCLUDED
-
-// TnzTools includes
-#include <tools/inputmanager.h>
-
-// std includes
-#include <cmath>
-
-
-#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
-
-
-//===================================================================
-
-//*****************************************************************************************
-//    TModifierTest definition
-//*****************************************************************************************
-
-class TModifierTest: public TInputModifier {
-public:
-  class Handler: public TTrackHandler {
-  public:
-    std::vector<double> angles;
-    Handler(TTrack &original): TTrackHandler(original) { }
-  };
-
-  class Modifier: public TTrackModifier {
-  public:
-    double angle;
-    double radius;
-    double speed;
-
-    Modifier(TTrackHandler &handler, double angle, double radius, double speed = 0.25);
-    TTrackPoint calcPoint(double originalIndex);
-  };
-
-public:
-  int count;
-  double radius;
-
-  explicit TModifierTest();
-
-  void modifyTrack(
-    const TTrackP &track,
-    const TInputSavePoint::Holder &savePoint,
-    TTrackList &outTracks ) override;
-};
-
-
-#endif
diff --git a/toonz/sources/include/tools/track.h b/toonz/sources/include/tools/track.h
index 0efccce..16331f9 100644
--- a/toonz/sources/include/tools/track.h
+++ b/toonz/sources/include/tools/track.h
@@ -35,6 +35,7 @@
 
 class TTrack;
 class TTrackPoint;
+class TTrackTangent;
 class TTrackHandler;
 class TTrackModifier;
 
@@ -43,6 +44,7 @@ typedef TSmartPointerT<TTrackHandler> TTrackHandlerP;
 typedef TSmartPointerT<TTrackModifier> TTrackModifierP;
 
 typedef std::vector<TTrackPoint> TTrackPointList;
+typedef std::vector<TTrackTangent> TTrackTangentList;
 typedef std::vector<TTrackP> TTrackList;
 
 //===================================================================
@@ -85,6 +87,28 @@ public:
 
 
 //*****************************************************************************************
+//    TTrackTangent definition
+//*****************************************************************************************
+
+class TTrackTangent {
+public:
+  TPointD position;
+  double pressure;
+  TPointD tilt;
+
+  inline explicit TTrackTangent(
+    const TPointD &position = TPointD(),
+    double pressure = 0.0,
+    const TPointD &tilt = TPointD()
+  ):
+    position(position),
+    pressure(pressure),
+    tilt(tilt)
+  { }
+};
+
+
+//*****************************************************************************************
 //    TTrackHandler definition
 //*****************************************************************************************
 
@@ -216,10 +240,14 @@ public:
     { return point(size() - pointsAdded); }
   inline TInputState::KeyState::Holder getKeyState(double time) const
     { return keyHistory.get(time); }
+  inline TInputState::KeyState::Holder getKeyState(const TTrackPoint &point) const
+    { return getKeyState(timeOffset() + point.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 getButtonState(const TTrackPoint &point) const
+    { return getButtonState(timeOffset() + point.time); }
   inline TInputState::ButtonState::Holder getCurrentButtonState() const
     { return getButtonState(current().time); }
 
@@ -287,6 +315,16 @@ public:
   static inline T interpolationLinear(const T &p0, const T &p1, double l)
     { return p0*(1.0 - l) + p1*l; }
 
+  template<typename T>
+  static T interpolationSpline(const T &p0, const T &p1, const T &t0, const T &t1, double l) {
+    double ll = l*l;
+    double lll = ll*l;
+    return p0*( 2.0*lll - 3.0*ll + 1.0)
+         + p1*(-2.0*lll + 3.0*ll      )
+         + t0*(     lll - 2.0*ll + l  )
+         + t1*(     lll - 1.0*ll      );
+  }
+
   static inline TTrackPoint interpolationLinear(const TTrackPoint &p0, const TTrackPoint &p1, double l) {
     if (l <= epsilon) return p0;
     if (l >= 1.0 - epsilon) return p1;
@@ -298,6 +336,24 @@ public:
       interpolationLinear(p0.time          , p1.time          , l),
       interpolationLinear(p0.length        , p1.length        , l) );
   }
+
+  static inline TTrackPoint interpolationSpline(
+    const TTrackPoint &p0,
+    const TTrackPoint &p1,
+    const TTrackTangent &t0,
+    const TTrackTangent &t1,
+    double l )
+  {
+    if (l <= epsilon) return p0;
+    if (l >= 1.0 - epsilon) return p1;
+    return TTrackPoint(
+      interpolationSpline(p0.position      , p1.position      , t0.position , t1.position , l),
+      interpolationSpline(p0.pressure      , p1.pressure      , t0.pressure , t1.pressure , l),
+      interpolationSpline(p0.tilt          , p1.tilt          , t0.tilt     , t1.tilt     , l),
+      interpolationLinear(p0.originalIndex , p1.originalIndex , l),
+      interpolationLinear(p0.time          , p1.time          , l),
+      interpolationLinear(p0.length        , p1.length        , l) );
+  }
 };
 
 #endif
diff --git a/toonz/sources/tnztools/CMakeLists.txt b/toonz/sources/tnztools/CMakeLists.txt
index c426de8..b1c8939 100644
--- a/toonz/sources/tnztools/CMakeLists.txt
+++ b/toonz/sources/tnztools/CMakeLists.txt
@@ -48,7 +48,9 @@ set(HEADERS
     ../include/tools/inputstate.h
     ../include/tools/track.h
     ../include/tools/inputmanager.h
-    ../include/tools/modifiertest.h
+    ../include/tools/modifiers/modifiertest.h
+    ../include/tools/modifiers/modifiertangents.h
+    ../include/tools/modifiers/modifiersegmentation.h
 )
 
 set(SOURCES
@@ -117,6 +119,8 @@ set(SOURCES
     track.cpp
     inputmanager.cpp
     modifiertest.cpp
+    modifiertangents.cpp
+    modifiersegmentation.cpp
 )
 
 set(RESOURCES tnztools.qrc)
diff --git a/toonz/sources/tnztools/fullcolorbrushtool.cpp b/toonz/sources/tnztools/fullcolorbrushtool.cpp
index 475241e..9f8a3b3 100644
--- a/toonz/sources/tnztools/fullcolorbrushtool.cpp
+++ b/toonz/sources/tnztools/fullcolorbrushtool.cpp
@@ -123,9 +123,9 @@ FullColorBrushTool::FullColorBrushTool(std::string name)
     , m_modifierEraser("ModifierEraser", false)
     , m_modifierLockAlpha("Lock Alpha", false)
     , m_preset("Preset:")
+    , m_enabledPressure(false)
     , m_minCursorThick(0)
     , m_maxCursorThick(0)
-    , m_enabledPressure(false)
     , m_toonz_brush(0)
     , m_tileSet(0)
     , m_tileSaver(0)
@@ -134,6 +134,11 @@ FullColorBrushTool::FullColorBrushTool(std::string name)
     , m_firstTime(true) {
   bind(TTool::RasterImage | TTool::EmptyTarget);
 
+  m_inputmanager.setHandler(this);
+  m_modifierTest = new TModifierTest();
+  m_modifierTangents = new TModifierTangents();
+  m_modifierSegmentation = new TModifierSegmentation();
+  
   m_thickness.setNonLinearSlider();
 
   m_prop.bind(m_thickness);
@@ -219,7 +224,7 @@ void FullColorBrushTool::onActivate() {
 //--------------------------------------------------------------------------------------------------
 
 void FullColorBrushTool::onDeactivate() {
-  if (m_mousePressed) leftButtonUp(m_mousePos, m_mouseEvent);
+  m_inputmanager.finishTracks();
   m_workRaster = TRaster32P();
   m_backUpRas  = TRasterP();
 }
@@ -288,6 +293,11 @@ bool FullColorBrushTool::askWrite(const TRect &rect) {
 //--------------------------------------------------------------------------------------------------
 
 bool FullColorBrushTool::preLeftButtonDown() {
+  m_inputmanager.clearModifiers();
+  m_inputmanager.addModifier( TInputModifierP(m_modifierTangents.getPointer()) );
+  m_inputmanager.addModifier( TInputModifierP(m_modifierSegmentation.getPointer()) );
+  m_inputmanager.addModifier( TInputModifierP(m_modifierTest.getPointer()) );
+  
   touchImage();
 
   if (m_isFrameCreated) {
@@ -303,12 +313,50 @@ bool FullColorBrushTool::preLeftButtonDown() {
 
 //---------------------------------------------------------------------------------------------------
 
-void FullColorBrushTool::leftButtonDown(const TPointD &pos,
-                                        const TMouseEvent &e) {
+void FullColorBrushTool::handleMouseEvent(MouseEventType type, const TPointD &pos, const TMouseEvent &e) {
+  TTimerTicks t = TToolTimer::ticks();
+  bool alt = e.getModifiersMask() & TMouseEvent::ALT_KEY;
+  bool shift = e.getModifiersMask() & TMouseEvent::SHIFT_KEY;
+  bool control = e.getModifiersMask() & TMouseEvent::CTRL_KEY;
+  if (alt != m_inputmanager.state.isKeyPressed(TKey::alt))
+    m_inputmanager.keyEvent(alt, TKey::alt, t, nullptr);
+  if (shift != m_inputmanager.state.isKeyPressed(TKey::shift))
+    m_inputmanager.keyEvent(shift, TKey::shift, t, nullptr);
+  if (control != m_inputmanager.state.isKeyPressed(TKey::control))
+    m_inputmanager.keyEvent(control, TKey::control, t, nullptr);
+  
+  if (type == ME_MOVE) {
+    THoverList hovers(1, pos);
+    m_inputmanager.hoverEvent(hovers);
+  } else {
+    m_inputmanager.trackEvent(
+      e.isTablet(), 0, pos,
+      e.isTablet() ? &e.m_pressure : nullptr, nullptr,
+      type == ME_UP, t );
+    m_inputmanager.processTracks();
+  }
+}
+
+//---------------------------------------------------------------------------------------------------
+
+void FullColorBrushTool::leftButtonDown(const TPointD &pos, const TMouseEvent &e)
+  { handleMouseEvent(ME_DOWN, pos, e); }
+void FullColorBrushTool::leftButtonDrag(const TPointD &pos, const TMouseEvent &e)
+  { handleMouseEvent(ME_DRAG, pos, e); }
+void FullColorBrushTool::leftButtonUp(const TPointD &pos, const TMouseEvent &e)
+  { handleMouseEvent(ME_UP, pos, e); }
+void FullColorBrushTool::mouseMove(const TPointD &pos, const TMouseEvent &e)
+  { handleMouseEvent(ME_MOVE, pos, e); }
+
+//---------------------------------------------------------------------------------------------------
+
+void FullColorBrushTool::inputLeftButtonDown(
+  const TTrackPoint &point, const TTrack &track )
+{
+  const TPointD &pos = point.position;
   TPointD previousBrushPos = m_brushPos;
   m_brushPos = m_mousePos = pos;
   m_mousePressed          = true;
-  m_mouseEvent            = e;
   Viewer *viewer          = getViewer();
   if (!viewer) return;
 
@@ -318,7 +366,8 @@ void FullColorBrushTool::leftButtonDown(const TPointD &pos,
   if (!ri) return;
 
   // Modifier to do straight line
-  if (e.isShiftPressed() || e.isCtrlPressed()) {
+  TInputState::KeyState::Holder keys = track.getKeyState(point);
+  if (keys.isPressed(TKey::shift) || keys.isPressed(TKey::control)) {
     m_isStraight = true;
     m_firstPoint = pos;
     m_lastPoint  = pos;
@@ -335,26 +384,24 @@ void FullColorBrushTool::leftButtonDown(const TPointD &pos,
   m_workRaster->lock();
 
   TPointD rasCenter = ras->getCenterD();
-  TPointD point(pos + rasCenter);
+  TPointD pt(pos + rasCenter);
 
-  double pressure;
-  if (getApplication()->getCurrentLevelStyle()->getTagId() ==
-      4001)  // mypaint brush case
-    pressure = m_enabledPressure && e.isTablet() ? e.m_pressure : 0.5;
-  else
-    pressure = m_enabledPressure ? e.m_pressure : 1.0;
+  double defPressure = 1.0;
+  if (getApplication()->getCurrentLevelStyle()->getTagId() == 4001) // mypaint brush case
+    defPressure = 0.5;
+  double pressure = m_enabledPressure && track.hasPressure ? point.pressure : defPressure;
 
   m_tileSet   = new TTileSetFullColor(ras->getSize());
   m_tileSaver = new TTileSaverFullColor(ras, m_tileSet);
 
   mypaint::Brush mypaintBrush;
   applyToonzBrushSettings(mypaintBrush);
-  m_toonz_brush = new MyPaintToonzBrush(m_workRaster, *this, mypaintBrush);
+  m_toonz_brush = new MyPaintToonzBrush(m_workRaster, *this, mypaintBrush, false);
 
   m_strokeRect.empty();
   m_strokeSegmentRect.empty();
   m_toonz_brush->beginStroke();
-  m_toonz_brush->strokeTo(point, pressure, restartBrushTimer());
+  m_toonz_brush->strokeTo(pt, pressure, restartBrushTimer());
   TRect updateRect = m_strokeSegmentRect * ras->getBounds();
   if (!updateRect.isEmpty())
     ras->extract(updateRect)->copy(m_workRaster->extract(updateRect));
@@ -369,14 +416,16 @@ void FullColorBrushTool::leftButtonDown(const TPointD &pos,
 
 //-------------------------------------------------------------------------------------------------------------
 
-void FullColorBrushTool::leftButtonDrag(const TPointD &pos,
-                                        const TMouseEvent &e) {
+void FullColorBrushTool::inputLeftButtonDrag(
+  const TTrackPoint &point, const TTrack &track )
+{
+  const TPointD &pos = point.position;
   TRectD invalidateRect;
+  TPointD previousLastPoint = m_lastPoint;
   m_lastPoint = pos;
 
   TPointD previousBrushPos = m_brushPos;
   m_brushPos = m_mousePos = pos;
-  m_mouseEvent            = e;
   TRasterImageP ri        = (TRasterImageP)getImage(true);
   if (!ri) return;
 
@@ -384,31 +433,23 @@ void FullColorBrushTool::leftButtonDrag(const TPointD &pos,
 
   TRasterP ras      = ri->getRaster();
   TPointD rasCenter = ras->getCenterD();
-  TPointD point(pos + rasCenter);
-  double pressure;
-  if (getApplication()->getCurrentLevelStyle()->getTagId() ==
-      4001)  // mypaint brush case
-    pressure = m_enabledPressure && e.isTablet() ? e.m_pressure : 0.5;
-  else
-    pressure = m_enabledPressure ? e.m_pressure : 1.0;
+  TPointD pt(pos + rasCenter);
+
+  double defPressure = 1.0;
+  if (getApplication()->getCurrentLevelStyle()->getTagId() == 4001) // mypaint brush case
+    defPressure = 0.5;
+  double pressure = m_enabledPressure && track.hasPressure ? point.pressure : defPressure;
 
   if (m_maxPressure < pressure) m_maxPressure = pressure;
 
   if (m_isStraight) {
-    invalidateRect = TRectD(m_firstPoint, m_lastPoint).enlarge(2);
-    if (e.isCtrlPressed()) {
-      double distance = (m_brushPos.x - m_maxCursorThick + 1) * 0.5;
-      TRectD brushRect =
-          TRectD(TPointD(m_brushPos.x - distance, m_brushPos.y - distance),
-                 TPointD(m_brushPos.x + distance, m_brushPos.y + distance));
-      invalidateRect += (brushRect);
-      double denominator = m_lastPoint.x - m_firstPoint.x;
-      if (denominator == 0) denominator = 0.001;
-      double slope = ((m_lastPoint.y - m_firstPoint.y) / denominator);
-      double angle = std::atan(slope) * (180 / 3.14159);
-      if (abs(angle) > 67.5)
+    if (track.getKeyState(point).isPressed(TKey::control)) {
+      TPointD dist = m_lastPoint - m_firstPoint;
+      double angle = fabs(atan(dist)) * (180 / 3.14159);
+      if (angle > 90) angle = 180 - angle;
+      if (angle > 90 - 22.5)
         m_lastPoint.x = m_firstPoint.x;
-      else if (abs(angle) < 22.5)
+      else if (angle < 22.5)
         m_lastPoint.y = m_firstPoint.y;
       else {
         double xDistance = m_lastPoint.x - m_firstPoint.x;
@@ -426,14 +467,18 @@ void FullColorBrushTool::leftButtonDrag(const TPointD &pos,
         }
       }
     }
-    m_mousePos = pos;
-    m_brushPos = pos;
+    double cursorSize = m_maxCursorThick/2 + 2;
+    TPointD cursorSize2d(cursorSize, cursorSize);
+    invalidateRect = TRectD(m_firstPoint, previousLastPoint).enlarge(2);
+    invalidateRect += TRectD(previousBrushPos - cursorSize2d, previousBrushPos + cursorSize2d);
+    invalidateRect += TRectD(m_brushPos - cursorSize2d, m_brushPos + cursorSize2d);
+    invalidateRect += TRectD(m_firstPoint, m_lastPoint).enlarge(2);
     invalidate(invalidateRect);
     return;
   }
 
   m_strokeSegmentRect.empty();
-  m_toonz_brush->strokeTo(point, pressure, restartBrushTimer());
+  m_toonz_brush->strokeTo(pt, pressure, restartBrushTimer());
   TRect updateRect = m_strokeSegmentRect * ras->getBounds();
   if (!updateRect.isEmpty())
     ras->extract(updateRect)->copy(m_workRaster->extract(updateRect));
@@ -448,8 +493,10 @@ void FullColorBrushTool::leftButtonDrag(const TPointD &pos,
 
 //---------------------------------------------------------------------------------------------------------------
 
-void FullColorBrushTool::leftButtonUp(const TPointD &pos,
-                                      const TMouseEvent &e) {
+void FullColorBrushTool::inputLeftButtonUp(
+  const TTrackPoint &point, const TTrack &track )
+{
+  const TPointD &pos = point.position;
   TPointD previousBrushPos = m_brushPos;
   m_brushPos = m_mousePos = pos;
 
@@ -460,24 +507,22 @@ void FullColorBrushTool::leftButtonUp(const TPointD &pos,
 
   TRasterP ras      = ri->getRaster();
   TPointD rasCenter = ras->getCenterD();
-  TPointD point;
+  TPointD pt;
   if (m_isStraight)
-    point = TPointD(m_lastPoint + rasCenter);
-  else
-    point = TPointD(pos + rasCenter);
-  double pressure;
-  if (getApplication()->getCurrentLevelStyle()->getTagId() ==
-      4001)  // mypaint brush case
-    pressure = m_enabledPressure && e.isTablet() ? e.m_pressure : 0.5;
+    pt = TPointD(m_lastPoint + rasCenter);
   else
-    pressure = m_enabledPressure ? e.m_pressure : 1.0;
+    pt = TPointD(pos + rasCenter);
 
-  if (m_isStraight && m_maxPressure > 0.0) {
+  double defPressure = 1.0;
+  if (getApplication()->getCurrentLevelStyle()->getTagId() == 4001) // mypaint brush case
+    defPressure = 0.5;
+  double pressure = m_enabledPressure && track.hasPressure ? point.pressure : defPressure;
+
+  if (m_isStraight && m_maxPressure > 0.0)
     pressure = m_maxPressure;
-  }
 
   m_strokeSegmentRect.empty();
-  m_toonz_brush->strokeTo(point, pressure, restartBrushTimer());
+  m_toonz_brush->strokeTo(pt, pressure, restartBrushTimer());
   m_toonz_brush->endStroke();
   TRect updateRect = m_strokeSegmentRect * ras->getBounds();
   if (!updateRect.isEmpty())
@@ -519,7 +564,9 @@ void FullColorBrushTool::leftButtonUp(const TPointD &pos,
 
 //---------------------------------------------------------------------------------------------------------------
 
-void FullColorBrushTool::mouseMove(const TPointD &pos, const TMouseEvent &e) {
+void FullColorBrushTool::inputMouseMove(
+  const TPointD &position, const TInputState &state )
+{
   struct Locals {
     FullColorBrushTool *m_this;
 
@@ -555,26 +602,18 @@ void FullColorBrushTool::mouseMove(const TPointD &pos, const TMouseEvent &e) {
 
       setValue(prop, value);
     }
-
   } locals = {this};
 
-  // if (e.isAltPressed() && !e.isCtrlPressed()) {
-  // const TPointD &diff = pos - m_mousePos;
-  // double add = (fabs(diff.x) > fabs(diff.y)) ? diff.x : diff.y;
-
-  // locals.addMinMax(m_thickness, int(add));
-  //} else
-  if (e.isCtrlPressed() && e.isAltPressed()) {
-    const TPointD &diff = pos - m_mousePos;
+  if (state.isKeyPressed(TKey::control) && state.isKeyPressed(TKey::alt)) {
+    const TPointD &diff = position - m_mousePos;
     double max          = diff.x / 2;
     double min          = diff.y / 2;
-
     locals.addMinMaxSeparate(m_thickness, int(min), int(max));
   } else {
-    m_brushPos = pos;
+    m_brushPos = position;
   }
 
-  m_mousePos = pos;
+  m_mousePos = position;
   invalidate();
 }
 
diff --git a/toonz/sources/tnztools/fullcolorbrushtool.h b/toonz/sources/tnztools/fullcolorbrushtool.h
index 23f5b58..6f2b38a 100644
--- a/toonz/sources/tnztools/fullcolorbrushtool.h
+++ b/toonz/sources/tnztools/fullcolorbrushtool.h
@@ -5,6 +5,11 @@
 
 #include <ctime>
 
+#include <tools/inputmanager.h>
+#include <tools/modifiers/modifiertest.h>
+#include <tools/modifiers/modifiertangents.h>
+#include <tools/modifiers/modifiersegmentation.h>
+
 #include "toonzrasterbrushtool.h"
 #include "mypainttoonzbrush.h"
 #include "toonz/mypaintbrushstyle.h"
@@ -28,7 +33,7 @@ class Brush;
 //    FullColor Brush Tool declaration
 //************************************************************************
 
-class FullColorBrushTool final : public TTool, public RasterController {
+class FullColorBrushTool final : public TTool, public RasterController, public TInputHandler {
   Q_DECLARE_TR_FUNCTIONS(FullColorBrushTool)
 
   void updateCurrentStyle();
@@ -57,6 +62,11 @@ public:
   void leftButtonUp(const TPointD &pos, const TMouseEvent &e) override;
   void mouseMove(const TPointD &pos, const TMouseEvent &e) override;
 
+  void inputLeftButtonDown(const TTrackPoint &point, const TTrack &track) override;
+  void inputLeftButtonDrag(const TTrackPoint &point, const TTrack &track) override;
+  void inputLeftButtonUp(const TTrackPoint &point, const TTrack &track) override;
+  void inputMouseMove(const TPointD &position, const TInputState &state) override;
+
   void draw() override;
 
   void onEnter() override;
@@ -83,7 +93,16 @@ public:
 
   TMyPaintBrushStyle *getBrushStyle();
 
+private:
+  enum MouseEventType { ME_DOWN, ME_DRAG, ME_UP, ME_MOVE };
+  void handleMouseEvent(MouseEventType type, const TPointD &pos, const TMouseEvent &e);
+  
 protected:
+  TInputManager m_inputmanager;
+  TSmartPointerT<TModifierTest> m_modifierTest;
+  TSmartPointerT<TModifierTangents> m_modifierTangents;
+  TSmartPointerT<TModifierSegmentation> m_modifierSegmentation;
+  
   TPropertyGroup m_prop;
 
   TIntPairProperty m_thickness;
@@ -121,7 +140,6 @@ protected:
   bool m_presetsLoaded;
   bool m_firstTime;
   bool m_mousePressed = false;
-  TMouseEvent m_mouseEvent;
 
   bool m_isStraight = false;
   TPointD m_firstPoint;
diff --git a/toonz/sources/tnztools/inputmanager.cpp b/toonz/sources/tnztools/inputmanager.cpp
index 61f7b2a..1f3aa55 100644
--- a/toonz/sources/tnztools/inputmanager.cpp
+++ b/toonz/sources/tnztools/inputmanager.cpp
@@ -116,7 +116,7 @@ TInputHandler::inputKeyEvent(
   QKeyEvent *event,
   const TInputManager &manager )
 {
-  return press && inputKeyDown(event);
+  return press && event && inputKeyDown(event);
 }
 
 
@@ -185,6 +185,7 @@ TInputHandler::inputPaintTracks(const TTrackList &tracks) {
 
 
 TInputManager::TInputManager():
+  m_lastTicks(TToolTimer::ticks()),
   m_handler(),
   m_tracks(1),
   m_hovers(1),
@@ -338,7 +339,7 @@ int
 TInputManager::trackCompare(
   const TTrack &track,
   TInputState::DeviceId deviceId,
-  TInputState::TouchId touchId )
+  TInputState::TouchId touchId ) const
 {
   if (track.deviceId < deviceId) return -1;
   if (deviceId < track.deviceId) return  1;
@@ -430,7 +431,7 @@ 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);
+      addTrackPoint(*i, p.position, p.pressure, p.tilt, fixTicks(m_lastTicks)*TToolTimer::step, finish);
     }
   }
 }
@@ -481,9 +482,8 @@ TInputManager::reset() {
 
 void
 TInputManager::setHandler(TInputHandler *handler) {
-  if (m_handler == handler)
-    return;
-  reset();
+  if (m_handler == handler) return;
+  finishTracks();
   m_handler = handler;
 }
 
@@ -540,8 +540,10 @@ TInputManager::trackEvent(
   if (getInputTracks().empty() && m_handler)
     m_handler->inputSetBusy(true);
 
+  ticks = fixTicks(ticks);
   TTrackP track = getTrack(deviceId, touchId, ticks, (bool)pressure, (bool)tilt);
   if (!track->finished()) {
+    ticks = fixTicks(ticks);
     double time = (double)(ticks - track->ticks())*TToolTimer::step - track->timeOffset();
     addTrackPoint(
       track,
@@ -561,6 +563,7 @@ TInputManager::keyEvent(
   TTimerTicks ticks,
   QKeyEvent *event )
 {
+  ticks = fixTicks(ticks);
   state.keyEvent(press, key, ticks);
   processTracks();
   bool result = m_handler && m_handler->inputKeyEvent(press, key, event, *this);
@@ -578,6 +581,7 @@ TInputManager::buttonEvent(
   TInputState::Button button,
   TTimerTicks ticks )
 {
+  ticks = fixTicks(ticks);
   state.buttonEvent(press, deviceId, button, ticks);
   processTracks();
   if (m_handler) m_handler->inputButtonEvent(press, deviceId, button, *this);
diff --git a/toonz/sources/tnztools/inputstate.cpp b/toonz/sources/tnztools/inputstate.cpp
index 5251d1e..536dd85 100644
--- a/toonz/sources/tnztools/inputstate.cpp
+++ b/toonz/sources/tnztools/inputstate.cpp
@@ -2,6 +2,9 @@
 
 #include <tools/inputstate.h>
 
+#include <iomanip>
+#include <QKeySequence>
+
 
 //*****************************************************************************************
 //    TKey static members
@@ -80,3 +83,61 @@ TInputState::buttonFindAny(Button button, DeviceId &outDevice) {
   outDevice = DeviceId();
   return ButtonState::Pointer();
 }
+
+
+namespace {
+  
+template<typename T>
+void printKey(const T &k, std::ostream &stream)
+  { stream << k; }
+
+template<>
+void printKey<TKey>(const TKey &k, std::ostream &stream) {
+  stream << QKeySequence(k.key).toString().toStdString() << "[" << std::hex << k.key << std::dec;
+  if (k.generic) stream << "g";
+  if (k.numPad) stream << "n";
+  stream << "]";
+}
+
+template<typename T>
+class Print {
+public:
+  typedef T Type;
+  typedef TKeyHistoryT<Type> History;
+  typedef typename History::StatePointer StatePointer;
+  typedef typename History::StateMap StateMap;
+  typedef typename History::LockSet LockSet;
+
+  static void print(const History &history, std::ostream &stream, const std::string &tab) {
+    const StateMap &states = history.getStates();
+    stream << tab << "states: " << std::endl;
+    for(typename StateMap::const_iterator i = states.begin(); i != states.end(); ++i) {
+      stream << tab << "- " << i->first << std::endl;
+      for(StatePointer p = i->second; p; p = p->previous) {
+        stream << tab << "- - " << p->ticks << ": ";
+        printKey(p->value, stream);
+        stream << std::endl;
+      }
+    }
+    
+    const LockSet &locks = history.getLocks();
+    stream << tab << "locks: ";
+    for(typename LockSet::const_iterator i = locks.begin(); i != locks.end(); ++i) {
+      if (i != locks.begin()) stream << ", ";
+      stream << *i;
+    }
+    stream << std::endl;
+  }
+};
+}
+
+
+void TInputState::print(std::ostream &stream, const std::string &tab) const {
+  stream << tab << "keys:" << std::endl;
+  Print<TKey>::print(*m_keyHistory, stream, tab + "  ");
+  for(ButtonHistoryMap::const_iterator i = m_buttonHistories.begin(); i != m_buttonHistories.end(); ++i) {
+    stream << tab << "buttons[" << i->first << "]:" << std::endl;
+    Print<TKey>::print(*m_keyHistory, stream, tab + "  ");
+  }
+}
+
diff --git a/toonz/sources/tnztools/modifiersegmentation.cpp b/toonz/sources/tnztools/modifiersegmentation.cpp
new file mode 100644
index 0000000..ec483fe
--- /dev/null
+++ b/toonz/sources/tnztools/modifiersegmentation.cpp
@@ -0,0 +1,84 @@
+
+
+#include <tools/modifiers/modifiersegmentation.h>
+#include <algorithm>
+
+
+//*****************************************************************************************
+//    TModifierSegmentation implementation
+//*****************************************************************************************
+
+
+TModifierSegmentation::TModifierSegmentation(double precision):
+  precision(std::max(TTrack::epsilon, precision)),
+  precisionSqr(this->precision * this->precision)
+{ }
+
+
+void
+TModifierSegmentation::addSegments(
+  TTrack &track,
+  const TTrackPoint &p0,
+  const TTrackPoint &p1,
+  int level)
+{
+  static const int maxRecursion = 10;
+  TPointD d = p1.position - p0.position;
+
+  if (level >= maxRecursion || d.x*d.x + d.y*d.y <= precisionSqr) {
+    track.push_back(p1);
+    return;
+  }
+
+  TTrackPoint p = track.modifier->calcPoint(0.5*(p0.originalIndex + p1.originalIndex));
+  addSegments(track, p0, p, level + 1);
+  addSegments(track, p, p1, level + 1);
+}
+
+
+void
+TModifierSegmentation::modifyTrack(
+  const TTrackP &track,
+  const TInputSavePoint::Holder &savePoint,
+  TTrackList &outTracks )
+{
+  if (!track->handler) {
+    track->handler = new TTrackHandler(*track);
+    track->handler->tracks.push_back(
+      new TTrack(
+        new TTrackModifier(*track->handler) ));
+  }
+
+  if (!track->changed() || track->handler->tracks.empty())
+    return;
+
+  TTrack &subTrack = *track->handler->tracks.front();
+  outTracks.push_back(track->handler->tracks.front());
+
+  // remove points
+  int start = track->size() - track->pointsAdded;
+  if (start < 0) start = 0;
+  int subStart = subTrack.floorIndex(subTrack.indexByOriginalIndex(start));
+  if (subStart < 0) subStart = 0;
+  if (subStart < subTrack.size() && subTrack[subStart].originalIndex + TTrack::epsilon < start)
+    ++subStart;
+
+  while(subStart > 0 && subTrack[subStart-1].originalIndex + TTrack::epsilon >= start)
+    --subStart;
+  if (subStart < subTrack.size()) {
+    subTrack.pointsRemoved += subTrack.size() - subStart;
+    subTrack.truncate(subStart);
+  }
+
+  // add points
+  TTrackPoint p0 = subTrack.modifier->calcPoint(start - 1);
+  for(int i = start; i < track->size(); ++i) {
+    TTrackPoint p1 = subTrack.modifier->calcPoint(i);
+    addSegments(subTrack, p0, p1);
+    p0 = p1;
+  }
+  subTrack.pointsAdded += subTrack.size() - subStart;
+
+  track->pointsRemoved = 0;
+  track->pointsAdded = 0;
+}
diff --git a/toonz/sources/tnztools/modifiertangents.cpp b/toonz/sources/tnztools/modifiertangents.cpp
new file mode 100644
index 0000000..c7c9f0f
--- /dev/null
+++ b/toonz/sources/tnztools/modifiertangents.cpp
@@ -0,0 +1,124 @@
+
+
+#include <tools/modifiers/modifiertangents.h>
+
+
+//*****************************************************************************************
+//    TModifierTangents::Modifier implementation
+//*****************************************************************************************
+
+
+TTrackPoint
+TModifierTangents::Modifier::calcPoint(double originalIndex) {
+  double frac;
+  int i0 = original.floorIndex(originalIndex, &frac);
+  int i1 = original.ceilIndex(originalIndex);
+  TTrackPoint p = i0 < 0 ? TTrackPoint()
+    : TTrack::interpolationSpline(
+        original[i0],
+        original[i1],
+        i0 < (int)tangents.size() ? tangents[i0] : TTrackTangent(),
+        i1 < (int)tangents.size() ? tangents[i1] : TTrackTangent(),
+        frac );
+  p.originalIndex = originalIndex;
+  return p;
+}
+
+
+//*****************************************************************************************
+//    TModifierTangents implementation
+//*****************************************************************************************
+
+
+void
+TModifierTangents::modifyTrack(
+  const TTrackP &track,
+  const TInputSavePoint::Holder &savePoint,
+  TTrackList &outTracks )
+{
+  if (!track->handler) {
+    track->handler = new TTrackHandler(*track);
+    track->handler->tracks.push_back(
+      new TTrack(
+        new Modifier(*track->handler) ));
+  }
+
+  if (track->handler->tracks.empty())
+    return;
+
+  TTrack &subTrack = *track->handler->tracks.front();
+  Modifier *modifier = dynamic_cast<Modifier*>(subTrack.modifier.getPointer());
+  if (!modifier)
+    return;
+
+  outTracks.push_back(track->handler->tracks.front());
+
+  if ( !track->changed()
+    && track->size() == subTrack.size()
+    && track->size() == (int)modifier->tangents.size() )
+      return;
+
+  if (!track->changed() && subTrack.size() == track->size() - 1) {
+    // add temporary point
+    modifier->tangents.push_back(TTrackTangent());
+    subTrack.push_back(track->back());
+    ++subTrack.pointsAdded;
+  } else {
+    // apply permanent changes
+
+    // remove points
+    int start = track->size() - track->pointsAdded;
+    if (start < 0) start = 0;
+    if (start > 1) --start;
+    if (start < subTrack.size()) {
+      subTrack.pointsRemoved += subTrack.size() - start;
+      subTrack.truncate(start);
+    }
+    if (start < (int)modifier->tangents.size())
+      modifier->tangents.erase(
+        modifier->tangents.begin() + start,
+        modifier->tangents.end() );
+
+    // add first point
+    int index = start;
+    if (index == 0) {
+      modifier->tangents.push_back(TTrackTangent());
+      subTrack.push_back(track->back());
+      ++index;
+    }
+
+    // add points with tangents
+    while(index < track->size() - 1) {
+      const TTrackPoint &p0 = (*track)[index-1];
+      const TTrackPoint &p1 = (*track)[index];
+      const TTrackPoint &p2 = (*track)[index+1];
+      double dt = p2.time - p0.time;
+      double k = dt > TTrack::epsilon ? (p1.time - p0.time)/dt : 0.5;
+      TTrackTangent tangent(
+        (p2.position - p0.position)*k,
+        (p2.pressure - p0.pressure)*k,
+        (p2.tilt - p0.tilt)*k );
+      modifier->tangents.push_back(tangent);
+      subTrack.push_back(p1);
+      ++index;
+    }
+
+    track->pointsRemoved = 0;
+    track->pointsAdded = 0;
+    subTrack.pointsAdded += index - start;
+
+    // release previous key point
+    modifier->savePoint.reset();
+
+    if (track->finished()) {
+      // finish
+      modifier->tangents.push_back(TTrackTangent());
+      subTrack.push_back(track->back());
+      ++subTrack.pointsAdded;
+    } else {
+      // save key point
+      modifier->savePoint = savePoint;
+    }
+  }
+}
+
diff --git a/toonz/sources/tnztools/modifiertest.cpp b/toonz/sources/tnztools/modifiertest.cpp
index c74cf17..a52ce6c 100644
--- a/toonz/sources/tnztools/modifiertest.cpp
+++ b/toonz/sources/tnztools/modifiertest.cpp
@@ -1,7 +1,9 @@
 
 
-#include <tools/modifiertest.h>
+#include <tools/modifiers/modifiertest.h>
 
+// std includes
+#include <cmath>
 
 //*****************************************************************************************
 //    TModifierTest::Modifier implementation
@@ -71,7 +73,7 @@ TModifierTest::modifyTrack(
   const double segmentSize = M_PI/180.0*10.0;
 
   if (!track->handler) {
-    if (track->getCurrentKeyState().isPressed(TKey(Qt::Key_T))) {
+    if (track->getCurrentKeyState().isPressed(TKey(Qt::Key_Alt))) {
       // TModifierTest::Handler for spiro
       track->handler = new Handler(*track);
       for(int i = 0; i < count; ++i)
diff --git a/toonz/sources/tnztools/mypainttoonzbrush.cpp b/toonz/sources/tnztools/mypainttoonzbrush.cpp
index cbf0728..3f97202 100644
--- a/toonz/sources/tnztools/mypainttoonzbrush.cpp
+++ b/toonz/sources/tnztools/mypainttoonzbrush.cpp
@@ -109,13 +109,18 @@ void Raster32PMyPaintSurface::setAntialiasing(bool value) {
 //
 //=======================================================
 
-MyPaintToonzBrush::MyPaintToonzBrush(const TRaster32P &ras,
-                                     RasterController &controller,
-                                     const mypaint::Brush &brush)
+MyPaintToonzBrush::MyPaintToonzBrush(
+  const TRaster32P &ras,
+  RasterController &controller,
+  const mypaint::Brush &brush,
+  bool interpolation
+)
     : m_ras(ras)
     , m_mypaintSurface(m_ras, controller)
     , brush(brush)
-    , reset(true) {
+    , reset(true)
+    , interpolation(interpolation)
+{
   // read brush antialiasing settings
   float aa = this->brush.getBaseValue(MYPAINT_BRUSH_SETTING_ANTI_ALIASING);
   m_mypaintSurface.setAntialiasing(aa > 0.5f);
@@ -135,7 +140,8 @@ void MyPaintToonzBrush::beginStroke() {
 
 void MyPaintToonzBrush::endStroke() {
   if (!reset) {
-    strokeTo(TPointD(current.x, current.y), current.pressure, 0.f);
+    if (interpolation)
+      strokeTo(TPointD(current.x, current.y), current.pressure, 0.f);
     beginStroke();
   }
 }
@@ -154,51 +160,55 @@ void MyPaintToonzBrush::strokeTo(const TPointD &point, double pressure,
     brush.setState(MYPAINT_BRUSH_STATE_ACTUAL_X, current.x);
     brush.setState(MYPAINT_BRUSH_STATE_ACTUAL_Y, current.y);
     return;
-  } else {
-    next.time = current.time + dtime;
   }
 
-  // accuracy
-  const double threshold    = 1.0;
-  const double thresholdSqr = threshold * threshold;
-  const int maxLevel        = 16;
-
-  // set initial segment
-  Segment stack[maxLevel + 1];
-  Params p0;
-  Segment *segment    = stack;
-  Segment *maxSegment = segment + maxLevel;
-  p0.setMedian(previous, current);
-  segment->p1 = current;
-  segment->p2.setMedian(current, next);
-
-  // process
-  while (true) {
-    double dx = segment->p2.x - p0.x;
-    double dy = segment->p2.y - p0.y;
-    if (dx * dx + dy * dy > thresholdSqr && segment != maxSegment) {
-      Segment *sub = segment + 1;
-      sub->p1.setMedian(p0, segment->p1);
-      segment->p1.setMedian(segment->p1, segment->p2);
-      sub->p2.setMedian(sub->p1, segment->p1);
-      segment = sub;
-    } else {
-      brush.strokeTo(m_mypaintSurface, segment->p2.x, segment->p2.y,
-                     segment->p2.pressure, 0.f, 0.f,
-                     segment->p2.time - p0.time);
-      if (segment == stack) break;
-      p0 = segment->p2;
-      --segment;
+  if (interpolation) {
+    next.time = current.time + dtime;
+  
+    // accuracy
+    const double threshold    = 1.0;
+    const double thresholdSqr = threshold * threshold;
+    const int maxLevel        = 16;
+
+    // set initial segment
+    Segment stack[maxLevel + 1];
+    Params p0;
+    Segment *segment    = stack;
+    Segment *maxSegment = segment + maxLevel;
+    p0.setMedian(previous, current);
+    segment->p1 = current;
+    segment->p2.setMedian(current, next);
+
+    // process
+    while (true) {
+      double dx = segment->p2.x - p0.x;
+      double dy = segment->p2.y - p0.y;
+      if (dx * dx + dy * dy > thresholdSqr && segment != maxSegment) {
+        Segment *sub = segment + 1;
+        sub->p1.setMedian(p0, segment->p1);
+        segment->p1.setMedian(segment->p1, segment->p2);
+        sub->p2.setMedian(sub->p1, segment->p1);
+        segment = sub;
+      } else {
+        brush.strokeTo(m_mypaintSurface, segment->p2.x, segment->p2.y,
+                      segment->p2.pressure, 0.f, 0.f,
+                      segment->p2.time - p0.time);
+        if (segment == stack) break;
+        p0 = segment->p2;
+        --segment;
+      }
     }
-  }
 
-  // keep parameters for future interpolation
-  previous = current;
-  current  = next;
+    // keep parameters for future interpolation
+    previous = current;
+    current  = next;
 
-  // shift time
-  previous.time = 0.0;
-  current.time  = dtime;
+    // shift time
+    previous.time = 0.0;
+    current.time  = dtime;
+  } else {
+    brush.strokeTo(m_mypaintSurface, point.x, point.y, pressure, 0.f, 0.f, dtime);
+  }
 }
 
 //----------------------------------------------------------------------------------
@@ -216,4 +226,4 @@ void MyPaintToonzBrush::updateDrawing(const TRasterCM32P rasCM,
   rasCM->copy(rasBackupCM->extract(targetRect), targetRect.getP00());
   putOnRasterCM(rasCM->extract(targetRect), m_ras->extract(targetRect), styleId,
                 lockAlpha);
-}
\ No newline at end of file
+}
diff --git a/toonz/sources/tnztools/mypainttoonzbrush.h b/toonz/sources/tnztools/mypainttoonzbrush.h
index f26aa60..5304fd7 100644
--- a/toonz/sources/tnztools/mypainttoonzbrush.h
+++ b/toonz/sources/tnztools/mypainttoonzbrush.h
@@ -120,10 +120,14 @@ private:
 
   bool reset;
   Params previous, current;
+  bool interpolation;
 
 public:
-  MyPaintToonzBrush(const TRaster32P &ras, RasterController &controller,
-                    const mypaint::Brush &brush);
+  MyPaintToonzBrush(
+    const TRaster32P &ras,
+    RasterController &controller,
+    const mypaint::Brush &brush,
+    bool interpolation = false );
   void beginStroke();
   void endStroke();
   void strokeTo(const TPointD &p, double pressure, double dtime);