Example #1
0
    int64_t CreateMappingExecutionNode::execute()
    {
        if(_tableName.substr(0, 7) == "SYSTEM_") {
            CSVSQLDB_THROW(CreateMappingException, "cant add mapping for system tables");
        }

        {
            std::ofstream mappingFile((_database.mappingPath() / _tableName).string());
            if(!mappingFile.good()) {
                CSVSQLDB_THROW(CreateMappingException, "cant open mapping file");
            }

            for(auto& mapping : _mappings) {
                mapping._mapping = mapping._mapping + "->" + _tableName;
            }

            mappingFile << FileMapping::asJson(_tableName, _mappings);
            mappingFile.close();
        }

        std::ifstream mappingFile((_database.mappingPath() / _tableName).string());
        if(!mappingFile.good()) {
            CSVSQLDB_THROW(CreateMappingException, "cant open mapping file");
        }

        _database.addMapping(FileMapping::fromJson(mappingFile));

        mappingFile.close();

        return 0;
    }
bool CategoryParser::parse(const QString &fileName)
{
    m_exploreObject = QJsonObject();
    m_tree.clear();
    m_errorString.clear();

    QFile mappingFile(fileName);

    if (mappingFile.open(QIODevice::ReadOnly)) {
        QJsonDocument document = QJsonDocument::fromJson(mappingFile.readAll());
        if (document.isObject()) {
            QJsonObject docObject = document.object();
            if (docObject.contains(QLatin1String("offline_explore"))) {
                m_exploreObject = docObject.value(QLatin1String("offline_explore"))
                                                .toObject();
                if (m_exploreObject.contains(QLatin1String("ROOT"))) {
                    processCategory(0, QString());
                    return true;
                }
            } else {
                m_errorString = fileName + QLatin1String("does not contain the "
                                                       "offline_explore property");
                return false;
            }
        } else {
            m_errorString = fileName + QLatin1String("is not an json object");
            return false;
        }
    }
    m_errorString = QString::fromLatin1("Unable to open ") + fileName;
    return false;
}
Example #3
0
    int64_t DropMappingExecutionNode::execute()
    {
        if(_tableName.substr(0, 7) == "SYSTEM_") {
            CSVSQLDB_THROW(DropMappingException, "cant drop mapping for system tables");
        }

        fs::path mappingFile(_database.mappingPath() / _tableName);
        if(!fs::exists(mappingFile)) {
            CSVSQLDB_THROW(DropMappingException, "mapping file does not exist");
        }

        boost::system::error_code ec;
        fs::remove(mappingFile, ec);
        if(ec) {
            CSVSQLDB_THROW(DropMappingException, "could not remove mapping file (" << ec.message() << ")");
        }

        _database.removeMapping(_tableName);

        return 0;
    }
