LCOV - code coverage report
Current view: top level - xenolith/scene/input - XLInputDispatcher.cc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 326 348 93.7 %
Date: 2024-05-12 00:16:13 Functions: 37 37 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 "XLInputDispatcher.h"
      25             : #include "XLInputListener.h"
      26             : 
      27             : namespace STAPPLER_VERSIONIZED stappler::xenolith {
      28             : 
      29         126 : InputListenerStorage::~InputListenerStorage() {
      30          63 :         clear();
      31         126 : }
      32             : 
      33          63 : InputListenerStorage::InputListenerStorage(PoolRef *p) : PoolRef(p) {
      34          63 :         perform([&, this] {
      35          63 :                 _preSceneEvents = new (_pool) memory::vector<Rec>;
      36          63 :                 _sceneEvents = new (_pool) memory::vector<Rec>;
      37          63 :                 _postSceneEvents = new (_pool) memory::vector<Rec>;
      38             : 
      39          63 :                 _sceneEvents->reserve(256);
      40          63 :         });
      41          63 : }
      42             : 
      43        9580 : void InputListenerStorage::clear() {
      44       10399 :         for (auto &it : *_preSceneEvents) {
      45         819 :                 it.listener->release(0);
      46             :         }
      47       32866 :         for (auto &it : *_sceneEvents) {
      48       23286 :                 it.listener->release(0);
      49             :         }
      50       19181 :         for (auto &it : *_postSceneEvents) {
      51        9601 :                 it.listener->release(0);
      52             :         }
      53             : 
      54        9580 :         _preSceneEvents->clear();
      55        9580 :         _sceneEvents->clear();
      56        9580 :         _postSceneEvents->clear();
      57        9580 :         _maxFocusValue = 0;
      58        9580 : }
      59             : 
      60        9517 : void InputListenerStorage::reserve(const InputListenerStorage *st) {
      61        9517 :         _preSceneEvents->reserve(st->_preSceneEvents->size());
      62        9517 :         _sceneEvents->reserve(st->_sceneEvents->size());
      63        9517 :         _postSceneEvents->reserve(st->_postSceneEvents->size());
      64        9517 : }
      65             : 
      66       33706 : void InputListenerStorage::addListener(InputListener *input, uint32_t focus) {
      67       33706 :         input->retain();
      68       33706 :         auto p = input->getPriority();
      69       33706 :         if (p == 0) {
      70       23286 :                 _sceneEvents->emplace_back(Rec{input, focus});
      71       10420 :         } else if (p < 0) {
      72        9601 :                 auto lb = std::lower_bound(_postSceneEvents->begin(), _postSceneEvents->end(), Rec{input, focus},
      73          63 :                                 [] (const Rec &l, const Rec &r) {
      74          63 :                         return l.listener->getPriority() < r.listener->getPriority();
      75        9601 :                 });
      76             : 
      77        9601 :                 if (lb == _postSceneEvents->end()) {
      78        9559 :                         _postSceneEvents->emplace_back(Rec{input, focus});
      79             :                 } else {
      80          42 :                         _postSceneEvents->emplace(lb, Rec{input, focus});
      81             :                 }
      82             :         } else {
      83         819 :                 auto lb = std::lower_bound(_preSceneEvents->begin(), _preSceneEvents->end(), Rec{input, focus},
      84          63 :                                 [] (const Rec &l, const Rec &r) {
      85          63 :                         return l.listener->getPriority() < r.listener->getPriority();
      86         819 :                 });
      87             : 
      88         819 :                 if (lb == _preSceneEvents->end()) {
      89         798 :                         _preSceneEvents->emplace_back(Rec{input, focus});
      90             :                 } else {
      91          21 :                         _preSceneEvents->emplace(lb, Rec{input, focus});
      92             :                 }
      93             :         }
      94       33706 : }
      95             : 
      96       42362 : void InputListenerStorage::updateFocus(uint32_t focusValue) {
      97       42362 :         _maxFocusValue = max(focusValue, _maxFocusValue);
      98       42362 : }
      99             : 
     100          42 : bool InputDispatcher::init(PoolRef *pool, TextInputViewInterface *view) {
     101          42 :         if (view) {
     102          42 :                 _textInput = Rc<TextInputManager>::create(view);
     103             :         }
     104          42 :         _pool = pool;
     105          42 :         return true;
     106             : }
     107             : 
     108        9538 : void InputDispatcher::update(const UpdateTime &time) {
     109        9538 :         _currentTime = time.global;
     110        9538 : }
     111             : 
     112        9559 : Rc<InputListenerStorage> InputDispatcher::acquireNewStorage() {
     113        9559 :         Rc<InputListenerStorage> req;
     114        9559 :         if (_tmpEvents) {
     115        9496 :                 req = move(_tmpEvents);
     116        9496 :                 _tmpEvents = nullptr;
     117             :         } else {
     118          63 :                 req = Rc<InputListenerStorage>::alloc(_pool);
     119             :         }
     120        9559 :         if (_events) {
     121        9517 :                 req->reserve(_events);
     122             :         }
     123        9559 :         return req;
     124           0 : }
     125             : 
     126        9559 : void InputDispatcher::commitStorage(Rc<InputListenerStorage> &&storage) {
     127        9559 :         _tmpEvents = move(_events);
     128        9559 :         _events = move(storage);
     129        9559 :         if (_tmpEvents) {
     130        9517 :                 _tmpEvents->clear();
     131             :         }
     132        9559 : }
     133             : 
     134        5816 : void InputDispatcher::handleInputEvent(const InputEventData &event) {
     135        5816 :         if (!_events) {
     136           0 :                 return;
     137             :         }
     138             : 
     139        5816 :         switch (event.event) {
     140           0 :         case InputEventName::None:
     141             :         case InputEventName::Max:
     142           0 :                 return;
     143             :                 break;
     144         913 :         case InputEventName::Begin: {
     145         913 :                 auto v = _activeEvents.find(event.id);
     146         913 :                 if (v == _activeEvents.end()) {
     147         892 :                         v = _activeEvents.emplace(event.id, EventHandlersInfo{getEventInfo(event), Vector<Rc<InputListener>>()}).first;
     148             :                 } else {
     149          21 :                         v->second.clear(true);
     150          21 :                         v->second.event = getEventInfo(event);
     151             :                 }
     152             : 
     153         913 :                 _events->foreach([&] (const InputListenerStorage::Rec &l) {
     154        6243 :                         if (l.listener->canHandleEvent(v->second.event)) {
     155        1559 :                                 v->second.listeners.emplace_back(l.listener);
     156             :                         }
     157        6243 :                         return true;
     158             :                 }, true);
     159             : 
     160         913 :                 v->second.handle(true);
     161         913 :                 break;
     162             :         }
     163         334 :         case InputEventName::Move: {
     164         334 :                 auto v = _activeEvents.find(event.id);
     165         334 :                 if (v != _activeEvents.end()) {
     166         334 :                         updateEventInfo(v->second.event, event);
     167         334 :                         v->second.handle(true);
     168             :                 }
     169         334 :                 break;
     170             :         }
     171         892 :         case InputEventName::End:
     172             :         case InputEventName::Cancel: {
     173         892 :                 auto v = _activeEvents.find(event.id);
     174         892 :                 if (v != _activeEvents.end()) {
     175         892 :                         updateEventInfo(v->second.event, event);
     176         892 :                         v->second.handle(false);
     177         892 :                         v->second.clear(false);
     178         892 :                         _activeEvents.erase(v);
     179             :                 }
     180         892 :                 break;
     181             :         }
     182        1279 :         case InputEventName::MouseMove: {
     183        1279 :                 _pointerLocation = Vec2(event.x, event.y);
     184             : 
     185        1279 :                 EventHandlersInfo handlers{getEventInfo(event)};
     186        1279 :                 _events->foreach([&] (const InputListenerStorage::Rec &l) {
     187        4433 :                         if (l.listener->canHandleEvent(handlers.event)) {
     188        1793 :                                 handlers.listeners.emplace_back(l.listener);
     189             :                         }
     190        4433 :                         return true;
     191             :                 }, false);
     192             : 
     193        1279 :                 handlers.handle(false);
     194             : 
     195        1321 :                 for (auto &it : _activeEvents) {
     196          42 :                         if ((it.second.event.data.modifiers & InputModifier::Unmanaged) == InputModifier::None) {
     197          42 :                                 it.second.event.data.x = event.x;
     198          42 :                                 it.second.event.data.y = event.y;
     199          42 :                                 it.second.event.data.event = InputEventName::Move;
     200          42 :                                 it.second.event.data.modifiers = event.modifiers;
     201          42 :                                 handleInputEvent(it.second.event.data);
     202             :                         }
     203             :                 }
     204        1279 :                 break;
     205        1279 :         }
     206          26 :         case InputEventName::Scroll: {
     207          26 :                 EventHandlersInfo handlers{getEventInfo(event)};
     208          26 :                 _events->foreach([&] (const InputListenerStorage::Rec &l) {
     209         136 :                         if (l.listener->canHandleEvent(handlers.event)) {
     210           0 :                                 handlers.listeners.emplace_back(l.listener);
     211             :                         }
     212         136 :                         return true;
     213             :                 }, false);
     214          26 :                 handlers.handle(false);
     215          26 :                 break;
     216          26 :         }
     217          84 :         case InputEventName::Background: {
     218          84 :                 _inBackground = event.getValue();
     219             : 
     220          84 :                 EventHandlersInfo handlers{getEventInfo(event)};
     221          84 :                 _events->foreach([&] (const InputListenerStorage::Rec &l) {
     222         420 :                         if (l.listener->canHandleEvent(handlers.event)) {
     223          42 :                                 handlers.listeners.emplace_back(l.listener);
     224             :                         }
     225         420 :                         return true;
     226             :                 }, false);
     227          84 :                 handlers.handle(false);
     228             : 
     229          84 :                 if (handlers.event.data.getValue()) {
     230             :                         // Mouse left window, cancel active mouse events
     231          42 :                         cancelTouchEvents(event.x, event.y, event.modifiers);
     232             :                 }
     233          84 :                 break;
     234          84 :         }
     235          88 :         case InputEventName::FocusGain: {
     236          88 :                 _hasFocus = event.getValue();
     237             : 
     238          88 :                 EventHandlersInfo handlers{getEventInfo(event)};
     239          88 :                 _events->foreach([&] (const InputListenerStorage::Rec &l) {
     240         347 :                         if (l.listener->canHandleEvent(handlers.event)) {
     241          43 :                                 handlers.listeners.emplace_back(l.listener);
     242             :                         }
     243         347 :                         return true;
     244             :                 }, false);
     245          88 :                 handlers.handle(false);
     246             : 
     247          88 :                 if (!handlers.event.data.getValue()) {
     248             :                         // Mouse left window, cancel active mouse events
     249          25 :                         cancelTouchEvents(event.x, event.y, event.modifiers);
     250             :                 }
     251          88 :                 break;
     252          88 :         }
     253         100 :         case InputEventName::PointerEnter: {
     254         100 :                 _pointerInWindow = event.getValue();
     255             : 
     256         100 :                 EventHandlersInfo handlers{getEventInfo(event)};
     257         100 :                 _events->foreach([&] (const InputListenerStorage::Rec &l) {
     258         471 :                         if (l.listener->canHandleEvent(handlers.event)) {
     259          49 :                                 handlers.listeners.emplace_back(l.listener);
     260             :                         }
     261         471 :                         return true;
     262             :                 }, false);
     263             : 
     264         100 :                 handlers.handle(false);
     265             : 
     266         100 :                 if (!handlers.event.data.getValue()) {
     267             :                         // Mouse left window, cancel active mouse events
     268          48 :                         cancelTouchEvents(event.x, event.y, event.modifiers);
     269             :                 }
     270         100 :                 break;
     271         100 :         }
     272         903 :         case InputEventName::KeyPressed: {
     273         903 :                 if (_textInput && _textInput->canHandleInputEvent(event)) {
     274             :                         // forward to text input
     275         777 :                         if (_textInput->handleInputEvent(event)) {
     276         756 :                                 clearKey(event);
     277         756 :                                 return;
     278             :                         }
     279             :                 }
     280             : 
     281         147 :                 auto v = resetKey(event);
     282             : 
     283         147 :                 _events->foreach([&] (const InputListenerStorage::Rec &l) {
     284         903 :                         if (l.listener->canHandleEvent(v->event)) {
     285          21 :                                 v->listeners.emplace_back(l.listener);
     286             :                         }
     287         903 :                         return true;
     288             :                 }, true);
     289         147 :                 v->handle(true);
     290         147 :                 break;
     291             :         }
     292         315 :         case InputEventName::KeyRepeated:
     293         315 :                 if (_textInput && _textInput->canHandleInputEvent(event)) {
     294             :                         // forward to text input
     295         231 :                         if (_textInput->handleInputEvent(event)) {
     296         231 :                                 clearKey(event);
     297         231 :                                 return;
     298             :                         }
     299             :                 }
     300             : 
     301          84 :                 handleKey(event, false);
     302          84 :                 break;
     303             : 
     304         882 :         case InputEventName::KeyReleased:
     305             :         case InputEventName::KeyCanceled:
     306         882 :                 if (_textInput && _textInput->canHandleInputEvent(event)) {
     307             :                         // forward to text input
     308         756 :                         if (_textInput->handleInputEvent(event)) {
     309          21 :                                 clearKey(event);
     310          21 :                                 return;
     311             :                         }
     312             :                 }
     313             : 
     314         861 :                 handleKey(event, true);
     315         861 :                 break;
     316             :         }
     317             : }
     318             : 
     319          21 : Vector<InputEventData> InputDispatcher::getActiveEvents() const {
     320          21 :         Vector<InputEventData> eventsTmp; eventsTmp.reserve(_activeEvents.size());
     321          42 :         for (auto &it : _activeEvents) {
     322          21 :                 eventsTmp.emplace_back(it.second.event.data);
     323             :         }
     324          21 :         return eventsTmp;
     325           0 : }
     326             : 
     327          63 : void InputDispatcher::setListenerExclusive(const InputListener *l) {
     328         105 :         for (auto &it : _activeEvents) {
     329          42 :                 setListenerExclusive(it.second, l);
     330             :         }
     331          84 :         for (auto &it : _activeKeys) {
     332          21 :                 setListenerExclusive(it.second, l);
     333             :         }
     334          63 : }
     335             : 
     336          73 : void InputDispatcher::setListenerExclusiveForTouch(const InputListener *l, uint32_t id) {
     337          73 :         auto it = _activeEvents.find(id);
     338          73 :         if (it != _activeEvents.end()) {
     339          73 :                 setListenerExclusive(it->second, l);
     340             :         }
     341          73 : }
     342             : 
     343          21 : void InputDispatcher::setListenerExclusiveForKey(const InputListener *l, InputKeyCode id) {
     344          21 :         auto it = _activeKeys.find(id);
     345          21 :         if (it != _activeKeys.end()) {
     346          21 :                 setListenerExclusive(it->second, l);
     347             :         }
     348          21 : }
     349             : 
     350          21 : bool InputDispatcher::hasActiveInput() const {
     351          21 :         return !_activeEvents.empty() || !_activeKeys.empty();
     352             : }
     353             : 
     354        2637 : InputEvent InputDispatcher::getEventInfo(const InputEventData &event) const {
     355        2637 :         auto loc = Vec2(event.x, event.y);
     356        2637 :         return InputEvent{event, loc, loc, loc, _currentTime, _currentTime, _currentTime, event.modifiers, event.modifiers};
     357             : }
     358             : 
     359        1436 : void InputDispatcher::updateEventInfo(InputEvent &event, const InputEventData &data) const {
     360        1436 :         event.previousLocation = event.currentLocation;
     361        1436 :         event.currentLocation = Vec2(data.x, data.y);
     362             : 
     363        1436 :         event.previousTime = event.currentTime;
     364        1436 :         event.currentTime = _currentTime;
     365             : 
     366        1436 :         event.previousModifiers = event.data.modifiers;
     367             : 
     368        1436 :         event.data.event = data.event;
     369        1436 :         event.data.x = data.x;
     370        1436 :         event.data.y = data.y;
     371        1436 :         event.data.button = data.button;
     372        1436 :         event.data.modifiers = data.modifiers;
     373             : 
     374        1436 :         if (event.data.isPointEvent()) {
     375        1226 :                 event.data.point.valueX = data.point.valueX;
     376        1226 :                 event.data.point.valueY = data.point.valueY;
     377        1226 :                 event.data.point.density = data.point.density;
     378         210 :         } else if (event.data.isKeyEvent()) {
     379         189 :                 event.data.key.keychar = data.key.keychar;
     380         189 :                 event.data.key.keycode = data.key.keycode;
     381         189 :                 event.data.key.keysym = data.key.keysym;
     382             :         }
     383        1436 : }
     384             : 
     385        4115 : void InputDispatcher::EventHandlersInfo::handle(bool removeOnFail) {
     386        4115 :         processed.clear();
     387        4115 :         if (exclusive) {
     388         277 :                 processed.emplace_back(exclusive.get());
     389         277 :                 auto res = exclusive->handleEvent(event);
     390         277 :                 if (res == InputEventState::Declined) {
     391           0 :                         exclusive = nullptr;
     392             :                 }
     393             :         } else {
     394        3838 :                 Vector<Rc<InputListener>> listenerToRemove;
     395        3838 :                 auto vec = listeners;
     396        8692 :                 for (auto &it : vec) {
     397        4927 :                         processed.emplace_back(it.get());
     398        4927 :                         auto res = it->handleEvent(event);
     399        4927 :                         if (res == InputEventState::Captured && !exclusive && it->shouldSwallowEvent(event)) {
     400           6 :                                 setExclusive(it);
     401             :                         }
     402             : 
     403        4927 :                         if (exclusive) {
     404          73 :                                 if (std::find(processed.begin(), processed.end(), exclusive.get()) == processed.end()) {
     405           0 :                                         auto res = exclusive->handleEvent(event);
     406           0 :                                         if (res == InputEventState::Declined) {
     407           0 :                                                 exclusive = nullptr;
     408             :                                         }
     409             :                                 }
     410          73 :                                 break;
     411             :                         }
     412             : 
     413        4854 :                         if (removeOnFail && res == InputEventState::Declined) {
     414           0 :                                 listenerToRemove.emplace_back(it);
     415             :                         }
     416             :                 }
     417             : 
     418        3838 :                 for (auto &it : listenerToRemove) {
     419           0 :                         auto iit = std::find(listeners.begin(), listeners.end(), it);
     420           0 :                         if (iit != listeners.end()) {
     421           0 :                                 listeners.erase(iit);
     422             :                         }
     423             :                 }
     424        3838 :         }
     425        4115 :         processed.clear();
     426        4115 : }
     427             : 
     428        1060 : void InputDispatcher::EventHandlersInfo::clear(bool cancel) {
     429        1060 :         if (cancel) {
     430          42 :                 event.data.event = isKeyEvent ? InputEventName::KeyCanceled : InputEventName::Cancel;
     431          42 :                 handle(false);
     432             :         }
     433             : 
     434        1060 :         listeners.clear();
     435        1060 :         exclusive = nullptr;
     436        1060 : }
     437             : 
     438         163 : void InputDispatcher::EventHandlersInfo::setExclusive(const InputListener *l) {
     439         163 :         if (exclusive) {
     440           6 :                 return;
     441             :         }
     442             : 
     443         157 :         auto v = std::find(listeners.begin(), listeners.end(), l);
     444         157 :         if (v != listeners.end()) {
     445          73 :                 exclusive = *v;
     446             : 
     447          73 :                 auto event = this->event;
     448          73 :                 event.data.event = isKeyEvent ? InputEventName::KeyCanceled : InputEventName::Cancel;
     449         246 :                 for (auto &iit : listeners) {
     450         173 :                         if (iit.get() != l) {
     451         100 :                                 iit->handleEvent(event);
     452             :                         }
     453             :                 }
     454          73 :                 listeners.clear();
     455             :         }
     456             : }
     457             : 
     458         157 : void InputDispatcher::setListenerExclusive(EventHandlersInfo &info, const InputListener *l) const {
     459         157 :         info.setExclusive(l);
     460         157 : }
     461             : 
     462        1008 : void InputDispatcher::clearKey(const InputEventData &event) {
     463        1008 :         if (event.key.keycode == InputKeyCode::Unknown) {
     464           0 :                 auto v = _activeKeySyms.find(event.key.keysym);
     465           0 :                 if (v != _activeKeySyms.end()) {
     466           0 :                         v->second.clear(true);
     467           0 :                         _activeKeySyms.erase(v);
     468             :                 }
     469             :         } else {
     470        1008 :                 auto v = _activeKeys.find(event.key.keycode);
     471        1008 :                 if (v != _activeKeys.end()) {
     472           0 :                         v->second.clear(true);
     473           0 :                         _activeKeys.erase(v);
     474             :                 }
     475             :         }
     476        1008 : }
     477             : 
     478         147 : InputDispatcher::EventHandlersInfo *InputDispatcher::resetKey(const InputEventData &event) {
     479         147 :         if (event.key.keycode == InputKeyCode::Unknown) {
     480          63 :                 auto v = _activeKeySyms.find(event.key.keysym);
     481          63 :                 if (v == _activeKeySyms.end()) {
     482          42 :                         v = _activeKeySyms.emplace(event.key.keysym, EventHandlersInfo{getEventInfo(event), Vector<Rc<InputListener>>()}).first;
     483             :                 } else {
     484          21 :                         v->second.clear(true);
     485          21 :                         v->second.event = getEventInfo(event);
     486             :                 }
     487          63 :                 v->second.isKeyEvent = true;
     488          63 :                 return &v->second;
     489             :         } else {
     490          84 :                 auto v = _activeKeys.find(event.key.keycode);
     491          84 :                 if (v == _activeKeys.end()) {
     492          84 :                         v = _activeKeys.emplace(event.key.keycode, EventHandlersInfo{getEventInfo(event), Vector<Rc<InputListener>>()}).first;
     493             :                 } else {
     494           0 :                         v->second.clear(true);
     495           0 :                         v->second.event = getEventInfo(event);
     496             :                 }
     497          84 :                 v->second.isKeyEvent = true;
     498          84 :                 return &v->second;
     499             :         }
     500             : }
     501             : 
     502         945 : void InputDispatcher::handleKey(const InputEventData &event, bool clear) {
     503         945 :         if (event.key.keycode == InputKeyCode::Unknown) {
     504          84 :                 auto v = _activeKeySyms.find(event.key.keysym);
     505          84 :                 if (v != _activeKeySyms.end()) {
     506          84 :                         updateEventInfo(v->second.event, event);
     507          84 :                         v->second.handle(!clear);
     508          84 :                         if (clear) {
     509          42 :                                 v->second.clear(false);
     510          42 :                                 _activeKeySyms.erase(v);
     511             :                         }
     512             :                 }
     513             :         } else {
     514         861 :                 auto v = _activeKeys.find(event.key.keycode);
     515         861 :                 if (v != _activeKeys.end()) {
     516         126 :                         updateEventInfo(v->second.event, event);
     517         126 :                         v->second.handle(!clear);
     518         126 :                         if (clear) {
     519          84 :                                 v->second.clear(false);
     520          84 :                                 _activeKeys.erase(v);
     521             :                         }
     522             :                 }
     523             :         }
     524         945 : }
     525             : 
     526         115 : void InputDispatcher::cancelTouchEvents(float x, float y, InputModifier mods) {
     527         115 :         auto tmpEvents = _activeEvents;
     528         136 :         for (auto &it : tmpEvents) {
     529          21 :                 it.second.event.data.x = x;
     530          21 :                 it.second.event.data.y = y;
     531          21 :                 it.second.event.data.event = InputEventName::Cancel;
     532          21 :                 it.second.event.data.modifiers = mods;
     533          21 :                 handleInputEvent(it.second.event.data);
     534             :         }
     535         115 :         _activeEvents.clear();
     536         115 : }
     537             : 
     538             : }

Generated by: LCOV version 1.14