Ctrl K
ComunidadGuías…

server/src/quit_hotkey_parse.h

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
/**
 * @file src/quit_hotkey_parse.h
 * @brief Reading the quit combo out of a config file, forgivingly.
 *
 * The combo is stored as a person would write it - "Ctrl+Alt+Shift+Q" - because it gets read by
 * a person: in the config file, in the web UI, in the log line that says what the server thinks
 * it was told. That costs a parser, and this is it.
 *
 * The one rule that matters: a bad value must never stop the server. A typo in a config file is
 * a person's mistake, not a reason for their stream host to refuse to start, so a value that
 * cannot be understood is reported rather than thrown, and the caller falls back to the default
 * and says so. Everything here is therefore pure - a string in, a decision out - which is also
 * what makes the awkward inputs cheap to test.
 *
 * This is the SHARED form of a combination. Windows wants a virtual-key code and Linux wants an
 * evdev code, and neither of those belongs in a config file; each platform resolves this into
 * its own form at the point where it needs one. There is deliberately only one combo_t.
 */
#pragma once

#include <string>

namespace quit_hotkey {
  /**
   * @brief A combination, as a person would describe it.
   */
  struct combo_t {
    char key = 'Q';        ///< 'A'-'Z' or '0'-'9'. Always upper-case. Meaningless if function_key.
    int function_key = 0;  ///< 1-24 when the key is a function key, otherwise 0.
    bool ctrl = true;      ///< Whether either Ctrl must be held.
    bool alt = true;       ///< Whether either Alt must be held.
    bool shift = true;     ///< Whether either Shift must be held.

    /// The shipped combination, in the form a person would write it.
    ///
    /// Q, because that is the key the client already uses to leave a stream. This feature exists
    /// for the moment the keyboard has moved and the client can no longer see that combination,
    /// so the host has to watch the one the user will actually reach for - not a second,
    /// unfamiliar key they would have to be told about. O is the client's "open stream settings",
    /// which is why watching it would give one keystroke two different meanings depending on
    /// where the keyboard happens to be.
    static std::string default_value();
  };

  /**
   * @brief What parsing produced, understood or not.
   *
   * `error` is in words and is never empty when `ok` is false, because it is going into the log
   * next to the value that was rejected - and "input_quit_hotkey: 'Ctrl+Bananaphone' is not a
   * key" is a sentence somebody can act on.
   */
  struct parse_result_t {
    bool ok = false;
    char key = 'Q';
    int function_key = 0;
    bool ctrl = false;
    bool alt = false;
    bool shift = false;
    std::string error;
  };

  /**
   * @brief Parse a combination such as "Ctrl+Alt+Shift+Q".
   *
   * Forgiving about the things people vary and strict about the things that matter. Modifier
   * order does not matter, and modifier names are case-insensitive, because "ctrl+alt+q" and
   * "Alt+Ctrl+Q" are the same request. The key must be one this program can register: a letter
   * A-Z, a digit 0-9, or a function key F1-F24. Anything else - an empty value, an unknown
   * modifier, a key that is not a key, or a string with no key at all - comes back not-ok with
   * a sentence naming the offending part.
   *
   * An unknown modifier is rejected rather than ignored on purpose: quietly dropping "Super"
   * from "Ctrl+Alt+Shift+Super+Q" would register a different combination than was asked for,
   * which is a worse outcome than refusing to use that setting.
   */
  parse_result_t parse(const std::string &value);

  /**
   * @brief The combination a successful parse produced.
   *
   * Only meaningful when `ok` is true. This exists because the two types answer different
   * questions: parse_result_t says whether a value was understood and, if not, why; combo_t is
   * the combination itself, which is what each platform's resolve() takes. Keeping them apart
   * means the error text cannot be mistaken for part of the combination.
   */
  combo_t to_combo(const parse_result_t &parsed);
}  // namespace quit_hotkey