Example #4
0
void Remapper::dataIn( Node::DataType type, QMutex *mutex, void *data, size_t bytes, qint64 timeStamp ) {
    switch( type ) {
        case DataType::Input: {
            // Copy incoming data to our own buffer
            GamepadState gamepad;
            {
                mutex->lock();
                gamepad = *reinterpret_cast<GamepadState *>( data );
                mutex->unlock();
            }

            int instanceID = gamepad.instanceID;
            int joystickID = gamepad.joystickID;
            QString GUID( QByteArray( reinterpret_cast<const char *>( gamepad.GUID.data ), 16 ).toHex() );

            // Do initial calibration if not done yet
            {
                if( deadzoneFlag[ GUID ] ) {
                    deadzoneFlag[ GUID ] = false;

                    // Apply default value
                    for( int i = 0; i < gamepad.joystickNumAxes; i++ ) {
                        deadzones[ GUID ][ i ] = 10000;

                        // Check analog value at this moment. If its magnitude is less than 30000 then it's most likely
                        // an analog stick. Otherwise, it might be a trigger (with a centered value of -32768)
                        deadzoneModes[ GUID ][ i ] = ( qAbs( static_cast<int>( gamepad.joystickAxis[ i ] ) ) < 30000 );
                    }

                    // TODO: Replace with stored value from disk
                }
            }

            // Inject deadzone settings into gamepad
            {
                for( int i = 0; i < gamepad.joystickNumAxes; i++ ) {
                    gamepad.deadzone[ i ] = deadzones[ GUID ][ i ];
                    gamepad.deadzoneMode[ i ] = deadzoneModes[ GUID ][ i ];
                }
            }

            // Send raw joystick data to the model
            // Do this before we apply joystick deadzones so the user sees completely unprocessed data
            {
                // Copy current gamepad into buffer
                this->mutex.lock();
                gamepadBuffer[ gamepadBufferIndex ] = gamepad;
                this->mutex.unlock();

                // Send buffer on its way
                emit rawJoystickData( &( this->mutex ), reinterpret_cast<void *>( &gamepadBuffer[ gamepadBufferIndex ] ) );

                // Increment the index
                gamepadBufferIndex = ( gamepadBufferIndex + 1 ) % 100;
            }

            // Apply deadzones to each stick and both triggers independently
            {
                qreal deadzone = 0.0;
                bool deadzoneMode = false;

                for( int i = 0; i < 4; i++ ) {
                    int xAxis;
                    int yAxis;

                    // For the analog sticks, average the underlying joystick axes together to get the final deadzone value
                    // If either axis has deadzone mode set to true, it'll apply to both
                    // FIXME: If users complain about this, expand the code to handle this case (one axis true and one axis false) and treat axes indepenently
                    switch( i ) {
                        case 0: {
                            xAxis = SDL_CONTROLLER_AXIS_LEFTX;
                            yAxis = SDL_CONTROLLER_AXIS_LEFTY;

                            Val val = gameControllerToJoystick[ GUID ][ Key( AXIS, SDL_CONTROLLER_AXIS_LEFTX ) ];
                            int axisID = val.second.first;

                            if( val.first == AXIS ) {
                                deadzone = deadzones[ GUID ][ axisID ];
                                deadzoneMode = deadzoneModes[ GUID ][ axisID ];
                            }

                            Val val2 = gameControllerToJoystick[ GUID ][ Key( AXIS, SDL_CONTROLLER_AXIS_LEFTY ) ];
                            axisID = val2.second.first;

                            if( val2.first == AXIS ) {
                                deadzone += deadzones[ GUID ][ axisID ];
                                deadzone /= 2.0;
                                deadzoneMode = deadzoneMode || deadzoneModes[ GUID ][ axisID ];
                            }

                            break;
                        }

                        case 1: {
                            xAxis = SDL_CONTROLLER_AXIS_RIGHTX;
                            yAxis = SDL_CONTROLLER_AXIS_RIGHTY;

                            Val val = gameControllerToJoystick[ GUID ][ Key( AXIS, SDL_CONTROLLER_AXIS_RIGHTX ) ];
                            int axisID = val.second.first;

                            if( val.first == AXIS ) {
                                deadzone = deadzones[ GUID ][ axisID ];
                                deadzoneMode = deadzoneModes[ GUID ][ axisID ];
                            }

                            Val val2 = gameControllerToJoystick[ GUID ][ Key( AXIS, SDL_CONTROLLER_AXIS_RIGHTY ) ];
                            axisID = val2.second.first;

                            if( val2.first == AXIS ) {
                                deadzone += deadzones[ GUID ][ axisID ];
                                deadzone /= 2.0;
                                deadzoneMode = deadzoneMode || deadzoneModes[ GUID ][ axisID ];
                            }

                            break;
                        }

                        // For simplicity, just map the triggers to the line y = x
                        case 2: {
                            xAxis = SDL_CONTROLLER_AXIS_TRIGGERLEFT;
                            yAxis = SDL_CONTROLLER_AXIS_TRIGGERLEFT;
                            Val val = gameControllerToJoystick[ GUID ][ Key( AXIS, SDL_CONTROLLER_AXIS_TRIGGERLEFT ) ];
                            int axisID = val.second.first;

                            if( val.first == AXIS ) {
                                deadzone = deadzones[ GUID ][ axisID ];
                                deadzoneMode = deadzoneModes[ GUID ][ axisID ];
                            }

                            break;
                        }

                        case 3: {
                            xAxis = SDL_CONTROLLER_AXIS_TRIGGERRIGHT;
                            yAxis = SDL_CONTROLLER_AXIS_TRIGGERRIGHT;
                            Val val = gameControllerToJoystick[ GUID ][ Key( AXIS, SDL_CONTROLLER_AXIS_TRIGGERRIGHT ) ];
                            int axisID = val.second.first;

                            if( val.first == AXIS ) {
                                deadzone = deadzones[ GUID ][ axisID ];
                                deadzoneMode = deadzoneModes[ GUID ][ axisID ];
                            }

                            break;
                        }
                    }

                    // Map from [-32768, 32767] to [0, 32767]
                    if( !deadzoneMode ) {
                        gamepad.axis[ xAxis ] /= 2;
                        gamepad.axis[ yAxis ] /= 2;
                        gamepad.axis[ xAxis ] += 16384;
                        gamepad.axis[ yAxis ] += 16384;
                    }

                    // Get axis coords in cartesian coords
                    // Bottom right is positive -> top right is positive
                    qreal xCoord = gamepad.axis[ xAxis ];
                    qreal yCoord = -gamepad.axis[ yAxis ];

                    // Get radius from center
                    QVector2D position( static_cast<float>( xCoord ), static_cast<float>( yCoord ) );
                    qreal radius = static_cast<qreal>( position.length() );

                    if( !( radius > deadzone ) ) {
                        gamepad.axis[ xAxis ] = 0;
                        gamepad.axis[ yAxis ] = 0;

                        if( xAxis == SDL_CONTROLLER_AXIS_TRIGGERLEFT ) {
                            gamepad.digitalL2 = false;
                        }

                        if( xAxis == SDL_CONTROLLER_AXIS_TRIGGERRIGHT ) {
                            gamepad.digitalR2 = false;
                        }
                    } else {
                        if( xAxis == SDL_CONTROLLER_AXIS_TRIGGERLEFT ) {
                            gamepad.digitalL2 = true;
                        }

                        if( xAxis == SDL_CONTROLLER_AXIS_TRIGGERRIGHT ) {
                            gamepad.digitalR2 = true;
                        }
                    }
                }
            }

            // Apply deadzones to all joystick axes
            // Used only when detecting input for remapping
            {
                for( int i = 0; i < 16; i++ ) {
                    qreal deadzoneRadius = deadzones[ GUID ][ i ];
                    qreal coord = gamepad.joystickAxis[ i ];

                    if( !deadzoneModes[ GUID ][ i ] ) {
                        coord += 32768;
                    }

                    if( !( qAbs( coord ) > deadzoneRadius ) ) {
                        gamepad.joystickAxis[ i ] = 0;
                    }
                }
            }

            // If ignoreMode is set, the user hasn't let go of the button they were remapping to
            // Do not let the button go through until they let go
            {
                if( ignoreMode && ignoreModeGUID == GUID && ignoreModeInstanceID == gamepad.instanceID ) {
                    if( ignoreModeVal.first == BUTTON ) {
                        if( gamepad.joystickButton[ ignoreModeVal.second.first ] == SDL_PRESSED ) {
                            gamepad.joystickButton[ ignoreModeVal.second.first ] = SDL_RELEASED;
                        } else {
                            ignoreMode = false;
                        }
                    } else if( ignoreModeVal.first == HAT ) {
                        if( gamepad.joystickHat[ ignoreModeVal.second.first ] != SDL_HAT_CENTERED ) {
                            gamepad.joystickHat[ ignoreModeVal.second.first ] = SDL_HAT_CENTERED;
                        } else {
                            ignoreMode = false;
                        }
                    } else if( ignoreModeVal.first == AXIS ) {
                        if( gamepad.joystickAxis[ ignoreModeVal.second.first ] != 0 ) {
                            gamepad.joystickAxis[ ignoreModeVal.second.first ] = 0;
                        } else {
                            ignoreMode = false;
                        }
                    }
                }
            }

            // If we opened an SDL2 Game controller handle from this class, keep it and inject it into all gamepads we send out
            {
                if( gameControllerHandles[ instanceID ] ) {
                    gamepad.gamecontrollerHandle = gameControllerHandles[ instanceID ];
                }
            }

            // If we are in remap mode, check for a button press from the stored GUID, and remap the stored button to that button
            // All game controller states are cleared past this point if in remap mode
            {
                if( remapMode && GUID == remapModeGUID ) {
                    // Find a button press, the first one we encounter will be the new remapping
                    bool foundInput = false;
                    Key key = remapModeKey;
                    Val value = Val( INVALID, VHat( -1, -1 ) );

                    // Prioritize buttons and hats over analog sticks
                    for( int joystickButton = 0; joystickButton < 256; joystickButton++ ) {
                        if( gamepad.joystickButton[ joystickButton ] == SDL_PRESSED ) {
                            qCDebug( phxInput ).nospace() << "Button b" << joystickButton
                                                          << " from GUID " << GUID << " now activates " << keyToMappingString( key );

                            foundInput = true;
                            value.first = BUTTON;
                            value.second = VHat( joystickButton, -1 );
                            break;
                        }
                    }

                    for( int joystickHat = 0; joystickHat < 16; joystickHat++ ) {
                        if( gamepad.joystickHat[ joystickHat ] != SDL_HAT_CENTERED ) {
                            qCDebug( phxInput ).nospace() << "Hat h" << joystickHat << "." << gamepad.joystickHat[ joystickHat ]
                                                          << " from GUID " << GUID << " now activates " << keyToMappingString( key );
                            foundInput = true;
                            value.first = HAT;
                            value.second = VHat( joystickHat, gamepad.joystickHat[ joystickHat ] );
                            break;
                        }
                    }

                    for( int joystickAxis = 0; joystickAxis < 16; joystickAxis++ ) {
                        if( gamepad.joystickAxis[ joystickAxis ] != 0 ) {
                            qCDebug( phxInput ).nospace() << "Axis a" << joystickAxis
                                                          << " from GUID " << GUID << " now activates " << keyToMappingString( key );
                            foundInput = true;
                            value.first = AXIS;
                            value.second = VHat( joystickAxis, -1 );
                            break;
                        }
                    }

                    if( foundInput ) {
                        // Store the new remapping internally
                        gameControllerToJoystick[ GUID ][ remapModeKey ] = value;

                        // Tell SDL2 about it
                        QString mappingString;
                        QString platform( SDL_GetPlatform() );
                        {
                            QString friendlyName = QString( SDL_JoystickName( gamepad.joystickHandle ) );

                            mappingString.append( GUID ).append( "," ).append( friendlyName ).append( "," );

                            for( Key key : gameControllerToJoystick[ GUID ].keys() ) {
                                if( gameControllerToJoystick[ GUID ][ key ].first != INVALID ) {
                                    mappingString.append( keyToMappingString( key ) ).append( ':' )
                                    .append( valToMappingString( gameControllerToJoystick[ GUID ][ key ] ) ).append( ',' );
                                }
                            }


                            mappingString.append( "platform:" ).append( platform ).append( "," );
                            qDebug().nospace() << mappingString;

                            // Give SDL the new mapping string
                            SDL_GameControllerAddMapping( mappingString.toUtf8().constData() );

                            // If this is not a game controller, reopen as one
                            SDL_GameController *gamecontrollerHandle = nullptr;

                            if( !gameControllerHandles[ instanceID ] ) {
                                gamecontrollerHandle = SDL_GameControllerOpen( joystickID );
                                gamepad.gamecontrollerHandle = gamecontrollerHandle;
                                // Store internally so we can inject it into all future events from this instanceID
                                gameControllerHandles[ instanceID ] = gamecontrollerHandle;
                                qDebug() << "Opened newly remapped joystick as a game controller:" << gamecontrollerHandle;
                            }
                        }

                        // Store this mapping to disk
                        {
                            if( !userDataPath.isEmpty() ) {
                                QFile mappingFile( userDataPath + "/gamecontrollerdb.txt" );

                                mappingFile.open( QIODevice::ReadWrite | QIODevice::Text );
                                QByteArray mappingFileData = mappingFile.readAll();

                                if( !mappingFile.isOpen() ) {
                                    qWarning() << "Unable to open mapping file for reading" << mappingFile.errorString();
                                }

                                mappingFile.close();

                                QTextStream mappingFileStreamIn( &mappingFileData );
                                mappingFileStreamIn.setCodec( "UTF-8" );

                                mappingFile.open( QIODevice::WriteOnly | QIODevice::Text );

                                if( !mappingFile.isOpen() ) {
                                    qWarning() << "Unable to open mapping file for writing" << mappingFile.errorString();
                                }

                                QTextStream mappingFileStreamOut( &mappingFile );
                                mappingFileStreamOut.setCodec( "UTF-8" );

                                QString line = "";

                                while( !line.isNull() ) {
                                    line = mappingFileStreamIn.readLine();

                                    // We want to replace the line (any line) for our platform that contains our GUID
                                    // We'll also filter out empty lines
                                    if( line.isEmpty() || ( line.contains( GUID ) && line.contains( platform ) ) ) {
                                        continue;
                                    }

                                    mappingFileStreamOut << line << endl;
                                }

                                mappingFileStreamOut << mappingString << endl;
                                mappingFile.close();
                            } else {
                                qWarning() << "Unable to open controller mapping file, user data path not set";
                            }
                        }

                        // End remap mode, start ignore mode
                        {
                            remapMode = false;
                            ignoreMode = true;
                            ignoreModeGUID = GUID;
                            ignoreModeVal = value;
                            ignoreModeInstanceID = gamepad.instanceID;
                        }

                        // Tell the model we're done
                        {
                            emit setMapping( GUID, keyToMappingString( key ), valToFriendlyString( value ) );
                            emit remappingEnded();
                        }
                    }

                    // Clear all game controller states (joystick states are untouched)
                    for( int i = 0; i < SDL_CONTROLLER_BUTTON_MAX; i++ ) {
                        gamepad.button[ i ] = 0;
                    }

                    for( int i = 0; i < SDL_CONTROLLER_AXIS_MAX; i++ ) {
                        gamepad.axis[ i ] = 0;
                    }
                } else if( remapMode ) {
                    // Clear all gamepad states
                    for( int i = 0; i < SDL_CONTROLLER_BUTTON_MAX; i++ ) {
                        gamepad.button[ i ] = 0;
                    }

                    for( int i = 0; i < SDL_CONTROLLER_AXIS_MAX; i++ ) {
                        gamepad.axis[ i ] = 0;
                    }
                }
            }

            // OR all joystick button, hat and analog states together by GUID for RemapperModel to indicate presses
            {
                for( int i = 0; i < 256; i++ ) {
                    pressed[ GUID ] |= gamepad.joystickButton[ i ];
                }

                for( int i = 0; i < 16; i++ ) {
                    pressed[ GUID ] |= ( gamepad.joystickHat[ i ] != SDL_HAT_CENTERED );
                }

                for( int i = 0; i < 16; i++ ) {
                    pressed[ GUID ] |= ( gamepad.joystickAxis[ i ] != 0 );
                }
            }

            // Apply axis to d-pad, if enabled
            // This will always be enabled if we're not currently playing so GlobalGamepad can use the analog stick
            {
                if( analogToDpad[ GUID ] || !playing ) {
                    // TODO: Support other axes?
                    int xAxis = SDL_CONTROLLER_AXIS_LEFTX;
                    int yAxis = SDL_CONTROLLER_AXIS_LEFTY;

                    // TODO: Let user configure these

                    qreal threshold = 16384.0;

                    // Size in degrees of the arc covering and centered around each cardinal direction
                    // If <90, there will be gaps in the diagonals
                    // If >180, this code will always produce diagonal inputs
                    qreal rangeDegrees = 180.0 - 45.0;

                    // Get axis coords in cartesian coords
                    // Bottom right is positive -> top right is positive
                    qreal xCoord = gamepad.axis[ xAxis ];
                    qreal yCoord = -gamepad.axis[ yAxis ];

                    // Get radius from center
                    QVector2D position( static_cast<float>( xCoord ), static_cast<float>( yCoord ) );
                    qreal radius = static_cast<qreal>( position.length() );

                    // Get angle in degrees
                    qreal angle = qRadiansToDegrees( qAtan2( yCoord, xCoord ) );

                    if( angle < 0.0 ) {
                        angle += 360.0;
                    }

                    if( radius > threshold ) {
                        qreal halfRange = rangeDegrees / 2.0;

                        if( angle > 90.0 - halfRange && angle < 90.0 + halfRange ) {
                            gamepad.button[ SDL_CONTROLLER_BUTTON_DPAD_UP ] = true;
                        }

                        if( angle > 270.0 - halfRange && angle < 270.0 + halfRange ) {
                            gamepad.button[ SDL_CONTROLLER_BUTTON_DPAD_DOWN ] = true;
                        }

                        if( angle > 180.0 - halfRange && angle < 180.0 + halfRange ) {
                            gamepad.button[ SDL_CONTROLLER_BUTTON_DPAD_LEFT ] = true;
                        }

                        if( angle > 360.0 - halfRange || angle < 0.0 + halfRange ) {
                            gamepad.button[ SDL_CONTROLLER_BUTTON_DPAD_RIGHT ] = true;
                        }
                    }
                }
            }

            // Apply d-pad to axis, if enabled
            {
                if( dpadToAnalog[ GUID ] ) {
                    gamepad = mapDpadToAnalog( gamepad );
                }
            }

            // Send updated data out
            {
                // Copy current gamepad into buffer
                this->mutex.lock();
                gamepadBuffer[ gamepadBufferIndex ] = gamepad;
                this->mutex.unlock();

                // Send buffer on its way
                emit dataOut( DataType::Input, &( this->mutex ),
                              reinterpret_cast<void *>( &gamepadBuffer[ gamepadBufferIndex ] ), 0,
                              nodeCurrentTime() );

                // Increment the index
                gamepadBufferIndex = ( gamepadBufferIndex + 1 ) % 100;
            }
            break;
        }

        case DataType::KeyboardInput: {
            // Unpack keyboard states and write to gamepad according to remap data
            {
                mutex->lock();
                KeyboardState keyboard = *reinterpret_cast<KeyboardState *>( data );

                for( int i = keyboard.head; i < keyboard.tail; i = ( i + 1 ) % 128 ) {
                    int key = keyboard.key[ i ];
                    bool pressed = keyboard.pressed[ i ];

                    if( keyboardKeyToSDLButton.contains( key ) ) {
                        keyboardGamepad.button[ keyboardKeyToSDLButton[ key ] ] = pressed ? SDL_PRESSED : SDL_RELEASED;
                    }
                }

                mutex->unlock();
            }

            // OR all key states together and store that value
            for( int i = 0; i < SDL_CONTROLLER_BUTTON_MAX; i++ ) {
                keyboardKeyPressed |= keyboardGamepad.button[ i ];
            }

            // Apply d-pad to axis, if enabled
            if( dpadToAnalogKeyboard ) {
                keyboardGamepad = mapDpadToAnalog( keyboardGamepad, true );
            }

            // Send gamepad on its way
            {
                // Copy current gamepad into buffer
                this->mutex.lock();
                gamepadBuffer[ gamepadBufferIndex ] = keyboardGamepad;
                this->mutex.unlock();

                // Send buffer on its way
                emit dataOut( DataType::Input, &( this->mutex ),
                              reinterpret_cast< void * >( &gamepadBuffer[ gamepadBufferIndex ] ), 0,
                              nodeCurrentTime() );

                // Increment the index
                gamepadBufferIndex = ( gamepadBufferIndex + 1 ) % 100;
            }
            break;
        }

        default: {
            emit dataOut( type, mutex, data, bytes, timeStamp );
            break;
        }
    }
}