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; }
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; }
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; } } }