LCOV - code coverage report
Current view: top level - xenolith/scene/input - XLInputListener.cc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 186 189 98.4 %
Date: 2024-05-12 00:16:13 Functions: 48 48 100.0 %

          Line data    Source code
       1             : /**
       2             :  Copyright (c) 2022 Roman Katuntsev <sbkarr@stappler.org>
       3             :  Copyright (c) 2023 Stappler LLC <admin@stappler.dev>
       4             : 
       5             :  Permission is hereby granted, free of charge, to any person obtaining a copy
       6             :  of this software and associated documentation files (the "Software"), to deal
       7             :  in the Software without restriction, including without limitation the rights
       8             :  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       9             :  copies of the Software, and to permit persons to whom the Software is
      10             :  furnished to do so, subject to the following conditions:
      11             : 
      12             :  The above copyright notice and this permission notice shall be included in
      13             :  all copies or substantial portions of the Software.
      14             : 
      15             :  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      16             :  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      17             :  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      18             :  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      19             :  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      20             :  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
      21             :  THE SOFTWARE.
      22             :  **/
      23             : 
      24             : #include "XLInputListener.h"
      25             : #include "XLDirector.h"
      26             : #include "XLInputDispatcher.h"
      27             : #include "XLGestureRecognizer.h"
      28             : #include "XLScheduler.h"
      29             : #include "XLScene.h"
      30             : 
      31             : namespace STAPPLER_VERSIONIZED stappler::xenolith {
      32             : 
      33             : InputListener::EventMask InputListener::EventMaskTouch = InputListener::makeEventMask({
      34             :         InputEventName::Begin,
      35             :         InputEventName::Move,
      36             :         InputEventName::End,
      37             :         InputEventName::Cancel,
      38             :         InputEventName::Scroll,
      39             : });
      40             : 
      41             : InputListener::EventMask InputListener::EventMaskKeyboard = InputListener::makeEventMask({
      42             :         InputEventName::KeyPressed,
      43             :         InputEventName::KeyRepeated,
      44             :         InputEventName::KeyReleased,
      45             :         InputEventName::KeyCanceled,
      46             : });
      47             : 
      48        1546 : InputListener::ButtonMask InputListener::makeButtonMask(std::initializer_list<InputMouseButton> &&il) {
      49        1546 :         ButtonMask ret;
      50        3113 :         for (auto &it : il) {
      51        1567 :                 ret.set(toInt(it));
      52             :         }
      53        1546 :         return ret;
      54             : }
      55             : 
      56         126 : InputListener::EventMask InputListener::makeEventMask(std::initializer_list<InputEventName> &&il) {
      57         126 :         EventMask ret;
      58         567 :         for (auto &it : il) {
      59         441 :                 ret.set(toInt(it));
      60             :         }
      61         126 :         return ret;
      62             : }
      63             : 
      64          63 : InputListener::KeyMask InputListener::makeKeyMask(std::initializer_list<InputKeyCode> &&il) {
      65          63 :         KeyMask ret;
      66         126 :         for (auto &it : il) {
      67          63 :                 ret.set(toInt(it));
      68             :         }
      69          63 :         return ret;
      70             : }
      71             : 
      72        1003 : InputListener::InputListener()
      73        1003 : : _enabled(true), _owner(nullptr) { }
      74             : 
      75        1922 : InputListener::~InputListener() { }
      76             : 
      77        1003 : bool InputListener::init(int32_t priority) {
      78        1003 :         _priority = priority;
      79        1003 :         return true;
      80             : }
      81             : 
      82         877 : void InputListener::onEnter(Scene *scene) {
      83         877 :         _running = true;
      84         877 :         _scene = scene;
      85             : 
      86         877 :         _scene->getDirector()->getScheduler()->scheduleUpdate(this);
      87             : 
      88        3002 :         for (auto &it : _recognizers) {
      89        2125 :                 it->onEnter(this);
      90             :         }
      91         877 : }
      92             : 
      93         877 : void InputListener::onExit() {
      94        3002 :         for (auto &it : _recognizers) {
      95        2125 :                 it->onExit();
      96             :         }
      97             : 
      98         877 :         _scene->getDirector()->getScheduler()->unschedule(this);
      99         877 :         _running = false;
     100         877 :         _scene = nullptr;
     101         877 : }
     102             : 
     103      151728 : void InputListener::update(UpdateTime dt) {
     104      534657 :         for (auto &it : _recognizers) {
     105      382929 :                 it->update(dt.delta);
     106             :         }
     107      151728 : }
     108             : 
     109        1171 : void InputListener::setOwner(Node *owner) {
     110        1171 :         _owner = owner;
     111        1171 : }
     112             : 
     113         105 : void InputListener::setEnabled(bool b) {
     114         105 :         _enabled = b;
     115         105 : }
     116             : 
     117          42 : void InputListener::setPriority(int32_t p) {
     118          42 :         _priority = p;
     119          42 : }
     120             : 
     121          21 : void InputListener::setDedicatedFocus(uint32_t v) {
     122          21 :         _dedicatedFocus = v;
     123          21 : }
     124             : 
     125          21 : void InputListener::setExclusive() {
     126          21 :         if (_scene) {
     127          21 :                 _scene->getDirector()->getInputDispatcher()->setListenerExclusive(this);
     128             :         }
     129          21 : }
     130             : 
     131          52 : void InputListener::setExclusiveForTouch(uint32_t eventId) {
     132          52 :         if (_scene) {
     133          52 :                 _scene->getDirector()->getInputDispatcher()->setListenerExclusiveForTouch(this, eventId);
     134             :         }
     135          52 : }
     136             : 
     137          21 : void InputListener::setSwallowEvents(EventMask &&mask) {
     138          21 :         if (_swallowEvents.any()) {
     139          21 :                 _swallowEvents |= mask;
     140             :         } else {
     141           0 :                 _swallowEvents = move(mask);
     142             :         }
     143          21 : }
     144             : 
     145         367 : void InputListener::setSwallowEvents(const EventMask &mask) {
     146         367 :         if (_swallowEvents.any()) {
     147           0 :                 _swallowEvents |= mask;
     148             :         } else {
     149         367 :                 _swallowEvents = mask;
     150             :         }
     151         367 : }
     152             : 
     153          21 : void InputListener::setSwallowAllEvents() {
     154          21 :         _swallowEvents.set();
     155          21 : }
     156             : 
     157          21 : void InputListener::setSwallowEvent(InputEventName event) {
     158          21 :         _swallowEvents.set(toInt(event));
     159          21 : }
     160             : 
     161          21 : void InputListener::clearSwallowAllEvents() {
     162          21 :         _swallowEvents.reset();
     163          21 : }
     164             : 
     165          21 : void InputListener::clearSwallowEvent(InputEventName event) {
     166          21 :         _swallowEvents.reset(toInt(event));
     167          21 : }
     168             : 
     169          42 : void InputListener::clearSwallowEvents(const EventMask &event) {
     170          42 :         _swallowEvents &= ~event;
     171          42 : }
     172             : 
     173          21 : bool InputListener::isSwallowAllEvents() const {
     174          21 :         return _swallowEvents.all();
     175             : }
     176             : 
     177          21 : bool InputListener::isSwallowAllEvents(const EventMask &event) const {
     178          21 :         return (_swallowEvents & event) == event;
     179             : }
     180             : 
     181          21 : bool InputListener::isSwallowAnyEvents(const EventMask &event) const {
     182          21 :         return (_swallowEvents & event).any();
     183             : }
     184             : 
     185          21 : bool InputListener::isSwallowEvent(InputEventName name) const {
     186          21 :         return _swallowEvents.test(toInt(name));
     187             : }
     188             : 
     189          63 : void InputListener::setTouchFilter(const EventFilter &filter) {
     190          63 :         _eventFilter = filter;
     191          63 : }
     192             : 
     193          48 : bool InputListener::shouldSwallowEvent(const InputEvent &event) const {
     194          48 :         return _swallowEvents.test(toInt(event.data.event));
     195             : }
     196             : 
     197       12953 : bool InputListener::canHandleEvent(const InputEvent &event) const {
     198       12953 :         if (!_running || !_owner) {
     199        2482 :                 return false;
     200             :         }
     201             : 
     202       10471 :         if (_eventMask.test(toInt(event.data.event)) && shouldProcessEvent(event)) {
     203        3544 :                 auto it = _callbacks.find(event.data.event);
     204        3544 :                 if (it != _callbacks.end()) {
     205        3507 :                         return true;
     206             :                 }
     207       11535 :                 for (auto &it : _recognizers) {
     208       11498 :                         if (!_running || !_owner) {
     209             :                                 break;
     210             :                         }
     211             : 
     212       11498 :                         if (it->canHandleEvent(event)) {
     213        3465 :                                 return true;
     214             :                         }
     215             :                 }
     216             :         }
     217        6964 :         return false;
     218             : }
     219             : 
     220        5304 : InputEventState InputListener::handleEvent(const InputEvent &event) {
     221        5304 :         InputEventState ret = InputEventState::Declined;
     222        5304 :         auto it = _callbacks.find(event.data.event);
     223        5304 :         if (it != _callbacks.end()) {
     224          42 :                 ret = std::max(it->second(event.data.getValue()) ? InputEventState::Processed : InputEventState::Declined, ret);
     225             :         }
     226       27369 :         for (auto &it : _recognizers) {
     227       22065 :                 if (!_running || !_owner) {
     228             :                         break;
     229             :                 }
     230             : 
     231       22065 :                 ret = std::max(it->handleInputEvent(event, _density), ret);
     232             :         }
     233        5304 :         return ret;
     234             : }
     235             : 
     236         172 : GestureRecognizer *InputListener::addTouchRecognizer(InputCallback<GestureData> &&cb, ButtonMask &&buttonMask) {
     237         172 :         return addRecognizer(Rc<GestureTouchRecognizer>::create(move(cb), move(buttonMask)));
     238             : }
     239             : 
     240         705 : GestureRecognizer *InputListener::addTapRecognizer(InputCallback<GestureTap> &&cb, ButtonMask &&buttonMask, uint32_t maxTapCount) {
     241         705 :         return addRecognizer(Rc<GestureTapRecognizer>::create(move(cb), move(buttonMask), maxTapCount));
     242             : }
     243             : 
     244         111 : GestureRecognizer *InputListener::addScrollRecognizer(InputCallback<GestureScroll> &&cb) {
     245         111 :         return addRecognizer(Rc<GestureScrollRecognizer>::create(move(cb)));
     246             : }
     247             : 
     248         537 : GestureRecognizer *InputListener::addPressRecognizer(InputCallback<GesturePress> &&cb, TimeInterval interval, bool continuous,
     249             :                 ButtonMask &&mask) {
     250         537 :         return addRecognizer(Rc<GesturePressRecognizer>::create(move(cb), interval, continuous, move(mask)));
     251             : }
     252             : 
     253         153 : GestureRecognizer *InputListener::addSwipeRecognizer(InputCallback<GestureSwipe> &&cb, float threshold, bool sendThreshold, ButtonMask &&mask) {
     254         153 :         return addRecognizer(Rc<GestureSwipeRecognizer>::create(move(cb), threshold, sendThreshold, move(mask)));
     255             : }
     256             : 
     257          21 : GestureRecognizer *InputListener::addPinchRecognizer(InputCallback<GesturePinch> &&cb, ButtonMask &&mask) {
     258          21 :         return addRecognizer(Rc<GesturePinchRecognizer>::create(move(cb), move(mask)));
     259             : }
     260             : 
     261          21 : GestureRecognizer *InputListener::addMoveRecognizer(InputCallback<GestureData> &&cb, bool withinNode) {
     262          21 :         return addRecognizer(Rc<GestureMoveRecognizer>::create(move(cb), withinNode));
     263             : }
     264             : 
     265         447 : GestureRecognizer *InputListener::addMouseOverRecognizer(InputCallback<GestureData> &&cb, float padding) {
     266         447 :         return addRecognizer(Rc<GestureMouseOverRecognizer>::create(move(cb)));
     267             : }
     268             : 
     269         105 : GestureKeyRecognizer *InputListener::addKeyRecognizer(InputCallback<GestureData> &&cb, KeyMask &&keys) {
     270         105 :         return (GestureKeyRecognizer *)addRecognizer(Rc<GestureKeyRecognizer>::create(move(cb), move(keys)));
     271             : }
     272             : 
     273          42 : void InputListener::setPointerEnterCallback(Function<bool(bool)> &&cb) {
     274          42 :         if (cb) {
     275          21 :                 _callbacks.insert_or_assign(InputEventName::PointerEnter, move(cb));
     276          21 :                 _eventMask.set(toInt(InputEventName::PointerEnter));
     277             :         } else {
     278          21 :                 _callbacks.erase(InputEventName::PointerEnter);
     279          21 :                 _eventMask.reset(toInt(InputEventName::PointerEnter));
     280             :         }
     281          42 : }
     282             : 
     283          63 : void InputListener::setBackgroudCallback(Function<bool(bool)> &&cb) {
     284          63 :         if (cb) {
     285          42 :                 _callbacks.insert_or_assign(InputEventName::Background, move(cb));
     286          42 :                 _eventMask.set(toInt(InputEventName::Background));
     287             :         } else {
     288          21 :                 _callbacks.erase(InputEventName::Background);
     289          21 :                 _eventMask.reset(toInt(InputEventName::Background));
     290             :         }
     291          63 : }
     292             : 
     293          42 : void InputListener::setFocusCallback(Function<bool(bool)> &&cb) {
     294          42 :         if (cb) {
     295          21 :                 _callbacks.insert_or_assign(InputEventName::FocusGain, move(cb));
     296          21 :                 _eventMask.set(toInt(InputEventName::FocusGain));
     297             :         } else {
     298          21 :                 _callbacks.erase(InputEventName::FocusGain);
     299          21 :                 _eventMask.reset(toInt(InputEventName::FocusGain));
     300             :         }
     301          42 : }
     302             : 
     303          21 : void InputListener::clear() {
     304          21 :         _eventMask.reset();
     305          21 :         _recognizers.clear();
     306          21 : }
     307             : 
     308        6790 : bool InputListener::shouldProcessEvent(const InputEvent &event) const {
     309        6790 :         if (!_eventFilter) {
     310        6597 :                 return _shouldProcessEvent(event);
     311             :         } else {
     312         193 :                 return _eventFilter(event, std::bind(&InputListener::_shouldProcessEvent, this, event));
     313             :         }
     314             : }
     315             : 
     316        6790 : bool InputListener::_shouldProcessEvent(const InputEvent &event) const {
     317        6790 :         auto node = getOwner();
     318        6790 :         if (node && _running) {
     319        6790 :                 bool visible = node->isVisible();
     320        6790 :                 auto p = node->getParent();
     321       21995 :                 while (visible && p) {
     322       15205 :                         visible = p->isVisible();
     323       15205 :                         p = p->getParent();
     324             :                 }
     325        6790 :                 if (visible && (!event.data.hasLocation() || event.data.event == InputEventName::MouseMove
     326        4847 :                                 || node->isTouched(event.currentLocation, _touchPadding))
     327       13580 :                                 && node->getOpacity() >= _opacityFilter) {
     328        3544 :                         return true;
     329             :                 }
     330             :         }
     331        3246 :         return false;
     332             : }
     333             : 
     334        2272 : void InputListener::addEventMask(const EventMask &mask) {
     335       34080 :         for (size_t i = 0; i < mask.size(); ++ i) {
     336       31808 :                 if (mask.test(i)) {
     337        8245 :                         _eventMask.set(i);
     338             :                 }
     339             :         }
     340        2272 : }
     341             : 
     342        2272 : GestureRecognizer *InputListener::addRecognizer(GestureRecognizer *rec) {
     343        2272 :         addEventMask(rec->getEventMask());
     344        2272 :         auto ret = _recognizers.emplace_back(move(rec)).get();
     345        2272 :         if (_running) {
     346           0 :                 ret->onEnter(this);
     347             :         }
     348        2272 :         return ret;
     349             : }
     350             : 
     351             : }

Generated by: LCOV version 1.14