void
KeyboardRepeat::fire_timer_callback(OSObject* owner, IOTimerEventSource* sender) {
  IOLOG_DEVEL("KeyboardRepeat::fire queue_.size = %d\n", static_cast<int>(queue_.size()));

  // ----------------------------------------
  for (KeyboardRepeat::Item* p = static_cast<KeyboardRepeat::Item*>(queue_.safe_front()); p; p = static_cast<KeyboardRepeat::Item*>(p->getnext())) {
    {
      {
        auto params = (p->getParamsBase()).get_Params_KeyboardEventCallBack();
        if (params) {
          EventOutputQueue::FireKey::fire(
              Params_KeyboardEventCallBack(
                  params->eventType,
                  params->flags,
                  params->key,
                  params->keyboardType,
                  queue_.size() == 1 ? true : false));
        }
      }

      {
        auto params = (p->getParamsBase()).get_Params_KeyboardSpecialEventCallback();
        if (params) {
          EventOutputQueue::FireConsumer::fire(
              Params_KeyboardSpecialEventCallback(
                  params->eventType,
                  params->flags,
                  params->key,
                  queue_.size() == 1 ? true : false));
        }
      }

      {
        auto params = (p->getParamsBase()).get_Params_RelativePointerEventCallback();
        if (params) {
          EventOutputQueue::FireRelativePointer::fire(params->buttons, params->dx, params->dy);
        }
      }
    }
  }

  fire_timer_.setTimeoutMS(keyRepeat_);
}
void
KeyboardRepeat::set(EventType eventType,
                    Flags flags,
                    KeyCode key,
                    KeyboardType keyboardType,
                    int delayUntilRepeat,
                    int keyRepeat) {
  if (key == KeyCode::VK_NONE) return;

  if (eventType == EventType::MODIFY) {
    goto cancel;

  } else if (eventType == EventType::UP) {
    // The repetition of plural keys is controlled by manual operation.
    // So, we ignore it.
    if (queue_.size() != 1) return;

    // We stop key repeat only when the repeating key is up.
    KeyboardRepeat::Item* p = static_cast<KeyboardRepeat::Item*>(queue_.safe_front());
    if (p) {
      auto params = (p->getParamsBase()).get_Params_KeyboardEventCallBack();
      if (params && key == params->key) {
        goto cancel;
      }
    }

  } else if (eventType == EventType::DOWN) {
    cancel();

    primitive_add(eventType, flags, key, keyboardType);
    primitive_start(delayUntilRepeat, keyRepeat);

    IOLOG_DEVEL("KeyboardRepeat::set key:%d flags:0x%x\n", key.get(), flags.get());

  } else {
    goto cancel;
  }

  return;

cancel:
  cancel();
}