bool
    PointingRelativeToScroll::remap(RemapPointingParams_relative& remapParams)
    {
      bool active = fromkeychecker_.isactive();

      if (remapParams.isremapped) return false;
      if (fromButton_ == PointingButton::NONE) {
        if (! FlagStatus::makeFlags().isOn(fromFlags_)) return false;
      } else {
        if (! fromkeychecker_.isFromPointingButton(remapParams.params, fromButton_, fromFlags_) && ! active) return false;
      }
      remapParams.isremapped = true;

      if (fromButton_ == PointingButton::NONE) {
        goto doremap;
      }

      // first time
      if (! active) {
        // if the source buttons contains left button, we cancel left click for iPhoto, or some applications.
        // iPhoto store the scroll events when left button is pressed, and restore events after left button is released.
        // PointingRelativeToScroll doesn't aim it, we release the left button and do normal scroll event.
        ButtonStatus::decrease(fromButton_);
        EventOutputQueue::FireRelativePointer::fire();
        ButtonStatus::increase(fromButton_);

        absolute_distance_ = 0;
        begin_ic_.begin();
        chained_ic_.begin();
        chained_delta1_ = 0;
        chained_delta2_ = 0;

        goto doremap;
      }

      // last time
      if (! fromkeychecker_.isactive()) {
        cancelScroll();

        const uint32_t DISTANCE_THRESHOLD = 5;
        const uint32_t TIME_THRESHOLD = 300;
        if (absolute_distance_ <= DISTANCE_THRESHOLD && begin_ic_.getmillisec() < TIME_THRESHOLD) {
          // Fire by a click event.
          ButtonStatus::increase(fromButton_);
          EventOutputQueue::FireRelativePointer::fire();
          ButtonStatus::decrease(fromButton_);
          EventOutputQueue::FireRelativePointer::fire();
        }
        return true;
      }

    doremap:
      // We need to call EventWatcher::on here.
      // See the comments in EventInputQueue::fire_timer_callback.
      EventWatcher::on();
      toscroll(remapParams);

      return true;
    }
    void
    PointingRelativeToScroll::toscroll(RemapPointingParams_relative& remapParams)
    {
      if (! queue_) return;

      // ----------------------------------------
      const uint32_t CANCEL_THRESHOLD = 100;
      if (chained_ic_.getmillisec() > CANCEL_THRESHOLD) {
        chained_delta1_ = 0;
        chained_delta2_ = 0;
        cancelScroll();
      }

      int delta1 = -remapParams.params.dy;
      int delta2 = -remapParams.params.dx;

      chained_ic_.begin();

      // ----------------------------------------
      if (Config::get_essential_config(BRIDGE_ESSENTIAL_CONFIG_INDEX_option_pointing_disable_vertical_scroll)) delta1 = 0;
      if (Config::get_essential_config(BRIDGE_ESSENTIAL_CONFIG_INDEX_option_pointing_disable_horizontal_scroll)) delta2 = 0;

      // ----------------------------------------
      // ignore minuscule move
      const unsigned int abs1 = abs(delta1);
      const unsigned int abs2 = abs(delta2);

      if (abs1 > abs2 * 2) {
        delta2 = 0;
      }
      if (abs2 > abs1 * 2) {
        delta1 = 0;
      }

      // ----------------------------------------
      // Fixation processing

      if (Config::get_essential_config(BRIDGE_ESSENTIAL_CONFIG_INDEX_option_pointing_enable_scrollwheel_fixation)) {
        // When 300ms passes from the last event, we reset a value.
        const uint32_t FIXATION_MILLISEC = 300;
        if (fixation_ic_.getmillisec() > FIXATION_MILLISEC) {
          fixation_begin_ic_.begin();
          fixation_delta1_ = 0;
          fixation_delta2_ = 0;
        }
        fixation_ic_.begin();

        if (fixation_delta1_ > fixation_delta2_ * 2) {
          delta2 = 0;
        }
        if (fixation_delta2_ > fixation_delta1_ * 2) {
          delta1 = 0;
        }

        // Only first 1000ms performs the addition of fixation_delta1, fixation_delta2.
        const uint32_t FIXATION_EARLY_MILLISEC  = 1000;
        if (fixation_begin_ic_.getmillisec() < FIXATION_EARLY_MILLISEC) {
          if (delta1 == 0) fixation_delta2_ += abs2;
          if (delta2 == 0) fixation_delta1_ += abs1;
        }
      }

      // ------------------------------------------------------------
      // when sign is different
      if (0 > delta1 * chained_delta1_ ||
          0 > delta2 * chained_delta2_) {
        queue_->clear();
        chained_delta1_ = delta1;
        chained_delta2_ = delta2;

      } else if (abs(delta1) > abs(chained_delta1_) ||
                 abs(delta2) > abs(chained_delta2_)) {
        // greater delta.
        chained_delta1_ = delta1;
        chained_delta2_ = delta2;
      }

      absolute_distance_ += abs(chained_delta1_) + abs(chained_delta2_);
      queue_->push_back(new Item(chained_delta1_ * EventOutputQueue::FireScrollWheel::DELTA_SCALE, chained_delta2_ * EventOutputQueue::FireScrollWheel::DELTA_SCALE));

      currentFromFlags_ = fromFlags_;
      timer_.setTimeoutMS(SCROLL_INTERVAL_MS, false);
    }
    bool
    PointingRelativeToScroll::remap(RemapParams& remapParams)
    {
      // ------------------------------------------------------------
      // PointingRelativeToScroll grabs all pointing movement events.
      // Therefore, if user write inappropriate <autogen> (empty flags and empty buttons),
      // user cannot control pointing device at all.
      //
      // For example:
      //   <autogen>__PointingRelativeToScroll__ PointingButton::LEFT | PointingButton::RIGHT</autogen>
      //
      // (Buttons(LEFT | RIGHT) will be ignored. So, this autogen is interpreted as
      // <autogen>__PointingRelativeToScroll__</autogen>.)
      //
      // Skip on error in order to avoid this situation.
      if (fromEvent_.getType() == FromEvent::Type::NONE &&
          fromFlags_ == Flags(0)) {
        IOLOG_WARN("Ignore __PointingRelativeToScroll__ with no option. "
                   "Please use \"__PointingRelativeToScroll__ PointingButton::NONE\".\n");
        return false;
      }

      // ------------------------------------------------------------
      if (remapParams.isremapped) return false;

      bool useFromEvent = true;
      if (fromEvent_.getType() == FromEvent::Type::NONE) {
        useFromEvent = false;
      }
      if (fromEvent_.getType() == FromEvent::Type::POINTING_BUTTON &&
          fromEvent_.getPointingButton() == PointingButton::NONE) {
        useFromEvent = false;
      }

      if (! useFromEvent) {
        if (! FlagStatus::makeFlags().isOn(fromFlags_)) return false;
        goto doremap;

      } else {
        // FromEvent == KeyCode or ConsumerKeyCode or PointingButton.

        bool pressingStateChanged = fromEvent_.changePressingState(remapParams.paramsUnion,
                                                                   FlagStatus::makeFlags(),
                                                                   fromFlags_);
        if (pressingStateChanged) {
          if (fromEvent_.isPressing()) {
            // down event
            FlagStatus::decrease(fromEvent_.getModifierFlag());
            ButtonStatus::decrease(fromEvent_.getPointingButton());

            absolute_distance_ = 0;
            begin_ic_.begin();
            chained_ic_.begin();
            chained_delta1_ = 0;
            chained_delta2_ = 0;

          } else {
            // up event
            FlagStatus::increase(fromEvent_.getModifierFlag());
            ButtonStatus::increase(fromEvent_.getPointingButton());

            cancelScroll();

            const uint32_t DISTANCE_THRESHOLD = 5;
            const uint32_t TIME_THRESHOLD = 300;
            if (absolute_distance_ <= DISTANCE_THRESHOLD && begin_ic_.getmillisec() < TIME_THRESHOLD) {
              // Fire by a click event.
              if (isToKeysDefined_) {
                keytokey_.call_remap_with_VK_PSEUDO_KEY(EventType::DOWN);
                keytokey_.call_remap_with_VK_PSEUDO_KEY(EventType::UP);

              } else {
                toEvent_.fire_downup(FlagStatus::makeFlags());
              }
            }
          }

          // ignore this event.
          goto returntrue;

        } else {
          if (! fromEvent_.isPressing()) {
            return false;
          }
        }
      }

    doremap:
      // change only cursor move events.
      {
        Params_RelativePointerEventCallback* params = remapParams.paramsUnion.get_Params_RelativePointerEventCallback();
        if (! params) return false;
        if (params->ex_button != PointingButton::NONE) return false;
      }

      // We need to call EventWatcher::on here.
      // See the comments in EventInputQueue::fire_timer_callback.
      EventWatcher::on();
      toscroll(remapParams);

    returntrue:
      remapParams.isremapped = true;
      return true;
    }