604 lines
19 KiB
C++
604 lines
19 KiB
C++
/***********************************************************************
|
|
* fmouse.h - Read mouse events *
|
|
* *
|
|
* This file is part of the FINAL CUT widget toolkit *
|
|
* *
|
|
* Copyright 2018-2021 Markus Gans *
|
|
* *
|
|
* FINAL CUT is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU Lesser General Public License as *
|
|
* published by the Free Software Foundation; either version 3 of *
|
|
* the License, or (at your option) any later version. *
|
|
* *
|
|
* FINAL CUT 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 Lesser General Public License for more details. *
|
|
* *
|
|
* You should have received a copy of the GNU Lesser General Public *
|
|
* License along with this program. If not, see *
|
|
* <http://www.gnu.org/licenses/>. *
|
|
***********************************************************************/
|
|
|
|
/* Inheritance diagram
|
|
* ═══════════════════
|
|
*
|
|
* ▕▔▔▔▔▔▔▔▔▔▔▔▔▔▔▏
|
|
* ▕ FMouseData ▏
|
|
* ▕▁▁▁▁▁▁▁▁▁▁▁▁▁▁▏
|
|
* ▲
|
|
* │
|
|
* ▕▔▔▔▔▔▔▔▔▔▔▏
|
|
* ▕ FMouse ▏
|
|
* ▕▁▁▁▁▁▁▁▁▁▁▏
|
|
* ▲
|
|
* │
|
|
* ┌─────────────┬──────┴───────┬─────────────┐
|
|
* │ │ │ │
|
|
* ▕▔▔▔▔▔▔▔▔▔▔▔▏ ▕▔▔▔▔▔▔▔▔▔▔▔▏ ▕▔▔▔▔▔▔▔▔▔▔▔▏ ▕▔▔▔▔▔▔▔▔▔▔▔▔▔▏
|
|
* ▕ FMouseGPM ▏ ▕ FMouseX11 ▏ ▕ FMouseSGR ▏ ▕ FMouseUrxvt ▏
|
|
* ▕▁▁▁▁▁▁▁▁▁▁▁▏ ▕▁▁▁▁▁▁▁▁▁▁▁▏ ▕▁▁▁▁▁▁▁▁▁▁▁▏ ▕▁▁▁▁▁▁▁▁▁▁▁▁▁▏
|
|
*
|
|
*
|
|
*
|
|
* ▕▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▏1 1▕▔▔▔▔▔▔▔▔▔▔▔▏
|
|
* ▕ FMouseControl ▏- -┬- - -▕ FMouseGPM ▏
|
|
* ▕▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▏ : ▕▁▁▁▁▁▁▁▁▁▁▁▏
|
|
* :
|
|
* : 1▕▔▔▔▔▔▔▔▔▔▔▔▏
|
|
* :- - -▕ FMouseX11 ▏
|
|
* : ▕▁▁▁▁▁▁▁▁▁▁▁▏
|
|
* :
|
|
* : 1▕▔▔▔▔▔▔▔▔▔▔▔▏
|
|
* └- - -▕ FMouseSGR ▏
|
|
* : ▕▁▁▁▁▁▁▁▁▁▁▁▏
|
|
* :
|
|
* : 1▕▔▔▔▔▔▔▔▔▔▔▔▔▔▏
|
|
* └- - -▕ FMouseUrxvt ▏
|
|
* ▕▁▁▁▁▁▁▁▁▁▁▁▁▁▏
|
|
*/
|
|
|
|
#ifndef FMOUSE_H
|
|
#define FMOUSE_H
|
|
|
|
#if !defined (USE_FINAL_H) && !defined (COMPILE_FINAL_CUT)
|
|
#error "Only <final/final.h> can be included directly."
|
|
#endif
|
|
|
|
#include <cstddef>
|
|
#include <functional>
|
|
#include <map>
|
|
#include <memory>
|
|
#include <queue>
|
|
#include <utility>
|
|
|
|
#include "final/fkeyboard.h"
|
|
#include "final/fpoint.h"
|
|
|
|
#if defined(__linux__)
|
|
#include <linux/keyboard.h> // need for gpm keyboard modifiers
|
|
#endif
|
|
|
|
#ifdef F_HAVE_LIBGPM
|
|
#include <gpm.h>
|
|
#endif
|
|
|
|
namespace finalcut
|
|
{
|
|
|
|
//----------------------------------------------------------------------
|
|
// class FMouseData
|
|
//----------------------------------------------------------------------
|
|
class FMouseData
|
|
{
|
|
public:
|
|
// Constructor
|
|
FMouseData() = default;
|
|
|
|
// Copy constructor
|
|
FMouseData (const FMouseData&) = default;
|
|
|
|
// Move constructor
|
|
FMouseData (FMouseData&&) noexcept = default;
|
|
|
|
// Destructor
|
|
virtual ~FMouseData() noexcept;
|
|
|
|
// copy assignment operator (=)
|
|
FMouseData& operator = (const FMouseData&) = default;
|
|
|
|
// Move assignment operator (=)
|
|
FMouseData& operator = (FMouseData&&) noexcept = default;
|
|
|
|
// Accessors
|
|
virtual FString getClassName() const;
|
|
const FPoint& getPos() const;
|
|
|
|
// Inquiries
|
|
bool isLeftButtonPressed() const;
|
|
bool isLeftButtonReleased() const;
|
|
bool isLeftButtonDoubleClick() const;
|
|
bool isRightButtonPressed() const;
|
|
bool isRightButtonReleased() const;
|
|
bool isMiddleButtonPressed() const;
|
|
bool isMiddleButtonReleased() const;
|
|
bool isShiftKeyPressed() const;
|
|
bool isControlKeyPressed() const;
|
|
bool isMetaKeyPressed() const;
|
|
bool isWheelUp() const;
|
|
bool isWheelDown() const;
|
|
bool isMoved() const;
|
|
|
|
// Methods
|
|
void clearButtonState();
|
|
|
|
protected:
|
|
// Enumerations
|
|
enum class State : uChar
|
|
{
|
|
Undefined = 0,
|
|
Pressed = 1,
|
|
Released = 2,
|
|
DoubleClick = 3
|
|
};
|
|
|
|
struct FMouseButton
|
|
{
|
|
State left_button{};
|
|
State right_button{};
|
|
State middle_button{};
|
|
bool shift_button{};
|
|
bool control_button{};
|
|
bool meta_button{};
|
|
bool wheel_up{};
|
|
bool wheel_down{};
|
|
bool mouse_moved{};
|
|
};
|
|
|
|
// Accessors
|
|
FMouseButton& getButtonState();
|
|
const FMouseButton& getButtonState() const;
|
|
|
|
// Mutator
|
|
void setPos (const FPoint&);
|
|
|
|
private:
|
|
// Data members
|
|
FMouseButton b_state{};
|
|
FPoint mouse{0, 0}; // mouse click position
|
|
};
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
// class FMouse
|
|
//----------------------------------------------------------------------
|
|
|
|
class FMouse : public FMouseData
|
|
{
|
|
public:
|
|
// Enumeration
|
|
enum class MouseType
|
|
{
|
|
None = 0,
|
|
Gpm = 1,
|
|
X11 = 2,
|
|
Sgr = 3,
|
|
Urxvt = 4
|
|
};
|
|
|
|
// Constructor
|
|
FMouse();
|
|
|
|
// Accessors
|
|
FString getClassName() const override;
|
|
void clearEvent();
|
|
|
|
// Mutators
|
|
void setMaxWidth (uInt16);
|
|
void setMaxHeight (uInt16);
|
|
void setDblclickInterval (const uInt64);
|
|
|
|
// Inquiries
|
|
virtual bool hasData() = 0;
|
|
bool hasEvent() const;
|
|
bool hasUnprocessedInput() const;
|
|
|
|
// Methods
|
|
template <typename ClassT>
|
|
static FMouse* createMouseObject ();
|
|
virtual void setRawData (FKeyboard::keybuffer&) = 0;
|
|
virtual void processEvent (const TimeValue&) = 0;
|
|
|
|
protected:
|
|
// Accessors
|
|
const FPoint& getNewPos() const;
|
|
uInt16 getMaxWidth() const;
|
|
uInt16 getMaxHeight() const;
|
|
uInt64 getDblclickInterval() const;
|
|
TimeValue getMousePressedTime() const;
|
|
|
|
// Mutator
|
|
void setNewPos (int, int);
|
|
void setPending (bool = true);
|
|
void setEvent();
|
|
void setMousePressedTime (const TimeValue&);
|
|
void resetMousePressedTime();
|
|
|
|
// Inquiry
|
|
bool isDblclickTimeout (const TimeValue&) const;
|
|
|
|
private:
|
|
// Data members
|
|
bool mouse_event_occurred{false};
|
|
bool unprocessed_buffer_data{false};
|
|
uInt16 max_width{80};
|
|
uInt16 max_height{25};
|
|
uInt64 dblclick_interval{500000}; // 500 ms
|
|
TimeValue time_mousepressed{};
|
|
FPoint new_mouse_position{};
|
|
};
|
|
|
|
//----------------------------------------------------------------------
|
|
template <typename ClassT>
|
|
inline FMouse* FMouse::createMouseObject()
|
|
{
|
|
return new ClassT;
|
|
}
|
|
|
|
|
|
#ifdef F_HAVE_LIBGPM
|
|
//----------------------------------------------------------------------
|
|
// class FMouseGPM
|
|
//----------------------------------------------------------------------
|
|
|
|
class FMouseGPM final : public FMouse
|
|
{
|
|
public:
|
|
// Constructor
|
|
FMouseGPM();
|
|
|
|
// Accessors
|
|
FString getClassName() const override;
|
|
|
|
// Mutators
|
|
void setStdinNo(int);
|
|
|
|
// Inquiry
|
|
bool hasData() override;
|
|
bool isGpmMouseEnabled() const;
|
|
|
|
// Methods
|
|
void setRawData (FKeyboard::keybuffer&) override;
|
|
void processEvent (const TimeValue&) override;
|
|
bool gpmMouse (bool = true);
|
|
bool enableGpmMouse();
|
|
bool disableGpmMouse();
|
|
bool hasSignificantEvents() const;
|
|
void interpretKeyDown();
|
|
void interpretKeyUp();
|
|
bool getGpmKeyPressed (bool = true);
|
|
void drawPointer() const;
|
|
|
|
private:
|
|
// Enumeration
|
|
enum class gpmEventType
|
|
{
|
|
None = 0,
|
|
Keyboard = 1,
|
|
Mouse = 2
|
|
};
|
|
|
|
// Method
|
|
gpmEventType gpmEvent (bool = true) const;
|
|
|
|
// Data member
|
|
Gpm_Event gpm_ev{};
|
|
bool has_gpm_mouse_data{false};
|
|
bool gpm_mouse_enabled{false};
|
|
int stdin_no{0};
|
|
};
|
|
|
|
//----------------------------------------------------------------------
|
|
inline bool FMouseGPM::enableGpmMouse()
|
|
{ return gpmMouse(true); }
|
|
|
|
//----------------------------------------------------------------------
|
|
inline bool FMouseGPM::disableGpmMouse()
|
|
{ return gpmMouse(false); }
|
|
|
|
//----------------------------------------------------------------------
|
|
inline bool FMouseGPM::isGpmMouseEnabled() const
|
|
{ return gpm_mouse_enabled; }
|
|
#endif // F_HAVE_LIBGPM
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
// class FMouseX11
|
|
//----------------------------------------------------------------------
|
|
|
|
class FMouseX11 final : public FMouse
|
|
{
|
|
public:
|
|
// Accessors
|
|
FString getClassName() const override;
|
|
|
|
// Inquiry
|
|
bool hasData() override;
|
|
|
|
// Methods
|
|
void setRawData (FKeyboard::keybuffer&) override;
|
|
void processEvent (const TimeValue&) override;
|
|
|
|
private:
|
|
// Enumeration
|
|
enum btn_states
|
|
{
|
|
key_shift = 0x04,
|
|
key_meta = 0x08,
|
|
key_ctrl = 0x10,
|
|
key_button_mask = 0x1c,
|
|
button1_pressed = 0x20,
|
|
button2_pressed = 0x21,
|
|
button3_pressed = 0x22,
|
|
all_buttons_released = 0x23,
|
|
button1_pressed_move = 0x40,
|
|
button2_pressed_move = 0x41,
|
|
button3_pressed_move = 0x42,
|
|
button_mask = 0x63,
|
|
button_up = 0x60,
|
|
button_down = 0x61,
|
|
button_up_move = 0x60,
|
|
button_down_move = 0x61
|
|
};
|
|
|
|
// Constant
|
|
static constexpr std::size_t MOUSE_BUF_SIZE = 4;
|
|
|
|
// Methods
|
|
void setKeyState (int);
|
|
void setMoveState (const FPoint&, int);
|
|
void setButtonState (const int, const TimeValue&);
|
|
|
|
// Data member
|
|
char x11_mouse[MOUSE_BUF_SIZE]{'\0'};
|
|
uChar x11_button_state{all_buttons_released};
|
|
};
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
// class FMouseSGR
|
|
//----------------------------------------------------------------------
|
|
|
|
class FMouseSGR final : public FMouse
|
|
{
|
|
public:
|
|
// Accessors
|
|
FString getClassName() const override;
|
|
|
|
// Inquiry
|
|
bool hasData() override;
|
|
|
|
// Methods
|
|
void setRawData (FKeyboard::keybuffer&) override;
|
|
void processEvent (const TimeValue&) override;
|
|
|
|
private:
|
|
// Enumeration
|
|
enum x11_ext_btn_states
|
|
{
|
|
key_shift = 0x04,
|
|
key_meta = 0x08,
|
|
key_ctrl = 0x10,
|
|
key_button_mask = 0x1c,
|
|
button1 = 0x00,
|
|
button2 = 0x01,
|
|
button3 = 0x02,
|
|
button1_move = 0x20,
|
|
button2_move = 0x21,
|
|
button3_move = 0x22,
|
|
button_mask = 0x63,
|
|
button_up = 0x40,
|
|
button_down = 0x41,
|
|
pressed = 'M',
|
|
released = 'm'
|
|
};
|
|
|
|
// Constant
|
|
static constexpr std::size_t MOUSE_BUF_SIZE = 13;
|
|
|
|
// Methods
|
|
void setKeyState (int);
|
|
void setMoveState (const FPoint&, int);
|
|
void setPressedButtonState (const int, const TimeValue&);
|
|
void setReleasedButtonState (const int);
|
|
|
|
// Data members
|
|
char sgr_mouse[MOUSE_BUF_SIZE]{'\0'};
|
|
uChar sgr_button_state{0x23};
|
|
};
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
// class FMouseUrxvt
|
|
//----------------------------------------------------------------------
|
|
|
|
class FMouseUrxvt final : public FMouse
|
|
{
|
|
public:
|
|
// Accessors
|
|
FString getClassName() const override;
|
|
|
|
// Inquiry
|
|
bool hasData() override;
|
|
|
|
// Methods
|
|
void setRawData (FKeyboard::keybuffer&) override;
|
|
void processEvent (const TimeValue&) override;
|
|
|
|
private:
|
|
// Enumeration
|
|
enum urxvt_btn_states
|
|
{
|
|
key_shift = 0x04,
|
|
key_meta = 0x08,
|
|
key_ctrl = 0x10,
|
|
key_button_mask = 0x1c,
|
|
button1_pressed = 0x20,
|
|
button2_pressed = 0x21,
|
|
button3_pressed = 0x22,
|
|
all_buttons_released = 0x23,
|
|
button1_pressed_move = 0x40,
|
|
button2_pressed_move = 0x41,
|
|
button3_pressed_move = 0x42,
|
|
button_mask = 0x63,
|
|
button_up = 0x60,
|
|
button_down = 0x61,
|
|
button_up_move = 0x60,
|
|
button_down_move = 0x61
|
|
};
|
|
|
|
// Constant
|
|
static constexpr std::size_t MOUSE_BUF_SIZE = 13;
|
|
|
|
// Methods
|
|
void setKeyState (int);
|
|
void setMoveState (const FPoint&, int);
|
|
void setButtonState (const int, const TimeValue&);
|
|
|
|
// Data members
|
|
char urxvt_mouse[MOUSE_BUF_SIZE]{'\0'};
|
|
uChar urxvt_button_state{all_buttons_released};
|
|
};
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
// class FMouseCommand
|
|
//----------------------------------------------------------------------
|
|
|
|
class FMouseCommand final
|
|
{
|
|
public:
|
|
// Constructors
|
|
FMouseCommand () = default;
|
|
explicit FMouseCommand (const std::function<void(const FMouseData&)>& fn)
|
|
: handler(fn)
|
|
{ }
|
|
|
|
// Method
|
|
template <typename T>
|
|
void execute(T&& arg) const
|
|
{
|
|
handler(std::forward<T>(arg));
|
|
}
|
|
|
|
private:
|
|
// Data members
|
|
std::function<void(const FMouseData&)> handler{};
|
|
};
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
// class FMouseControl
|
|
//----------------------------------------------------------------------
|
|
|
|
class FMouseControl
|
|
{
|
|
public:
|
|
// Constructor
|
|
FMouseControl();
|
|
|
|
// Destructor
|
|
virtual ~FMouseControl();
|
|
|
|
// Accessors
|
|
virtual FString getClassName() const;
|
|
static auto getInstance() -> FMouseControl&;
|
|
const FPoint& getPos();
|
|
void clearEvent();
|
|
|
|
// Mutators
|
|
void setStdinNo (int);
|
|
void setMaxWidth (uInt16);
|
|
void setMaxHeight (uInt16);
|
|
void setDblclickInterval (const uInt64) const;
|
|
void setEventCommand (const FMouseCommand&);
|
|
void useGpmMouse (bool = true);
|
|
void useXtermMouse (bool = true);
|
|
|
|
// Inquiries
|
|
bool hasData();
|
|
bool hasEvent();
|
|
bool isLeftButtonPressed();
|
|
bool isLeftButtonReleased();
|
|
bool isLeftButtonDoubleClick();
|
|
bool isRightButtonPressed();
|
|
bool isRightButtonReleased();
|
|
bool isMiddleButtonPressed();
|
|
bool isMiddleButtonReleased();
|
|
bool isShiftKeyPressed();
|
|
bool isControlKeyPressed();
|
|
bool isMetaKeyPressed();
|
|
bool isWheelUp();
|
|
bool isWheelDown();
|
|
bool isMoved();
|
|
bool hasUnprocessedInput();
|
|
bool hasDataInQueue() const;
|
|
bool isGpmMouseEnabled();
|
|
|
|
// Methods
|
|
void enable();
|
|
void disable();
|
|
virtual void setRawData ( FMouse::MouseType
|
|
, FKeyboard::keybuffer& );
|
|
virtual void processEvent (const TimeValue&);
|
|
void processQueuedInput();
|
|
bool getGpmKeyPressed (bool = true);
|
|
void drawPointer();
|
|
|
|
private:
|
|
// Using-declaration
|
|
using FMousePtr = std::unique_ptr<FMouse>;
|
|
using FMouseDataPtr = std::unique_ptr<FMouseData>;
|
|
using FMouseProtocol = std::map<FMouse::MouseType, FMousePtr>;
|
|
|
|
// Accessor
|
|
FMouse::MouseType getMouseWithData();
|
|
FMouse::MouseType getMouseWithEvent();
|
|
void xtermMouse (bool = true) const;
|
|
void enableXTermMouse() const;
|
|
void disableXTermMouse() const;
|
|
|
|
// Data member
|
|
FMouseProtocol mouse_protocol{};
|
|
FMouseCommand event_cmd{};
|
|
std::queue<FMouseDataPtr> fmousedata_queue{};
|
|
FPoint zero_point{0, 0};
|
|
bool use_gpm_mouse{false};
|
|
bool use_xterm_mouse{false};
|
|
};
|
|
|
|
// FMouseControl inline functions
|
|
//----------------------------------------------------------------------
|
|
inline FString FMouseControl::getClassName() const
|
|
{ return "FMouseControl"; }
|
|
|
|
//----------------------------------------------------------------------
|
|
inline void FMouseControl::setEventCommand (const FMouseCommand& cmd)
|
|
{ event_cmd = cmd; }
|
|
|
|
//----------------------------------------------------------------------
|
|
inline bool FMouseControl::hasDataInQueue() const
|
|
{ return ! fmousedata_queue.empty(); }
|
|
|
|
//----------------------------------------------------------------------
|
|
inline void FMouseControl::enableXTermMouse() const
|
|
{ xtermMouse(true); }
|
|
|
|
//----------------------------------------------------------------------
|
|
inline void FMouseControl::disableXTermMouse() const
|
|
{ xtermMouse(false); }
|
|
|
|
} // namespace finalcut
|
|
|
|
#endif // FMOUSE_H
|