# # 表单交互事件处理机制

Foxit PDF SDK for Web 为填表模式下的表单交互提供了一套完整的事件处理机制，使开发者能够精确控制和定制表单交互行为。该机制支持多种事件类型，包括鼠标事件（如按下、移动、释放等）和键盘事件（如按下、释放等）。开发者可以通过以下三种方式实现事件控制：

- 事件监听：通过 `FormFillerService.onMouseDownWidget`、`FormFillerService.onMouseDownWidget` 等方法监听表单交互事件。
- 拦截器：通过实现 `FormInteractionEventInterceptor`
  (opens new window) 接口，拦截并处理表单交互事件。
- 方法重写：通过 `ViewerAnnotManager.registerMatchRule` 方法注册 mixin 方法，继承 `WidgetAnnot` 并重写相关方法，如 `handleOnGotFocus` 和 `handleOnClick` 等。

以下将详细介绍每种方式的具体用法。

## # 表单交互事件监听

事件监听允许开发者在表单控件交互过程中，通过事件回调处理与控件实现无关的逻辑。这种方式可以在不改变控件原有行为的基础上，添加额外的处理逻辑。典型的应用场景包括：

- 用户行为分析：
  - 通过监听表单控件的交互事件（如点击、移动、键盘输入）收集用户行为数据。
- 实时帮助和提示：
  - 在用户输入或点击特定字段时，动态触发帮助信息或工具提示的显示。
- 其他场景：
  - 根据具体业务需求，扩展更多定制化功能。

Foxit PDF SDK for Web 提供了以下事件监听方法：

- `FormFillerService.onMouseDownWidget`：监听鼠标按下事件。
- `FormFillerService.onMouseMoveWidget`：监听鼠标移动事件。
- `FormFillerService.onMouseUpWidget`：监听鼠标释放事件。
- `FormFillerService.onClickWidget`：监听鼠标左键点击事件。
- `FormFillerService.onRightClickWidget`：监听鼠标右键点击事件。
- `FormFillerService.onMouseOverWidget`：监听鼠标移入事件。
- `FormFillerService.onMouseLeaveWidget`：监听鼠标移出事件。
- `FormFillerService.onKeyDown`：监听键盘按下事件。
- `FormFillerService.onKeyUp`：监听键盘释放事件。
- `FormFillerService.onFocusChange`：监听焦点变化事件。

更多接口信息请参考 FormFillerService
(opens new window) 文档。

以下是一个简单的示例：

    const formFillerService = pdfViewer.getFormFillerService();
    // 使用 removeEvent 函数可以在需要时移除事件监听
    const removeEvent = formFillerService.onMouseOverWidget((widgetId, event) => {
        console.log('Mouse over widget:', widgetId, event);
    });

    const removeEvent = formFillerService.onMouseDownWidget((widgetId, event) => {
      if(widgetId) {
        console.log('Mouse down on widget:', widgetId, event);
      } else {
        console.log('Mouse down on page');
      }
    });

## # 表单交互事件拦截器

拦截器机制允许开发者在事件发生前或发生后进行干预，从而选择性地允许或阻止事件传播。典型的应用场景包括：

- 访问控制：
  - 根据用户角色或权限动态控制表单字段的可交互性。
- 用户界面保护：
  - 通过拦截事件（如 `mouseup`），在执行高风险操作前提示用户确认，降低误操作风险。
- 行为修改：
  - 根据场景需求修改表单交互行为。

Foxit PDF SDK for Web 提供的拦截器接口如下：

    interface FormInteractionEvent {
      type: string; // mousedown|mousemove|mouseup|keydown|keyup
      timestamp: number; // 事件发生的时间戳，单位为毫秒
    }
    interface FormInteractionEventInterceptorOptions {
      type: FormInteractionEvent;
      widgetId: AnnotId;
    }
    type FormInteractionEventInterceptor = (options:FormInteractionEventInterceptorOptions,next:()=>Promise<unknown>)=>Promise<void>;

其中，`options` 参数包含目标表单域的 ID（一个包含 `pageIndex` 和 `objNumber` 的对象）和事件类型。`next` 函数用于调用下一个拦截器。更多详细信息请参考 FormInteractionEventInterceptor
(opens new window) 文档。

以下是一个拦截器实现示例：

    // removeInterceptor 用于在特定时机移除拦截器
    const removeInterceptor = formFillerService.appendInteractionEventInterceptor(async (options, next) => {
      if(options.type === 'mouseup') {
        // 拦截鼠标释放事件
        console.log("Before mouse up");
        // 调用下一个拦截器或处理真实事件
        await next();
        // 在鼠标释放事件完成后执行
        console.log("After mouse up");
      }
    })

注意事项：

1. 如果不调用 `next` 方法，拦截器将阻止事件传递，SDK 内部的处理逻辑将不会执行。
2. `click` 和 `right-click` 是 `mousedown/mouseup` 在特定条件下的组合事件，无法直接处理，只能通过拦截 `mousedown` 或 `mouseup` 事件实现。

完整示例可参考：<examples/UIExtension/form/interaction-event-interceptor/index.js>

## # 方法重写

方法重写通过 `ViewerAnnotManager.registerMatchRule` 注册 mixin 方法，继承 `WidgetAnnot` 并重写 `handleOnGotFocus` 和 `handleOnClick` 等方法。这种方式不仅可以监听事件，还可以控制是否执行 SDK 内部的表现层处理逻辑。典型的应用场景包括：

- 事件监听器支持的所有场景。
- 需要覆盖 Foxit PDF SDK for Web 表现层处理逻辑的场景。

Foxit PDF SDK for Web 提供的可重写的事件相关方法如下：

- `handleOnClick`：处理鼠标左键点击事件。
- `handleOnMouseOver`：处理鼠标移入事件。
- `handleOnMouseLeave`：处理鼠标移出事件。
- `handleOnGotFocus`：处理获取焦点事件。
- `handleOnLostFocus`：处理失去焦点事件。

注意：若需覆盖鼠标右键事件或自定义右键菜单，可以通过重写 `showContextMenu` 方法来实现。

以下是一个简单的示例：

    pdfViewer.getAnnotManager().registerMatchRule(function(annot, AnnotComponentClass) {
      if(annot.getType() !== 'widget') {
          return;
      }
      return class CustomWidgetAnnot extends AnnotComponentClass {
          handleOnClick() {
              super.handleOnClick();
              console.log('CustomWidgetAnnot handleOnClick');
          }
          handleOnMouseOver() {
              super.handleOnMouseOver();
              console.log('Handle on mouse over');
          }
          handleOnMouseLeave() {
              super.handleOnMouseLeave();
              console.log('Handle on mouse leave');
          }
          handleOnGotFocus() {
              super.handleOnGotFocus();
              console.log('Handle on got focus');
          }
          handleOnLostFocus() {
              super.handleOnLostFocus();
              console.log('Handle on lost focus');
          }
      }
    })

## # 方法对比

方法 | 支持范围 | 控制层次 | 灵活性
--- | --- | --- | ---
事件监听 | mousedown/mouseover/mouseup/click/right-click/mouseover/mouseleave/keydown/keyup/focus-change | 事件发生后 | 一般
拦截器 | mousedown/mousemove/mouseup/keydown/keyup | 事件发生前和发生后 | 最高
方法重写 | click/mouseover/mouseleave/get-focus/lost-focus | 事件发生后 | 一般