//------------------------------------------------------------------------------
// emInput.h
//
// Copyright (C) 2005-2012,2014-2015,2018 Oliver Hamann.
//
// Homepage: http://eaglemode.sourceforge.net/
//
// This program is free software: you can redistribute it and/or modify it under
// the terms of the GNU General Public License version 3 as published by the
// Free Software Foundation.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU General Public License version 3 for
// more details.
//
// You should have received a copy of the GNU General Public License version 3
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//------------------------------------------------------------------------------
#ifndef emInput_h
#define emInput_h
#ifndef emStd2_h
#include <emCore/emStd2.h>
#endif
#ifndef emArray_h
#include <emCore/emArray.h>
#endif
//==============================================================================
//================================= emInputKey =================================
//==============================================================================
enum emInputKey {
// None:
EM_KEY_NONE = 0x00,
// Mouse buttons and wheel:
EM_KEY_LEFT_BUTTON = 0xF0,
EM_KEY_MIDDLE_BUTTON = 0xF1,
EM_KEY_RIGHT_BUTTON = 0xF2,
EM_KEY_WHEEL_UP = 0xF3,
EM_KEY_WHEEL_DOWN = 0xF4,
EM_KEY_WHEEL_LEFT = 0xF5,
EM_KEY_WHEEL_RIGHT = 0xF6,
EM_KEY_BACK_BUTTON = 0xF7,
EM_KEY_FORWARD_BUTTON = 0xF8,
// Screen touch:
EM_KEY_TOUCH = 0xEF,
// Keyboard keys:
EM_KEY_SHIFT = 0x81,
EM_KEY_CTRL = 0x82,
EM_KEY_ALT = 0x83,
EM_KEY_META = 0x84,
EM_KEY_ALT_GR = 0x85,
EM_KEY_CURSOR_UP = 0x91,
EM_KEY_CURSOR_DOWN = 0x92,
EM_KEY_CURSOR_LEFT = 0x93,
EM_KEY_CURSOR_RIGHT = 0x94,
EM_KEY_PAGE_UP = 0x95,
EM_KEY_PAGE_DOWN = 0x96,
EM_KEY_HOME = 0x97,
EM_KEY_END = 0x98,
EM_KEY_PRINT = 0x99,
EM_KEY_PAUSE = 0x9A,
EM_KEY_MENU = 0x9B,
EM_KEY_INSERT = 0x9F,
EM_KEY_DELETE = 0x7F,
EM_KEY_BACKSPACE = 0x08,
EM_KEY_TAB = 0x09,
EM_KEY_ENTER = 0x0D,
EM_KEY_ESCAPE = 0x1B,
EM_KEY_SPACE = 0x20,
EM_KEY_0 = 0x30,
EM_KEY_1 = 0x31,
EM_KEY_2 = 0x32,
EM_KEY_3 = 0x33,
EM_KEY_4 = 0x34,
EM_KEY_5 = 0x35,
EM_KEY_6 = 0x36,
EM_KEY_7 = 0x37,
EM_KEY_8 = 0x38,
EM_KEY_9 = 0x39,
EM_KEY_A = 0x41,
EM_KEY_B = 0x42,
EM_KEY_C = 0x43,
EM_KEY_D = 0x44,
EM_KEY_E = 0x45,
EM_KEY_F = 0x46,
EM_KEY_G = 0x47,
EM_KEY_H = 0x48,
EM_KEY_I = 0x49,
EM_KEY_J = 0x4A,
EM_KEY_K = 0x4B,
EM_KEY_L = 0x4C,
EM_KEY_M = 0x4D,
EM_KEY_N = 0x4E,
EM_KEY_O = 0x4F,
EM_KEY_P = 0x50,
EM_KEY_Q = 0x51,
EM_KEY_R = 0x52,
EM_KEY_S = 0x53,
EM_KEY_T = 0x54,
EM_KEY_U = 0x55,
EM_KEY_V = 0x56,
EM_KEY_W = 0x57,
EM_KEY_X = 0x58,
EM_KEY_Y = 0x59,
EM_KEY_Z = 0x5A,
EM_KEY_F1 = 0xA1,
EM_KEY_F2 = 0xA2,
EM_KEY_F3 = 0xA3,
EM_KEY_F4 = 0xA4,
EM_KEY_F5 = 0xA5,
EM_KEY_F6 = 0xA6,
EM_KEY_F7 = 0xA7,
EM_KEY_F8 = 0xA8,
EM_KEY_F9 = 0xA9,
EM_KEY_F10 = 0xAA,
EM_KEY_F11 = 0xAB,
EM_KEY_F12 = 0xAC
};
bool emIsMouseInputKey(emInputKey key);
// True for mouse buttons and mouse wheel.
bool emIsTouchInputKey(emInputKey key);
// True screen touch.
bool emIsKeyboardInputKey(emInputKey key);
// True for all keyboard keys, including modifiers.
bool emIsModifierInputKey(emInputKey key);
// True for shift, ctrl, alt and meta.
const char * emInputKeyToString(emInputKey key);
emInputKey emStringToInputKey(const char * str);
// Convert an input key to and from string representation.
//==============================================================================
//================================ emInputEvent ================================
//==============================================================================
class emInputEvent : public emUncopyable {
public:
// Class for an input event. Such an event consists of an input key
// (mouse buttons and wheel are even "keys" here), which has changed
// from non-pressed to pressed state. Instead of a key, or in addition
// to the key, a translation into text characters may be provided. It is
// possible that an original event comes through two input events: one
// with the input key, and one with the translated text characters (at
// the time of writing this, it is so with emWndsWindowPort, but not
// with emX11WindowPort).
emInputEvent();
// Construct an event which is initially empty.
void Setup(emInputKey key, const emString & chars, int repeat,
int variant);
// Set-up the event.
// Arguments:
// key - see GetKey().
// chars - see GetChars().
// repeat - see GetRepeat().
// variant - see GetVariant().
emInputKey GetKey() const;
// Get the key. This is EM_KEY_NONE if the event is empty or if
// the event provides characters only (see GetChars()).
const emString & GetChars() const;
// Get the translated text characters. This should be at most
// one text character, but possibly encoded as a multi-byte
// sequence (e.g. UTF-8). This is an empty string if the event
// is empty, or if the key could not be translated.
int GetRepeat() const;
// Get number of event repetitions. For example, 1 means
// double-click for mouse buttons.
int GetVariant() const;
// Get variant of the event source. If the key is on the numeric
// key pad, or if it is the right shift, right ctrl or right alt
// key, then this should be 1. Otherwise this should be 0.
void Eat();
// Eat this event (make it an empty event).
bool IsEmpty() const;
bool IsMouseEvent() const;
bool IsTouchEvent() const;
bool IsKeyboardEvent() const;
// Ask for the type of event. One of these returns true.
bool IsKey(emInputKey key) const;
// Like GetKey()==key.
bool IsLeftButton() const;
bool IsMiddleButton() const;
bool IsRightButton() const;
// Like GetKey()==EM_KEY_LEFT_BUTTON and so on.
private:
emInputKey Key;
emString Chars;
int Repeat,Variant;
};
//==============================================================================
//================================ emInputState ================================
//==============================================================================
class emInputState {
public:
// Class for the state of keyboard and mouse. The state consists of the
// mouse pointer position, and which keys are pressed. (Mouse buttons
// are even keys)
emInputState();
// Construct without having any key pressed.
emInputState(const emInputState & inputState);
// Construct a copy of an input state.
emInputState & operator = (const emInputState & inputState);
// Copy another input state to this input state.
bool operator == (const emInputState & inputState) const;
bool operator != (const emInputState & inputState) const;
// Comparison operators.
double GetMouseX() const;
double GetMouseY() const;
void SetMouse(double mouseX, double mouseY);
// Get or set the mouse position in pixel coordinates of the
// view.
int GetTouchCount() const;
// Get number of touches.
int SearchTouch(emUInt64 id) const;
// Search a touch by id. Returns the index or -1 if not found.
emUInt64 GetTouchId(int index) const;
// Get the id of a touch. A touch may get another index over the
// time, but it should keep its id.
double GetTouchX(int index) const;
double GetTouchY(int index) const;
// Get position of a touch in pixel coordinates of the view.
void AddTouch(emUInt64 id, double x, double y);
// Add a touch.
void SetTouch(int index, emUInt64 id, double x, double y);
// Modify an existing touch.
void RemoveTouch(int index);
// Remove a touch.
void ClearTouches();
// Remove all touches.
bool Get(emInputKey key) const;
void Set(emInputKey key, bool pressed);
// Get or set the state of a particular key. It is true if the
// key or button is pressed, false otherwise. EM_KEY_WHEEL_UP
// and EM_KEY_WHEEL_DOWN should never be set here.
bool GetLeftButton() const;
bool GetMiddleButton() const;
bool GetRightButton() const;
bool GetShift() const;
bool GetCtrl() const;
bool GetAlt() const;
bool GetMeta() const;
// These are just some abbreviations. It's like
// Get(EM_KEY_LEFT_BUTTON) and so on.
bool IsNoMod() const;
bool IsShiftMod() const;
bool IsShiftCtrlMod() const;
bool IsShiftCtrlAltMod() const;
bool IsShiftCtrlAltMetaMod() const;
bool IsShiftCtrlMetaMod() const;
bool IsShiftAltMod() const;
bool IsShiftAltMetaMod() const;
bool IsShiftMetaMod() const;
bool IsCtrlMod() const;
bool IsCtrlAltMod() const;
bool IsCtrlAltMetaMod() const;
bool IsCtrlMetaMod() const;
bool IsAltMod() const;
bool IsAltMetaMod() const;
bool IsMetaMod() const;
// Test the four modifier keys at once. For example,
// IsShiftMetaMod() is like (GetShift() && !GetCtrl() &&
// !GetAlt() && GetMeta()).
bool ClearKeyStates();
// Set all keys to non-pressed state. Returns true if something
// was pressed.
const unsigned char * GetKeyStates() const;
unsigned char * GetKeyStates();
// Get a pointer to the states of all keyboard keys and mouse
// buttons, even for modification. The size of the returned
// array is 32 bytes. A key is pressed if
// GetKeyStates()[key>>3]&(1<<(key&7)) is non-zero.
private:
struct Touch {
emUInt64 Id;
double X, Y;
};
double MouseX, MouseY;
unsigned char KeyStates[32];
emArray<Touch> Touches;
};
//==============================================================================
//=============================== emInputHotkey ================================
//==============================================================================
class emInputHotkey {
public:
// Class for a hotkey. It is a combination of modifier keys and a
// non-modifier keyboard key.
emInputHotkey();
// Construct an invalid hotkey.
emInputHotkey(const emInputHotkey & hotkey);
// Copy constructor.
emInputHotkey(emInputKey key);
emInputHotkey(emInputKey modifier, emInputKey key);
emInputHotkey(emInputKey modifier1, emInputKey modifier2,
emInputKey key);
emInputHotkey(emInputKey modifier1, emInputKey modifier2,
emInputKey modifier3, emInputKey key);
emInputHotkey(emInputKey modifier1, emInputKey modifier2,
emInputKey modifier3, emInputKey modifier4,
emInputKey key);
// Construct a valid hotkey. The last argument must be a
// non-modifier keyboard key, the other arguments must be
// modifier keys.
emInputHotkey(const emInputEvent & event, const emInputState & state);
// Construct form an input event and an input state. The hotkey
// gets invalid if the event is not a non-modifier keyboard key.
emInputHotkey & operator = (const emInputHotkey & hotkey);
// Copy operator.
bool operator == (const emInputHotkey & hotkey) const;
bool operator != (const emInputHotkey & hotkey) const;
// Comparison operators.
void TryParse(const char * str);
// Try to set this hotkey from a human-readable string
// representation (e.g. "Ctrl+C"). On failure, the hotkey is set
// invalid and an error message is thrown.
emString GetString() const;
void GetString(char * buf, int bufSize) const;
// Create a human-readable string representation (e.g.
// "Ctrl+C"). If the hotkey is invalid, an empty string is
// returned.
bool IsValid() const;
// Whether this is a valid hotkey.
bool GetShift() const;
bool GetCtrl() const;
bool GetAlt() const;
bool GetMeta() const;
// Whether the respective modifier key is part of this hotkey.
emInputKey GetKey() const;
// Get the event key. Returns EM_KEY_NONE if the hotkey is not
// valid.
bool Match(const emInputEvent & event, const emInputState & state) const;
// Ask whether the input event and input state matches this
// hotkey.
void ClearModifiers();
// Remove all modifiers.
void AddModifier(emInputKey modifier);
// Add a modifier.
void SetKey(emInputKey key);
// Set the event key. Must be a non-modifier keyboard key or the
// hotkey gets invalid.
private:
static const char * Key2Name(emInputKey key);
static emInputKey Name2Key(const char * name, int len);
enum {
MF_SHIFT=(1<<0),
MF_CTRL =(1<<1),
MF_ALT =(1<<2),
MF_META =(1<<3)
};
union {
emUInt16 Packed;
struct {
emByte MFlags;
emByte Key;
} Data;
};
};
//==============================================================================
//=========================== Inline Implementations ===========================
//==============================================================================
inline bool emIsMouseInputKey(emInputKey key)
{
return key>=EM_KEY_LEFT_BUTTON;
}
inline bool emIsTouchInputKey(emInputKey key)
{
return key==EM_KEY_TOUCH;
}
inline bool emIsKeyboardInputKey(emInputKey key)
{
return key && key<EM_KEY_TOUCH;
}
inline bool emIsModifierInputKey(emInputKey key)
{
return (((int)key)&0xF8)==0x80;
}
inline emInputKey emInputEvent::GetKey() const
{
return Key;
}
inline const emString & emInputEvent::GetChars() const
{
return Chars;
}
inline int emInputEvent::GetRepeat() const
{
return Repeat;
}
inline int emInputEvent::GetVariant() const
{
return Variant;
}
inline bool emInputEvent::IsEmpty() const
{
return Key==EM_KEY_NONE && Chars.IsEmpty();
}
inline bool emInputEvent::IsMouseEvent() const
{
return emIsMouseInputKey(Key);
}
inline bool emInputEvent::IsTouchEvent() const
{
return emIsTouchInputKey(Key);
}
inline bool emInputEvent::IsKeyboardEvent() const
{
return emIsKeyboardInputKey(Key) || !Chars.IsEmpty();
}
inline bool emInputEvent::IsKey(emInputKey key) const
{
return Key==key;
}
inline bool emInputEvent::IsLeftButton() const
{
return Key==EM_KEY_LEFT_BUTTON;
}
inline bool emInputEvent::IsMiddleButton() const
{
return Key==EM_KEY_MIDDLE_BUTTON;
}
inline bool emInputEvent::IsRightButton() const
{
return Key==EM_KEY_RIGHT_BUTTON;
}
inline double emInputState::GetMouseX() const
{
return MouseX;
}
inline double emInputState::GetMouseY() const
{
return MouseY;
}
inline void emInputState::SetMouse(double mouseX, double mouseY)
{
MouseX=mouseX;
MouseY=mouseY;
}
inline int emInputState::GetTouchCount() const
{
return Touches.GetCount();
}
inline emUInt64 emInputState::GetTouchId(int index) const
{
return Touches[index].Id;
}
inline double emInputState::GetTouchX(int index) const
{
return Touches[index].X;
}
inline double emInputState::GetTouchY(int index) const
{
return Touches[index].Y;
}
inline bool emInputState::GetLeftButton() const
{
return (KeyStates[EM_KEY_LEFT_BUTTON>>3]&(1<<(EM_KEY_LEFT_BUTTON&7)))!=0;
}
inline bool emInputState::GetMiddleButton() const
{
return (KeyStates[EM_KEY_MIDDLE_BUTTON>>3]&(1<<(EM_KEY_MIDDLE_BUTTON&7)))!=0;
}
inline bool emInputState::GetRightButton() const
{
return (KeyStates[EM_KEY_RIGHT_BUTTON>>3]&(1<<(EM_KEY_RIGHT_BUTTON&7)))!=0;
}
inline bool emInputState::GetShift() const
{
return (KeyStates[EM_KEY_SHIFT>>3]&(1<<(EM_KEY_SHIFT&7)))!=0;
}
inline bool emInputState::GetCtrl() const
{
return (KeyStates[EM_KEY_CTRL>>3]&(1<<(EM_KEY_CTRL&7)))!=0;
}
inline bool emInputState::GetAlt() const
{
return (KeyStates[EM_KEY_ALT>>3]&(1<<(EM_KEY_ALT&7)))!=0;
}
inline bool emInputState::GetMeta() const
{
return (KeyStates[EM_KEY_META>>3]&(1<<(EM_KEY_META&7)))!=0;
}
inline const unsigned char * emInputState::GetKeyStates() const
{
return KeyStates;
}
inline unsigned char * emInputState::GetKeyStates()
{
return KeyStates;
}
inline emInputHotkey::emInputHotkey()
{
Packed=0;
}
inline emInputHotkey::emInputHotkey(const emInputHotkey & hotkey)
{
Packed=hotkey.Packed;
}
inline emInputHotkey & emInputHotkey::operator = (const emInputHotkey & hotkey)
{
Packed=hotkey.Packed;
return *this;
}
inline bool emInputHotkey::operator == (const emInputHotkey & hotkey) const
{
return Packed==hotkey.Packed;
}
inline bool emInputHotkey::operator != (const emInputHotkey & hotkey) const
{
return Packed!=hotkey.Packed;
}
inline bool emInputHotkey::IsValid() const
{
return Data.Key!=(emByte)EM_KEY_NONE;
}
inline bool emInputHotkey::GetShift() const
{
return (Data.MFlags&MF_SHIFT)!=0;
}
inline bool emInputHotkey::GetCtrl() const
{
return (Data.MFlags&MF_CTRL)!=0;
}
inline bool emInputHotkey::GetAlt() const
{
return (Data.MFlags&MF_ALT)!=0;
}
inline bool emInputHotkey::GetMeta() const
{
return (Data.MFlags&MF_META)!=0;
}
inline emInputKey emInputHotkey::GetKey() const
{
return (emInputKey)Data.Key;
}
inline void emInputHotkey::ClearModifiers()
{
Data.MFlags=0;
}
#endif