chromium/ui/events/win/keyboard_hook_win_base.h

// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef UI_EVENTS_WIN_KEYBOARD_HOOK_WIN_BASE_H_
#define UI_EVENTS_WIN_KEYBOARD_HOOK_WIN_BASE_H_

#include <windows.h>

#include <memory>
#include <optional>

#include "base/check.h"
#include "base/component_export.h"
#include "base/containers/flat_set.h"
#include "base/threading/thread_checker.h"
#include "ui/events/event.h"
#include "ui/events/keyboard_hook_base.h"
#include "ui/events/keycodes/dom/dom_code.h"

namespace ui {

// Exposes a method to drive the Windows KeyboardHook implementation by feeding
// it key event data.  This method is used by both the low-level keyboard hook
// and by unit tests which simulate the hooked behavior w/o actually installing
// a hook (doing so would cause problems with test parallelization).
class COMPONENT_EXPORT(KEYBOARD_HOOK) KeyboardHookWinBase
    : public KeyboardHookBase {
 public:
  KeyboardHookWinBase(std::optional<base::flat_set<DomCode>> dom_codes,
                      KeyEventCallback callback,
                      bool enable_hook_registration);

  KeyboardHookWinBase(const KeyboardHookWinBase&) = delete;
  KeyboardHookWinBase& operator=(const KeyboardHookWinBase&) = delete;

  ~KeyboardHookWinBase() override;

  // Create a KeyboardHookWinBase instance which does not register a
  // low-level hook and captures modifier keys.
  static std::unique_ptr<KeyboardHookWinBase>
  CreateModifierKeyboardHookForTesting(
      std::optional<base::flat_set<DomCode>> dom_codes,
      KeyEventCallback callback);

  // Create a KeyboardHookWinBase instance which does not register a
  // low-level hook and captures media keys.
  static std::unique_ptr<KeyboardHookWinBase> CreateMediaKeyboardHookForTesting(
      KeyEventCallback callback);

  // Called when a key event message is delivered via the low-level hook.
  // Exposed here to allow for testing w/o engaging the low-level hook.
  // Returns true if the message was handled.
  virtual bool ProcessKeyEventMessage(WPARAM w_param,
                                      DWORD vk,
                                      DWORD scan_code,
                                      DWORD time_stamp) = 0;

 protected:
  bool Register(HOOKPROC hook_proc);
  bool enable_hook_registration() const { return enable_hook_registration_; }

  static LRESULT CALLBACK ProcessKeyEvent(KeyboardHookWinBase* instance,
                                          int code,
                                          WPARAM w_param,
                                          LPARAM l_param);

 private:
  const bool enable_hook_registration_ = true;
  HHOOK hook_ = nullptr;
  THREAD_CHECKER(thread_checker_);
};

}  // namespace ui

#endif  // UI_EVENTS_WIN_KEYBOARD_HOOK_WIN_BASE_H_