/** * @author Edouard DUPIN * * @copyright 2011, Edouard DUPIN, all right reserved * * @license APACHE v2.0 (see license file) */ #include #include #include #include #include #include #include #include #include #include #include #include #define EVENT_DEBUG EWOL_VERBOSE //#define EVENT_DEBUG EWOL_DEBUG void ewol::context::InputManager::calculateLimit() { m_eventInputLimit.sepatateTime = 300000; // µs m_eventInputLimit.DpiOffset = m_dpi*100; m_eventMouseLimit.sepatateTime = 300000; // µs m_eventMouseLimit.DpiOffset = (float)m_dpi*(float)0.1; } void ewol::context::InputManager::setDpi(int32_t newDPI) { m_dpi = newDPI; // recalculate the DPI system ... calculateLimit(); } bool ewol::context::InputManager::localEventInput(enum gale::key::type _type, std::shared_ptr _destWidget, int32_t _IdInput, enum gale::key::status _status, vec2 _pos) { if (nullptr != _destWidget) { if (_type == gale::key::type_mouse || _type == gale::key::type_finger) { // create the system Event : ewol::event::InputSystem tmpEventSystem(_type, _status, _IdInput, _pos, _destWidget, 0, m_specialKey); // TODO : set the real ID ... // generate the event : return _destWidget->systemEventInput(tmpEventSystem); } else { return false; } } return false; } void ewol::context::InputManager::abortElement(InputPoperty *_eventTable, int32_t _idInput, enum gale::key::type _type) { if (nullptr == _eventTable) { return; } if (_eventTable[_idInput].isUsed == true) { localEventInput(_type, _eventTable[_idInput].curentWidgetEvent.lock(), _eventTable[_idInput].destinationInputId, gale::key::status_abort, _eventTable[_idInput].posEvent); } } void ewol::context::InputManager::cleanElement(InputPoperty *_eventTable, int32_t _idInput) { if (nullptr == _eventTable) { return; } //EWOL_INFO("CleanElement[" << idInput << "] = @" << (int64_t)eventTable); _eventTable[_idInput].isUsed = false; _eventTable[_idInput].destinationInputId = 0; _eventTable[_idInput].lastTimeEvent = 0; _eventTable[_idInput].curentWidgetEvent.reset(); _eventTable[_idInput].origin.setValue(0,0); _eventTable[_idInput].size.setValue(99999999,99999999); _eventTable[_idInput].downStart.setValue(0,0); _eventTable[_idInput].isDown = false; _eventTable[_idInput].isInside = false; _eventTable[_idInput].nbClickEvent = 0; _eventTable[_idInput].posEvent.setValue(0,0); } void ewol::context::InputManager::transfertEvent(std::shared_ptr _source, std::shared_ptr _destination) { if( _source == nullptr || _destination == nullptr) { // prevent errors ... return; } for(int32_t iii=0; iii tmpWidget = m_eventInputSaved[iii].curentWidgetEvent.lock(); if (tmpWidget == _source) { // inform the widget that it does not receive the event now EVENT_DEBUG("GUI : Input ID=" << iii << " == >" << m_eventInputSaved[iii].destinationInputId << " [EVENT_INPUT_TYPE_ABORT] " << m_eventInputSaved[iii].posEvent); localEventInput(gale::key::type_finger, tmpWidget, m_eventInputSaved[iii].destinationInputId, gale::key::status_abort, m_eventInputSaved[iii].posEvent); // set the new widget ... m_eventInputSaved[iii].curentWidgetEvent = _destination; // inform the widget that he receive the event property now... EVENT_DEBUG("GUI : Input ID=" << iii << " == >" << m_eventInputSaved[iii].destinationInputId << " [EVENT_INPUT_TYPE_TRANSFERT] " << m_eventInputSaved[iii].posEvent); localEventInput(gale::key::type_finger, _destination, m_eventInputSaved[iii].destinationInputId, gale::key::status_transfert, m_eventInputSaved[iii].posEvent); } tmpWidget = m_eventMouseSaved[iii].curentWidgetEvent.lock(); if (tmpWidget == _source) { // inform the widget that it does not receive the event now EVENT_DEBUG("GUI : Input ID=" << iii << " == >" << m_eventMouseSaved[iii].destinationInputId << " [EVENT_INPUT_TYPE_ABORT] " << m_eventMouseSaved[iii].posEvent); localEventInput(gale::key::type_mouse, tmpWidget, m_eventMouseSaved[iii].destinationInputId, gale::key::status_abort, m_eventMouseSaved[iii].posEvent); // set the new widget ... m_eventMouseSaved[iii].curentWidgetEvent = _destination; // inform the widget that he receive the event property now... EVENT_DEBUG("GUI : Input ID=" << iii << " == >" << m_eventMouseSaved[iii].destinationInputId << " [EVENT_INPUT_TYPE_TRANSFERT] " << m_eventMouseSaved[iii].posEvent); localEventInput(gale::key::type_mouse, _destination, m_eventMouseSaved[iii].destinationInputId, gale::key::status_transfert, m_eventMouseSaved[iii].posEvent); } } } void ewol::context::InputManager::grabPointer(std::shared_ptr _widget) { if(_widget == nullptr) { return; } m_grabWidget = _widget; /* TODO : m_context.grabPointerEvents(true, _widget->getOrigin() + ivec2(_widget->getSize().x()/2.0f, _widget->getSize().y()/2.0f) ); */ } void ewol::context::InputManager::unGrabPointer() { m_grabWidget.reset(); // TODO: m_context.grabPointerEvents(false, vec2(0,0)); } void ewol::context::InputManager::newLayerSet() { for(int32_t iii=0; iii _destWidget, int32_t _realInputId) { if (_type == gale::key::type_finger) { int32_t lastMinimum = 0; for(int32_t iii=0; iii tmpWidget = m_eventInputSaved[iii].curentWidgetEvent.lock(); if (tmpWidget == _destWidget) { if (iii != _realInputId) { lastMinimum = std::max(lastMinimum, m_eventInputSaved[iii].destinationInputId); } } } } return lastMinimum+1; } return _realInputId; } // note if id<0 == > the it was finger event ... void ewol::context::InputManager::motion(enum gale::key::type _type, int _pointerID, vec2 _pos) { EVENT_DEBUG("motion event : " << _type << " " << _pointerID << " " << _pos); if (MAX_MANAGE_INPUT <= _pointerID) { // reject pointer == > out of IDs... return; } InputPoperty *eventTable = nullptr; if (_type == gale::key::type_mouse) { eventTable = m_eventMouseSaved; } else if (_type == gale::key::type_finger) { eventTable = m_eventInputSaved; } else { EWOL_ERROR("Unknown type of event"); return; } if( _pointerID > MAX_MANAGE_INPUT || _pointerID < 0) { // not manage input return; } std::shared_ptr tmpWindows = m_context.getWindows(); // special case for the mouse event 0 that represent the hover event of the system : if (_type == gale::key::type_mouse && _pointerID == 0) { // this event is all time on the good widget ... and manage the enter and leave ... // NOTE : the "layer widget" force us to get the widget at the specific position all the time : std::shared_ptr tmpWidget; if (m_grabWidget.lock() != nullptr) { // grab all events ... tmpWidget = m_grabWidget.lock(); } else { if (nullptr != tmpWindows) { tmpWidget = tmpWindows->getWidgetAtPos(_pos); } } if( tmpWidget != eventTable[_pointerID].curentWidgetEvent.lock() || ( true == eventTable[_pointerID].isInside && ( eventTable[_pointerID].origin.x() > _pos.x() || eventTable[_pointerID].origin.y() > _pos.y() || (eventTable[_pointerID].origin.x() + eventTable[_pointerID].size.x()) < _pos.x() || (eventTable[_pointerID].origin.y() + eventTable[_pointerID].size.y()) < _pos.y()) ) ) { eventTable[_pointerID].isInside = false; EVENT_DEBUG("GUI : Input ID=" << _pointerID << " == >" << eventTable[_pointerID].destinationInputId << " [LEAVE] " << _pos); eventTable[_pointerID].posEvent = _pos; localEventInput(_type, eventTable[_pointerID].curentWidgetEvent.lock(), eventTable[_pointerID].destinationInputId, gale::key::status_leave, _pos); } if (eventTable[_pointerID].isInside == false) { // set the element inside ... eventTable[_pointerID].isInside = true; // get destination widget : eventTable[_pointerID].curentWidgetEvent = tmpWidget; if (tmpWidget == nullptr) { eventTable[_pointerID].isInside = false; } else { eventTable[_pointerID].origin = tmpWidget->getOrigin(); eventTable[_pointerID].size = tmpWidget->getSize(); } eventTable[_pointerID].destinationInputId = 0; EVENT_DEBUG("GUI : Input ID=" << _pointerID << " == >" << eventTable[_pointerID].destinationInputId << " [ENTER] " << _pos); eventTable[_pointerID].posEvent = _pos; localEventInput(_type, tmpWidget, eventTable[_pointerID].destinationInputId, gale::key::status_enter, _pos); } EVENT_DEBUG("GUI : Input ID=" << _pointerID << " == >" << eventTable[_pointerID].destinationInputId << " [MOVE] " << _pos); eventTable[_pointerID].posEvent = _pos; localEventInput(_type, tmpWidget, eventTable[_pointerID].destinationInputId, gale::key::status_move, _pos); } else if (true == eventTable[_pointerID].isUsed) { if (true == eventTable[_pointerID].isInside) { if( eventTable[_pointerID].origin.x() > _pos.x() || eventTable[_pointerID].origin.y() > _pos.y() || (eventTable[_pointerID].origin.x() + eventTable[_pointerID].size.x()) < _pos.x() || (eventTable[_pointerID].origin.y() + eventTable[_pointerID].size.y()) < _pos.y()) { eventTable[_pointerID].isInside = false; EVENT_DEBUG("GUI : Input ID=" << _pointerID << " == >" << eventTable[_pointerID].destinationInputId << " [LEAVE] " << _pos); eventTable[_pointerID].posEvent = _pos; localEventInput(_type, eventTable[_pointerID].curentWidgetEvent.lock(), eventTable[_pointerID].destinationInputId, gale::key::status_leave, _pos); } } else { if( ( eventTable[_pointerID].origin.x() <= _pos.x() && (eventTable[_pointerID].origin.x() + eventTable[_pointerID].size.x()) >= _pos.x() ) && ( eventTable[_pointerID].origin.y() <= _pos.y() && (eventTable[_pointerID].origin.y() + eventTable[_pointerID].size.y()) >= _pos.y() ) ) { eventTable[_pointerID].isInside = true; EVENT_DEBUG("GUI : Input ID=" << _pointerID << " == >" << eventTable[_pointerID].destinationInputId << " [ENTER] " << _pos); eventTable[_pointerID].posEvent = _pos; localEventInput(_type, eventTable[_pointerID].curentWidgetEvent.lock(), eventTable[_pointerID].destinationInputId, gale::key::status_enter, _pos); } } EVENT_DEBUG("GUI : Input ID=" << _pointerID << " == >" << eventTable[_pointerID].destinationInputId << " [MOVE] " << _pos); eventTable[_pointerID].posEvent = _pos; localEventInput(_type, eventTable[_pointerID].curentWidgetEvent.lock(), eventTable[_pointerID].destinationInputId, gale::key::status_move, _pos); } } void ewol::context::InputManager::state(enum gale::key::type _type, int _pointerID, bool _isDown, vec2 _pos) { if (MAX_MANAGE_INPUT <= _pointerID) { // reject pointer == > out of IDs... return; } EVENT_DEBUG("event pointerId=" << _pointerID); // convert position in open-GL coordonates ... InputPoperty *eventTable = nullptr; InputLimit localLimit; if (_type == gale::key::type_mouse) { eventTable = m_eventMouseSaved; localLimit = m_eventMouseLimit; } else if (_type == gale::key::type_finger) { eventTable = m_eventInputSaved; localLimit = m_eventInputLimit; } else { EWOL_ERROR("Unknown type of event"); return; } if( _pointerID > MAX_MANAGE_INPUT || _pointerID <= 0) { // not manage input return; } // get the curent time ... int64_t currentTime = ewol::getTime(); std::shared_ptr tmpWindows = m_context.getWindows(); if (true == _isDown) { EVENT_DEBUG("GUI : Input ID=" << _pointerID << " == >" << eventTable[_pointerID].destinationInputId << " [DOWN] " << _pos); if(true == eventTable[_pointerID].isUsed) { // we have an event previously ... check delay between click and offset position if (currentTime - eventTable[_pointerID].lastTimeEvent > localLimit.sepatateTime) { cleanElement(eventTable, _pointerID); } else if( abs(eventTable[_pointerID].downStart.x() - _pos.x()) >= localLimit.DpiOffset || abs(eventTable[_pointerID].downStart.y() - _pos.y()) >= localLimit.DpiOffset ){ cleanElement(eventTable, _pointerID); } } if(true == eventTable[_pointerID].isUsed) { // save start time eventTable[_pointerID].lastTimeEvent = currentTime; // generate DOWN Event EVENT_DEBUG("GUI : Input ID=" << _pointerID << " == >" << eventTable[_pointerID].destinationInputId << " [DOWN] " << _pos); eventTable[_pointerID].posEvent = _pos; localEventInput(_type, eventTable[_pointerID].curentWidgetEvent.lock(), eventTable[_pointerID].destinationInputId, gale::key::status_down, _pos); } else { // Mark it used : eventTable[_pointerID].isUsed = true; // Save current position : eventTable[_pointerID].downStart = _pos; // save start time eventTable[_pointerID].lastTimeEvent = currentTime; // set the element inside ... eventTable[_pointerID].isInside = true; std::shared_ptr tmpWidget = m_grabWidget.lock(); // get destination widget : if(nullptr != tmpWindows) { if ( tmpWidget != nullptr && _type == gale::key::type_mouse) { eventTable[_pointerID].curentWidgetEvent = tmpWidget; } else { eventTable[_pointerID].curentWidgetEvent = tmpWindows->getWidgetAtPos(_pos); } } else { eventTable[_pointerID].curentWidgetEvent.reset(); } tmpWidget = eventTable[_pointerID].curentWidgetEvent.lock(); if (tmpWidget != nullptr) { eventTable[_pointerID].origin = tmpWidget->getOrigin(); eventTable[_pointerID].size = tmpWidget->getSize(); eventTable[_pointerID].destinationInputId = localGetDestinationId(_type, tmpWidget, _pointerID); } else { eventTable[_pointerID].destinationInputId = -1; } // generate DOWN Event EVENT_DEBUG("GUI : Input ID=" << _pointerID << " == >" << eventTable[_pointerID].destinationInputId << " [DOWN] " << _pos); eventTable[_pointerID].posEvent = _pos; localEventInput(_type, tmpWidget, eventTable[_pointerID].destinationInputId, gale::key::status_down, _pos); } } else { EVENT_DEBUG("GUI : Input ID=" << _pointerID << " == >" << eventTable[_pointerID].destinationInputId << " [UP] " << _pos); if(false == eventTable[_pointerID].isUsed) { // bad case ... ??? EWOL_DEBUG("Up event without previous down ... "); // Mark it un-used : eventTable[_pointerID].isUsed = false; // revove the widget ... eventTable[_pointerID].curentWidgetEvent.reset(); } else { std::shared_ptr tmpWidget = eventTable[_pointerID].curentWidgetEvent.lock(); // generate UP Event EVENT_DEBUG("GUI : Input ID=" << _pointerID << " == >" << eventTable[_pointerID].destinationInputId << " [UP] " << _pos); eventTable[_pointerID].posEvent = _pos; // send up event after the single event to prevent multiple widget getting elements localEventInput(_type, tmpWidget, _pointerID, gale::key::status_up, _pos); // generate event (single) if( abs(eventTable[_pointerID].downStart.x() - _pos.x()) < localLimit.DpiOffset && abs(eventTable[_pointerID].downStart.y() - _pos.y()) < localLimit.DpiOffset ){ // Save current position : eventTable[_pointerID].downStart = _pos; // save start time eventTable[_pointerID].lastTimeEvent = currentTime; int32_t nbClickMax = 0; if(tmpWidget != nullptr) { nbClickMax = tmpWidget->getMouseLimit(); if (nbClickMax>5) { nbClickMax = 5; } } // in grab mode the single to quinte event are not generated .... if( ( m_grabWidget.lock() == nullptr || _type != gale::key::type_mouse ) && eventTable[_pointerID].nbClickEvent < nbClickMax) { // generate event SINGLE : eventTable[_pointerID].nbClickEvent++; EVENT_DEBUG("GUI : Input ID=" << _pointerID << " == >" << eventTable[_pointerID].destinationInputId << " [" << eventTable[_pointerID].nbClickEvent << "] " << _pos); eventTable[_pointerID].posEvent = _pos; localEventInput(_type, tmpWidget, eventTable[_pointerID].destinationInputId, (enum gale::key::status)(gale::key::status_single + eventTable[_pointerID].nbClickEvent-1), _pos); if( eventTable[_pointerID].nbClickEvent >= nbClickMax) { eventTable[_pointerID].nbClickEvent = 0; } } else { eventTable[_pointerID].nbClickEvent = 0; } } // send up event after the single event to prevent multiple widget getting elements localEventInput(_type, tmpWidget, _pointerID, gale::key::status_upAfter, _pos); // specific for tuch event if (_type == gale::key::type_finger) { cleanElement(eventTable, _pointerID); } } } }