// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
#pragma once
#include "InputDevice.h"
///
/// Represents a single hardware keyboard device. Used by the Input to report raw keyboard input events.
///
API_CLASS(NoSpawn) class FLAXENGINE_API Keyboard : public InputDevice
{
DECLARE_SCRIPTING_TYPE_NO_SPAWN(Keyboard);
public:
///
/// The mouse state.
///
struct State
{
///
/// The input text length (characters count).
///
uint16 InputTextLength;
///
/// The input text.
///
Char InputText[32];
///
/// The keys.
///
bool Keys[(int32)KeyboardKeys::MAX];
///
/// Clears the state.
///
void Clear()
{
Platform::MemoryClear(this, sizeof(State));
}
};
protected:
State _state;
State _prevState;
explicit Keyboard()
: InputDevice(SpawnParams(Guid::New(), TypeInitializer), TEXT("Keyboard"))
{
_state.Clear();
_prevState.Clear();
}
public:
///
/// Gets the text entered during the current frame.
///
/// The input text (Unicode).
API_PROPERTY() StringView GetInputText() const
{
return StringView(_state.InputText, _state.InputTextLength);
}
///
/// Gets keyboard key state.
///
/// Key ID to check.
/// True if user holds down the key identified by id, otherwise false.
API_FUNCTION() FORCE_INLINE bool GetKey(KeyboardKeys key) const
{
return _state.Keys[static_cast(key)];
}
///
/// Gets keyboard key down state.
///
/// Key ID to check
/// True if user starts pressing down the key, otherwise false.
API_FUNCTION() FORCE_INLINE bool GetKeyDown(KeyboardKeys key) const
{
return _state.Keys[static_cast(key)] && !_prevState.Keys[static_cast(key)];
}
///
/// Gets keyboard key up state.
///
/// Key ID to check
/// True if user releases the key, otherwise false.
API_FUNCTION() FORCE_INLINE bool GetKeyUp(KeyboardKeys key) const
{
return !_state.Keys[static_cast(key)] && _prevState.Keys[static_cast(key)];
}
///
/// Called when keyboard enters input character.
///
/// The Unicode character entered by the user.
/// The target window to receive this event, otherwise input system will pick the window automatically.
void OnCharInput(const Char c, Window* target = nullptr)
{
// Skip control characters
if (c < 32)
return;
Event& e = _queue.AddOne();
e.Type = EventType::Char;
e.Target = target;
e.CharData.Char = c;
}
///
/// Called when key goes up.
///
/// The keyboard key.
/// The target window to receive this event, otherwise input system will pick the window automatically.
void OnKeyUp(const KeyboardKeys key, Window* target = nullptr)
{
Event& e = _queue.AddOne();
e.Type = EventType::KeyUp;
e.Target = target;
e.KeyData.Key = key;
}
///
/// Called when key goes down.
///
/// The keyboard key.
/// The target window to receive this event, otherwise input system will pick the window automatically.
void OnKeyDown(const KeyboardKeys key, Window* target = nullptr)
{
Event& e = _queue.AddOne();
e.Type = EventType::KeyDown;
e.Target = target;
e.KeyData.Key = key;
}
public:
// [InputDevice]
void ResetState() override
{
InputDevice::ResetState();
_prevState.Clear();
_state.Clear();
}
bool Update(EventQueue& queue) final override
{
// Move the current state to the previous
Platform::MemoryCopy(&_prevState, &_state, sizeof(State));
// Gather new events
if (UpdateState())
return true;
// Handle events
for (int32 i = 0; i < _queue.Count(); i++)
{
const Event& e = _queue[i];
switch (e.Type)
{
case EventType::Char:
{
if (_state.InputTextLength < ARRAY_COUNT(_state.InputText) - 1)
_state.InputText[_state.InputTextLength++] = e.CharData.Char;
break;
}
case EventType::KeyDown:
{
_state.Keys[static_cast(e.KeyData.Key)] = true;
break;
}
case EventType::KeyUp:
{
_state.Keys[static_cast(e.KeyData.Key)] = false;
break;
}
}
}
// Send events further
queue.Add(_queue);
_queue.Clear();
return false;
}
};