• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

gansm / finalcut / #760

06 Feb 2026 01:45AM UTC coverage: 69.064% (-0.02%) from 69.083%
#760

push

travis-ci

gansm
Reduce pointer arithmetic and use safe iterators more often

206 of 432 new or added lines in 27 files covered. (47.69%)

25 existing lines in 6 files now uncovered.

37622 of 54474 relevant lines covered (69.06%)

243.8 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

83.52
/final/input/fmouse.cpp
1
/***********************************************************************
2
* fmouse.cpp - Read mouse events                                       *
3
*                                                                      *
4
* This file is part of the FINAL CUT widget toolkit                    *
5
*                                                                      *
6
* Copyright 2018-2026 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
#if defined(__CYGWIN__)
24
  #include "final/fconfig.h"  // includes _GNU_SOURCE for fd_set
25
#endif
26

27
#include <cstdio>
28
#include <cstring>
29
#include <unistd.h>
30

31
#include <algorithm>
32
#include <iostream>
33
#include <new>
34

35
#include "final/fapplication.h"
36
#include "final/fconfig.h"
37
#include "final/fobject.h"
38
#include "final/ftypes.h"
39
#include "final/input/fkeyboard.h"
40
#include "final/input/fmouse.h"
41
#include "final/output/tty/fterm.h"
42
#include "final/output/tty/ftermlinux.h"
43

44
namespace finalcut
45
{
46

47
// Function prototypes
48
template <typename IterT, typename NumT, typename UnaryPredicate>
49
auto parseNumberIf (const char*&, NumT&, UnaryPredicate) -> bool;
50

51
// non-member functions
52
//----------------------------------------------------------------------
53
template <typename IterT, typename NumT, typename UnaryPredicate>
54
inline auto parseNumberIf ( IterT& iter
162✔
55
                          , IterT end
56
                          , NumT& number
57
                          , UnaryPredicate up ) -> bool
58
{
59
  while ( iter != end && *iter && up(*iter) )
365✔
60
  {
61
    if ( ! std::isdigit(static_cast<unsigned char>(*iter)) )
209✔
62
      return false;
6✔
63

64
    number = 10 * number + (*iter - '0');
203✔
65
    iter = std::next(iter);
406✔
66
  }
67

68
  return true;
156✔
69
}
70

71
//----------------------------------------------------------------------
72
// class FMouseData
73
//----------------------------------------------------------------------
74

75
// constructor and destructor
76
//----------------------------------------------------------------------
77
FMouseData::~FMouseData() noexcept = default;  // destructor
57✔
78

79

80
// public methods of FMouseData
81
//----------------------------------------------------------------------
82
auto FMouseData::getClassName() const -> FString
×
83
{
84
  return "FMouseData";
×
85
}
86

87
//----------------------------------------------------------------------
88
auto FMouseControl::getCurrentMouseEvent() -> FMouseDataPtr&
47✔
89
{
90
  static const auto& current_mouse_event = std::make_unique<FMouseDataPtr>();
47✔
91
  return *current_mouse_event;
47✔
92
}
93

94
//----------------------------------------------------------------------
95
auto FMouseData::getPos() const & noexcept -> const FPoint&
170✔
96
{
97
  return mouse;
170✔
98
}
99

100
//----------------------------------------------------------------------
101
auto FMouseData::isLeftButtonPressed() const noexcept -> bool
52✔
102
{
103
  return getButtonState().left_button == State::Pressed;
52✔
104
}
105

106
//----------------------------------------------------------------------
107
auto FMouseData::isLeftButtonReleased() const noexcept -> bool
32✔
108
{
109
  return getButtonState().left_button == State::Released;
32✔
110
}
111

112
//----------------------------------------------------------------------
113
auto FMouseData::isLeftButtonDoubleClick() const noexcept -> bool
32✔
114
{
115
  return getButtonState().left_button == State::DoubleClick;
32✔
116
}
117

118
//----------------------------------------------------------------------
119
auto FMouseData::isRightButtonPressed() const noexcept -> bool
46✔
120
{
121
  return getButtonState().right_button == State::Pressed;
46✔
122
}
123

124
//----------------------------------------------------------------------
125
auto FMouseData::isRightButtonReleased() const noexcept -> bool
35✔
126
{
127
  return getButtonState().right_button == State::Released;
35✔
128
}
129
//----------------------------------------------------------------------
130
auto FMouseData::isMiddleButtonPressed() const noexcept -> bool
46✔
131
{
132
  return getButtonState().middle_button == State::Pressed;
46✔
133
}
134

135
//----------------------------------------------------------------------
136
auto FMouseData::isMiddleButtonReleased() const noexcept -> bool
35✔
137
{
138
  return getButtonState().middle_button == State::Released;
35✔
139
}
140

141
//----------------------------------------------------------------------
142
auto FMouseData::isShiftKeyPressed() const noexcept -> bool
40✔
143
{
144
  return getButtonState().shift_button;
40✔
145
}
146

147
//----------------------------------------------------------------------
148
auto FMouseData::isControlKeyPressed() const noexcept -> bool
40✔
149
{
150
  return getButtonState().control_button;
40✔
151
}
152

153
//----------------------------------------------------------------------
154
auto FMouseData::isMetaKeyPressed() const noexcept -> bool
40✔
155
{
156
  return getButtonState().meta_button;
40✔
157
}
158

159
//----------------------------------------------------------------------
160
auto FMouseData::isWheelUp() const noexcept -> bool
82✔
161
{
162
  return getButtonState().wheel_up;
82✔
163
}
164

165
//----------------------------------------------------------------------
166
auto FMouseData::isWheelDown() const noexcept -> bool
82✔
167
{
168
  return getButtonState().wheel_down;
82✔
169
}
170

171
//----------------------------------------------------------------------
172
auto FMouseData::isWheelLeft() const noexcept -> bool
78✔
173
{
174
  return getButtonState().wheel_left;
78✔
175
}
176

177
//----------------------------------------------------------------------
178
auto FMouseData::isWheelRight() const noexcept -> bool
74✔
179
{
180
  return getButtonState().wheel_right;
74✔
181
}
182

183
//----------------------------------------------------------------------
184
auto FMouseData::isMoved() const noexcept -> bool
39✔
185
{
186
  return getButtonState().mouse_moved;
39✔
187
}
188

189
//----------------------------------------------------------------------
190
void FMouseData::clearButtonState() noexcept
108✔
191
{
192
  b_state.left_button    = State::Undefined;
108✔
193
  b_state.right_button   = State::Undefined;
108✔
194
  b_state.middle_button  = State::Undefined;
108✔
195
  b_state.shift_button   = false;
108✔
196
  b_state.control_button = false;
108✔
197
  b_state.meta_button    = false;
108✔
198
  b_state.wheel_up       = false;
108✔
199
  b_state.wheel_down     = false;
108✔
200
  b_state.wheel_left     = false;
108✔
201
  b_state.wheel_right    = false;
108✔
202
  b_state.mouse_moved    = false;
108✔
203
}
108✔
204

205

206
// protected methods of FMouseData
207
//----------------------------------------------------------------------
208
inline auto FMouseData::getButtonState() & noexcept -> FMouseButton&
310✔
209
{
210
  return b_state;
310✔
211
}
212

213
//----------------------------------------------------------------------
214
inline auto FMouseData::getButtonState() const & noexcept -> const FMouseButton&
753✔
215
{
216
  return b_state;
753✔
217
}
218

219
//----------------------------------------------------------------------
220
void FMouseData::setPos (const FPoint& m) noexcept
75✔
221
{
222
  mouse = m;
75✔
223
}
75✔
224

225

226
//----------------------------------------------------------------------
227
// class FMouse
228
//----------------------------------------------------------------------
229

230
// constructors and destructor
231
//----------------------------------------------------------------------
232
FMouse::FMouse()
31✔
233
{
234
  resetMousePressedTime();
31✔
235
  clearButtonState();
31✔
236
}
31✔
237

238

239
// public methods of FMouse
240
//----------------------------------------------------------------------
241
auto FMouse::getClassName() const -> FString
1✔
242
{
243
  return "FMouse";
1✔
244
}
245

246
//----------------------------------------------------------------------
247
auto FMouse::getMouseTypeID() const noexcept -> MouseType
55✔
248
{
249
  return MouseType_id;
55✔
250
}
251

252
//----------------------------------------------------------------------
253
void FMouse::clearEvent() noexcept
24✔
254
{
255
  mouse_event_occurred = false;
24✔
256
}
24✔
257

258
//----------------------------------------------------------------------
259
void FMouse::setMaxWidth (uInt16 x_max) noexcept
3✔
260
{
261
  max_width = x_max;
3✔
262
}
3✔
263

264
//----------------------------------------------------------------------
265
void FMouse::setMaxHeight (uInt16 y_max) noexcept
3✔
266
{
267
  max_height = y_max;
3✔
268
}
3✔
269

270
//----------------------------------------------------------------------
271
void FMouse::setDblclickInterval (const uInt64 timeout) noexcept
10✔
272
{
273
  dblclick_interval = timeout;
10✔
274
}
10✔
275

276
//----------------------------------------------------------------------
277
auto FMouse::hasEvent() const noexcept -> bool
346✔
278
{
279
  return mouse_event_occurred;
346✔
280
}
281

282
//----------------------------------------------------------------------
283
auto FMouse::hasUnprocessedInput() const noexcept -> bool
71✔
284
{
285
  return unprocessed_buffer_data;
71✔
286
}
287

288

289
// protected methods of FMouse
290
//----------------------------------------------------------------------
291
auto FMouse::getNewPos() const & noexcept -> const FPoint&
114✔
292
{
293
  return new_mouse_position;
114✔
294
}
295

296
//----------------------------------------------------------------------
297
auto FMouse::getMaxWidth() const noexcept -> uInt16
27✔
298
{
299
  return max_width;
27✔
300
}
301

302
//----------------------------------------------------------------------
303
auto FMouse::getMaxHeight() const noexcept -> uInt16
27✔
304
{
305
  return max_height;
27✔
306
}
307

308
//----------------------------------------------------------------------
309
auto FMouse::getDblclickInterval() const noexcept -> uInt64
1✔
310
{
311
  return dblclick_interval;
1✔
312
}
313

314
//----------------------------------------------------------------------
315
auto FMouse::getMousePressedTime() const noexcept -> TimeValue
3✔
316
{
317
  return time_mousepressed;
3✔
318
}
319

320
//----------------------------------------------------------------------
321
void FMouse::setMouseTypeID (MouseType mt) noexcept
27✔
322
{
323
  MouseType_id = mt;
27✔
324
}
27✔
325

326
//----------------------------------------------------------------------
327
void FMouse::setNewPos (int x, int y) noexcept
78✔
328
{
329
  new_mouse_position.setPoint (x, y);
78✔
330
}
78✔
331

332
//----------------------------------------------------------------------
333
void FMouse::useNewPos() noexcept
49✔
334
{
335
  setPos(new_mouse_position);
49✔
336
}
49✔
337

338
//----------------------------------------------------------------------
339
void FMouse::setPending (bool is_pending) noexcept
83✔
340
{
341
  unprocessed_buffer_data = is_pending;
83✔
342
}
83✔
343

344
//----------------------------------------------------------------------
345
void FMouse::setMousePressedTime (const TimeValue& time) noexcept
31✔
346
{
347
  time_mousepressed = time;
31✔
348
}
31✔
349

350
//----------------------------------------------------------------------
351
void FMouse::resetMousePressedTime() noexcept
59✔
352
{
353
  time_mousepressed = TimeValue{};  // Set to epoch time
59✔
354
}
59✔
355

356
//----------------------------------------------------------------------
357
void FMouse::setEvent() noexcept
74✔
358
{
359
  mouse_event_occurred = true;
74✔
360
}
74✔
361

362
//----------------------------------------------------------------------
363
auto FMouse::isDblclickTimeout (const TimeValue& time) const -> bool
9✔
364
{
365
  return FObjectTimer::isTimeout (time, dblclick_interval);
9✔
366
}
367

368

369
#ifdef F_HAVE_LIBGPM
370
//----------------------------------------------------------------------
371
// class FMouseGPM
372
//----------------------------------------------------------------------
373

374
// constructors and destructor
375
//----------------------------------------------------------------------
376
FMouseGPM::FMouseGPM()
3✔
377
{
378
  gpm_ev.x = -1;
3✔
379
  setMouseTypeID (FMouse::MouseType::Gpm);
3✔
380
}
3✔
381

382

383
// public methods of FMouseX11
384
//----------------------------------------------------------------------
385
auto FMouseGPM::getClassName() const -> FString
1✔
386
{
387
  return "FMouseGPM";
1✔
388
}
389

390
//----------------------------------------------------------------------
391
void FMouseGPM::setStdinNo (int file_descriptor) noexcept
1✔
392
{
393
  stdin_no = file_descriptor;
1✔
394
}
1✔
395

396
//----------------------------------------------------------------------
397
auto FMouseGPM::hasData() noexcept -> bool
1✔
398
{
399
  return has_gpm_mouse_data;
1✔
400
}
401

402
//----------------------------------------------------------------------
403
void FMouseGPM::setRawData (FKeyboard::keybuffer&) noexcept
×
404
{
405
  // This method need not be implemented for FMouseGPM
406
}
×
407

408
//----------------------------------------------------------------------
409
void FMouseGPM::processEvent (const TimeValue&)
×
410
{
411
  clearButtonState();
×
412

413
  if ( Gpm_GetEvent(&gpm_ev) == 1 )
×
414
  {
415
    handleMouseEvent();
×
416

417
    if ( ! hasSignificantEvents() )
×
418
    {
419
      resetMouseState();
×
420
      return;
×
421
    }
422

423
    handleMouseMovement();
×
424
    handleMouseWheel();
×
425
    interpretMouseEvent();
×
426
    updateMousePosition();
×
427
    setPending ( gpmEvent(false) == gpmEventType::Mouse );
×
428
    has_gpm_mouse_data = false;
×
429
    setEvent();
×
430
    return;
×
431
  }
432

433
  gpm_fd = -1;
×
434
  resetMouseState();
×
435
}
436

437
//----------------------------------------------------------------------
438
auto FMouseGPM::gpmMouse (bool enable) -> bool
2✔
439
{
440
  // activate/deactivate the gpm mouse support
441

442
  static constexpr int gpm_error = -1;
443
  static constexpr int gpm_xterm_is_in_use = -2;
444

445
  if ( enable )
2✔
446
  {
447
    Gpm_Connect conn;
448
    conn.eventMask   = GPM_MOVE | GPM_DRAG | GPM_DOWN | GPM_UP;
1✔
449
    conn.defaultMask = 0;
1✔
450
    conn.maxMod      = 0;
1✔
451
    conn.minMod      = 0;
1✔
452
    Gpm_Open(&conn, 0);
1✔
453

454
    if ( gpm_fd == gpm_error || gpm_fd == gpm_xterm_is_in_use )
1✔
455
      return false;
×
456
  }
457
  else
458
  {
459
    Gpm_Close();
1✔
460
  }
461

462
  gpm_mouse_enabled = enable;
2✔
463
  return enable;
2✔
464
}
465

466
//----------------------------------------------------------------------
467
auto FMouseGPM::hasSignificantEvents() const noexcept -> bool
×
468
{
469
  return ! (gpm_ev.type & GPM_MOVE)
×
470
      || gpm_ev.wdy != 0
×
471
      || gpm_ev.buttons & GPM_B_UP
×
472
      || gpm_ev.buttons & GPM_B_DOWN;
×
473
}
474

475
//----------------------------------------------------------------------
476
void FMouseGPM::interpretKeyDown() noexcept
×
477
{
478
  if ( gpm_ev.buttons & GPM_B_LEFT )
×
479
  {
480
    if ( gpm_ev.type & GPM_DOUBLE )
×
481
      getButtonState().left_button = State::DoubleClick;
×
482
    else
483
      getButtonState().left_button = State::Pressed;
×
484
  }
485

486
  if ( gpm_ev.buttons & GPM_B_MIDDLE )
×
487
    getButtonState().middle_button = State::Pressed;
×
488

489
  if ( gpm_ev.buttons & GPM_B_RIGHT )
×
490
    getButtonState().right_button = State::Pressed;
×
491

492
  getButtonState().wheel_up = bool(gpm_ev.buttons & GPM_B_UP);
×
493
  getButtonState().wheel_down = bool(gpm_ev.buttons & GPM_B_DOWN);
×
494

495
  // Keyboard modifiers
496
  getButtonState().shift_button = bool(gpm_ev.modifiers & (1 << KG_SHIFT));
×
497
  getButtonState().meta_button = bool(gpm_ev.modifiers & ((1 << KG_ALT) | (1 << KG_ALTGR)));
×
498
  getButtonState().control_button = bool(gpm_ev.modifiers & (1 << KG_CTRL));
×
499
}
×
500

501
//----------------------------------------------------------------------
502
void FMouseGPM::interpretKeyUp() noexcept
×
503
{
504
  if ( gpm_ev.buttons & GPM_B_LEFT )
×
505
    getButtonState().left_button = State::Released;
×
506

507
  if ( gpm_ev.buttons & GPM_B_MIDDLE )
×
508
    getButtonState().middle_button = State::Released;
×
509

510
  if ( gpm_ev.buttons & GPM_B_RIGHT )
×
511
    getButtonState().right_button = State::Released;
×
512
}
×
513

514
//----------------------------------------------------------------------
515
auto FMouseGPM::getGpmKeyPressed (bool is_pending) -> bool
×
516
{
517
  setPending(is_pending);
×
518
  const auto type = gpmEvent();
×
519
  has_gpm_mouse_data = bool( type == gpmEventType::Mouse );
×
520

521
  if ( type == gpmEventType::Keyboard )
×
522
    return true;
×
523

524
  return false;
×
525
}
526

527
//----------------------------------------------------------------------
528
void FMouseGPM::drawPointer() const
×
529
{
530
  if ( isGpmMouseEnabled() && gpm_ev.x != -1 )
×
531
  {
532
#if defined(__clang__)
533
  #pragma clang diagnostic push
534
  #pragma clang diagnostic ignored "-Wunsafe-buffer-usage"
535
#endif
536
    GPM_DRAWPOINTER(&gpm_ev);
×
537
#if defined(__clang__)
538
  #pragma clang diagnostic pop
539
#endif
540
  }
UNCOV
541
}
×
542

543
// private methods of FMouseGPM
544
//----------------------------------------------------------------------
545
inline void FMouseGPM::handleMouseEvent()
×
546
{
547
  Gpm_FitEvent(&gpm_ev);
×
548
#if defined(__clang__)
549
  #pragma clang diagnostic push
550
  #pragma clang diagnostic ignored "-Wunsafe-buffer-usage"
551
#endif
552
  GPM_DRAWPOINTER(&gpm_ev);
×
553
#if defined(__clang__)
554
  #pragma clang diagnostic pop
555
#endif
UNCOV
556
}
×
557

558
//----------------------------------------------------------------------
559
inline void FMouseGPM::resetMouseState()
×
560
{
561
  has_gpm_mouse_data = false;
×
562
  clearEvent();
×
563
}
×
564

565
//----------------------------------------------------------------------
566
inline void FMouseGPM::handleMouseMovement()
×
567
{
568
  if ( gpm_ev.type & GPM_DRAG && gpm_ev.wdx == 0 && gpm_ev.wdy == 0 )
×
569
    getButtonState().mouse_moved = true;
×
570
}
×
571

572
//----------------------------------------------------------------------
573
inline void FMouseGPM::handleMouseWheel()
×
574
{
575
  getButtonState().wheel_up    = bool( gpm_ev.wdy > 0 );
×
576
  getButtonState().wheel_down  = bool( gpm_ev.wdy < 0 );
×
577
  getButtonState().wheel_right = bool( gpm_ev.wdx > 0 );
×
578
  getButtonState().wheel_left  = bool( gpm_ev.wdx < 0 );
×
579
}
×
580

581
//----------------------------------------------------------------------
582
inline void FMouseGPM::interpretMouseEvent()
×
583
{
584
  switch ( gpm_ev.type & 0x0f )
×
585
  {
586
    case GPM_DOWN:
×
587
    case GPM_DRAG:
588
      interpretKeyDown();
×
589
      break;
×
590

591
    case GPM_UP:
×
592
      interpretKeyUp();
×
593
      break;
×
594

595
    default:
×
596
      break;
×
597
    }
598
}
×
599

600
//----------------------------------------------------------------------
601
inline void FMouseGPM::updateMousePosition()
×
602
{
603
  setPos (FPoint{ std::max(gpm_ev.x, sInt16(1))
×
604
                , std::max(gpm_ev.y, sInt16(1)) });
×
605
}
×
606

607
//----------------------------------------------------------------------
608
auto FMouseGPM::gpmEvent (bool clear) const -> gpmEventType
×
609
{
610
#if defined(__clang__)
611
  #pragma clang diagnostic push
612
  #pragma clang diagnostic ignored "-Wunsafe-buffer-usage"
613
#endif
614
  const int max = std::max(gpm_fd, stdin_no);
×
615
  fd_set ifds{};
×
616
  struct timeval tv{};
×
617

618
  FD_ZERO(&ifds);
×
619
  FD_SET(stdin_no, &ifds);
×
620
  FD_SET(gpm_fd, &ifds);
×
621
  tv.tv_sec  = 0;
×
622
  tv.tv_usec = suseconds_t(FKeyboard::getReadBlockingTime());  // preset to 100 ms
×
623
  const int result = select (max + 1, &ifds, nullptr, nullptr, &tv);
×
624

625
  if ( result > 0 && FD_ISSET(stdin_no, &ifds) )
×
626
  {
627
    if ( clear )
×
628
      FD_CLR (stdin_no, &ifds);
×
629

630
    return gpmEventType::Keyboard;
×
631
  }
632

633
  if ( clear && result > 0 && FD_ISSET(gpm_fd, &ifds) )
×
634
    FD_CLR (gpm_fd, &ifds);
×
635

636
  if ( result > 0 )
×
637
    return gpmEventType::Mouse;
×
638

639
  return gpmEventType::None;
×
640
#if defined(__clang__)
641
  #pragma clang diagnostic pop
642
#endif
643
}
644
#endif  // F_HAVE_LIBGPM
645

646

647
//----------------------------------------------------------------------
648
// class FMouseX11
649
//----------------------------------------------------------------------
650

651
// constructors and destructor
652
//----------------------------------------------------------------------
653
FMouseX11::FMouseX11()
8✔
654
{
655
  setMouseTypeID (FMouse::MouseType::X11);
8✔
656
}
8✔
657

658
// public methods of FMouseX11
659
//----------------------------------------------------------------------
660
auto FMouseX11::getClassName() const -> FString
1✔
661
{
662
  return "FMouseX11";
1✔
663
}
664

665
//----------------------------------------------------------------------
666
auto FMouseX11::hasData() noexcept -> bool
45✔
667
{
668
  return ( x11_mouse[0] );
45✔
669
}
670

671
//----------------------------------------------------------------------
672
void FMouseX11::setRawData (FKeyboard::keybuffer& fifo_buf) noexcept
27✔
673
{
674
  // Import the X11 xterm mouse protocol (SGR-Mode) raw mouse data
675

676
  static constexpr std::size_t len = 6;
677
  x11_mouse[0] = fifo_buf[3];
27✔
678
  x11_mouse[1] = fifo_buf[4];
27✔
679
  x11_mouse[2] = fifo_buf[5];
27✔
680
  x11_mouse[3] = '\0';
27✔
681
  fifo_buf.pop(len);  // Remove founded entry
27✔
682
  setPending(fifo_buf.hasData());
27✔
683
}
27✔
684

685
//----------------------------------------------------------------------
686
void FMouseX11::processEvent (const TimeValue& time)
27✔
687
{
688
  // Parse and interpret the X11 xterm mouse string
689

690
  const auto& mouse_position = getPos();
27✔
691
  const auto x = uChar(x11_mouse[1] - 0x20);
27✔
692
  const auto y = uChar(x11_mouse[2] - 0x20);
27✔
693
  const int btn = uChar(x11_mouse[0]);
27✔
694
  setNewPos (x, y);
27✔
695
  clearButtonState();
27✔
696
  setKeyState (btn);
27✔
697
  setMoveState (mouse_position, btn);
27✔
698
  setButtonState (btn & button_mask, time);
27✔
699

700
  if ( noChanges(mouse_position, uChar(btn)) )
27✔
701
  {
702
    clearEvent();
1✔
703
    x11_mouse[0] = '\0';  // Delete already interpreted data
1✔
704
    return;
1✔
705
  }
706

707
  setEvent();
26✔
708
  setPos (FPoint{x, y});
26✔
709
  // Get the button state from string
710
  x11_button_state = uChar(btn);
26✔
711
  // Delete already interpreted data
712
  x11_mouse[0] = '\0';
26✔
713
}
714

715

716
// private methods of FMouseX11
717
//----------------------------------------------------------------------
718
void FMouseX11::setKeyState (int btn) noexcept
27✔
719
{
720
  getButtonState().shift_button   = bool((btn & key_shift) == key_shift);
27✔
721
  getButtonState().meta_button    = bool((btn & key_meta)  == key_meta);
27✔
722
  getButtonState().control_button = bool((btn & key_ctrl)  == key_ctrl);
27✔
723
}
27✔
724

725
//----------------------------------------------------------------------
726
void FMouseX11::setMoveState (const FPoint& mouse_position, int btn) noexcept
27✔
727
{
728
  if ( (btn & button_mask) >= button1_pressed_move
54✔
729
    && (btn & button_mask) <= button3_pressed_move
9✔
730
    && ! mouse_position.isOrigin() )
36✔
731
  {
732
    getButtonState().mouse_moved = true;
1✔
733
  }
734
}
27✔
735

736
//----------------------------------------------------------------------
737
inline auto FMouseX11::isMouseClickButton (const int btn) const noexcept -> bool
27✔
738
{
739
  return btn == button1_pressed
740
      || btn == button2_pressed
18✔
741
      || btn == button3_pressed
17✔
742
      || btn == button1_pressed_move
16✔
743
      || btn == button2_pressed_move
15✔
744
      || btn == button3_pressed_move;
45✔
745
}
746

747
//----------------------------------------------------------------------
748
inline auto FMouseX11::isMouseWheelButton (const int btn) const noexcept -> bool
8✔
749
{
750
  return btn == button_up
751
      || btn == button_down
6✔
752
      || btn == button_left
4✔
753
      || btn == button_right;
14✔
754
}
755

756
//----------------------------------------------------------------------
757
inline auto FMouseX11::noChanges (const FPoint& mouse_position, uChar btn) const noexcept -> bool
27✔
758
{
759
  return mouse_position == getNewPos()
27✔
760
    && ! isWheelUp()
18✔
761
    && ! isWheelDown()
18✔
762
    && ! isWheelLeft()
16✔
763
    && ! isWheelRight()
14✔
764
    && btn == x11_button_state;
45✔
765
}
766

767
//----------------------------------------------------------------------
768
void FMouseX11::handleMouseClickButton ( int btn
12✔
769
                                       , const TimeValue& time) noexcept
770
{
771
  switch ( btn )
12✔
772
  {
773
    case button1_pressed:
10✔
774
    case button1_pressed_move:
775
      handleButton1Pressed(time);
10✔
776
      break;
10✔
777

778
    case button2_pressed:
1✔
779
    case button2_pressed_move:
780
      resetMousePressedTime();
1✔
781
      getButtonState().middle_button = State::Pressed;
1✔
782
      break;
1✔
783

784
    case button3_pressed:
1✔
785
    case button3_pressed_move:
786
      resetMousePressedTime();
1✔
787
      getButtonState().right_button = State::Pressed;
1✔
788
      break;
1✔
789

790
      default:
×
791
        break;
×
792
  }
793
}
12✔
794

795
//----------------------------------------------------------------------
796
void FMouseX11::handleMouseWheelButton (int btn) noexcept
8✔
797
{
798
  resetMousePressedTime();
8✔
799

800
  switch ( btn )
8✔
801
  {
802
    case button_up:
2✔
803
      getButtonState().wheel_up = true;
2✔
804
      break;
2✔
805

806
    case button_down:
2✔
807
      getButtonState().wheel_down = true;
2✔
808
      break;
2✔
809

810
    case button_left:
2✔
811
      getButtonState().wheel_left = true;
2✔
812
      break;
2✔
813

814
    case button_right:
2✔
815
      getButtonState().wheel_right = true;
2✔
816
      break;
2✔
817

818
      default:
×
819
        break;
×
820
  }
821
}
8✔
822

823
//----------------------------------------------------------------------
824
void FMouseX11::setButtonState (const int btn, const TimeValue& time) noexcept
27✔
825
{
826
  // Get the x11 mouse button state
827

828
  if ( isMouseClickButton(btn) )
27✔
829
  {
830
    handleMouseClickButton (btn, time);
12✔
831
  }
832
  else if ( btn == all_buttons_released )
15✔
833
  {
834
    handleButtonRelease();
7✔
835
  }
836
  else if ( isMouseWheelButton(btn) )
8✔
837
  {
838
    handleMouseWheelButton(btn);
8✔
839
  }
840
}
27✔
841

842
//----------------------------------------------------------------------
843
void FMouseX11::handleButton1Pressed (const TimeValue& time) noexcept
10✔
844
{
845
  if ( getPos() == getNewPos()
10✔
846
    && x11_button_state == all_buttons_released
4✔
847
    && ! isDblclickTimeout(getMousePressedTime()) )
14✔
848
  {
849
    resetMousePressedTime();
1✔
850
    getButtonState().left_button = State::DoubleClick;
1✔
851
  }
852
  else
853
  {
854
    setMousePressedTime (time);  // save click time
9✔
855
    getButtonState().left_button = State::Pressed;
9✔
856
  }
857
}
10✔
858

859
//----------------------------------------------------------------------
860
void FMouseX11::handleButtonRelease() noexcept
7✔
861
{
862
  switch ( x11_button_state & button_mask )
7✔
863
  {
864
    case button1_pressed:
3✔
865
    case button1_pressed_move:
866
      getButtonState().left_button = State::Released;
3✔
867
      break;
3✔
868

869
    case button2_pressed:
1✔
870
    case button2_pressed_move:
871
      getButtonState().middle_button = State::Released;
1✔
872
      break;
1✔
873

874
    case button3_pressed:
1✔
875
    case button3_pressed_move:
876
      getButtonState().right_button = State::Released;
1✔
877
      break;
1✔
878

879
    default:
2✔
880
      break;
2✔
881
  }
882
}
7✔
883

884

885
//----------------------------------------------------------------------
886
// class FMouseSGR
887
//----------------------------------------------------------------------
888

889
// constructors and destructor
890
//----------------------------------------------------------------------
891
FMouseSGR::FMouseSGR()
8✔
892
{
893
  setMouseTypeID (FMouse::MouseType::Sgr);
8✔
894
}
8✔
895

896
// public methods of FMouseSGR
897
//----------------------------------------------------------------------
898
auto FMouseSGR::getClassName() const -> FString
1✔
899
{
900
  return "FMouseSGR";
1✔
901
}
902

903
//----------------------------------------------------------------------
904
auto FMouseSGR::hasData() noexcept -> bool
38✔
905
{
906
  return ( sgr_mouse[0] );
38✔
907
}
908

909
//----------------------------------------------------------------------
910
void FMouseSGR::setRawData (FKeyboard::keybuffer& fifo_buf) noexcept
28✔
911
{
912
  // Import the X11 xterm mouse protocol (SGR-Mode) raw mouse data
913

914
  const auto max = fifo_buf.getSize();
28✔
915
  std::size_t len{0};
28✔
916
  std::size_t n{3};
28✔
917

918
  while ( n < max )
181✔
919
  {
920
    sgr_mouse[n - 3] = fifo_buf[n];
181✔
921

922
    if ( fifo_buf[n] == 'M' || fifo_buf[n] == 'm' )
181✔
923
    {
924
      n++;
28✔
925
      len = n;
28✔
926
      break;
28✔
927
    }
928

929
    n++;
153✔
930
  }
931

932
  sgr_mouse[n - 3] = '\0';
28✔
933
  fifo_buf.pop(len);  // Remove founded entry
28✔
934
  setPending(fifo_buf.hasData());
28✔
935
}
28✔
936

937
//----------------------------------------------------------------------
938
void FMouseSGR::processEvent (const TimeValue& time)
28✔
939
{
940
  const auto& mouse_position = getPos();
28✔
941
  Tokens token{};
28✔
942

943
  if ( parseSGRMouseString(token) == ParseError::Yes )
28✔
944
  {
945
    clearEvent();
3✔
946
    sgr_mouse[0] = '\0';  // Delete already interpreted data
3✔
947
    return;
4✔
948
  }
949

950
  setNewPos (token.x, token.y);  // Update the mouse state
25✔
951
  clearButtonState();
25✔
952
  setKeyState (token.btn);
25✔
953
  setMoveState (mouse_position, token.btn);
25✔
954

955
  if ( *token.iter == pressed )
25✔
956
    setPressedButtonState (token.btn & button_mask, time);
19✔
957
  else  // *token.p == released
958
    setReleasedButtonState (token.btn & button_mask);
6✔
959

960
  if ( noChanges(mouse_position, uChar(((*token.iter & 0x20) << 2) + token.btn)) )
25✔
961
  {
962
    clearEvent();
1✔
963
    sgr_mouse[0] = '\0';  // Delete already interpreted data
1✔
964
    return;
1✔
965
  }
966

967
  setEvent();
24✔
968
  useNewPos();
24✔
969
  // Get the button state from string
970
  sgr_button_state = uChar(((*token.iter & 0x20) << 2) + token.btn);
24✔
971
  // Delete already interpreted data
972
  sgr_mouse[0] = '\0';
24✔
973
}
974

975
// private methods of FMouseSGR
976
//----------------------------------------------------------------------
977
void FMouseSGR::setKeyState (int btn) noexcept
25✔
978
{
979
  getButtonState().shift_button   = bool((btn & key_shift) == key_shift);
25✔
980
  getButtonState().meta_button    = bool((btn & key_meta)  == key_meta);
25✔
981
  getButtonState().control_button = bool((btn & key_ctrl)  == key_ctrl);
25✔
982
}
25✔
983

984
//----------------------------------------------------------------------
985
void FMouseSGR::setMoveState (const FPoint& mouse_position, int btn) noexcept
25✔
986
{
987
  if ( (btn & button_mask) >= button1_move
50✔
988
    && (btn & button_mask) <= button3_move
6✔
989
    && ! mouse_position.isOrigin() )
31✔
990
  {
991
    getButtonState().mouse_moved = true;
2✔
992
  }
993
}
25✔
994

995
//----------------------------------------------------------------------
996
inline auto FMouseSGR::isMouseClickButton (const int btn) const noexcept -> bool
19✔
997
{
998
  return btn == button1
999
      || btn == button2
10✔
1000
      || btn == button3
8✔
1001
      || btn == button1_move
6✔
1002
      || btn == button2_move
4✔
1003
      || btn == button3_move;
29✔
1004
}
1005

1006
//----------------------------------------------------------------------
1007
inline auto FMouseSGR::isMouseWheelButton (const int btn) const noexcept -> bool
4✔
1008
{
1009
  return btn == button_up
1010
      || btn == button_down
3✔
1011
      || btn == button_left
2✔
1012
      || btn == button_right;
7✔
1013
}
1014

1015
//----------------------------------------------------------------------
1016
inline auto FMouseSGR::parseSGRMouseString (FMouseSGR::Tokens& token) const noexcept -> ParseError
28✔
1017
{
1018
  // Parse the SGR mouse string
1019
  token.iter = sgr_mouse.cbegin();
28✔
1020
  const auto end = sgr_mouse.cend();
28✔
1021

1022
  // Parse button
1023
  if ( ! parseNumberIf (token.iter, end, token.btn, [] (char ch) { return ch != ';'; }) )
92✔
1024
    return ParseError::Yes;
1✔
1025

1026
  if ( *token.iter )
27✔
1027
    token.iter = std::next(token.iter);  // ship one character after the number
54✔
1028

1029
  // Parse x-value
1030
  if ( ! parseNumberIf (token.iter, end, token.x, [] (char ch) { return ch != ';'; }) )
84✔
1031
    return ParseError::Yes;
1✔
1032

1033
  if ( *token.iter )
26✔
1034
    token.iter = std::next(token.iter);  // ship one character after the number
52✔
1035

1036
  // Parse y-value
1037
  if ( ! parseNumberIf (token.iter, end, token.y, [] (char ch) { return ch != 'M' && ch != 'm'; }) )
77✔
1038
    return ParseError::Yes;
1✔
1039

1040
  return ParseError::No;
25✔
1041
}
1042

1043
//----------------------------------------------------------------------
1044
inline auto FMouseSGR::noChanges (const FPoint& mouse_position, uChar btn) const noexcept -> bool
25✔
1045
{
1046
  return mouse_position == getNewPos()
25✔
1047
    && ! isWheelUp()
11✔
1048
    && ! isWheelDown()
11✔
1049
    && ! isWheelLeft()
10✔
1050
    && ! isWheelRight()
9✔
1051
    && btn == sgr_button_state;
36✔
1052
}
1053

1054
//----------------------------------------------------------------------
1055
void FMouseSGR::handleMouseClickButton ( int btn
15✔
1056
                                       , const TimeValue& time) noexcept
1057
{
1058
  switch ( btn )
15✔
1059
  {
1060
    case button1:
11✔
1061
    case button1_move:
1062
      handleButton1Pressed(time);
11✔
1063
      break;
11✔
1064

1065
    case button2:
2✔
1066
    case button2_move:
1067
      resetMousePressedTime();
2✔
1068
      getButtonState().middle_button = State::Pressed;
2✔
1069
      break;
2✔
1070

1071
    case button3:
2✔
1072
    case button3_move:
1073
      resetMousePressedTime();
2✔
1074
      getButtonState().right_button = State::Pressed;
2✔
1075
      break;
2✔
1076

1077
    default:
×
1078
      break;
×
1079
  }
1080
}
15✔
1081

1082
//----------------------------------------------------------------------
1083
void FMouseSGR::handleMouseWheelButton (int btn) noexcept
4✔
1084
{
1085
  resetMousePressedTime();
4✔
1086

1087
  switch ( btn )
4✔
1088
  {
1089
    case button_up:
1✔
1090
      getButtonState().wheel_up = true;
1✔
1091
      break;
1✔
1092

1093
    case button_down:
1✔
1094
      getButtonState().wheel_down = true;
1✔
1095
      break;
1✔
1096

1097
    case button_left:
1✔
1098
      getButtonState().wheel_left = true;
1✔
1099
      break;
1✔
1100

1101
    case button_right:
1✔
1102
      getButtonState().wheel_right = true;
1✔
1103
      break;
1✔
1104

1105
    default:
×
1106
      break;
×
1107
  }
1108
}
4✔
1109

1110
//----------------------------------------------------------------------
1111
void FMouseSGR::setPressedButtonState ( const int btn
19✔
1112
                                      , const TimeValue& time ) noexcept
1113
{
1114
  // Gets the extended x11 mouse mode (SGR) status for pressed buttons
1115

1116
  if ( isMouseClickButton(btn) )
19✔
1117
  {
1118
    handleMouseClickButton (btn, time);
15✔
1119
  }
1120
  else if ( isMouseWheelButton(btn) )
4✔
1121
  {
1122
    handleMouseWheelButton(btn);
4✔
1123
  }
1124
}
19✔
1125

1126
//----------------------------------------------------------------------
1127
void FMouseSGR::handleButton1Pressed (const TimeValue& time) noexcept
11✔
1128
{
1129
  if ( getPos() == getNewPos()
11✔
1130
    && (((sgr_button_state & 0x80) >> 2) + 'M') == released
5✔
1131
    && ! isDblclickTimeout(getMousePressedTime()) )
16✔
1132
  {
1133
    resetMousePressedTime();
1✔
1134
    getButtonState().left_button = State::DoubleClick;
1✔
1135
  }
1136
  else
1137
  {
1138
    setMousePressedTime (time);  // save click time
10✔
1139
    getButtonState().left_button = State::Pressed;
10✔
1140
  }
1141
}
11✔
1142

1143
//----------------------------------------------------------------------
1144
void FMouseSGR::setReleasedButtonState (const int btn) noexcept
6✔
1145
{
1146
  // Gets the extended x11 mouse mode (SGR) status for released buttons
1147

1148
  switch ( btn )
6✔
1149
  {
1150
    case button1:
3✔
1151
    case button1_move:
1152
      getButtonState().left_button = State::Released;
3✔
1153
      break;
3✔
1154

1155
    case button2:
2✔
1156
    case button2_move:
1157
      getButtonState().middle_button = State::Released;
2✔
1158
      break;
2✔
1159

1160
    case button3:
1✔
1161
    case button3_move:
1162
      getButtonState().right_button = State::Released;
1✔
1163
      break;
1✔
1164

1165
    default:
×
1166
      break;
×
1167
  }
1168
}
6✔
1169

1170

1171
//----------------------------------------------------------------------
1172
// class FMouseUrxvt
1173
//----------------------------------------------------------------------
1174

1175
// constructors and destructor
1176
//----------------------------------------------------------------------
1177
FMouseUrxvt::FMouseUrxvt()
8✔
1178
{
1179
  setMouseTypeID (FMouse::MouseType::Urxvt);
8✔
1180
}
8✔
1181

1182
// public methods of FMouseUrxvt
1183
//----------------------------------------------------------------------
1184
auto FMouseUrxvt::getClassName() const -> FString
1✔
1185
{
1186
  return "FMouseUrxvt";
1✔
1187
}
1188

1189
//----------------------------------------------------------------------
1190
auto FMouseUrxvt::hasData() noexcept -> bool
37✔
1191
{
1192
  return ( urxvt_mouse[0] );
37✔
1193
}
1194

1195
//----------------------------------------------------------------------
1196
void FMouseUrxvt::setRawData (FKeyboard::keybuffer& fifo_buf) noexcept
28✔
1197
{
1198
  // Import the X11 xterm mouse protocol (Urxvt-Mode) raw mouse data
1199

1200
  const auto max = fifo_buf.getSize();
28✔
1201
  std::size_t len{0};
28✔
1202
  std::size_t n{2};
28✔
1203

1204
  while ( n < max )
204✔
1205
  {
1206
    urxvt_mouse[n - 2] = fifo_buf[n];
204✔
1207

1208
    if ( fifo_buf[n] == 'M' || fifo_buf[n] == 'm' )
204✔
1209
    {
1210
      n++;
28✔
1211
      len = n;
28✔
1212
      break;
28✔
1213
    }
1214

1215
    n++;
176✔
1216
  }
1217

1218
  urxvt_mouse[n - 2] = '\0';
28✔
1219
  fifo_buf.pop(len);  // Remove founded entry
28✔
1220
  setPending(fifo_buf.hasData());
28✔
1221
}
28✔
1222

1223
//----------------------------------------------------------------------
1224
void FMouseUrxvt::processEvent (const TimeValue& time)
28✔
1225
{
1226
  // Parse and interpret the X11 xterm mouse string (Urxvt-Mode)
1227

1228
  const auto& mouse_position = getPos();
28✔
1229
  Tokens token{};
28✔
1230

1231
  if ( parseUrxvtMouseString(token) == ParseError::Yes )
28✔
1232
  {
1233
    clearEvent();
3✔
1234
    urxvt_mouse[0] = '\0';  // Delete already interpreted data
3✔
1235
    return;
4✔
1236
  }
1237

1238
  adjustAndSetPosition (token);
25✔
1239
  clearButtonState();
25✔
1240
  setKeyState (token.btn);
25✔
1241
  setMoveState (mouse_position, token.btn);
25✔
1242
  setButtonState (token.btn & button_mask, time);
25✔
1243

1244
  if ( noChanges(mouse_position, uChar(token.btn)) )
25✔
1245
  {
1246
    clearEvent();
1✔
1247
    urxvt_mouse[0] = '\0';  // Delete already interpreted data
1✔
1248
    return;
1✔
1249
  }
1250

1251
  setEvent();
24✔
1252
  useNewPos();
24✔
1253
  urxvt_button_state = uChar(token.btn);
24✔
1254
  // Delete already interpreted data
1255
  urxvt_mouse[0] = '\0';
24✔
1256
}
1257

1258

1259
// private methods of FMouseUrxvt
1260
//----------------------------------------------------------------------
1261
void FMouseUrxvt::setKeyState (int btn) noexcept
25✔
1262
{
1263
  getButtonState().shift_button   = bool((btn & key_shift) == key_shift);
25✔
1264
  getButtonState().meta_button    = bool((btn & key_meta)  == key_meta);
25✔
1265
  getButtonState().control_button = bool((btn & key_ctrl)  == key_ctrl);
25✔
1266
}
25✔
1267

1268
//----------------------------------------------------------------------
1269
void FMouseUrxvt::setMoveState (const FPoint& mouse_position, int btn) noexcept
25✔
1270
{
1271
  if ( (btn & button_mask) >= button1_pressed_move
50✔
1272
    && (btn & button_mask) <= button3_pressed_move
5✔
1273
    && ! mouse_position.isOrigin() )
30✔
1274
  {
1275
    getButtonState().mouse_moved = true;
1✔
1276
  }
1277
}
25✔
1278

1279
//----------------------------------------------------------------------
1280
inline auto FMouseUrxvt::isMouseClickButton (const int btn) const noexcept -> bool
25✔
1281
{
1282
  return btn == button1_pressed
1283
      || btn == button2_pressed
13✔
1284
      || btn == button3_pressed
12✔
1285
      || btn == button1_pressed_move
10✔
1286
      || btn == button2_pressed_move
9✔
1287
      || btn == button3_pressed_move;
38✔
1288
}
1289

1290
//----------------------------------------------------------------------
1291
inline auto FMouseUrxvt::isMouseWheelButton (const int btn) const noexcept -> bool
4✔
1292
{
1293
  return btn == button_up
1294
      || btn == button_down
3✔
1295
      || btn == button_left
2✔
1296
      || btn == button_right;
7✔
1297
}
1298

1299
//----------------------------------------------------------------------
1300
inline auto FMouseUrxvt::parseUrxvtMouseString (FMouseUrxvt::Tokens& token) const noexcept -> ParseError
28✔
1301
{
1302
  // Parse the Urxvt mouse string
1303
  token.iter = urxvt_mouse.cbegin();
28✔
1304
  auto end = urxvt_mouse.cend();
28✔
1305

1306
  // Parse button
1307
  if ( ! parseNumberIf (token.iter, end, token.btn, [] (char ch) { return ch != ';'; }) )
111✔
1308
    return ParseError::Yes;
1✔
1309

1310
  if ( *(token.iter = std::next(token.iter)) == '-' )
54✔
1311
  {
1312
    token.iter = std::next(token.iter);
1✔
1313
    token.x_neg = true;
1✔
1314
  }
1315

1316
  // Parse x-value
1317
  if ( ! parseNumberIf (token.iter, end, token.x, [] (char ch) { return ch != ';'; }) )
85✔
1318
    return ParseError::Yes;
1✔
1319

1320
  if ( *(token.iter = std::next(token.iter)) == '-' )
52✔
1321
  {
1322
    token.iter = std::next(token.iter);
1✔
1323
    token.y_neg = true;
1✔
1324
  }
1325

1326
  // Parse y-value
1327
  if ( ! parseNumberIf (token.iter, end, token.y, [] (char ch) { return ch != 'M'; }) )
78✔
1328
    return ParseError::Yes;
1✔
1329

1330
  return ParseError::No;
25✔
1331
}
1332

1333
//----------------------------------------------------------------------
1334
inline void FMouseUrxvt::adjustAndSetPosition (FMouseUrxvt::Tokens& token)
25✔
1335
{
1336
  if ( token.x_neg || token.x == 0 )
25✔
1337
    token.x = 1;
1✔
1338

1339
  if ( token.y_neg || token.y == 0 )
25✔
1340
    token.y = 1;
1✔
1341

1342
  token.x = std::min(token.x, sInt16(getMaxWidth()));
25✔
1343
  token.y = std::min(token.y, sInt16(getMaxHeight()));
25✔
1344
  setNewPos(token.x, token.y);
25✔
1345
}
25✔
1346

1347
//----------------------------------------------------------------------
1348
inline auto FMouseUrxvt::noChanges (const FPoint& mouse_position, uChar btn) const noexcept -> bool
25✔
1349
{
1350
  return mouse_position == getNewPos()
25✔
1351
      && ! isWheelUp()
10✔
1352
      && ! isWheelDown()
10✔
1353
      && ! isWheelLeft()
9✔
1354
      && ! isWheelRight()
8✔
1355
      && urxvt_button_state == uChar(btn);
35✔
1356
}
1357

1358
//----------------------------------------------------------------------
1359
void FMouseUrxvt::handleMouseClickButton ( int btn
16✔
1360
                                         , const TimeValue& time) noexcept
1361
{
1362
  const auto& mouse_position = getPos();
16✔
1363

1364
  if ( btn == button1_pressed || btn == button1_pressed_move )
16✔
1365
  {
1366
    if ( mouse_position == getNewPos()
13✔
1367
      && urxvt_button_state == all_buttons_released
5✔
1368
      && ! isDblclickTimeout(getMousePressedTime()) )
18✔
1369
    {
1370
      resetMousePressedTime();
1✔
1371
      getButtonState().left_button = State::DoubleClick;
1✔
1372
    }
1373
    else
1374
    {
1375
      setMousePressedTime(time); // save click time
12✔
1376
      getButtonState().left_button = State::Pressed;
12✔
1377
    }
1378
  }
1379
  else if ( btn == button2_pressed || btn == button2_pressed_move )
3✔
1380
  {
1381
    resetMousePressedTime();
1✔
1382
    getButtonState().middle_button = State::Pressed;
1✔
1383
  }
1384
  else if ( btn == button3_pressed || btn == button3_pressed_move )
2✔
1385
  {
1386
    resetMousePressedTime();
2✔
1387
    getButtonState().right_button = State::Pressed;
2✔
1388
  }
1389
}
16✔
1390

1391
//----------------------------------------------------------------------
1392
void FMouseUrxvt::handleButtonRelease() noexcept
5✔
1393
{
1394
  switch ( urxvt_button_state & button_mask )
5✔
1395
  {
1396
    case button1_pressed:
2✔
1397
    case button1_pressed_move:
1398
      getButtonState().left_button = State::Released;
2✔
1399
      break;
2✔
1400

1401
    case button2_pressed:
1✔
1402
    case button2_pressed_move:
1403
      getButtonState().middle_button = State::Released;
1✔
1404
      break;
1✔
1405

1406
    case button3_pressed:
2✔
1407
    case button3_pressed_move:
1408
      getButtonState().right_button = State::Released;
2✔
1409
      break;
2✔
1410

1411
    default:
×
1412
      break;
×
1413
  }
1414
}
5✔
1415

1416
//----------------------------------------------------------------------
1417
void FMouseUrxvt::handleMouseWheelButton (int btn) noexcept
4✔
1418
{
1419
  resetMousePressedTime();
4✔
1420

1421
  switch ( btn )
4✔
1422
  {
1423
    case button_up:
1✔
1424
      getButtonState().wheel_up = true;
1✔
1425
      break;
1✔
1426

1427
    case button_down:
1✔
1428
      getButtonState().wheel_down = true;
1✔
1429
      break;
1✔
1430

1431
    case button_left:
1✔
1432
      getButtonState().wheel_left = true;
1✔
1433
      break;
1✔
1434

1435
    case button_right:
1✔
1436
      getButtonState().wheel_right = true;
1✔
1437
      break;
1✔
1438

1439
    default:
×
1440
      break;
×
1441
  }
1442
}
4✔
1443

1444
//----------------------------------------------------------------------
1445
void FMouseUrxvt::setButtonState (const int btn, const TimeValue& time) noexcept
25✔
1446
{
1447
  // Get the urxvt mouse button state
1448

1449
  if ( isMouseClickButton(btn) )
25✔
1450
  {
1451
    handleMouseClickButton (btn, time);
16✔
1452
  }
1453
  else if ( btn == all_buttons_released )
9✔
1454
  {
1455
    handleButtonRelease();
5✔
1456
  }
1457
  else if ( isMouseWheelButton(btn) )
4✔
1458
  {
1459
    handleMouseWheelButton(btn);
4✔
1460
  }
1461
}
25✔
1462

1463

1464
//----------------------------------------------------------------------
1465
// class FMouseControl
1466
//----------------------------------------------------------------------
1467

1468
// constructors and destructor
1469
//----------------------------------------------------------------------
1470
FMouseControl::FMouseControl()
5✔
1471
{
1472
#ifdef F_HAVE_LIBGPM
1473
  if ( FTermLinux::isLinuxConsole() )
5✔
1474
    mouse_protocol.push_back(FMouse::createMouseObject<FMouseGPM>());
×
1475
#endif
1476

1477
  mouse_protocol.push_back(FMouse::createMouseObject<FMouseX11>());
5✔
1478
  mouse_protocol.push_back(FMouse::createMouseObject<FMouseSGR>());
5✔
1479
  mouse_protocol.push_back(FMouse::createMouseObject<FMouseUrxvt>());
5✔
1480
}
5✔
1481

1482
//----------------------------------------------------------------------
1483
FMouseControl::~FMouseControl() = default;  // destructor
7✔
1484

1485

1486
// public methods of FMouseControl
1487
//----------------------------------------------------------------------
1488
auto FMouseControl::getInstance() -> FMouseControl&
2✔
1489
{
1490
  static const auto& mouse = std::make_unique<FMouseControl>();
2✔
1491
  return *mouse;
2✔
1492
}
1493

1494
//----------------------------------------------------------------------
1495
auto FMouseControl::getPos() & -> const FPoint&
9✔
1496
{
1497
  const auto& iter = findMouseWithEvent();
9✔
1498

1499
  if ( iter != mouse_protocol.end() )
9✔
1500
    return (*iter)->getPos();
8✔
1501

1502
  return zero_point;
1✔
1503
}
1504

1505
//----------------------------------------------------------------------
1506
void FMouseControl::clearEvent()
14✔
1507
{
1508
  FMouseProtocol::const_iterator iter;
14✔
1509

1510
  do
1511
  {
1512
    iter = findMouseWithEvent();
26✔
1513

1514
    if ( iter != mouse_protocol.end() )
26✔
1515
      (*iter)->clearEvent();
12✔
1516
  }
1517
  while ( iter != mouse_protocol.end() );
26✔
1518
}
14✔
1519

1520
//----------------------------------------------------------------------
1521
#ifdef F_HAVE_LIBGPM
1522
void FMouseControl::setStdinNo (int file_descriptor)
3✔
1523
{
1524
  const auto iter = findMouseWithType (FMouse::MouseType::Gpm);
3✔
1525

1526
  if ( iter != mouse_protocol.end() )
3✔
1527
    static_cast<FMouseGPM*>(iter->get())->setStdinNo(file_descriptor);
×
1528
}
3✔
1529
#else
1530
void FMouseControl::setStdinNo (int)
1531
{ }
1532
#endif  // F_HAVE_LIBGPM
1533

1534
//----------------------------------------------------------------------
1535
void FMouseControl::setMaxWidth (uInt16 x_max)
1✔
1536
{
1537
  const auto iter = findMouseWithType (FMouse::MouseType::Urxvt);
1✔
1538

1539
  if ( iter != mouse_protocol.end() )
1✔
1540
    (*iter)->setMaxWidth(x_max);
1✔
1541
}
1✔
1542

1543
//----------------------------------------------------------------------
1544
void FMouseControl::setMaxHeight (uInt16 y_max)
1✔
1545
{
1546
  const auto iter = findMouseWithType (FMouse::MouseType::Urxvt);
1✔
1547

1548
  if ( iter != mouse_protocol.end() )
1✔
1549
    (*iter)->setMaxHeight(y_max);
1✔
1550
}
1✔
1551

1552
//----------------------------------------------------------------------
1553
void FMouseControl::setDblclickInterval (const uInt64 timeout) const
3✔
1554
{
1555
  for (auto&& mouse : mouse_protocol)
12✔
1556
  {
1557
    if ( mouse )
9✔
1558
      mouse->setDblclickInterval(timeout);
9✔
1559
  }
1560
}
3✔
1561

1562
//----------------------------------------------------------------------
1563
void FMouseControl::useGpmMouse (bool enable)
1✔
1564
{
1565
  use_gpm_mouse = enable;
1✔
1566
}
1✔
1567

1568
//----------------------------------------------------------------------
1569
void FMouseControl::useXtermMouse (bool enable)
1✔
1570
{
1571
  use_xterm_mouse = enable;
1✔
1572
}
1✔
1573

1574
//----------------------------------------------------------------------
1575
auto FMouseControl::hasData() -> bool
12✔
1576
{
1577
  return findMouseWithData() != mouse_protocol.end();  // with data
12✔
1578
}
1579

1580
//----------------------------------------------------------------------
1581
auto FMouseControl::hasEvent() -> bool
6✔
1582
{
1583
  return findMouseWithEvent() != mouse_protocol.end();  // with event
6✔
1584
}
1585

1586
//----------------------------------------------------------------------
1587
auto FMouseControl::isLeftButtonPressed() -> bool
7✔
1588
{
1589
  auto iter = findMouseWithEvent();
7✔
1590
  const bool found = (iter != mouse_protocol.end());
7✔
1591
  return found ? (*iter)->isLeftButtonPressed() : false;
14✔
1592
}
1593

1594
//----------------------------------------------------------------------
1595
auto FMouseControl::isLeftButtonReleased() -> bool
7✔
1596
{
1597
  auto iter = findMouseWithEvent();
7✔
1598
  const bool found = (iter != mouse_protocol.end());
7✔
1599
  return found ? (*iter)->isLeftButtonReleased() : false;
14✔
1600
}
1601

1602
//----------------------------------------------------------------------
1603
auto FMouseControl::isLeftButtonDoubleClick() -> bool
7✔
1604
{
1605
  auto iter = findMouseWithEvent();
7✔
1606
  const bool found = (iter != mouse_protocol.end());
7✔
1607
  return found ? (*iter)->isLeftButtonDoubleClick() : false;
14✔
1608
}
1609

1610
//----------------------------------------------------------------------
1611
auto FMouseControl::isRightButtonPressed() -> bool
7✔
1612
{
1613
  auto iter = findMouseWithEvent();
7✔
1614
  const bool found = (iter != mouse_protocol.end());
7✔
1615
  return found ? (*iter)->isRightButtonPressed() : false;
14✔
1616
}
1617

1618
//----------------------------------------------------------------------
1619
auto FMouseControl::isRightButtonReleased() -> bool
7✔
1620
{
1621
  auto iter = findMouseWithEvent();
7✔
1622
  const bool found = (iter != mouse_protocol.end());
7✔
1623
  return found ? (*iter)->isRightButtonReleased() : false;
14✔
1624
}
1625

1626
//----------------------------------------------------------------------
1627
auto FMouseControl::isMiddleButtonPressed() -> bool
7✔
1628
{
1629
  auto iter = findMouseWithEvent();
7✔
1630
  const bool found = (iter != mouse_protocol.end());
7✔
1631
  return found ? (*iter)->isMiddleButtonPressed() : false;
14✔
1632
}
1633

1634
//----------------------------------------------------------------------
1635
auto FMouseControl::isMiddleButtonReleased() -> bool
7✔
1636
{
1637
  auto iter = findMouseWithEvent();
7✔
1638
  const bool found = (iter != mouse_protocol.end());
7✔
1639
  return found ? (*iter)->isMiddleButtonReleased() : false;
14✔
1640
}
1641

1642
//----------------------------------------------------------------------
1643
auto FMouseControl::isShiftKeyPressed() -> bool
6✔
1644
{
1645
  auto iter = findMouseWithEvent();
6✔
1646
  const bool found = (iter != mouse_protocol.end());
6✔
1647
  return found ? (*iter)->isShiftKeyPressed() : false;
12✔
1648
}
1649

1650
//----------------------------------------------------------------------
1651
auto FMouseControl::isControlKeyPressed() -> bool
6✔
1652
{
1653
  auto iter = findMouseWithEvent();
6✔
1654
  const bool found = (iter != mouse_protocol.end());
6✔
1655
  return found ? (*iter)->isControlKeyPressed() : false;
12✔
1656
}
1657

1658
//----------------------------------------------------------------------
1659
auto FMouseControl::isMetaKeyPressed() -> bool
6✔
1660
{
1661
  auto iter = findMouseWithEvent();
6✔
1662
  const bool found = (iter != mouse_protocol.end());
6✔
1663
  return found ? (*iter)->isMetaKeyPressed() : false;
12✔
1664
}
1665

1666
//----------------------------------------------------------------------
1667
auto FMouseControl::isWheelUp() -> bool
9✔
1668
{
1669
  auto iter = findMouseWithEvent();
9✔
1670
  const bool found = (iter != mouse_protocol.end());
9✔
1671
  return found ? (*iter)->isWheelUp() : false;
18✔
1672
}
1673

1674
//----------------------------------------------------------------------
1675
auto FMouseControl::isWheelDown() -> bool
9✔
1676
{
1677
  auto iter = findMouseWithEvent();
9✔
1678
  const bool found = (iter != mouse_protocol.end());
9✔
1679
  return found ? (*iter)->isWheelDown() : false;
18✔
1680
}
1681

1682
//----------------------------------------------------------------------
1683
auto FMouseControl::isWheelLeft() -> bool
9✔
1684
{
1685
  auto iter = findMouseWithEvent();
9✔
1686
  const bool found = (iter != mouse_protocol.end());
9✔
1687
  return found ? (*iter)->isWheelLeft() : false;
18✔
1688
}
1689

1690
//----------------------------------------------------------------------
1691
auto FMouseControl::isWheelRight() -> bool
9✔
1692
{
1693
  auto iter = findMouseWithEvent();
9✔
1694
  const bool found = (iter != mouse_protocol.end());
9✔
1695
  return found ? (*iter)->isWheelRight() : false;
18✔
1696
}
1697

1698
//----------------------------------------------------------------------
1699
auto FMouseControl::isMoved() -> bool
8✔
1700
{
1701
  auto iter = findMouseWithEvent();
8✔
1702
  const bool found = (iter != mouse_protocol.end());
8✔
1703
  return found ? (*iter)->isMoved() : false;
16✔
1704
}
1705

1706
//----------------------------------------------------------------------
1707
auto FMouseControl::hasUnprocessedInput() const -> bool
13✔
1708
{
1709
  return std::any_of ( std::cbegin(mouse_protocol)
26✔
1710
                     , std::cend(mouse_protocol)
13✔
1711
                     , [] (const auto& mouse)
27✔
1712
                       {
1713
                         return mouse->hasUnprocessedInput();
27✔
1714
                       }
1715
                     );
13✔
1716
}
1717

1718
//----------------------------------------------------------------------
1719
#ifdef F_HAVE_LIBGPM
1720
auto FMouseControl::isGpmMouseEnabled() noexcept -> bool
1✔
1721
{
1722
  if ( ! use_gpm_mouse || mouse_protocol.empty() )
1✔
1723
    return false;
×
1724

1725
  const auto iter = findMouseWithType (FMouse::MouseType::Gpm);
1✔
1726

1727
  return ( iter != mouse_protocol.end() )
1✔
1728
       ? static_cast<FMouseGPM*>(iter->get())->isGpmMouseEnabled()
1✔
1729
       : false;
1✔
1730
}
1731
#else  // F_HAVE_LIBGPM
1732
bool FMouseControl::isGpmMouseEnabled() noexcept
1733
{
1734
  return false;
1735
}
1736
#endif  // F_HAVE_LIBGPM
1737

1738
//----------------------------------------------------------------------
1739
void FMouseControl::enable()
1✔
1740
{
1741
#ifdef F_HAVE_LIBGPM
1742
  if ( use_gpm_mouse )
1✔
1743
  {
1744
    const auto iter = findMouseWithType (FMouse::MouseType::Gpm);
1✔
1745

1746
    if ( iter != mouse_protocol.end() )
1✔
1747
      use_gpm_mouse = static_cast<FMouseGPM*>(iter->get())->enableGpmMouse();
×
1748
  }
1749
#endif  // F_HAVE_LIBGPM
1750

1751
  if ( use_xterm_mouse )
1✔
1752
    enableXTermMouse();
1✔
1753
}
1✔
1754

1755
//----------------------------------------------------------------------
1756
void FMouseControl::disable()
1✔
1757
{
1758
#ifdef F_HAVE_LIBGPM
1759
  if ( use_gpm_mouse )
1✔
1760
  {
1761
    const auto iter = findMouseWithType (FMouse::MouseType::Gpm);
1✔
1762

1763
    if ( iter != mouse_protocol.end() )
1✔
1764
      use_gpm_mouse = static_cast<FMouseGPM*>(iter->get())->disableGpmMouse();
×
1765
  }
1766
#endif  // F_HAVE_LIBGPM
1767

1768
  if ( use_xterm_mouse )
1✔
1769
    disableXTermMouse();
1✔
1770
}
1✔
1771

1772
//----------------------------------------------------------------------
1773
void FMouseControl::setRawData ( const FMouse::MouseType& mt
13✔
1774
                               , FKeyboard::keybuffer& fifo_buf )
1775
{
1776
  const auto iter = findMouseWithType(mt);
13✔
1777

1778
  if ( iter != mouse_protocol.end() )
13✔
1779
    (*iter)->setRawData (fifo_buf);
13✔
1780
}
13✔
1781

1782
//----------------------------------------------------------------------
1783
void FMouseControl::processQueuedInput()
5✔
1784
{
1785
  while ( ! fmousedata_queue.isEmpty() )
16✔
1786
  {
1787
    if ( FApplication::isQuit() )
11✔
1788
      return;
×
1789

1790
    FMouseDataPtr md(std::move(fmousedata_queue.front()));
11✔
1791
    fmousedata_queue.pop();
11✔
1792

1793
    if ( md )
11✔
1794
    {
1795
      setCurrentMouseEvent (md);
11✔
1796
      event_cmd.execute(*md);
11✔
1797
      resetCurrentMouseEvent();
11✔
1798
    }
1799

1800
    if ( FApplication::isQuit() )
11✔
1801
      return;
×
1802
  }
11✔
1803
}
1804

1805
//----------------------------------------------------------------------
1806
void FMouseControl::processEvent (const TimeValue& time)
13✔
1807
{
1808
  const auto iter = findMouseWithData();
13✔
1809

1810
  // Clear all old mouse events
1811
  clearEvent();
13✔
1812

1813
  if ( iter != mouse_protocol.end() )
13✔
1814
  {
1815
    (*iter)->processEvent(time);
13✔
1816
    auto& md = static_cast<FMouseData&>(**iter);
13✔
1817
    fmousedata_queue.emplace(std::make_unique<FMouseData>(std::move(md)));
13✔
1818
  }
1819
}
13✔
1820

1821
//----------------------------------------------------------------------
1822
#ifdef F_HAVE_LIBGPM
1823
auto FMouseControl::getGpmKeyPressed (bool pending) -> bool
×
1824
{
1825
  if ( mouse_protocol.empty() )
×
1826
    return false;
×
1827

1828
  const auto iter = findMouseWithType (FMouse::MouseType::Gpm);
×
1829

1830
  return ( iter != mouse_protocol.end() )
×
1831
       && static_cast<FMouseGPM*>(iter->get())->getGpmKeyPressed(pending);
×
1832
}
1833
#else  // F_HAVE_LIBGPM
1834
bool FMouseControl::getGpmKeyPressed (bool)
1835
{
1836
  return false;
1837
}
1838
#endif  // F_HAVE_LIBGPM
1839

1840
//----------------------------------------------------------------------
1841
#ifdef F_HAVE_LIBGPM
1842
void FMouseControl::drawPointer()
×
1843
{
1844
  if ( mouse_protocol.empty() )
×
1845
    return;
×
1846

1847
  const auto iter = findMouseWithType (FMouse::MouseType::Gpm);
×
1848

1849
  if ( iter != mouse_protocol.end() )
×
1850
    static_cast<FMouseGPM*>(iter->get())->drawPointer();
×
1851
}
1852
#else  // F_HAVE_LIBGPM
1853
void FMouseControl::drawPointer()
1854
{ }
1855
#endif  // F_HAVE_LIBGPM
1856

1857

1858
// private methods of FMouseControl
1859
//----------------------------------------------------------------------
1860
auto FMouseControl::findMouseWithType (const FMouse::MouseType& mt) const -> FMouseProtocol::const_iterator
21✔
1861
{
1862
  return std::find_if ( std::cbegin(mouse_protocol)
42✔
1863
                      , std::cend(mouse_protocol)
21✔
1864
                      , [&mt] (const auto& mouse)
46✔
1865
                        {
1866
                          return mouse->getMouseTypeID() == mt;
46✔
1867
                        }
1868
                      );
21✔
1869
}
1870

1871
//----------------------------------------------------------------------
1872
auto FMouseControl::findMouseWithData() const -> FMouseProtocol::const_iterator
25✔
1873
{
1874
  return std::find_if ( std::cbegin(mouse_protocol)
50✔
1875
                      , std::cend(mouse_protocol)
25✔
1876
                      , [] (const auto& mouse)
52✔
1877
                        {
1878
                          return mouse->hasData();
52✔
1879
                        }
1880
                      );
25✔
1881
}
1882

1883
//----------------------------------------------------------------------
1884
auto FMouseControl::findMouseWithEvent() const -> FMouseProtocol::const_iterator
152✔
1885
{
1886
  return std::find_if ( std::cbegin(mouse_protocol)
304✔
1887
                      , std::cend(mouse_protocol)
152✔
1888
                      , [] (const auto& mouse)
302✔
1889
                        {
1890
                          return mouse->hasEvent();
302✔
1891
                        }
1892
                      );
152✔
1893
}
1894

1895
//----------------------------------------------------------------------
1896
void FMouseControl::xtermMouse (bool enable) const
2✔
1897
{
1898
  // activate/deactivate the xterm mouse support
1899

1900
  if ( ! use_xterm_mouse )
2✔
1901
    return;
×
1902

1903
  if ( enable )
2✔
1904
    enable_xterm_mouse_cmd.execute();
1✔
1905
  else
1906
    disable_xterm_mouse_cmd.execute();
1✔
1907
}
1908

1909
//----------------------------------------------------------------------
1910
void FMouseControl::setCurrentMouseEvent (const FMouseDataPtr& ptr)
11✔
1911
{
1912
  getCurrentMouseEvent() = ptr;
11✔
1913
}
11✔
1914

1915
//----------------------------------------------------------------------
1916
void FMouseControl::resetCurrentMouseEvent()
11✔
1917
{
1918
  getCurrentMouseEvent() = nullptr;
11✔
1919
}
11✔
1920

1921
}  // namespace finalcut
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc