1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
//! Provides decoders for the keyboard-related signals.
//!
//! Keyboards, while components, do not expose any methods, so no component wrapper is provided in
//! this module.
use crate::helpers::decode_u32_from_signal;
use core::num::NonZeroU32;
use minicbor::{Decode, Decoder};
use oc_wasm_safe::Address;
/// Information about a key press or release event, excluding the name of the player who pressed or
/// released the key.
///
/// This structure, unlike [`KeySignal`](KeySignal), is fully owned. Thus, a typical application
/// which does not care about the player name can convert a [`KeySignal`](KeySignal) into a
/// `BasicKeySignal` in order to regain use of the decode buffer.
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct BasicKeySignal {
/// The address of the keyboard component.
pub keyboard: Address,
/// The character that was pressed or released, if any.
///
/// This is `None` if the event does not produce a character. Examples of
/// non-character-producing key events are events related to lock keys, arrow keys, modifier
/// keys, navigation keys, or other special keys.
pub character: Option<char>,
/// The keycode that was pressed or released, if any.
///
/// This is `None` if the event does not have a keycode. One example of a non-keycode-producing
/// key event is a composed character; in this case, the individual keystrokes are not
/// reported, but the composed character is reported as a character without associated keycode.
/// Another example is a Windows key (aka super key) or Menu key, both of which (under some
/// operating systems at least) send key signals with neither `character` nor `keycode` filled
/// in.
pub keycode: Option<NonZeroU32>,
}
impl<'buffer> From<&KeySignal<'buffer>> for BasicKeySignal {
fn from(source: &KeySignal<'buffer>) -> Self {
Self {
keyboard: source.keyboard,
character: source.character,
keycode: source.keycode,
}
}
}
/// Information about a key press or release signal.
#[derive(Clone, Debug, Decode, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[cbor(array)]
pub struct KeySignal<'buffer> {
/// The address of the keyboard component.
#[b(0)]
pub keyboard: Address,
/// The character that was pressed or released, if any.
///
/// This is `None` if the signal does not produce a character. Examples of
/// non-character-producing key signals are signals related to lock keys, arrow keys, modifier
/// keys, navigation keys, or other special keys.
#[b(1)]
#[cbor(decode_with = "KeySignal::decode_character")]
pub character: Option<char>,
/// The keycode that was pressed or released, if any.
///
/// This is `None` if the signal does not have a keycode. One example of a
/// non-keycode-producing key signal is a composed character; in this case, the individual
/// keystrokes are not reported, but the composed character is reported as a character without
/// associated keycode. Another example is a Windows key (aka super key) or Menu key, both of
/// which (under some operating systems at least) send key signals with neither `character` nor
/// `keycode` filled in.
#[b(2)]
#[cbor(decode_with = "KeySignal::decode_keycode")]
pub keycode: Option<NonZeroU32>,
/// The name of the player who pressed or released the key.
///
/// This is `None` if reporting of player names is disabled in the mod configuration.
#[b(3)]
pub player: Option<&'buffer str>,
}
impl<'buffer> KeySignal<'buffer> {
/// The name of the signal sent when a key is pressed.
///
/// This includes typematic repeats of held keys.
pub const KEY_DOWN: &'static str = "key_down";
/// The name of the signal sent when a key is released.
pub const KEY_UP: &'static str = "key_up";
/// Decodes the `character` field of a `KeySignal`.
///
/// This field is encoded as a double-precision floating point number in CBOR and needs to be
/// converted to its proper type.
fn decode_character<Context>(
d: &mut Decoder<'buffer>,
_: &mut Context,
) -> Result<Option<char>, minicbor::decode::Error> {
// Unicode code points are 0≤N≤0x10FFFF.
let character = decode_u32_from_signal(d)?;
if character == 0 {
Ok(None)
} else {
Ok(char::from_u32(character))
}
}
/// Decodes the `keycode` field of a `KeySignal`.
///
/// This field is encoded as a double-precision floating point number in CBOR and needs to be
/// converted to its proper type.
fn decode_keycode<Context>(
d: &mut Decoder<'buffer>,
_: &mut Context,
) -> Result<Option<NonZeroU32>, minicbor::decode::Error> {
// Keycodes are small nonnegative numbers.
let keycode = decode_u32_from_signal(d)?;
Ok(NonZeroU32::new(keycode))
}
/// Discards the player name information from this value.
#[must_use]
pub fn to_basic(&self) -> BasicKeySignal {
BasicKeySignal::from(self)
}
}
/// Information about a clipboard paste signal.
#[derive(Clone, Debug, Decode, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[cbor(array)]
pub struct ClipboardSignal<'buffer> {
/// The address of the keyboard component.
#[b(0)]
pub keyboard: Address,
/// The text that was pasted.
#[b(1)]
pub text: &'buffer str,
/// The name of the player who pasted the text.
///
/// This is `None` if reporting of player names is disabled in the mod configuration.
#[b(2)]
pub player: Option<&'buffer str>,
}
impl ClipboardSignal<'_> {
/// The name of the signal sent when text is pasted from the clipboard.
pub const SIGNAL: &'static str = "clipboard";
}