FINAL CUT
fkeyboard.h
1 /***********************************************************************
2 * fkeyboard.h - Read keyboard events *
3 * *
4 * This file is part of the FINAL CUT widget toolkit *
5 * *
6 * Copyright 2018-2023 Markus Gans *
7 * *
8 * FINAL CUT is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU Lesser General Public License as *
10 * published by the Free Software Foundation; either version 3 of *
11 * the License, or (at your option) any later version. *
12 * *
13 * FINAL CUT is distributed in the hope that it will be useful, but *
14 * WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU Lesser General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU Lesser General Public *
19 * License along with this program. If not, see *
20 * <http://www.gnu.org/licenses/>. *
21 ***********************************************************************/
22 
23 /* Standalone class
24  * ════════════════
25  *
26  * ▕▔▔▔▔▔▔▔▔▔▔▔▏
27  * ▕ FKeyboard ▏
28  * ▕▁▁▁▁▁▁▁▁▁▁▁▏
29  */
30 
31 #ifndef FKEYBOARD_H
32 #define FKEYBOARD_H
33 
34 #if !defined (USE_FINAL_H) && !defined (COMPILE_FINAL_CUT)
35  #error "Only <final/final.h> can be included directly."
36 #endif
37 
38 #include <sys/time.h>
39 
40 #include <algorithm>
41 #include <array>
42 #include <functional>
43 #include <memory>
44 #include <string>
45 #include <utility>
46 
47 #include "final/ftypes.h"
48 #include "final/input/fkey_hashmap.h"
49 #include "final/input/fkey_map.h"
50 #include "final/util/char_ringbuffer.h"
51 #include "final/util/fstring.h"
52 
53 namespace finalcut
54 {
55 
56 // class forward declaration
57 class FApplication;
58 class FString;
59 
60 //----------------------------------------------------------------------
61 // class FKeyboardCommand
62 //----------------------------------------------------------------------
63 
64 class FKeyboardCommand final
65 {
66  public:
67  // Constructors
68  FKeyboardCommand () = default;
69  explicit FKeyboardCommand (std::function<void()>&& fn)
70  : handler(std::move(fn))
71  { }
72 
73  // Method
74  inline void execute() const
75  {
76  handler();
77  }
78 
79  private:
80  // Data members
81  std::function<void()> handler{};
82 };
83 
84 
85 //----------------------------------------------------------------------
86 // class FKeyboard
87 //----------------------------------------------------------------------
88 
89 class FKeyboard final
90 {
91  public:
92  // Constants
93  static constexpr std::size_t FIFO_BUF_SIZE{512};
94 
95  // Using-declaration
97 
98  // Constructor
99  FKeyboard();
100 
101  // Disable copy constructor
102  FKeyboard (const FKeyboard&) = delete;
103 
104  // Disable move constructor
105  FKeyboard (FKeyboard&&) noexcept = delete;
106 
107  // Disable copy assignment operator (=)
108  auto operator = (const FKeyboard&) -> FKeyboard& = delete;
109 
110  // Disable move assignment operator (=)
111  auto operator = (FKeyboard&&) noexcept -> FKeyboard& = delete;
112 
113  // Accessors
114  auto getClassName() const -> FString;
115  static auto getInstance() -> FKeyboard&;
116  auto getKey() const noexcept -> FKey;
117  auto getKeyName (const FKey) const -> FString;
118  auto getKeyBuffer() & noexcept -> keybuffer&;
119  auto getKeyPressedTime() const noexcept -> TimeValue;
120  static auto getKeypressTimeout() noexcept -> uInt64;
121  static auto getReadBlockingTime() noexcept -> uInt64;
122 
123  // Mutators
124  template <typename T>
125  void setTermcapMap (const T&);
126  void setTermcapMap();
127  static void setKeypressTimeout (const uInt64) noexcept;
128  static void setReadBlockingTime (const uInt64) noexcept;
129  static void setNonBlockingInputSupport (bool = true) noexcept;
130  void setNonBlockingInput (bool = true);
131  void unsetNonBlockingInput() noexcept;
132  void enableUTF8() noexcept;
133  void disableUTF8() noexcept;
134  void enableMouseSequences() noexcept;
135  void disableMouseSequences() noexcept;
136  void setPressCommand (const FKeyboardCommand&);
137  void setReleaseCommand (const FKeyboardCommand&);
138  void setEscPressedCommand (const FKeyboardCommand&);
139  void setMouseTrackingCommand (const FKeyboardCommand&);
140 
141  // Inquiry
142  auto hasPendingInput() const noexcept -> bool;
143  auto hasDataInQueue() const -> bool;
144 
145  // Methods
146  auto hasUnprocessedInput() const noexcept -> bool;
147  auto isKeyPressed (uInt64 = read_blocking_time) -> bool;
148  void clearKeyBuffer() noexcept;
149  void clearKeyBufferOnTimeout();
150  void fetchKeyCode();
151  void escapeKeyHandling();
152  void processQueuedInput();
153 
154  private:
155  // Constants
156  static constexpr FKey NOT_SET = static_cast<FKey>(-2);
157  static constexpr std::size_t MAX_QUEUE_SIZE = 32;
158 
159  // Using-declaration
160  using FKeyMapPtr = std::shared_ptr<FKeyMap::KeyCapMapType>;
161  using KeyMapEnd = FKeyMap::KeyCapMapType::const_iterator;
163 
164  // Accessors
165  auto getMouseProtocolKey() const -> FKey;
166  auto getTermcapKey() -> FKey;
167  auto getKnownKey() -> FKey;
168  auto getSingleKey() -> FKey;
169 
170  // Inquiry
171  static auto isKeypressTimeout() -> bool;
172  static auto isIntervalTimeout() -> bool;
173 
174  // Methods
175  auto UTF8decode (const std::size_t) const noexcept -> FKey;
176  auto readKey() -> ssize_t;
177  void parseKeyBuffer();
178  auto parseKeyString() -> FKey;
179  auto keyCorrection (const FKey&) const -> FKey;
180  void substringKeyHandling();
181  void keyPressedCommand() const;
182  void keyReleasedCommand() const;
183  void escapeKeyPressedCommand() const;
184  void mouseTrackingCommand() const;
185 
186  // Data members
187  FKeyboardCommand keypressed_cmd{};
188  FKeyboardCommand keyreleased_cmd{};
189  FKeyboardCommand escape_key_cmd{};
190  FKeyboardCommand mouse_tracking_cmd{};
191 
192  static TimeValue time_keypressed;
193  static uInt64 read_blocking_time;
194  static uInt64 read_blocking_time_short;
195  static uInt64 key_timeout;
196  static bool non_blocking_input_support;
197  FKeyMapPtr key_cap_ptr{};
198  KeyMapEnd key_cap_end{};
199  keybuffer fifo_buf{};
200  KeyQueue fkey_queue{};
201  FKey fkey{FKey::None};
202  FKey key{FKey::None};
203  int stdin_status_flags{0};
204  char read_character{};
205  bool has_pending_input{false};
206  bool fifo_in_use{false};
207  bool utf8_input{false};
208  bool mouse_support{true};
209  bool non_blocking_stdin{false};
210 };
211 
212 // FKeyboard inline functions
213 //----------------------------------------------------------------------
214 inline auto FKeyboard::getClassName() const -> FString
215 { return "FKeyboard"; }
216 
217 //----------------------------------------------------------------------
218 inline auto FKeyboard::getKey() const noexcept -> FKey
219 { return key; }
220 
221 //----------------------------------------------------------------------
222 inline auto FKeyboard::getKeyBuffer() & noexcept -> keybuffer&
223 { return fifo_buf; }
224 
225 //----------------------------------------------------------------------
226 inline auto FKeyboard::getKeyPressedTime() const noexcept -> TimeValue
227 { return time_keypressed; }
228 
229 //----------------------------------------------------------------------
230 inline auto FKeyboard::getKeypressTimeout() noexcept -> uInt64
231 { return key_timeout; }
232 
233 //----------------------------------------------------------------------
234 inline auto FKeyboard::getReadBlockingTime() noexcept -> uInt64
235 { return read_blocking_time; }
236 
237 //----------------------------------------------------------------------
238 template <typename T>
239 inline void FKeyboard::setTermcapMap (const T& keymap)
240 {
241  key_cap_ptr = std::make_shared<T>(keymap);
242  key_cap_end = key_cap_ptr->cend();
243  fkeyhashmap::setKeyCapMap<keybuffer>(key_cap_ptr->cbegin(), key_cap_end);
244 }
245 
246 //----------------------------------------------------------------------
247 inline void FKeyboard::setTermcapMap()
248 {
249  using type = FKeyMap::KeyCapMapType;
250  key_cap_ptr = std::make_shared<type>(FKeyMap::getKeyCapMap());
251  // Search for the first entry with a string length of 0 at the end
252  key_cap_end = std::find_if ( key_cap_ptr->cbegin()
253  , key_cap_ptr->cend()
254  , [] (const FKeyMap::KeyCapMap& entry)
255  { return entry.length == 0; }
256  );
257  fkeyhashmap::setKeyCapMap<keybuffer>(key_cap_ptr->cbegin(), key_cap_end);
258 }
259 
260 //----------------------------------------------------------------------
261 inline void FKeyboard::setKeypressTimeout (const uInt64 timeout) noexcept
262 { key_timeout = timeout; }
263 
264 //----------------------------------------------------------------------
265 inline void FKeyboard::setReadBlockingTime (const uInt64 blocking_time) noexcept
266 { read_blocking_time = blocking_time; }
267 
268 //----------------------------------------------------------------------
269 inline void FKeyboard::setNonBlockingInputSupport (bool enable) noexcept
270 { non_blocking_input_support = enable; }
271 
272 //----------------------------------------------------------------------
273 inline void FKeyboard::unsetNonBlockingInput() noexcept
274 { setNonBlockingInput(false); }
275 
276 //----------------------------------------------------------------------
277 inline auto FKeyboard::hasPendingInput() const noexcept -> bool
278 { return has_pending_input; }
279 
280 //----------------------------------------------------------------------
281 inline auto FKeyboard::hasDataInQueue() const -> bool
282 { return ! fkey_queue.isEmpty(); }
283 
284 //----------------------------------------------------------------------
285 inline void FKeyboard::enableUTF8() noexcept
286 { utf8_input = true; }
287 
288 //----------------------------------------------------------------------
289 inline void FKeyboard::disableUTF8() noexcept
290 { utf8_input = false; }
291 
292 //----------------------------------------------------------------------
293 inline void FKeyboard::enableMouseSequences() noexcept
294 { mouse_support = true; }
295 
296 //----------------------------------------------------------------------
297 inline void FKeyboard::disableMouseSequences() noexcept
298 { mouse_support = false; }
299 
300 //----------------------------------------------------------------------
301 inline void FKeyboard::setPressCommand (const FKeyboardCommand& cmd)
302 { keypressed_cmd = cmd; }
303 
304 //----------------------------------------------------------------------
305 inline void FKeyboard::setReleaseCommand (const FKeyboardCommand& cmd)
306 { keyreleased_cmd = cmd; }
307 
308 //----------------------------------------------------------------------
309 inline void FKeyboard::setEscPressedCommand (const FKeyboardCommand& cmd)
310 { escape_key_cmd = cmd; }
311 
312 //----------------------------------------------------------------------
313 inline void FKeyboard::setMouseTrackingCommand (const FKeyboardCommand& cmd)
314 { mouse_tracking_cmd = cmd; }
315 
316 } // namespace finalcut
317 
318 #endif // FKEYBOARD_H
Definition: fkeyboard.h:89
Definition: fkeyboard.h:64
Definition: fkey_map.h:44
Definition: class_template.cpp:25
Definition: fstring.h:79